diff options
Diffstat (limited to '')
641 files changed, 118883 insertions, 0 deletions
diff --git a/third_party/libwebrtc/rtc_base/BUILD.gn b/third_party/libwebrtc/rtc_base/BUILD.gn new file mode 100644 index 0000000000..3d57e3bfb4 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/BUILD.gn @@ -0,0 +1,2227 @@ +# Copyright (c) 2014 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") + +if (is_android) { + import("//build/config/android/config.gni") + import("//build/config/android/rules.gni") +} + +if (!rtc_build_ssl) { + config("external_ssl_library") { + assert(rtc_ssl_root != "", + "You must specify rtc_ssl_root when rtc_build_ssl==0.") + include_dirs = [ rtc_ssl_root ] + } +} + +rtc_source_set("protobuf_utils") { + sources = [ "protobuf_utils.h" ] + if (rtc_enable_protobuf) { + public_configs = [ "//third_party/protobuf:protobuf_config" ] + deps = [ "//third_party/protobuf:protobuf_lite" ] + } +} + +rtc_source_set("bitstream_reader") { + sources = [ + "bitstream_reader.cc", + "bitstream_reader.h", + ] + deps = [ + ":checks", + ":safe_conversions", + "../api:array_view", + ] + absl_deps = [ + "//third_party/abseil-cpp/absl/base:core_headers", + "//third_party/abseil-cpp/absl/numeric:bits", + "//third_party/abseil-cpp/absl/strings", + ] +} + +rtc_source_set("compile_assert_c") { + sources = [ "compile_assert_c.h" ] +} + +rtc_source_set("ignore_wundef") { + sources = [ "ignore_wundef.h" ] +} + +rtc_source_set("untyped_function") { + sources = [ "untyped_function.h" ] + deps = [ "system:assume" ] +} + +rtc_source_set("callback_list") { + sources = [ + "callback_list.cc", + "callback_list.h", + ] + deps = [ + ":checks", + ":untyped_function", + "../api:function_view", + "system:assume", + "system:inline", + "system:rtc_export", + ] +} + +rtc_source_set("buffer") { + visibility = [ "*" ] + sources = [ "buffer.h" ] + deps = [ + ":checks", + ":type_traits", + ":zero_memory", + "../api:array_view", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/strings" ] +} + +rtc_source_set("byte_order") { + visibility = [ "*" ] + sources = [ "byte_order.h" ] + deps = [ "system:arch" ] +} + +rtc_source_set("mod_ops") { + visibility = [ "*" ] + sources = [ "numerics/mod_ops.h" ] + deps = [ ":checks" ] +} + +rtc_source_set("moving_max_counter") { + visibility = [ "*" ] + sources = [ "numerics/moving_max_counter.h" ] + deps = [ ":checks" ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] +} + +rtc_source_set("one_time_event") { + visibility = [ "*" ] + sources = [ "one_time_event.h" ] + deps = [ "synchronization:mutex" ] +} + +rtc_source_set("strong_alias") { + visibility = [ "*" ] + sources = [ "strong_alias.h" ] +} + +rtc_source_set("swap_queue") { + visibility = [ "*" ] + sources = [ "swap_queue.h" ] + deps = [ ":checks" ] + absl_deps = [ "//third_party/abseil-cpp/absl/base:core_headers" ] +} + +rtc_source_set("macromagic") { + sources = [ + "arraysize.h", + "thread_annotations.h", + ] + deps = [ "system:arch" ] +} + +rtc_library("bit_buffer") { + visibility = [ "*" ] + sources = [ + "bit_buffer.cc", + "bit_buffer.h", + ] + deps = [ + ":checks", + "../api/units:data_size", + ] + absl_deps = [ + "//third_party/abseil-cpp/absl/numeric:bits", + "//third_party/abseil-cpp/absl/strings:strings", + ] +} + +rtc_library("byte_buffer") { + visibility = [ "*" ] + sources = [ + "byte_buffer.cc", + "byte_buffer.h", + ] + deps = [ + ":buffer", + ":byte_order", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/strings" ] +} + +rtc_library("buffer_queue") { + visibility = [ "*" ] + sources = [ + "buffer_queue.cc", + "buffer_queue.h", + ] + deps = [ + ":buffer", + ":macromagic", + "../api:sequence_checker", + "system:no_unique_address", + ] +} + +rtc_library("copy_on_write_buffer") { + visibility = [ "*" ] + sources = [ + "copy_on_write_buffer.cc", + "copy_on_write_buffer.h", + ] + deps = [ + ":buffer", + ":checks", + ":refcount", + ":type_traits", + "../api:scoped_refptr", + "system:rtc_export", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/strings" ] +} + +rtc_library("event_tracer") { + visibility = [ "*" ] + sources = [ + "event_tracer.cc", + "event_tracer.h", + "trace_event.h", + ] + deps = [ + ":checks", + ":logging", + ":macromagic", + ":platform_thread", + ":platform_thread_types", + ":rtc_event", + ":timeutils", + "../api:sequence_checker", + "synchronization:mutex", + "system:rtc_export", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/strings" ] +} + +rtc_library("histogram_percentile_counter") { + visibility = [ "*" ] + sources = [ + "numerics/histogram_percentile_counter.cc", + "numerics/histogram_percentile_counter.h", + ] + deps = [ ":checks" ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] +} + +rtc_library("race_checker") { + visibility = [ "*" ] + sources = [ + "race_checker.cc", + "race_checker.h", + ] + deps = [ + ":checks", + ":macromagic", + ":platform_thread_types", + ] +} + +rtc_library("random") { + visibility = [ "*" ] + sources = [ + "random.cc", + "random.h", + ] + deps = [ + ":checks", + ":safe_conversions", + ] +} + +rtc_library("bitrate_tracker") { + visibility = [ "*" ] + sources = [ + "bitrate_tracker.cc", + "bitrate_tracker.h", + ] + deps = [ + ":rate_statistics", + "../api/units:data_rate", + "../api/units:data_size", + "../api/units:time_delta", + "../api/units:timestamp", + "system:rtc_export", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] +} + +rtc_library("frequency_tracker") { + visibility = [ "*" ] + sources = [ + "frequency_tracker.cc", + "frequency_tracker.h", + ] + deps = [ + ":rate_statistics", + "../api/units:frequency", + "../api/units:time_delta", + "../api/units:timestamp", + "system:rtc_export", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] +} + +rtc_library("rate_statistics") { + # TODO(bugs.webrtc.org/13756): Restrict visibility to private when all usage + # of the RateStatistics is migrated to BitrateTracker and FrequencyTracker. + visibility = [ "*" ] + sources = [ + "rate_statistics.cc", + "rate_statistics.h", + ] + deps = [ + ":checks", + ":logging", + ":safe_conversions", + "system:rtc_export", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] +} + +rtc_library("rate_tracker") { + visibility = [ "*" ] + sources = [ + "rate_tracker.cc", + "rate_tracker.h", + ] + deps = [ + ":checks", + ":timeutils", + ] +} + +rtc_library("sample_counter") { + visibility = [ "*" ] + sources = [ + "numerics/sample_counter.cc", + "numerics/sample_counter.h", + ] + deps = [ + ":checks", + ":safe_conversions", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] +} + +if (!build_with_mozilla) { # See Bug 1820869. +rtc_library("timestamp_aligner") { + visibility = [ "*" ] + sources = [ + "timestamp_aligner.cc", + "timestamp_aligner.h", + ] + deps = [ + ":checks", + ":logging", + ":timeutils", + "system:rtc_export", + ] +} +} + +rtc_library("zero_memory") { + visibility = [ "*" ] + sources = [ + "zero_memory.cc", + "zero_memory.h", + ] + deps = [ + ":checks", + "../api:array_view", + ] +} + +rtc_library("platform_thread_types") { + sources = [ + "platform_thread_types.cc", + "platform_thread_types.h", + ] + deps = [ + ":checks", + ":macromagic", + ] +} + +rtc_source_set("refcount") { + visibility = [ "*" ] + sources = [ + "ref_count.h", + "ref_counted_object.h", + "ref_counter.h", + ] + deps = [ + ":macromagic", + "../api:scoped_refptr", + ] +} + +rtc_library("criticalsection") { + sources = [ + "deprecated/recursive_critical_section.cc", + "deprecated/recursive_critical_section.h", + ] + deps = [ + ":checks", + ":macromagic", + ":platform_thread_types", + "synchronization:yield", + "system:unused", + ] +} + +rtc_library("platform_thread") { + sources = [ + "platform_thread.cc", + "platform_thread.h", + ] + deps = [ + ":checks", + ":macromagic", + ":platform_thread_types", + ":rtc_event", + ":timeutils", + "../api:sequence_checker", + ] + absl_deps = [ + "//third_party/abseil-cpp/absl/memory", + "//third_party/abseil-cpp/absl/strings", + "//third_party/abseil-cpp/absl/types:optional", + ] +} + +rtc_library("rtc_event") { + if (build_with_chromium) { + sources = [ + "../../webrtc_overrides/rtc_base/event.cc", + "../../webrtc_overrides/rtc_base/event.h", + ] + deps = [ + ":checks", + "../api/units:time_delta", + "system:rtc_export", # Only Chromium's rtc::Event use RTC_EXPORT. + "//base", # Dependency on chromium's waitable_event. + ] + } else { + sources = [ + "event.cc", + "event.h", + ] + deps = [ + ":checks", + ":timeutils", + "../api/units:time_delta", + "synchronization:yield_policy", + "system:warn_current_thread_is_deadlocked", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] + } +} + +config("chromium_logging_config") { + defines = [ "LOGGING_INSIDE_WEBRTC" ] +} + +rtc_library("logging") { + visibility = [ "*" ] + libs = [] + deps = [ + ":checks", + ":macromagic", + ":platform_thread_types", + ":stringutils", + ":timeutils", + "../api/units:timestamp", + "synchronization:mutex", + ] + absl_deps = [ + "//third_party/abseil-cpp/absl/base:core_headers", + "//third_party/abseil-cpp/absl/meta:type_traits", + "//third_party/abseil-cpp/absl/strings", + "//third_party/abseil-cpp/absl/types:optional", + ] + + # Added to allow including apm_data_dumper.h in rtc_base/logging.cc + # for Mozilla controlling aec logging from about:webrtc. + if (build_with_mozilla) { + configs += [ "../modules/audio_processing:apm_debug_dump" ] + } + + if (build_with_chromium) { + # Dependency on chromium's logging (in //base). + deps += [ "//base" ] + sources = [ + "../../webrtc_overrides/rtc_base/logging.cc", + "../../webrtc_overrides/rtc_base/logging.h", + ] + + # This macro needs to be both present in all WebRTC targets (see its + # definition in //BUILD.gn but also propagated to all the targets + # depending on the Chromium component defined in + # //third_party/webrtc_overrides:webrtc_component. This public_config + # allows GN to propagate the macro accordingly. + public_configs = [ ":chromium_logging_config" ] + } else { + sources = [ + "logging.cc", + "logging.h", + ] + deps += [ "system:inline" ] + + if (is_mac) { + frameworks = [ "Foundation.framework" ] + } + + if (is_android) { + libs += [ "log" ] + } + } +} + +rtc_library("checks") { + # TODO(bugs.webrtc.org/9607): This should not be public. + visibility = [ "*" ] + libs = [] + sources = [ + "checks.cc", + "checks.h", + ] + deps = [ + ":safe_compare", + "../api:scoped_refptr", + "system:inline", + "system:rtc_export", + ] + if (build_with_chromium) { + sources += [ "../../webrtc_overrides/rtc_base/checks_overrides.cc" ] + deps += [ "//base" ] + } + absl_deps = [ + "//third_party/abseil-cpp/absl/meta:type_traits", + "//third_party/abseil-cpp/absl/strings", + ] + if (is_android) { + libs += [ "log" ] + } +} + +rtc_library("rate_limiter") { + sources = [ + "rate_limiter.cc", + "rate_limiter.h", + ] + deps = [ + ":macromagic", + ":rate_statistics", + "../system_wrappers", + "synchronization:mutex", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] +} + +rtc_source_set("sanitizer") { + sources = [ "sanitizer.h" ] + absl_deps = [ "//third_party/abseil-cpp/absl/meta:type_traits" ] +} + +rtc_source_set("bounded_inline_vector") { + public = [ "bounded_inline_vector.h" ] + sources = [ "bounded_inline_vector_impl.h" ] + deps = [ ":checks" ] +} + +rtc_source_set("divide_round") { + sources = [ "numerics/divide_round.h" ] + deps = [ + ":checks", + ":safe_compare", + ] +} + +rtc_source_set("safe_compare") { + sources = [ "numerics/safe_compare.h" ] + deps = [ ":type_traits" ] +} + +rtc_source_set("safe_minmax") { + sources = [ "numerics/safe_minmax.h" ] + deps = [ + ":checks", + ":safe_compare", + ":type_traits", + ] +} + +rtc_source_set("safe_conversions") { + sources = [ + "numerics/safe_conversions.h", + "numerics/safe_conversions_impl.h", + ] + deps = [ ":checks" ] +} + +rtc_library("timeutils") { + visibility = [ "*" ] + sources = [ + "system_time.cc", + "system_time.h", + "time_utils.cc", + "time_utils.h", + ] + deps = [ + ":checks", + ":safe_conversions", + ":stringutils", + "system:rtc_export", + ] + + if (rtc_exclude_system_time) { + defines = [ "WEBRTC_EXCLUDE_SYSTEM_TIME" ] + } + + libs = [] + if (is_win) { + libs += [ "winmm.lib" ] + deps += [ ":win32" ] + } +} + +rtc_library("stringutils") { + sources = [ + "string_encode.cc", + "string_encode.h", + "string_to_number.cc", + "string_to_number.h", + "string_utils.cc", + "string_utils.h", + "strings/string_builder.cc", + "strings/string_builder.h", + "strings/string_format.cc", + "strings/string_format.h", + ] + deps = [ + ":checks", + ":macromagic", + ":safe_minmax", + "../api:array_view", + ] + absl_deps = [ + "//third_party/abseil-cpp/absl/strings", + "//third_party/abseil-cpp/absl/types:optional", + ] +} + +rtc_library("audio_format_to_string") { + sources = [ + "strings/audio_format_to_string.cc", + "strings/audio_format_to_string.h", + ] + deps = [ + ":stringutils", + "../api/audio_codecs:audio_codecs_api", + ] +} + +rtc_source_set("type_traits") { + sources = [ "type_traits.h" ] +} + +rtc_library("rtc_task_queue") { + visibility = [ "*" ] + sources = [ + "task_queue.cc", + "task_queue.h", + ] + deps = [ + ":macromagic", + "../api/task_queue", + "system:rtc_export", + ] + absl_deps = [ + "//third_party/abseil-cpp/absl/functional:any_invocable", + "//third_party/abseil-cpp/absl/memory", + ] +} + +rtc_source_set("rtc_operations_chain") { + visibility = [ "*" ] + sources = [ + "operations_chain.cc", + "operations_chain.h", + ] + deps = [ + ":checks", + ":macromagic", + ":refcount", + "../api:make_ref_counted", + "../api:refcountedbase", + "../api:scoped_refptr", + "../api:sequence_checker", + "system:no_unique_address", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] +} + +if (rtc_enable_libevent) { + rtc_library("rtc_task_queue_libevent") { + visibility = [ "../api/task_queue:default_task_queue_factory" ] + sources = [ + "task_queue_libevent.cc", + "task_queue_libevent.h", + ] + deps = [ + ":checks", + ":logging", + ":macromagic", + ":platform_thread", + ":platform_thread_types", + ":safe_conversions", + ":timeutils", + "../api/task_queue", + "../api/units:time_delta", + "synchronization:mutex", + ] + absl_deps = [ + "//third_party/abseil-cpp/absl/container:inlined_vector", + "//third_party/abseil-cpp/absl/functional:any_invocable", + "//third_party/abseil-cpp/absl/strings", + ] + if (rtc_build_libevent) { + deps += [ "//third_party/libevent" ] + } + } +} + +if (is_mac || is_ios) { + rtc_library("rtc_task_queue_gcd") { + visibility = [ "../api/task_queue:default_task_queue_factory" ] + sources = [ + "task_queue_gcd.cc", + "task_queue_gcd.h", + ] + deps = [ + ":checks", + ":logging", + "../api:location", + "../api/task_queue", + "../api/units:time_delta", + "synchronization:mutex", + "system:gcd_helpers", + ] + absl_deps = [ + "//third_party/abseil-cpp/absl/functional:any_invocable", + "//third_party/abseil-cpp/absl/strings", + ] + } +} + +if (is_win) { + rtc_library("rtc_task_queue_win") { + visibility = [ "../api/task_queue:default_task_queue_factory" ] +# See Bug 1797161 for more info. Remove from build until win32k +# usage is removed. +if (!build_with_mozilla) { + sources = [ + "task_queue_win.cc", + "task_queue_win.h", + ] +} + deps = [ + ":checks", + ":logging", + ":macromagic", + ":platform_thread", + ":rtc_event", + ":safe_conversions", + ":timeutils", + "../api/task_queue", + "../api/units:time_delta", + "../api/units:timestamp", + "synchronization:mutex", + ] + absl_deps = [ + "//third_party/abseil-cpp/absl/functional:any_invocable", + "//third_party/abseil-cpp/absl/strings", + "//third_party/abseil-cpp/absl/types:optional", + ] + } +} + +rtc_library("rtc_task_queue_stdlib") { + sources = [ + "task_queue_stdlib.cc", + "task_queue_stdlib.h", + ] + deps = [ + ":checks", + ":divide_round", + ":logging", + ":macromagic", + ":platform_thread", + ":rtc_event", + ":safe_conversions", + ":timeutils", + "../api/task_queue", + "../api/units:time_delta", + "synchronization:mutex", + ] + absl_deps = [ + "//third_party/abseil-cpp/absl/functional:any_invocable", + "//third_party/abseil-cpp/absl/strings", + ] +} + +if (rtc_include_tests) { + rtc_library("task_queue_stdlib_unittest") { + testonly = true + + sources = [ "task_queue_stdlib_unittest.cc" ] + deps = [ + ":gunit_helpers", + ":rtc_task_queue_stdlib", + "../api/task_queue:task_queue_test", + "../test:test_main", + "../test:test_support", + ] + } +} + +rtc_library("weak_ptr") { + sources = [ + "weak_ptr.cc", + "weak_ptr.h", + ] + deps = [ + ":refcount", + "../api:scoped_refptr", + "../api:sequence_checker", + "system:no_unique_address", + ] +} + +rtc_library("rtc_numerics") { + sources = [ + "numerics/event_based_exponential_moving_average.cc", + "numerics/event_based_exponential_moving_average.h", + "numerics/exp_filter.cc", + "numerics/exp_filter.h", + "numerics/math_utils.h", + "numerics/moving_average.cc", + "numerics/moving_average.h", + "numerics/moving_percentile_filter.h", + "numerics/percentile_filter.h", + "numerics/running_statistics.h", + "numerics/sequence_number_unwrapper.h", + "numerics/sequence_number_util.h", + ] + deps = [ + ":checks", + ":mod_ops", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] +} + +rtc_library("rtc_stats_counters") { + sources = [ + "numerics/event_rate_counter.cc", + "numerics/event_rate_counter.h", + "numerics/sample_stats.cc", + "numerics/sample_stats.h", + ] + deps = [ + "../api/numerics", + "../api/units:data_rate", + "../api/units:time_delta", + "../api/units:timestamp", + ] + absl_deps = [] +} + +config("rtc_json_suppressions") { + if (!is_win || is_clang) { + cflags_cc = [ + # TODO(bugs.webrtc.org/10814): Remove -Wno-undef as soon as it get + # removed upstream. + "-Wno-undef", + ] + } +} + +rtc_library("rtc_json") { + testonly = true + public_configs = [ ":rtc_json_suppressions" ] + defines = [] + sources = [ + "strings/json.cc", + "strings/json.h", + ] + deps = [ ":stringutils" ] +if (!build_with_mozilla) { + all_dependent_configs = [ "//third_party/jsoncpp:jsoncpp_config" ] +} + if (rtc_build_json) { + deps += [ "//third_party/jsoncpp" ] + } else { + include_dirs = [ "$rtc_jsoncpp_root" ] + } + absl_deps = [ "//third_party/abseil-cpp/absl/strings" ] +} + +rtc_library("net_helpers") { + visibility = [ "*" ] + sources = [ + "net_helpers.cc", + "net_helpers.h", + ] + deps = [ "system:rtc_export" ] + if (is_android) { + deps += [ ":ifaddrs_android" ] + } + if (is_win) { + deps += [ + ":win32", + "win:windows_version", + ] + } + absl_deps = [ "//third_party/abseil-cpp/absl/strings" ] +} + +rtc_library("net_test_helpers") { + # TODO(mbonadei): Enable once net_helpers don't depend + # on this target anymore. + # testonly = true + sources = [ + "net_test_helpers.cc", + "net_test_helpers.h", + ] + deps = [ "system:rtc_export" ] + if (is_android) { + deps += [ ":ifaddrs_android" ] + } + if (is_win) { + deps += [ + ":win32", + "win:windows_version", + ] + } +} + +rtc_library("async_resolver_interface") { + visibility = [ "*" ] + sources = [ + "async_resolver_interface.cc", + "async_resolver_interface.h", + ] + deps = [ + ":checks", + ":socket_address", + "system:rtc_export", + "third_party/sigslot", + ] +} + +rtc_library("async_dns_resolver") { + sources = [ + "async_dns_resolver.cc", + "async_dns_resolver.h", + ] + deps = [ + ":logging", + ":macromagic", + ":platform_thread", + ":refcount", + "../api:async_dns_resolver", + "../api:make_ref_counted", + "../api:sequence_checker", + "../api/task_queue:pending_task_safety_flag", + "system:rtc_export", + ] +} + +rtc_library("async_dns_resolver_unittests") { + testonly = true + sources = [ "async_dns_resolver_unittest.cc" ] + deps = [ + ":async_dns_resolver", + ":gunit_helpers", + "../test:run_loop", + "../test:test_support", + ] +} + +rtc_library("ip_address") { + visibility = [ "*" ] + sources = [ + "ip_address.cc", + "ip_address.h", + ] + deps = [ + ":byte_order", + ":net_helpers", + ":stringutils", + "system:rtc_export", + ] + if (is_win) { + deps += [ ":win32" ] + } + absl_deps = [ "//third_party/abseil-cpp/absl/strings" ] +} + +rtc_library("socket_address") { + visibility = [ "*" ] + sources = [ + "socket_address.cc", + "socket_address.h", + ] + deps = [ + ":byte_order", + ":checks", + ":ip_address", + ":logging", + ":net_helpers", + ":safe_conversions", + ":stringutils", + "system:rtc_export", + ] + if (is_win) { + deps += [ ":win32" ] + } + absl_deps = [ "//third_party/abseil-cpp/absl/strings" ] +} + +rtc_library("null_socket_server") { + sources = [ + "null_socket_server.cc", + "null_socket_server.h", + ] + deps = [ + ":checks", + ":rtc_event", + ":socket", + ":socket_server", + "../api/units:time_delta", + "system:rtc_export", + ] +} + +rtc_source_set("socket_server") { + visibility = [ "*" ] + sources = [ "socket_server.h" ] + deps = [ + ":rtc_event", + ":socket_factory", + "../api/units:time_delta", + ] +} + +rtc_library("threading") { + visibility = [ "*" ] + + sources = [ + "async_resolver.cc", + "async_resolver.h", + "internal/default_socket_server.cc", + "internal/default_socket_server.h", + "network_monitor.cc", + "network_monitor.h", + "network_monitor_factory.cc", + "network_monitor_factory.h", + "physical_socket_server.cc", + "physical_socket_server.h", + "thread.cc", + "thread.h", + ] + absl_deps = [ + "//third_party/abseil-cpp/absl/algorithm:container", + "//third_party/abseil-cpp/absl/base:core_headers", + "//third_party/abseil-cpp/absl/cleanup", + "//third_party/abseil-cpp/absl/functional:any_invocable", + "//third_party/abseil-cpp/absl/memory", + "//third_party/abseil-cpp/absl/strings", + ] + deps = [ + ":async_dns_resolver", + ":async_resolver_interface", + ":byte_order", + ":checks", + ":criticalsection", + ":event_tracer", + ":ip_address", + ":logging", + ":macromagic", + ":network_constants", + ":null_socket_server", + ":platform_thread", + ":platform_thread_types", + ":refcount", + ":rtc_event", + ":rtc_task_queue", + ":socket", + ":socket_address", + ":socket_server", + ":timeutils", + "../api:async_dns_resolver", + "../api:function_view", + "../api:location", + "../api:refcountedbase", + "../api:scoped_refptr", + "../api:sequence_checker", + "../api/task_queue", + "../api/task_queue:pending_task_safety_flag", + "../api/units:time_delta", + "../system_wrappers:field_trial", + "synchronization:mutex", + "system:no_unique_address", + "system:rtc_export", + "third_party/sigslot", + ] + if (is_android) { + deps += [ ":ifaddrs_android" ] + } + if (is_win) { + deps += [ ":win32" ] + } + if (is_mac || is_ios) { + deps += [ "system:cocoa_threading" ] + } +} + +rtc_source_set("socket_factory") { + sources = [ "socket_factory.h" ] + deps = [ ":socket" ] +} + +rtc_library("async_socket") { + sources = [ + "async_socket.cc", + "async_socket.h", + ] + deps = [ + ":checks", + ":socket", + ":socket_address", + "third_party/sigslot", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/memory" ] +} + +rtc_library("socket") { + sources = [ + "socket.cc", + "socket.h", + ] + deps = [ + ":macromagic", + ":socket_address", + "third_party/sigslot", + ] + if (is_win) { + deps += [ ":win32" ] + } +} + +rtc_source_set("network_constants") { + visibility = [ "*" ] + sources = [ + "network_constants.cc", + "network_constants.h", + ] + deps = [ ":checks" ] +} + +if (is_android) { + rtc_library("ifaddrs_android") { + sources = [ + "ifaddrs_android.cc", + "ifaddrs_android.h", + ] + libs = [ + "log", + "GLESv2", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/cleanup" ] + } +} + +if (is_win) { + rtc_library("win32") { + sources = [ + "win32.cc", + "win32.h", + ] + + deps = [ + ":byte_order", + ":checks", + ":macromagic", + ":stringutils", + ] + + libs = [ + "crypt32.lib", + "iphlpapi.lib", + "secur32.lib", + ] + + defines = [ "_CRT_NONSTDC_NO_DEPRECATE" ] + } +} + +rtc_library("ifaddrs_converter") { + sources = [] + deps = [ + ":checks", + ":ip_address", + ":logging", + ] + + if (is_android) { + deps += [ ":ifaddrs_android" ] + } + + if (is_ios || is_mac) { + sources += [ "mac_ifaddrs_converter.cc" ] + } + + if (is_posix || is_fuchsia) { + sources += [ + "ifaddrs_converter.cc", + "ifaddrs_converter.h", + ] + } +} + +rtc_library("rolling_accumulator") { + sources = [ "rolling_accumulator.h" ] + deps = [ + ":checks", + ":rtc_numerics", + ] +} + +if (is_win) { + rtc_library("win32_socket_init") { + sources = [ "win32_socket_init.h" ] + deps = [ ":win32" ] + } +} + +if (!build_with_chromium) { + rtc_library("log_sinks") { + visibility = [ "*" ] + sources = [ + "log_sinks.cc", + "log_sinks.h", + ] + deps = [ + ":checks", + ":file_rotating_stream", + ":logging", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/strings" ] + } +} + +rtc_library("network") { +if (!build_with_mozilla) { + visibility = [ "*" ] + sources = [ + "network.cc", + "network.h", + ] + deps = [ + ":checks", + ":ifaddrs_converter", + ":ip_address", + ":logging", + ":macromagic", + ":mdns_responder_interface", + ":socket", + ":socket_factory", + ":stringutils", + ":threading", + "../api:array_view", + "../api:field_trials_view", + "../api:sequence_checker", + "../api/task_queue:pending_task_safety_flag", + "../api/transport:field_trial_based_config", + "../api/units:time_delta", + "experiments:field_trial_parser", + "memory:always_valid_pointer", + "system:rtc_export", + "third_party/sigslot", + ] + absl_deps = [ + "//third_party/abseil-cpp/absl/algorithm:container", + "//third_party/abseil-cpp/absl/base:core_headers", + "//third_party/abseil-cpp/absl/memory", + "//third_party/abseil-cpp/absl/strings", + ] + + if (is_win) { + deps += [ ":win32" ] + } +} +} + +rtc_library("socket_address_pair") { +if (!build_with_mozilla) { + sources = [ + "socket_address_pair.cc", + "socket_address_pair.h", + ] + deps = [ ":socket_address" ] +} +} + +rtc_library("net_helper") { +if (!build_with_mozilla) { + visibility = [ "*" ] + sources = [ + "net_helper.cc", + "net_helper.h", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/strings" ] + deps = [ "system:rtc_export" ] +} +} + +rtc_library("socket_adapters") { +if (!build_with_mozilla) { + visibility = [ "*" ] + sources = [ + "socket_adapters.cc", + "socket_adapters.h", + ] + deps = [ + ":async_socket", + ":buffer", + ":byte_buffer", + ":checks", + ":crypt_string", + ":http_common", + ":logging", + ":stringutils", + ":zero_memory", + "../api:array_view", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/strings" ] +} +} + +rtc_library("network_route") { + sources = [ + "network_route.cc", + "network_route.h", + ] + deps = [ + ":network_constants", + ":stringutils", + "system:inline", + ] +} + +rtc_library("async_tcp_socket") { +if (!build_with_mozilla) { + sources = [ + "async_tcp_socket.cc", + "async_tcp_socket.h", + ] + deps = [ + ":async_packet_socket", + ":buffer", + ":byte_order", + ":checks", + ":logging", + ":socket", + ":socket_address", + ":timeutils", + "../api:array_view", + "network:sent_packet", + ] +} +} + +rtc_library("async_udp_socket") { +if (!build_with_mozilla) { + visibility = [ "*" ] + sources = [ + "async_udp_socket.cc", + "async_udp_socket.h", + ] + deps = [ + ":async_packet_socket", + ":checks", + ":logging", + ":macromagic", + ":socket", + ":socket_address", + ":socket_factory", + ":timeutils", + "../api:sequence_checker", + "../system_wrappers:field_trial", + "network:sent_packet", + "system:no_unique_address", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] +} +} + +rtc_library("async_packet_socket") { +if (!build_with_mozilla) { + visibility = [ "*" ] + sources = [ + "async_packet_socket.cc", + "async_packet_socket.h", + ] + deps = [ + ":callback_list", + ":dscp", + ":socket", + ":timeutils", + "../api:sequence_checker", + "network:sent_packet", + "system:no_unique_address", + "system:rtc_export", + "third_party/sigslot", + ] +} +} + +rtc_library("mdns_responder_interface") { + sources = [ "mdns_responder_interface.h" ] + deps = [ ":ip_address" ] + absl_deps = [ "//third_party/abseil-cpp/absl/strings" ] +} + +rtc_library("dscp") { + sources = [ "dscp.h" ] +} + +rtc_library("proxy_info") { +if (!build_with_mozilla) { + visibility = [ "*" ] + sources = [ + "proxy_info.cc", + "proxy_info.h", + ] + deps = [ + ":crypt_string", + ":socket_address", + ] +} +} + +rtc_library("file_rotating_stream") { + sources = [ + "file_rotating_stream.cc", + "file_rotating_stream.h", + ] + deps = [ + ":checks", + ":logging", + ":stringutils", + "system:file_wrapper", + ] + absl_deps = [ + "//third_party/abseil-cpp/absl/algorithm:container", + "//third_party/abseil-cpp/absl/strings", + "//third_party/abseil-cpp/absl/types:optional", + ] +} + +rtc_library("data_rate_limiter") { + sources = [ + "data_rate_limiter.cc", + "data_rate_limiter.h", + ] + deps = [ "system:rtc_export" ] +} + +rtc_library("unique_id_generator") { +if (!build_with_mozilla) { + sources = [ + "unique_id_generator.cc", + "unique_id_generator.h", + ] + deps = [ + ":ssl", + ":stringutils", + "../api:array_view", + "../api:sequence_checker", + "synchronization:mutex", + "system:no_unique_address", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/strings" ] +} +} + +rtc_library("crc32") { + sources = [ + "crc32.cc", + "crc32.h", + ] + deps = [ ":macromagic" ] + absl_deps = [ "//third_party/abseil-cpp/absl/strings" ] +} + +rtc_library("stream") { + visibility = [ "*" ] + sources = [ + "stream.cc", + "stream.h", + ] + deps = [ + ":buffer", + ":checks", + ":threading", + "../api:array_view", + "system:rtc_export", + "third_party/sigslot", + ] +} + +rtc_library("rtc_certificate_generator") { +if (!build_with_mozilla) { + visibility = [ "*" ] + sources = [ + "rtc_certificate_generator.cc", + "rtc_certificate_generator.h", + ] + deps = [ + ":checks", + ":ssl", + ":threading", + "../api:scoped_refptr", + "system:rtc_export", + ] + absl_deps = [ + "//third_party/abseil-cpp/absl/functional:any_invocable", + "//third_party/abseil-cpp/absl/types:optional", + ] +} +} + +rtc_library("ssl") { +if (!build_with_mozilla) { + visibility = [ "*" ] + sources = [ + "helpers.cc", + "helpers.h", + "message_digest.cc", + "message_digest.h", + "openssl.h", + "openssl_adapter.cc", + "openssl_adapter.h", + "openssl_digest.cc", + "openssl_digest.h", + "openssl_key_pair.cc", + "openssl_key_pair.h", + "openssl_session_cache.cc", + "openssl_session_cache.h", + "openssl_stream_adapter.cc", + "openssl_stream_adapter.h", + "openssl_utility.cc", + "openssl_utility.h", + "rtc_certificate.cc", + "rtc_certificate.h", + "ssl_adapter.cc", + "ssl_adapter.h", + "ssl_certificate.cc", + "ssl_certificate.h", + "ssl_fingerprint.cc", + "ssl_fingerprint.h", + "ssl_identity.cc", + "ssl_identity.h", + "ssl_stream_adapter.cc", + "ssl_stream_adapter.h", + ] + + deps = [ + ":async_socket", + ":buffer", + ":checks", + ":copy_on_write_buffer", + ":logging", + ":macromagic", + ":safe_conversions", + ":socket", + ":socket_address", + ":stream", + ":stringutils", + ":threading", + ":timeutils", + "../api:array_view", + "../api:refcountedbase", + "../api:scoped_refptr", + "../api/task_queue:pending_task_safety_flag", + "../api/units:time_delta", + "../system_wrappers:field_trial", + "synchronization:mutex", + "system:rtc_export", + "task_utils:repeating_task", + "third_party/base64", + "third_party/sigslot", + ] + + absl_deps = [ + "//third_party/abseil-cpp/absl/algorithm:container", + "//third_party/abseil-cpp/absl/base:core_headers", + "//third_party/abseil-cpp/absl/functional:any_invocable", + "//third_party/abseil-cpp/absl/memory", + "//third_party/abseil-cpp/absl/strings", + "//third_party/abseil-cpp/absl/types:optional", + ] + + # If we are building the SSL library ourselves, we know it's BoringSSL. + if (rtc_build_ssl) { + sources += [ + "boringssl_certificate.cc", + "boringssl_certificate.h", + "boringssl_identity.cc", + "boringssl_identity.h", + ] + + deps += [ "//third_party/boringssl" ] + } else { + sources += [ + "openssl_certificate.cc", + "openssl_certificate.h", + "openssl_identity.cc", + "openssl_identity.h", + ] + + configs += [ ":external_ssl_library" ] + } + + if (build_with_chromium) { + include_dirs = [ "../../boringssl/src/include" ] + } else { + sources += [ "ssl_roots.h" ] + } + + if (is_win) { + deps += [ ":win32" ] + } +} +} + +rtc_library("crypt_string") { + sources = [ + "crypt_string.cc", + "crypt_string.h", + ] +} + +rtc_library("http_common") { +if (!build_with_mozilla) { + sources = [ + "http_common.cc", + "http_common.h", + ] + deps = [ + ":crypt_string", + ":logging", + ":socket_address", + ":ssl", + ":stringutils", + ":zero_memory", + "third_party/base64", + ] + + absl_deps = [ "//third_party/abseil-cpp/absl/strings" ] +} +} + +rtc_source_set("gtest_prod") { + sources = [ "gtest_prod_util.h" ] +} + +rtc_library("gunit_helpers") { + testonly = true + sources = [ + "gunit.cc", + "gunit.h", + ] + deps = [ + ":logging", + ":rtc_base_tests_utils", + ":stringutils", + ":threading", + "../test:test_support", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/strings" ] +} + +rtc_library("testclient") { + testonly = true + sources = [ + "test_client.cc", + "test_client.h", + ] + deps = [ + ":async_udp_socket", + ":gunit_helpers", + ":rtc_base_tests_utils", + ":threading", + ":timeutils", + "synchronization:mutex", + ] +} + +rtc_library("callback_list_unittests") { + testonly = true + + sources = [ "callback_list_unittest.cc" ] + deps = [ + ":callback_list", + ":gunit_helpers", + "../api:function_view", + "../test:test_support", + ] +} + +rtc_library("rtc_base_tests_utils") { + testonly = true + sources = [ + "cpu_time.cc", + "cpu_time.h", + "fake_clock.cc", + "fake_clock.h", + "fake_mdns_responder.h", + "fake_network.h", + "fake_ssl_identity.cc", + "fake_ssl_identity.h", + "firewall_socket_server.cc", + "firewall_socket_server.h", + "memory_stream.cc", + "memory_stream.h", + "memory_usage.cc", + "memory_usage.h", + "nat_server.cc", + "nat_server.h", + "nat_socket_factory.cc", + "nat_socket_factory.h", + "nat_types.cc", + "nat_types.h", + "proxy_server.cc", + "proxy_server.h", + "server_socket_adapters.cc", + "server_socket_adapters.h", + "sigslot_tester.h", + "socket_stream.cc", + "socket_stream.h", + "test_base64.h", + "test_certificate_verifier.h", + "test_echo_server.cc", + "test_echo_server.h", + "test_utils.cc", + "test_utils.h", + "virtual_socket_server.cc", + "virtual_socket_server.h", + ] + deps = [ + ":async_packet_socket", + ":async_socket", + ":async_tcp_socket", + ":async_udp_socket", + ":byte_buffer", + ":checks", + ":ip_address", + ":logging", + ":macromagic", + ":mdns_responder_interface", + ":network", + ":rtc_event", + ":socket", + ":socket_adapters", + ":socket_address", + ":socket_address_pair", + ":socket_factory", + ":socket_server", + ":ssl", + ":stream", + ":stringutils", + ":threading", + ":timeutils", + "../api:make_ref_counted", + "../api:refcountedbase", + "../api:scoped_refptr", + "../api/task_queue", + "../api/units:time_delta", + "../api/units:timestamp", + "../test:scoped_key_value_config", + "memory:always_valid_pointer", + "memory:fifo_buffer", + "synchronization:mutex", + "third_party/sigslot", + ] + absl_deps = [ + "//third_party/abseil-cpp/absl/algorithm:container", + "//third_party/abseil-cpp/absl/memory", + "//third_party/abseil-cpp/absl/strings", + "//third_party/abseil-cpp/absl/types:optional", + ] + if (is_fuchsia) { + deps += [ "//third_party/fuchsia-sdk/sdk/pkg/zx" ] + } +} + +rtc_library("task_queue_for_test") { + testonly = true + + sources = [ + "task_queue_for_test.cc", + "task_queue_for_test.h", + ] + deps = [ + ":checks", + ":macromagic", + ":rtc_event", + ":rtc_task_queue", + "../api:function_view", + "../api/task_queue", + "../api/task_queue:default_task_queue_factory", + ] + absl_deps = [ + "//third_party/abseil-cpp/absl/cleanup", + "//third_party/abseil-cpp/absl/strings", + ] +} + +if (rtc_include_tests) { + rtc_library("sigslot_unittest") { + testonly = true + sources = [ "sigslot_unittest.cc" ] + deps = [ + ":gunit_helpers", + ":rtc_base_tests_utils", + "../test:test_support", + "synchronization:mutex", + "third_party/sigslot", + ] + } + + rtc_library("untyped_function_unittest") { + testonly = true + sources = [ "untyped_function_unittest.cc" ] + deps = [ + ":untyped_function", + "../test:test_support", + ] + } + + rtc_library("rtc_operations_chain_unittests") { + testonly = true + + sources = [ "operations_chain_unittest.cc" ] + deps = [ + ":gunit_helpers", + ":rtc_event", + ":rtc_operations_chain", + ":threading", + "../test:test_support", + ] + } + + if (!build_with_chromium) { + rtc_library("rtc_base_nonparallel_tests") { + testonly = true + + sources = [ + "cpu_time_unittest.cc", + "file_rotating_stream_unittest.cc", + "null_socket_server_unittest.cc", + "physical_socket_server_unittest.cc", + "socket_address_unittest.cc", + "socket_unittest.cc", + "socket_unittest.h", + ] + deps = [ + ":async_packet_socket", + ":async_udp_socket", + ":buffer", + ":checks", + ":file_rotating_stream", + ":gunit_helpers", + ":ip_address", + ":logging", + ":macromagic", + ":net_helpers", + ":net_test_helpers", + ":null_socket_server", + ":platform_thread", + ":rtc_base_tests_utils", + ":socket", + ":socket_address", + ":socket_server", + ":testclient", + ":threading", + ":timeutils", + "../api/units:time_delta", + "../system_wrappers", + "../test:field_trial", + "../test:fileutils", + "../test:test_main", + "../test:test_support", + "third_party/sigslot", + "//testing/gtest", + ] + absl_deps = [ + "//third_party/abseil-cpp/absl/memory", + "//third_party/abseil-cpp/absl/strings", + ] + } + + rtc_library("rtc_base_approved_unittests") { + testonly = true + sources = [ + "base64_unittest.cc", + "bit_buffer_unittest.cc", + "bitrate_tracker_unittest.cc", + "bitstream_reader_unittest.cc", + "bounded_inline_vector_unittest.cc", + "buffer_queue_unittest.cc", + "buffer_unittest.cc", + "byte_buffer_unittest.cc", + "byte_order_unittest.cc", + "checks_unittest.cc", + "copy_on_write_buffer_unittest.cc", + "deprecated/recursive_critical_section_unittest.cc", + "event_tracer_unittest.cc", + "event_unittest.cc", + "frequency_tracker_unittest.cc", + "logging_unittest.cc", + "numerics/divide_round_unittest.cc", + "numerics/histogram_percentile_counter_unittest.cc", + "numerics/mod_ops_unittest.cc", + "numerics/moving_max_counter_unittest.cc", + "numerics/safe_compare_unittest.cc", + "numerics/safe_minmax_unittest.cc", + "numerics/sample_counter_unittest.cc", + "one_time_event_unittest.cc", + "platform_thread_unittest.cc", + "random_unittest.cc", + "rate_limiter_unittest.cc", + "rate_statistics_unittest.cc", + "rate_tracker_unittest.cc", + "ref_counted_object_unittest.cc", + "sanitizer_unittest.cc", + "string_encode_unittest.cc", + "string_to_number_unittest.cc", + "string_utils_unittest.cc", + "strings/string_builder_unittest.cc", + "strings/string_format_unittest.cc", + "strong_alias_unittest.cc", + "swap_queue_unittest.cc", + "thread_annotations_unittest.cc", + "time_utils_unittest.cc", + "timestamp_aligner_unittest.cc", + "virtual_socket_unittest.cc", + "zero_memory_unittest.cc", + ] + deps = [ + ":async_packet_socket", + ":async_udp_socket", + ":bit_buffer", + ":bitrate_tracker", + ":bitstream_reader", + ":bounded_inline_vector", + ":buffer", + ":buffer_queue", + ":byte_buffer", + ":byte_order", + ":checks", + ":copy_on_write_buffer", + ":criticalsection", + ":divide_round", + ":event_tracer", + ":frequency_tracker", + ":gunit_helpers", + ":histogram_percentile_counter", + ":ip_address", + ":logging", + ":macromagic", + ":mod_ops", + ":moving_max_counter", + ":null_socket_server", + ":one_time_event", + ":platform_thread", + ":random", + ":rate_limiter", + ":rate_statistics", + ":rate_tracker", + ":refcount", + ":rtc_base_tests_utils", + ":rtc_event", + ":rtc_numerics", + ":rtc_task_queue", + ":safe_compare", + ":safe_minmax", + ":sample_counter", + ":sanitizer", + ":socket", + ":socket_address", + ":socket_server", + ":ssl", + ":stringutils", + ":strong_alias", + ":swap_queue", + ":testclient", + ":threading", + ":timestamp_aligner", + ":timeutils", + ":zero_memory", + "../api:array_view", + "../api:make_ref_counted", + "../api:scoped_refptr", + "../api/numerics", + "../api/units:data_rate", + "../api/units:data_size", + "../api/units:frequency", + "../api/units:time_delta", + "../api/units:timestamp", + "../system_wrappers", + "../test:fileutils", + "../test:test_main", + "../test:test_support", + "containers:flat_map", + "containers:unittests", + "memory:unittests", + "synchronization:mutex", + "task_utils:repeating_task", + "third_party/base64", + "third_party/sigslot", + ] + absl_deps = [ + "//third_party/abseil-cpp/absl/base:core_headers", + "//third_party/abseil-cpp/absl/memory", + "//third_party/abseil-cpp/absl/numeric:bits", + "//third_party/abseil-cpp/absl/strings", + "//third_party/abseil-cpp/absl/types:optional", + ] + + if (is_win) { + deps += [ "win:windows_version_unittest" ] + } + } + + rtc_library("rtc_task_queue_unittests") { + testonly = true + + sources = [ "task_queue_unittest.cc" ] + deps = [ + ":gunit_helpers", + ":rtc_base_tests_utils", + ":rtc_event", + ":rtc_task_queue", + ":task_queue_for_test", + ":timeutils", + "../api/units:time_delta", + "../test:test_main", + "../test:test_support", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/memory" ] + } + + rtc_library("weak_ptr_unittests") { + testonly = true + + sources = [ "weak_ptr_unittest.cc" ] + deps = [ + ":gunit_helpers", + ":rtc_base_tests_utils", + ":rtc_event", + ":task_queue_for_test", + ":weak_ptr", + "../test:test_main", + "../test:test_support", + ] + } + + rtc_library("rtc_numerics_unittests") { + testonly = true + + sources = [ + "numerics/event_based_exponential_moving_average_unittest.cc", + "numerics/exp_filter_unittest.cc", + "numerics/moving_average_unittest.cc", + "numerics/moving_percentile_filter_unittest.cc", + "numerics/percentile_filter_unittest.cc", + "numerics/running_statistics_unittest.cc", + "numerics/sequence_number_unwrapper_unittest.cc", + "numerics/sequence_number_util_unittest.cc", + ] + deps = [ + ":rtc_numerics", + ":timeutils", + "../test:test_main", + "../test:test_support", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/algorithm:container" ] + } + + rtc_library("rtc_json_unittests") { + testonly = true + + sources = [ "strings/json_unittest.cc" ] + deps = [ + ":gunit_helpers", + ":rtc_base_tests_utils", + ":rtc_json", + "../test:test_main", + "../test:test_support", + ] + } + + rtc_library("rtc_base_unittests") { + testonly = true + defines = [] + + sources = [ + "crc32_unittest.cc", + "data_rate_limiter_unittest.cc", + "fake_clock_unittest.cc", + "helpers_unittest.cc", + "ip_address_unittest.cc", + "memory_usage_unittest.cc", + "message_digest_unittest.cc", + "nat_unittest.cc", + "network_route_unittest.cc", + "network_unittest.cc", + "proxy_unittest.cc", + "rolling_accumulator_unittest.cc", + "rtc_certificate_generator_unittest.cc", + "rtc_certificate_unittest.cc", + "sigslot_tester_unittest.cc", + "test_client_unittest.cc", + "thread_unittest.cc", + "unique_id_generator_unittest.cc", + ] + deps = [ + ":async_packet_socket", + ":async_tcp_socket", + ":async_udp_socket", + ":buffer", + ":buffer_queue", + ":checks", + ":crc32", + ":data_rate_limiter", + ":gunit_helpers", + ":ifaddrs_converter", + ":ip_address", + ":logging", + ":macromagic", + ":net_helpers", + ":net_test_helpers", + ":network", + ":network_route", + ":null_socket_server", + ":refcount", + ":rolling_accumulator", + ":rtc_base_tests_utils", + ":rtc_certificate_generator", + ":rtc_event", + ":safe_conversions", + ":socket", + ":socket_adapters", + ":socket_address", + ":socket_factory", + ":socket_server", + ":ssl", + ":stream", + ":stringutils", + ":testclient", + ":threading", + ":timeutils", + ":unique_id_generator", + "../api:array_view", + "../api:field_trials_view", + "../api:make_ref_counted", + "../api/task_queue", + "../api/task_queue:pending_task_safety_flag", + "../api/task_queue:task_queue_test", + "../api/units:time_delta", + "../test:field_trial", + "../test:fileutils", + "../test:rtc_expect_death", + "../test:scoped_key_value_config", + "../test:test_main", + "../test:test_support", + "memory:fifo_buffer", + "synchronization:mutex", + "third_party/sigslot", + ] + if (rtc_enable_google_benchmarks) { + deps += [ "synchronization:synchronization_unittests" ] + } + if (is_win) { + sources += [ "win32_unittest.cc" ] + deps += [ ":win32" ] + } + if (is_posix || is_fuchsia || is_win) { + sources += [ + "openssl_adapter_unittest.cc", + "openssl_session_cache_unittest.cc", + "openssl_utility_unittest.cc", + "ssl_adapter_unittest.cc", + "ssl_identity_unittest.cc", + "ssl_stream_adapter_unittest.cc", + ] + } + absl_deps = [ + "//third_party/abseil-cpp/absl/algorithm:container", + "//third_party/abseil-cpp/absl/functional:any_invocable", + "//third_party/abseil-cpp/absl/memory", + "//third_party/abseil-cpp/absl/strings", + "//third_party/abseil-cpp/absl/types:optional", + ] + + if (build_with_chromium) { + include_dirs = [ "../../boringssl/src/include" ] + } + if (rtc_build_ssl) { + deps += [ "//third_party/boringssl" ] + } else { + configs += [ ":external_ssl_library" ] + } + } + } +} + +if (is_android && !build_with_mozilla) { + rtc_android_library("base_java") { + visibility = [ "*" ] + sources = [ + "java/src/org/webrtc/ContextUtils.java", + "java/src/org/webrtc/Loggable.java", + "java/src/org/webrtc/Logging.java", + "java/src/org/webrtc/Size.java", + "java/src/org/webrtc/ThreadUtils.java", + ] + deps = [ "//third_party/androidx:androidx_annotation_annotation_java" ] + } + java_cpp_enum("network_monitor_enums") { + sources = [ "network_monitor.h" ] + visibility = [ "*" ] + } +} diff --git a/third_party/libwebrtc/rtc_base/DEPS b/third_party/libwebrtc/rtc_base/DEPS new file mode 100644 index 0000000000..3a77b5502a --- /dev/null +++ b/third_party/libwebrtc/rtc_base/DEPS @@ -0,0 +1,15 @@ +include_rules = [ + "+json", + "+system_wrappers", + "+third_party/jsoncpp", + "+third_party/libevent", +] + +specific_include_rules = { + "protobuf_utils.h": [ + "+third_party/protobuf", + ], + "gunit\.h": [ + "+testing/base/public/gunit.h" + ], +} diff --git a/third_party/libwebrtc/rtc_base/OWNERS b/third_party/libwebrtc/rtc_base/OWNERS new file mode 100644 index 0000000000..3a420a088e --- /dev/null +++ b/third_party/libwebrtc/rtc_base/OWNERS @@ -0,0 +1,7 @@ +hta@webrtc.org +mflodman@webrtc.org +tommi@webrtc.org +mbonadei@webrtc.org + +per-file rate_statistics*=sprang@webrtc.org +per-file rate_statistics*=stefan@webrtc.org diff --git a/third_party/libwebrtc/rtc_base/arraysize.h b/third_party/libwebrtc/rtc_base/arraysize.h new file mode 100644 index 0000000000..bf8e6d8810 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/arraysize.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2015 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 RTC_BASE_ARRAYSIZE_H_ +#define RTC_BASE_ARRAYSIZE_H_ + +#include <stddef.h> + +// This file defines the arraysize() macro and is derived from Chromium's +// base/macros.h. + +// The arraysize(arr) macro returns the # of elements in an array arr. +// The expression is a compile-time constant, and therefore can be +// used in defining new arrays, for example. If you use arraysize on +// a pointer by mistake, you will get a compile-time error. + +// This template function declaration is used in defining arraysize. +// Note that the function doesn't need an implementation, as we only +// use its type. +template <typename T, size_t N> +char (&ArraySizeHelper(T (&array)[N]))[N]; + +#define arraysize(array) (sizeof(ArraySizeHelper(array))) + +#endif // RTC_BASE_ARRAYSIZE_H_ diff --git a/third_party/libwebrtc/rtc_base/async_dns_resolver.cc b/third_party/libwebrtc/rtc_base/async_dns_resolver.cc new file mode 100644 index 0000000000..8cbd21cb6d --- /dev/null +++ b/third_party/libwebrtc/rtc_base/async_dns_resolver.cc @@ -0,0 +1,204 @@ +/* + * Copyright 2023 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 "rtc_base/async_dns_resolver.h" + +#include <memory> +#include <string> +#include <utility> +#include <vector> + +#include "api/make_ref_counted.h" +#include "rtc_base/logging.h" +#include "rtc_base/platform_thread.h" + +#if defined(WEBRTC_MAC) || defined(WEBRTC_IOS) +#include <dispatch/dispatch.h> +#endif + +namespace webrtc { + +namespace { + +#ifdef __native_client__ +int ResolveHostname(absl::string_view hostname, + int family, + std::vector<rtc::IPAddress>* addresses) { + RTC_DCHECK_NOTREACHED(); + RTC_LOG(LS_WARNING) << "ResolveHostname() is not implemented for NaCl"; + return -1; +} +#else // notdef(__native_client__) +int ResolveHostname(absl::string_view hostname, + int family, + std::vector<rtc::IPAddress>& addresses) { + addresses.clear(); + struct addrinfo* result = nullptr; + struct addrinfo hints = {0}; + hints.ai_family = family; + // `family` here will almost always be AF_UNSPEC, because `family` comes from + // AsyncResolver::addr_.family(), which comes from a SocketAddress constructed + // with a hostname. When a SocketAddress is constructed with a hostname, its + // family is AF_UNSPEC. However, if someday in the future we construct + // a SocketAddress with both a hostname and a family other than AF_UNSPEC, + // then it would be possible to get a specific family value here. + + // The behavior of AF_UNSPEC is roughly "get both ipv4 and ipv6", as + // documented by the various operating systems: + // Linux: http://man7.org/linux/man-pages/man3/getaddrinfo.3.html + // Windows: https://msdn.microsoft.com/en-us/library/windows/desktop/ + // ms738520(v=vs.85).aspx + // Mac: https://developer.apple.com/legacy/library/documentation/Darwin/ + // Reference/ManPages/man3/getaddrinfo.3.html + // Android (source code, not documentation): + // https://android.googlesource.com/platform/bionic/+/ + // 7e0bfb511e85834d7c6cb9631206b62f82701d60/libc/netbsd/net/getaddrinfo.c#1657 + hints.ai_flags = AI_ADDRCONFIG; + int ret = + getaddrinfo(std::string(hostname).c_str(), nullptr, &hints, &result); + if (ret != 0) { + return ret; + } + struct addrinfo* cursor = result; + for (; cursor; cursor = cursor->ai_next) { + if (family == AF_UNSPEC || cursor->ai_family == family) { + rtc::IPAddress ip; + if (IPFromAddrInfo(cursor, &ip)) { + addresses.push_back(ip); + } + } + } + freeaddrinfo(result); + return 0; +} +#endif // !__native_client__ + +// Special task posting for Mac/iOS +#if defined(WEBRTC_MAC) || defined(WEBRTC_IOS) +void GlobalGcdRunTask(void* context) { + std::unique_ptr<absl::AnyInvocable<void() &&>> task( + static_cast<absl::AnyInvocable<void() &&>*>(context)); + std::move (*task)(); +} + +// Post a task into the system-defined global concurrent queue. +void PostTaskToGlobalQueue( + std::unique_ptr<absl::AnyInvocable<void() &&>> task) { + dispatch_async_f( + dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), + task.release(), &GlobalGcdRunTask); +} +#endif // defined(WEBRTC_MAC) || defined(WEBRTC_IOS) + +} // namespace + +class AsyncDnsResolver::State : public rtc::RefCountedBase { + public: + enum class Status { + kActive, // Running request, or able to be passed one + kFinished, // Request has finished processing + kDead // The owning AsyncDnsResolver has been deleted + }; + static rtc::scoped_refptr<AsyncDnsResolver::State> Create() { + return rtc::make_ref_counted<AsyncDnsResolver::State>(); + } + + // Execute the passed function if the state is Active. + void Finish(absl::AnyInvocable<void()> function) { + webrtc::MutexLock lock(&mutex_); + if (status_ != Status::kActive) { + return; + } + status_ = Status::kFinished; + function(); + } + void Kill() { + webrtc::MutexLock lock(&mutex_); + status_ = Status::kDead; + } + + private: + webrtc::Mutex mutex_; + Status status_ RTC_GUARDED_BY(mutex_) = Status::kActive; +}; + +AsyncDnsResolver::AsyncDnsResolver() : state_(State::Create()) {} + +AsyncDnsResolver::~AsyncDnsResolver() { + state_->Kill(); +} + +void AsyncDnsResolver::Start(const rtc::SocketAddress& addr, + absl::AnyInvocable<void()> callback) { + Start(addr, addr.family(), std::move(callback)); +} + +// Start address resolution of the hostname in `addr` matching `family`. +void AsyncDnsResolver::Start(const rtc::SocketAddress& addr, + int family, + absl::AnyInvocable<void()> callback) { + RTC_DCHECK_RUN_ON(&result_.sequence_checker_); + result_.addr_ = addr; + callback_ = std::move(callback); + auto thread_function = [this, addr, family, flag = safety_.flag(), + caller_task_queue = webrtc::TaskQueueBase::Current(), + state = state_] { + std::vector<rtc::IPAddress> addresses; + int error = ResolveHostname(addr.hostname(), family, addresses); + // We assume that the caller task queue is still around if the + // AsyncDnsResolver has not been destroyed. + state->Finish([this, error, flag, caller_task_queue, + addresses = std::move(addresses)]() { + caller_task_queue->PostTask( + SafeTask(flag, [this, error, addresses = std::move(addresses)] { + RTC_DCHECK_RUN_ON(&result_.sequence_checker_); + result_.addresses_ = addresses; + result_.error_ = error; + callback_(); + })); + }); + }; +#if defined(WEBRTC_MAC) || defined(WEBRTC_IOS) + PostTaskToGlobalQueue( + std::make_unique<absl::AnyInvocable<void() &&>>(thread_function)); +#else + rtc::PlatformThread::SpawnDetached(std::move(thread_function), + "AsyncResolver"); +#endif +} + +const AsyncDnsResolverResult& AsyncDnsResolver::result() const { + return result_; +} + +bool AsyncDnsResolverResultImpl::GetResolvedAddress( + int family, + rtc::SocketAddress* addr) const { + RTC_DCHECK_RUN_ON(&sequence_checker_); + RTC_DCHECK(addr); + if (error_ != 0 || addresses_.empty()) + return false; + + *addr = addr_; + for (const auto& address : addresses_) { + if (family == address.family()) { + addr->SetResolvedIP(address); + return true; + } + } + return false; +} + +int AsyncDnsResolverResultImpl::GetError() const { + RTC_DCHECK_RUN_ON(&sequence_checker_); + return error_; +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/async_dns_resolver.h b/third_party/libwebrtc/rtc_base/async_dns_resolver.h new file mode 100644 index 0000000000..288751efa4 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/async_dns_resolver.h @@ -0,0 +1,63 @@ +/* + * Copyright 2023 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 RTC_BASE_ASYNC_DNS_RESOLVER_H_ +#define RTC_BASE_ASYNC_DNS_RESOLVER_H_ + +#include <vector> + +#include "api/async_dns_resolver.h" +#include "api/sequence_checker.h" +#include "api/task_queue/pending_task_safety_flag.h" +#include "rtc_base/ref_counted_object.h" +#include "rtc_base/system/rtc_export.h" +#include "rtc_base/thread_annotations.h" + +namespace webrtc { +// This file contains a default implementation of +// webrtc::AsyncDnsResolverInterface, for use when there is no need for special +// treatment. + +class AsyncDnsResolverResultImpl : public AsyncDnsResolverResult { + public: + bool GetResolvedAddress(int family, rtc::SocketAddress* addr) const override; + // Returns error from resolver. + int GetError() const override; + + private: + friend class AsyncDnsResolver; + RTC_NO_UNIQUE_ADDRESS webrtc::SequenceChecker sequence_checker_; + rtc::SocketAddress addr_ RTC_GUARDED_BY(sequence_checker_); + std::vector<rtc::IPAddress> addresses_ RTC_GUARDED_BY(sequence_checker_); + int error_ RTC_GUARDED_BY(sequence_checker_); +}; + +class RTC_EXPORT AsyncDnsResolver : public AsyncDnsResolverInterface { + public: + AsyncDnsResolver(); + ~AsyncDnsResolver(); + // Start address resolution of the hostname in `addr`. + void Start(const rtc::SocketAddress& addr, + absl::AnyInvocable<void()> callback) override; + // Start address resolution of the hostname in `addr` matching `family`. + void Start(const rtc::SocketAddress& addr, + int family, + absl::AnyInvocable<void()> callback) override; + const AsyncDnsResolverResult& result() const override; + + private: + class State; + ScopedTaskSafety safety_; // To check for client going away + rtc::scoped_refptr<State> state_; // To check for "this" going away + AsyncDnsResolverResultImpl result_; + absl::AnyInvocable<void()> callback_; +}; + +} // namespace webrtc +#endif // RTC_BASE_ASYNC_DNS_RESOLVER_H_ diff --git a/third_party/libwebrtc/rtc_base/async_dns_resolver_gn/moz.build b/third_party/libwebrtc/rtc_base/async_dns_resolver_gn/moz.build new file mode 100644 index 0000000000..866c7aec5a --- /dev/null +++ b/third_party/libwebrtc/rtc_base/async_dns_resolver_gn/moz.build @@ -0,0 +1,233 @@ +# 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/rtc_base/async_dns_resolver.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_ENABLE_LIBEVENT"] = 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 += [ + "GLESv2", + "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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("async_dns_resolver_gn") diff --git a/third_party/libwebrtc/rtc_base/async_dns_resolver_unittest.cc b/third_party/libwebrtc/rtc_base/async_dns_resolver_unittest.cc new file mode 100644 index 0000000000..11f8b1b6f4 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/async_dns_resolver_unittest.cc @@ -0,0 +1,58 @@ +/* + * Copyright 2023 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 "rtc_base/async_dns_resolver.h" + +#include "rtc_base/gunit.h" +#include "test/gtest.h" +#include "test/run_loop.h" + +namespace webrtc { +namespace { +const int kDefaultTimeout = 1000; +const int kPortNumber = 3027; + +TEST(AsyncDnsResolver, ConstructorWorks) { + AsyncDnsResolver resolver; +} + +TEST(AsyncDnsResolver, ResolvingLocalhostWorks) { + test::RunLoop loop; // Ensure that posting back to main thread works + AsyncDnsResolver resolver; + rtc::SocketAddress address("localhost", + kPortNumber); // Port number does not matter + rtc::SocketAddress resolved_address; + bool done = false; + resolver.Start(address, [&done] { done = true; }); + ASSERT_TRUE_WAIT(done, kDefaultTimeout); + EXPECT_EQ(resolver.result().GetError(), 0); + if (resolver.result().GetResolvedAddress(AF_INET, &resolved_address)) { + EXPECT_EQ(resolved_address, rtc::SocketAddress("127.0.0.1", kPortNumber)); + } else { + RTC_LOG(LS_INFO) << "Resolution gave no address, skipping test"; + } +} + +TEST(AsyncDnsResolver, ResolveAfterDeleteDoesNotReturn) { + test::RunLoop loop; + std::unique_ptr<AsyncDnsResolver> resolver = + std::make_unique<AsyncDnsResolver>(); + rtc::SocketAddress address("localhost", + kPortNumber); // Port number does not matter + rtc::SocketAddress resolved_address; + bool done = false; + resolver->Start(address, [&done] { done = true; }); + resolver.reset(); // Deletes resolver. + rtc::Thread::Current()->SleepMs(1); // Allows callback to execute + EXPECT_FALSE(done); // Expect no result. +} + +} // namespace +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/async_packet_socket.cc b/third_party/libwebrtc/rtc_base/async_packet_socket.cc new file mode 100644 index 0000000000..f50138cb62 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/async_packet_socket.cc @@ -0,0 +1,49 @@ +/* + * Copyright 2015 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 "rtc_base/async_packet_socket.h" + +namespace rtc { + +PacketTimeUpdateParams::PacketTimeUpdateParams() = default; + +PacketTimeUpdateParams::PacketTimeUpdateParams( + const PacketTimeUpdateParams& other) = default; + +PacketTimeUpdateParams::~PacketTimeUpdateParams() = default; + +PacketOptions::PacketOptions() = default; +PacketOptions::PacketOptions(DiffServCodePoint dscp) : dscp(dscp) {} +PacketOptions::PacketOptions(const PacketOptions& other) = default; +PacketOptions::~PacketOptions() = default; + +AsyncPacketSocket::~AsyncPacketSocket() = default; + +void AsyncPacketSocket::SubscribeCloseEvent( + const void* removal_tag, + std::function<void(AsyncPacketSocket*, int)> callback) { + RTC_DCHECK_RUN_ON(&network_checker_); + on_close_.AddReceiver(removal_tag, std::move(callback)); +} + +void AsyncPacketSocket::UnsubscribeCloseEvent(const void* removal_tag) { + RTC_DCHECK_RUN_ON(&network_checker_); + on_close_.RemoveReceivers(removal_tag); +} + +void CopySocketInformationToPacketInfo(size_t packet_size_bytes, + const AsyncPacketSocket& socket_from, + bool is_connectionless, + rtc::PacketInfo* info) { + info->packet_size_bytes = packet_size_bytes; + info->ip_overhead_bytes = socket_from.GetLocalAddress().ipaddr().overhead(); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/async_packet_socket.h b/third_party/libwebrtc/rtc_base/async_packet_socket.h new file mode 100644 index 0000000000..0d3ceb94e7 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/async_packet_socket.h @@ -0,0 +1,191 @@ +/* + * 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 RTC_BASE_ASYNC_PACKET_SOCKET_H_ +#define RTC_BASE_ASYNC_PACKET_SOCKET_H_ + +#include <vector> + +#include "api/sequence_checker.h" +#include "rtc_base/callback_list.h" +#include "rtc_base/dscp.h" +#include "rtc_base/network/sent_packet.h" +#include "rtc_base/socket.h" +#include "rtc_base/system/no_unique_address.h" +#include "rtc_base/system/rtc_export.h" +#include "rtc_base/third_party/sigslot/sigslot.h" +#include "rtc_base/time_utils.h" + +namespace rtc { + +// This structure holds the info needed to update the packet send time header +// extension, including the information needed to update the authentication tag +// after changing the value. +struct PacketTimeUpdateParams { + PacketTimeUpdateParams(); + PacketTimeUpdateParams(const PacketTimeUpdateParams& other); + ~PacketTimeUpdateParams(); + + int rtp_sendtime_extension_id = -1; // extension header id present in packet. + std::vector<char> srtp_auth_key; // Authentication key. + int srtp_auth_tag_len = -1; // Authentication tag length. + int64_t srtp_packet_index = -1; // Required for Rtp Packet authentication. +}; + +// This structure holds meta information for the packet which is about to send +// over network. +struct RTC_EXPORT PacketOptions { + PacketOptions(); + explicit PacketOptions(DiffServCodePoint dscp); + PacketOptions(const PacketOptions& other); + ~PacketOptions(); + + DiffServCodePoint dscp = DSCP_NO_CHANGE; + // When used with RTP packets (for example, webrtc::PacketOptions), the value + // should be 16 bits. A value of -1 represents "not set". + int64_t packet_id = -1; + PacketTimeUpdateParams packet_time_params; + // PacketInfo is passed to SentPacket when signaling this packet is sent. + PacketInfo info_signaled_after_sent; + // True if this is a batchable packet. Batchable packets are collected at low + // levels and sent first when their AsyncPacketSocket receives a + // OnSendBatchComplete call. + bool batchable = false; + // True if this is the last packet of a batch. + bool last_packet_in_batch = false; +}; + +// Provides the ability to receive packets asynchronously. Sends are not +// buffered since it is acceptable to drop packets under high load. +class RTC_EXPORT AsyncPacketSocket : public sigslot::has_slots<> { + public: + enum State { + STATE_CLOSED, + STATE_BINDING, + STATE_BOUND, + STATE_CONNECTING, + STATE_CONNECTED + }; + + AsyncPacketSocket() = default; + ~AsyncPacketSocket() override; + + AsyncPacketSocket(const AsyncPacketSocket&) = delete; + AsyncPacketSocket& operator=(const AsyncPacketSocket&) = delete; + + // Returns current local address. Address may be set to null if the + // socket is not bound yet (GetState() returns STATE_BINDING). + virtual SocketAddress GetLocalAddress() const = 0; + + // Returns remote address. Returns zeroes if this is not a client TCP socket. + virtual SocketAddress GetRemoteAddress() const = 0; + + // Send a packet. + virtual int Send(const void* pv, size_t cb, const PacketOptions& options) = 0; + virtual int SendTo(const void* pv, + size_t cb, + const SocketAddress& addr, + const PacketOptions& options) = 0; + + // Close the socket. + virtual int Close() = 0; + + // Returns current state of the socket. + virtual State GetState() const = 0; + + // Get/set options. + virtual int GetOption(Socket::Option opt, int* value) = 0; + virtual int SetOption(Socket::Option opt, int value) = 0; + + // Get/Set current error. + // TODO: Remove SetError(). + virtual int GetError() const = 0; + virtual void SetError(int error) = 0; + + // Register a callback to be called when the socket is closed. + void SubscribeCloseEvent( + const void* removal_tag, + std::function<void(AsyncPacketSocket*, int)> callback); + void UnsubscribeCloseEvent(const void* removal_tag); + + // Emitted each time a packet is read. Used only for UDP and + // connected TCP sockets. + sigslot::signal5<AsyncPacketSocket*, + const char*, + size_t, + const SocketAddress&, + // TODO(bugs.webrtc.org/9584): Change to passing the int64_t + // timestamp by value. + const int64_t&> + SignalReadPacket; + + // Emitted each time a packet is sent. + sigslot::signal2<AsyncPacketSocket*, const SentPacket&> SignalSentPacket; + + // Emitted when the socket is currently able to send. + sigslot::signal1<AsyncPacketSocket*> SignalReadyToSend; + + // Emitted after address for the socket is allocated, i.e. binding + // is finished. State of the socket is changed from BINDING to BOUND + // (for UDP sockets). + sigslot::signal2<AsyncPacketSocket*, const SocketAddress&> SignalAddressReady; + + // Emitted for client TCP sockets when state is changed from + // CONNECTING to CONNECTED. + sigslot::signal1<AsyncPacketSocket*> SignalConnect; + + void NotifyClosedForTest(int err) { NotifyClosed(err); } + + protected: + // TODO(bugs.webrtc.org/11943): Remove after updating downstream code. + void SignalClose(AsyncPacketSocket* s, int err) { + RTC_DCHECK_EQ(s, this); + NotifyClosed(err); + } + + void NotifyClosed(int err) { + RTC_DCHECK_RUN_ON(&network_checker_); + on_close_.Send(this, err); + } + + RTC_NO_UNIQUE_ADDRESS webrtc::SequenceChecker network_checker_{ + webrtc::SequenceChecker::kDetached}; + + private: + webrtc::CallbackList<AsyncPacketSocket*, int> on_close_ + RTC_GUARDED_BY(&network_checker_); +}; + +// Listen socket, producing an AsyncPacketSocket when a peer connects. +class RTC_EXPORT AsyncListenSocket : public sigslot::has_slots<> { + public: + enum class State { + kClosed, + kBound, + }; + + // Returns current state of the socket. + virtual State GetState() const = 0; + + // Returns current local address. Address may be set to null if the + // socket is not bound yet (GetState() returns kBinding). + virtual SocketAddress GetLocalAddress() const = 0; + + sigslot::signal2<AsyncListenSocket*, AsyncPacketSocket*> SignalNewConnection; +}; + +void CopySocketInformationToPacketInfo(size_t packet_size_bytes, + const AsyncPacketSocket& socket_from, + bool is_connectionless, + rtc::PacketInfo* info); + +} // namespace rtc + +#endif // RTC_BASE_ASYNC_PACKET_SOCKET_H_ diff --git a/third_party/libwebrtc/rtc_base/async_packet_socket_gn/moz.build b/third_party/libwebrtc/rtc_base/async_packet_socket_gn/moz.build new file mode 100644 index 0000000000..0038aa7ef8 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/async_packet_socket_gn/moz.build @@ -0,0 +1,205 @@ +# 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("async_packet_socket_gn") diff --git a/third_party/libwebrtc/rtc_base/async_resolver.cc b/third_party/libwebrtc/rtc_base/async_resolver.cc new file mode 100644 index 0000000000..f79200bc05 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/async_resolver.cc @@ -0,0 +1,239 @@ +/* + * Copyright 2008 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 "rtc_base/async_resolver.h" + +#include <memory> +#include <string> +#include <utility> + +#include "absl/strings/string_view.h" +#include "api/ref_counted_base.h" +#include "rtc_base/synchronization/mutex.h" +#include "rtc_base/thread_annotations.h" + +#if defined(WEBRTC_WIN) +#include <ws2spi.h> +#include <ws2tcpip.h> + +#include "rtc_base/win32.h" +#endif +#if defined(WEBRTC_POSIX) && !defined(__native_client__) +#if defined(WEBRTC_ANDROID) +#include "rtc_base/ifaddrs_android.h" +#else +#include <ifaddrs.h> +#endif +#endif // defined(WEBRTC_POSIX) && !defined(__native_client__) + +#include "api/task_queue/task_queue_base.h" +#include "rtc_base/ip_address.h" +#include "rtc_base/logging.h" +#include "rtc_base/platform_thread.h" +#include "rtc_base/task_queue.h" +#include "rtc_base/third_party/sigslot/sigslot.h" // for signal_with_thread... + +#if defined(WEBRTC_MAC) || defined(WEBRTC_IOS) +#include <dispatch/dispatch.h> +#endif + +namespace rtc { + +#if defined(WEBRTC_MAC) || defined(WEBRTC_IOS) +namespace { + +void GlobalGcdRunTask(void* context) { + std::unique_ptr<absl::AnyInvocable<void() &&>> task( + static_cast<absl::AnyInvocable<void() &&>*>(context)); + std::move (*task)(); +} + +// Post a task into the system-defined global concurrent queue. +void PostTaskToGlobalQueue( + std::unique_ptr<absl::AnyInvocable<void() &&>> task) { + dispatch_async_f( + dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), + task.release(), &GlobalGcdRunTask); +} + +} // namespace +#endif + +int ResolveHostname(absl::string_view hostname, + int family, + std::vector<IPAddress>* addresses) { +#ifdef __native_client__ + RTC_DCHECK_NOTREACHED(); + RTC_LOG(LS_WARNING) << "ResolveHostname() is not implemented for NaCl"; + return -1; +#else // __native_client__ + if (!addresses) { + return -1; + } + addresses->clear(); + struct addrinfo* result = nullptr; + struct addrinfo hints = {0}; + hints.ai_family = family; + // `family` here will almost always be AF_UNSPEC, because `family` comes from + // AsyncResolver::addr_.family(), which comes from a SocketAddress constructed + // with a hostname. When a SocketAddress is constructed with a hostname, its + // family is AF_UNSPEC. However, if someday in the future we construct + // a SocketAddress with both a hostname and a family other than AF_UNSPEC, + // then it would be possible to get a specific family value here. + + // The behavior of AF_UNSPEC is roughly "get both ipv4 and ipv6", as + // documented by the various operating systems: + // Linux: http://man7.org/linux/man-pages/man3/getaddrinfo.3.html + // Windows: https://msdn.microsoft.com/en-us/library/windows/desktop/ + // ms738520(v=vs.85).aspx + // Mac: https://developer.apple.com/legacy/library/documentation/Darwin/ + // Reference/ManPages/man3/getaddrinfo.3.html + // Android (source code, not documentation): + // https://android.googlesource.com/platform/bionic/+/ + // 7e0bfb511e85834d7c6cb9631206b62f82701d60/libc/netbsd/net/getaddrinfo.c#1657 + hints.ai_flags = AI_ADDRCONFIG; + int ret = + getaddrinfo(std::string(hostname).c_str(), nullptr, &hints, &result); + if (ret != 0) { + return ret; + } + struct addrinfo* cursor = result; + for (; cursor; cursor = cursor->ai_next) { + if (family == AF_UNSPEC || cursor->ai_family == family) { + IPAddress ip; + if (IPFromAddrInfo(cursor, &ip)) { + addresses->push_back(ip); + } + } + } + freeaddrinfo(result); + return 0; +#endif // !__native_client__ +} + +struct AsyncResolver::State : public RefCountedBase { + webrtc::Mutex mutex; + enum class Status { + kLive, + kDead + } status RTC_GUARDED_BY(mutex) = Status::kLive; +}; + +AsyncResolver::AsyncResolver() : error_(-1), state_(new State) {} + +AsyncResolver::~AsyncResolver() { + RTC_DCHECK_RUN_ON(&sequence_checker_); + + // Ensure the thread isn't using a stale reference to the current task queue, + // or calling into ResolveDone post destruction. + webrtc::MutexLock lock(&state_->mutex); + state_->status = State::Status::kDead; +} + +void RunResolution(void* obj) { + std::function<void()>* function_ptr = + static_cast<std::function<void()>*>(obj); + (*function_ptr)(); + delete function_ptr; +} + +void AsyncResolver::Start(const SocketAddress& addr) { + Start(addr, addr.family()); +} + +void AsyncResolver::Start(const SocketAddress& addr, int family) { + RTC_DCHECK_RUN_ON(&sequence_checker_); + RTC_DCHECK(!destroy_called_); + addr_ = addr; + auto thread_function = [this, addr, family, + caller_task_queue = webrtc::TaskQueueBase::Current(), + state = state_] { + std::vector<IPAddress> addresses; + int error = ResolveHostname(addr.hostname(), family, &addresses); + webrtc::MutexLock lock(&state->mutex); + if (state->status == State::Status::kLive) { + caller_task_queue->PostTask( + [this, error, addresses = std::move(addresses), state] { + bool live; + { + // ResolveDone can lead to instance destruction, so make sure + // we don't deadlock. + webrtc::MutexLock lock(&state->mutex); + live = state->status == State::Status::kLive; + } + if (live) { + RTC_DCHECK_RUN_ON(&sequence_checker_); + ResolveDone(std::move(addresses), error); + } + }); + } + }; +#if defined(WEBRTC_MAC) || defined(WEBRTC_IOS) + PostTaskToGlobalQueue( + std::make_unique<absl::AnyInvocable<void() &&>>(thread_function)); +#else + PlatformThread::SpawnDetached(std::move(thread_function), "AsyncResolver"); +#endif +} + +bool AsyncResolver::GetResolvedAddress(int family, SocketAddress* addr) const { + RTC_DCHECK_RUN_ON(&sequence_checker_); + RTC_DCHECK(!destroy_called_); + if (error_ != 0 || addresses_.empty()) + return false; + + *addr = addr_; + for (size_t i = 0; i < addresses_.size(); ++i) { + if (family == addresses_[i].family()) { + addr->SetResolvedIP(addresses_[i]); + return true; + } + } + return false; +} + +int AsyncResolver::GetError() const { + RTC_DCHECK_RUN_ON(&sequence_checker_); + RTC_DCHECK(!destroy_called_); + return error_; +} + +void AsyncResolver::Destroy(bool wait) { + // Some callers have trouble guaranteeing that Destroy is called on the + // sequence guarded by `sequence_checker_`. + // RTC_DCHECK_RUN_ON(&sequence_checker_); + RTC_DCHECK(!destroy_called_); + destroy_called_ = true; + MaybeSelfDestruct(); +} + +const std::vector<IPAddress>& AsyncResolver::addresses() const { + RTC_DCHECK_RUN_ON(&sequence_checker_); + RTC_DCHECK(!destroy_called_); + return addresses_; +} + +void AsyncResolver::ResolveDone(std::vector<IPAddress> addresses, int error) { + addresses_ = addresses; + error_ = error; + recursion_check_ = true; + SignalDone(this); + MaybeSelfDestruct(); +} + +void AsyncResolver::MaybeSelfDestruct() { + if (!recursion_check_) { + delete this; + } else { + recursion_check_ = false; + } +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/async_resolver.h b/third_party/libwebrtc/rtc_base/async_resolver.h new file mode 100644 index 0000000000..9de4d12fed --- /dev/null +++ b/third_party/libwebrtc/rtc_base/async_resolver.h @@ -0,0 +1,80 @@ +/* + * Copyright 2008 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 RTC_BASE_ASYNC_RESOLVER_H_ +#define RTC_BASE_ASYNC_RESOLVER_H_ + +#if defined(WEBRTC_POSIX) +#include <sys/socket.h> +#elif WEBRTC_WIN +#include <winsock2.h> // NOLINT +#endif + +#include <vector> + +#include "api/sequence_checker.h" +#include "api/task_queue/pending_task_safety_flag.h" +#include "rtc_base/async_resolver_interface.h" +#include "rtc_base/event.h" +#include "rtc_base/ip_address.h" +#include "rtc_base/socket_address.h" +#include "rtc_base/system/no_unique_address.h" +#include "rtc_base/system/rtc_export.h" +#include "rtc_base/thread.h" +#include "rtc_base/thread_annotations.h" + +namespace rtc { + +// AsyncResolver will perform async DNS resolution, signaling the result on +// the SignalDone from AsyncResolverInterface when the operation completes. +// +// This class is thread-compatible, and all methods and destruction needs to +// happen from the same rtc::Thread, except for Destroy which is allowed to +// happen on another context provided it's not happening concurrently to another +// public API call, and is the last access to the object. +// TODO(bugs.webrtc.org/12598): Deprecate and remove +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wstrict-aliasing" +class [[deprecated("Use AsyncDnsResolver")]] RTC_EXPORT AsyncResolver + : public AsyncResolverInterface { +#pragma clang diagnostic pop + public: + AsyncResolver(); + ~AsyncResolver() override; + + void Start(const SocketAddress& addr) override; + void Start(const SocketAddress& addr, int family) override; + bool GetResolvedAddress(int family, SocketAddress* addr) const override; + int GetError() const override; + void Destroy(bool wait) override; + + const std::vector<IPAddress>& addresses() const; + + private: + // Fwd decl. + struct State; + + void ResolveDone(std::vector<IPAddress> addresses, int error) + RTC_EXCLUSIVE_LOCKS_REQUIRED(sequence_checker_); + void MaybeSelfDestruct(); + + SocketAddress addr_ RTC_GUARDED_BY(sequence_checker_); + std::vector<IPAddress> addresses_ RTC_GUARDED_BY(sequence_checker_); + int error_ RTC_GUARDED_BY(sequence_checker_); + bool recursion_check_ = + false; // Protects against SignalDone calling into Destroy. + bool destroy_called_ = false; + scoped_refptr<State> state_; + RTC_NO_UNIQUE_ADDRESS webrtc::SequenceChecker sequence_checker_; +}; + +} // namespace rtc + +#endif // RTC_BASE_ASYNC_RESOLVER_H_ diff --git a/third_party/libwebrtc/rtc_base/async_resolver_interface.cc b/third_party/libwebrtc/rtc_base/async_resolver_interface.cc new file mode 100644 index 0000000000..ff8c87e346 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/async_resolver_interface.cc @@ -0,0 +1,19 @@ +/* + * Copyright 2015 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 "rtc_base/async_resolver_interface.h" + +namespace rtc { + +AsyncResolverInterface::AsyncResolverInterface() {} + +AsyncResolverInterface::~AsyncResolverInterface() = default; + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/async_resolver_interface.h b/third_party/libwebrtc/rtc_base/async_resolver_interface.h new file mode 100644 index 0000000000..a0bda2774a --- /dev/null +++ b/third_party/libwebrtc/rtc_base/async_resolver_interface.h @@ -0,0 +1,55 @@ +/* + * Copyright 2013 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 RTC_BASE_ASYNC_RESOLVER_INTERFACE_H_ +#define RTC_BASE_ASYNC_RESOLVER_INTERFACE_H_ + +#include "rtc_base/checks.h" +#include "rtc_base/socket_address.h" +#include "rtc_base/system/rtc_export.h" +#include "rtc_base/third_party/sigslot/sigslot.h" + +namespace rtc { + +// This interface defines the methods to resolve the address asynchronously. +// TODO(bugs.webrtc.org/12598): Deprecate and remove. +class [[deprecated("Use AsyncDnsResolver")]] RTC_EXPORT AsyncResolverInterface { + public: + AsyncResolverInterface(); + virtual ~AsyncResolverInterface(); + + // Start address resolution of the hostname in `addr`. + virtual void Start(const SocketAddress& addr) = 0; + // Start address resolution of the hostname in `addr` matching `family`. + virtual void Start(const SocketAddress& addr, int family) = 0; + // Returns true iff the address from `Start` was successfully resolved. + // If the address was successfully resolved, sets `addr` to a copy of the + // address from `Start` with the IP address set to the top most resolved + // address of `family` (`addr` will have both hostname and the resolved ip). + virtual bool GetResolvedAddress(int family, SocketAddress* addr) const = 0; + // Returns error from resolver. + virtual int GetError() const = 0; + // Delete the resolver. + virtual void Destroy(bool wait) = 0; + // Returns top most resolved IPv4 address if address is resolved successfully. + // Otherwise returns address set in SetAddress. + SocketAddress address() const { + SocketAddress addr; + GetResolvedAddress(AF_INET, &addr); + return addr; + } + + // This signal is fired when address resolve process is completed. + sigslot::signal1<AsyncResolverInterface*> SignalDone; +}; + +} // namespace rtc + +#endif diff --git a/third_party/libwebrtc/rtc_base/async_resolver_interface_gn/moz.build b/third_party/libwebrtc/rtc_base/async_resolver_interface_gn/moz.build new file mode 100644 index 0000000000..485ef7ae1c --- /dev/null +++ b/third_party/libwebrtc/rtc_base/async_resolver_interface_gn/moz.build @@ -0,0 +1,233 @@ +# 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/rtc_base/async_resolver_interface.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_ENABLE_LIBEVENT"] = 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 += [ + "GLESv2", + "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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("async_resolver_interface_gn") diff --git a/third_party/libwebrtc/rtc_base/async_socket.cc b/third_party/libwebrtc/rtc_base/async_socket.cc new file mode 100644 index 0000000000..7289b5c959 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/async_socket.cc @@ -0,0 +1,113 @@ +/* + * Copyright 2010 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 "rtc_base/async_socket.h" + +#include "absl/memory/memory.h" +#include "rtc_base/checks.h" + +namespace rtc { + +AsyncSocketAdapter::AsyncSocketAdapter(Socket* socket) + : socket_(absl::WrapUnique(socket)) { + RTC_DCHECK(socket_); + socket_->SignalConnectEvent.connect(this, + &AsyncSocketAdapter::OnConnectEvent); + socket_->SignalReadEvent.connect(this, &AsyncSocketAdapter::OnReadEvent); + socket_->SignalWriteEvent.connect(this, &AsyncSocketAdapter::OnWriteEvent); + socket_->SignalCloseEvent.connect(this, &AsyncSocketAdapter::OnCloseEvent); +} + +SocketAddress AsyncSocketAdapter::GetLocalAddress() const { + return socket_->GetLocalAddress(); +} + +SocketAddress AsyncSocketAdapter::GetRemoteAddress() const { + return socket_->GetRemoteAddress(); +} + +int AsyncSocketAdapter::Bind(const SocketAddress& addr) { + return socket_->Bind(addr); +} + +int AsyncSocketAdapter::Connect(const SocketAddress& addr) { + return socket_->Connect(addr); +} + +int AsyncSocketAdapter::Send(const void* pv, size_t cb) { + return socket_->Send(pv, cb); +} + +int AsyncSocketAdapter::SendTo(const void* pv, + size_t cb, + const SocketAddress& addr) { + return socket_->SendTo(pv, cb, addr); +} + +int AsyncSocketAdapter::Recv(void* pv, size_t cb, int64_t* timestamp) { + return socket_->Recv(pv, cb, timestamp); +} + +int AsyncSocketAdapter::RecvFrom(void* pv, + size_t cb, + SocketAddress* paddr, + int64_t* timestamp) { + return socket_->RecvFrom(pv, cb, paddr, timestamp); +} + +int AsyncSocketAdapter::Listen(int backlog) { + return socket_->Listen(backlog); +} + +Socket* AsyncSocketAdapter::Accept(SocketAddress* paddr) { + return socket_->Accept(paddr); +} + +int AsyncSocketAdapter::Close() { + return socket_->Close(); +} + +int AsyncSocketAdapter::GetError() const { + return socket_->GetError(); +} + +void AsyncSocketAdapter::SetError(int error) { + return socket_->SetError(error); +} + +Socket::ConnState AsyncSocketAdapter::GetState() const { + return socket_->GetState(); +} + +int AsyncSocketAdapter::GetOption(Option opt, int* value) { + return socket_->GetOption(opt, value); +} + +int AsyncSocketAdapter::SetOption(Option opt, int value) { + return socket_->SetOption(opt, value); +} + +void AsyncSocketAdapter::OnConnectEvent(Socket* socket) { + SignalConnectEvent(this); +} + +void AsyncSocketAdapter::OnReadEvent(Socket* socket) { + SignalReadEvent(this); +} + +void AsyncSocketAdapter::OnWriteEvent(Socket* socket) { + SignalWriteEvent(this); +} + +void AsyncSocketAdapter::OnCloseEvent(Socket* socket, int err) { + SignalCloseEvent(this, err); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/async_socket.h b/third_party/libwebrtc/rtc_base/async_socket.h new file mode 100644 index 0000000000..0772cb8d97 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/async_socket.h @@ -0,0 +1,65 @@ +/* + * 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 RTC_BASE_ASYNC_SOCKET_H_ +#define RTC_BASE_ASYNC_SOCKET_H_ + +#include <stddef.h> +#include <stdint.h> + +#include <memory> + +#include "rtc_base/socket.h" +#include "rtc_base/socket_address.h" +#include "rtc_base/third_party/sigslot/sigslot.h" + +namespace rtc { + +class AsyncSocketAdapter : public Socket, public sigslot::has_slots<> { + public: + // Takes ownership of the passed in socket. + // TODO(bugs.webrtc.org/6424): Change to unique_ptr here and in callers. + explicit AsyncSocketAdapter(Socket* socket); + + SocketAddress GetLocalAddress() const override; + SocketAddress GetRemoteAddress() const override; + int Bind(const SocketAddress& addr) override; + int Connect(const SocketAddress& addr) override; + int Send(const void* pv, size_t cb) override; + int SendTo(const void* pv, size_t cb, const SocketAddress& addr) override; + int Recv(void* pv, size_t cb, int64_t* timestamp) override; + int RecvFrom(void* pv, + size_t cb, + SocketAddress* paddr, + int64_t* timestamp) override; + int Listen(int backlog) override; + Socket* Accept(SocketAddress* paddr) override; + int Close() override; + int GetError() const override; + void SetError(int error) override; + ConnState GetState() const override; + int GetOption(Option opt, int* value) override; + int SetOption(Option opt, int value) override; + + protected: + virtual void OnConnectEvent(Socket* socket); + virtual void OnReadEvent(Socket* socket); + virtual void OnWriteEvent(Socket* socket); + virtual void OnCloseEvent(Socket* socket, int err); + + Socket* GetSocket() const { return socket_.get(); } + + private: + const std::unique_ptr<Socket> socket_; +}; + +} // namespace rtc + +#endif // RTC_BASE_ASYNC_SOCKET_H_ diff --git a/third_party/libwebrtc/rtc_base/async_tcp_socket.cc b/third_party/libwebrtc/rtc_base/async_tcp_socket.cc new file mode 100644 index 0000000000..367c5b04e7 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/async_tcp_socket.cc @@ -0,0 +1,354 @@ +/* + * 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 "rtc_base/async_tcp_socket.h" + +#include <stdint.h> +#include <string.h> + +#include <algorithm> +#include <memory> + +#include "api/array_view.h" +#include "rtc_base/byte_order.h" +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" +#include "rtc_base/network/sent_packet.h" +#include "rtc_base/time_utils.h" // for TimeMillis + +#if defined(WEBRTC_POSIX) +#include <errno.h> +#endif // WEBRTC_POSIX + +namespace rtc { + +static const size_t kMaxPacketSize = 64 * 1024; + +typedef uint16_t PacketLength; +static const size_t kPacketLenSize = sizeof(PacketLength); + +static const size_t kBufSize = kMaxPacketSize + kPacketLenSize; + +// The input buffer will be resized so that at least kMinimumRecvSize bytes can +// be received (but it will not grow above the maximum size passed to the +// constructor). +static const size_t kMinimumRecvSize = 128; + +static const int kListenBacklog = 5; + +// Binds and connects `socket` +Socket* AsyncTCPSocketBase::ConnectSocket( + rtc::Socket* socket, + const rtc::SocketAddress& bind_address, + const rtc::SocketAddress& remote_address) { + std::unique_ptr<rtc::Socket> owned_socket(socket); + if (socket->Bind(bind_address) < 0) { + RTC_LOG(LS_ERROR) << "Bind() failed with error " << socket->GetError(); + return nullptr; + } + if (socket->Connect(remote_address) < 0) { + RTC_LOG(LS_ERROR) << "Connect() failed with error " << socket->GetError(); + return nullptr; + } + return owned_socket.release(); +} + +AsyncTCPSocketBase::AsyncTCPSocketBase(Socket* socket, size_t max_packet_size) + : socket_(socket), + max_insize_(max_packet_size), + max_outsize_(max_packet_size) { + inbuf_.EnsureCapacity(kMinimumRecvSize); + + socket_->SignalConnectEvent.connect(this, + &AsyncTCPSocketBase::OnConnectEvent); + socket_->SignalReadEvent.connect(this, &AsyncTCPSocketBase::OnReadEvent); + socket_->SignalWriteEvent.connect(this, &AsyncTCPSocketBase::OnWriteEvent); + socket_->SignalCloseEvent.connect(this, &AsyncTCPSocketBase::OnCloseEvent); +} + +AsyncTCPSocketBase::~AsyncTCPSocketBase() {} + +SocketAddress AsyncTCPSocketBase::GetLocalAddress() const { + return socket_->GetLocalAddress(); +} + +SocketAddress AsyncTCPSocketBase::GetRemoteAddress() const { + return socket_->GetRemoteAddress(); +} + +int AsyncTCPSocketBase::Close() { + return socket_->Close(); +} + +AsyncTCPSocket::State AsyncTCPSocketBase::GetState() const { + switch (socket_->GetState()) { + case Socket::CS_CLOSED: + return STATE_CLOSED; + case Socket::CS_CONNECTING: + return STATE_CONNECTING; + case Socket::CS_CONNECTED: + return STATE_CONNECTED; + default: + RTC_DCHECK_NOTREACHED(); + return STATE_CLOSED; + } +} + +int AsyncTCPSocketBase::GetOption(Socket::Option opt, int* value) { + return socket_->GetOption(opt, value); +} + +int AsyncTCPSocketBase::SetOption(Socket::Option opt, int value) { + return socket_->SetOption(opt, value); +} + +int AsyncTCPSocketBase::GetError() const { + return socket_->GetError(); +} + +void AsyncTCPSocketBase::SetError(int error) { + return socket_->SetError(error); +} + +int AsyncTCPSocketBase::SendTo(const void* pv, + size_t cb, + const SocketAddress& addr, + const rtc::PacketOptions& options) { + const SocketAddress& remote_address = GetRemoteAddress(); + if (addr == remote_address) + return Send(pv, cb, options); + // Remote address may be empty if there is a sudden network change. + RTC_DCHECK(remote_address.IsNil()); + socket_->SetError(ENOTCONN); + return -1; +} + +int AsyncTCPSocketBase::FlushOutBuffer() { + RTC_DCHECK_GT(outbuf_.size(), 0); + rtc::ArrayView<uint8_t> view = outbuf_; + int res; + while (view.size() > 0) { + res = socket_->Send(view.data(), view.size()); + if (res <= 0) { + break; + } + if (static_cast<size_t>(res) > view.size()) { + RTC_DCHECK_NOTREACHED(); + res = -1; + break; + } + view = view.subview(res); + } + if (res > 0) { + // The output buffer may have been written out over multiple partial Send(), + // so reconstruct the total written length. + RTC_DCHECK_EQ(view.size(), 0); + res = outbuf_.size(); + outbuf_.Clear(); + } else { + // There was an error when calling Send(), so there will still be data left + // to send at a later point. + RTC_DCHECK_GT(view.size(), 0); + // In the special case of EWOULDBLOCK, signal that we had a partial write. + if (socket_->GetError() == EWOULDBLOCK) { + res = outbuf_.size() - view.size(); + } + if (view.size() < outbuf_.size()) { + memmove(outbuf_.data(), view.data(), view.size()); + outbuf_.SetSize(view.size()); + } + } + return res; +} + +void AsyncTCPSocketBase::AppendToOutBuffer(const void* pv, size_t cb) { + RTC_DCHECK(outbuf_.size() + cb <= max_outsize_); + outbuf_.AppendData(static_cast<const uint8_t*>(pv), cb); +} + +void AsyncTCPSocketBase::OnConnectEvent(Socket* socket) { + SignalConnect(this); +} + +void AsyncTCPSocketBase::OnReadEvent(Socket* socket) { + RTC_DCHECK(socket_.get() == socket); + + size_t total_recv = 0; + while (true) { + size_t free_size = inbuf_.capacity() - inbuf_.size(); + if (free_size < kMinimumRecvSize && inbuf_.capacity() < max_insize_) { + inbuf_.EnsureCapacity(std::min(max_insize_, inbuf_.capacity() * 2)); + free_size = inbuf_.capacity() - inbuf_.size(); + } + + int len = socket_->Recv(inbuf_.data() + inbuf_.size(), free_size, nullptr); + if (len < 0) { + // TODO(stefan): Do something better like forwarding the error to the + // user. + if (!socket_->IsBlocking()) { + RTC_LOG(LS_ERROR) << "Recv() returned error: " << socket_->GetError(); + } + break; + } + + total_recv += len; + inbuf_.SetSize(inbuf_.size() + len); + if (!len || static_cast<size_t>(len) < free_size) { + break; + } + } + + if (!total_recv) { + return; + } + + size_t size = inbuf_.size(); + ProcessInput(inbuf_.data<char>(), &size); + + if (size > inbuf_.size()) { + RTC_LOG(LS_ERROR) << "input buffer overflow"; + RTC_DCHECK_NOTREACHED(); + inbuf_.Clear(); + } else { + inbuf_.SetSize(size); + } +} + +void AsyncTCPSocketBase::OnWriteEvent(Socket* socket) { + RTC_DCHECK(socket_.get() == socket); + + if (outbuf_.size() > 0) { + FlushOutBuffer(); + } + + if (outbuf_.size() == 0) { + SignalReadyToSend(this); + } +} + +void AsyncTCPSocketBase::OnCloseEvent(Socket* socket, int error) { + NotifyClosed(error); +} + +// AsyncTCPSocket +// Binds and connects `socket` and creates AsyncTCPSocket for +// it. Takes ownership of `socket`. Returns null if bind() or +// connect() fail (`socket` is destroyed in that case). +AsyncTCPSocket* AsyncTCPSocket::Create(Socket* socket, + const SocketAddress& bind_address, + const SocketAddress& remote_address) { + return new AsyncTCPSocket( + AsyncTCPSocketBase::ConnectSocket(socket, bind_address, remote_address)); +} + +AsyncTCPSocket::AsyncTCPSocket(Socket* socket) + : AsyncTCPSocketBase(socket, kBufSize) {} + +int AsyncTCPSocket::Send(const void* pv, + size_t cb, + const rtc::PacketOptions& options) { + if (cb > kBufSize) { + SetError(EMSGSIZE); + return -1; + } + + // If we are blocking on send, then silently drop this packet + if (!IsOutBufferEmpty()) + return static_cast<int>(cb); + + PacketLength pkt_len = HostToNetwork16(static_cast<PacketLength>(cb)); + AppendToOutBuffer(&pkt_len, kPacketLenSize); + AppendToOutBuffer(pv, cb); + + int res = FlushOutBuffer(); + if (res <= 0) { + // drop packet if we made no progress + ClearOutBuffer(); + return res; + } + + rtc::SentPacket sent_packet(options.packet_id, rtc::TimeMillis(), + options.info_signaled_after_sent); + CopySocketInformationToPacketInfo(cb, *this, false, &sent_packet.info); + SignalSentPacket(this, sent_packet); + + // We claim to have sent the whole thing, even if we only sent partial + return static_cast<int>(cb); +} + +void AsyncTCPSocket::ProcessInput(char* data, size_t* len) { + SocketAddress remote_addr(GetRemoteAddress()); + + while (true) { + if (*len < kPacketLenSize) + return; + + PacketLength pkt_len = rtc::GetBE16(data); + if (*len < kPacketLenSize + pkt_len) + return; + + SignalReadPacket(this, data + kPacketLenSize, pkt_len, remote_addr, + TimeMicros()); + + *len -= kPacketLenSize + pkt_len; + if (*len > 0) { + memmove(data, data + kPacketLenSize + pkt_len, *len); + } + } +} + +AsyncTcpListenSocket::AsyncTcpListenSocket(std::unique_ptr<Socket> socket) + : socket_(std::move(socket)) { + RTC_DCHECK(socket_.get() != nullptr); + socket_->SignalReadEvent.connect(this, &AsyncTcpListenSocket::OnReadEvent); + if (socket_->Listen(kListenBacklog) < 0) { + RTC_LOG(LS_ERROR) << "Listen() failed with error " << socket_->GetError(); + } +} + +AsyncTcpListenSocket::State AsyncTcpListenSocket::GetState() const { + switch (socket_->GetState()) { + case Socket::CS_CLOSED: + return State::kClosed; + case Socket::CS_CONNECTING: + return State::kBound; + default: + RTC_DCHECK_NOTREACHED(); + return State::kClosed; + } +} + +SocketAddress AsyncTcpListenSocket::GetLocalAddress() const { + return socket_->GetLocalAddress(); +} + +void AsyncTcpListenSocket::OnReadEvent(Socket* socket) { + RTC_DCHECK(socket_.get() == socket); + + rtc::SocketAddress address; + rtc::Socket* new_socket = socket->Accept(&address); + if (!new_socket) { + // TODO(stefan): Do something better like forwarding the error + // to the user. + RTC_LOG(LS_ERROR) << "TCP accept failed with error " << socket_->GetError(); + return; + } + + HandleIncomingConnection(new_socket); + + // Prime a read event in case data is waiting. + new_socket->SignalReadEvent(new_socket); +} + +void AsyncTcpListenSocket::HandleIncomingConnection(Socket* socket) { + SignalNewConnection(this, new AsyncTCPSocket(socket)); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/async_tcp_socket.h b/third_party/libwebrtc/rtc_base/async_tcp_socket.h new file mode 100644 index 0000000000..541080fba7 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/async_tcp_socket.h @@ -0,0 +1,123 @@ +/* + * 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 RTC_BASE_ASYNC_TCP_SOCKET_H_ +#define RTC_BASE_ASYNC_TCP_SOCKET_H_ + +#include <stddef.h> + +#include <memory> + +#include "rtc_base/async_packet_socket.h" +#include "rtc_base/buffer.h" +#include "rtc_base/socket.h" +#include "rtc_base/socket_address.h" + +namespace rtc { + +// Simulates UDP semantics over TCP. Send and Recv packet sizes +// are preserved, and drops packets silently on Send, rather than +// buffer them in user space. +class AsyncTCPSocketBase : public AsyncPacketSocket { + public: + AsyncTCPSocketBase(Socket* socket, size_t max_packet_size); + ~AsyncTCPSocketBase() override; + + AsyncTCPSocketBase(const AsyncTCPSocketBase&) = delete; + AsyncTCPSocketBase& operator=(const AsyncTCPSocketBase&) = delete; + + // Pure virtual methods to send and recv data. + int Send(const void* pv, + size_t cb, + const rtc::PacketOptions& options) override = 0; + virtual void ProcessInput(char* data, size_t* len) = 0; + + SocketAddress GetLocalAddress() const override; + SocketAddress GetRemoteAddress() const override; + int SendTo(const void* pv, + size_t cb, + const SocketAddress& addr, + const rtc::PacketOptions& options) override; + int Close() override; + + State GetState() const override; + int GetOption(Socket::Option opt, int* value) override; + int SetOption(Socket::Option opt, int value) override; + int GetError() const override; + void SetError(int error) override; + + protected: + // Binds and connects `socket` and creates AsyncTCPSocket for + // it. Takes ownership of `socket`. Returns null if bind() or + // connect() fail (`socket` is destroyed in that case). + static Socket* ConnectSocket(Socket* socket, + const SocketAddress& bind_address, + const SocketAddress& remote_address); + int FlushOutBuffer(); + // Add data to `outbuf_`. + void AppendToOutBuffer(const void* pv, size_t cb); + + // Helper methods for `outpos_`. + bool IsOutBufferEmpty() const { return outbuf_.size() == 0; } + void ClearOutBuffer() { outbuf_.Clear(); } + + private: + // Called by the underlying socket + void OnConnectEvent(Socket* socket); + void OnReadEvent(Socket* socket); + void OnWriteEvent(Socket* socket); + void OnCloseEvent(Socket* socket, int error); + + std::unique_ptr<Socket> socket_; + Buffer inbuf_; + Buffer outbuf_; + size_t max_insize_; + size_t max_outsize_; +}; + +class AsyncTCPSocket : public AsyncTCPSocketBase { + public: + // Binds and connects `socket` and creates AsyncTCPSocket for + // it. Takes ownership of `socket`. Returns null if bind() or + // connect() fail (`socket` is destroyed in that case). + static AsyncTCPSocket* Create(Socket* socket, + const SocketAddress& bind_address, + const SocketAddress& remote_address); + explicit AsyncTCPSocket(Socket* socket); + ~AsyncTCPSocket() override {} + + AsyncTCPSocket(const AsyncTCPSocket&) = delete; + AsyncTCPSocket& operator=(const AsyncTCPSocket&) = delete; + + int Send(const void* pv, + size_t cb, + const rtc::PacketOptions& options) override; + void ProcessInput(char* data, size_t* len) override; +}; + +class AsyncTcpListenSocket : public AsyncListenSocket { + public: + explicit AsyncTcpListenSocket(std::unique_ptr<Socket> socket); + + State GetState() const override; + SocketAddress GetLocalAddress() const override; + + virtual void HandleIncomingConnection(rtc::Socket* socket); + + private: + // Called by the underlying socket + void OnReadEvent(Socket* socket); + + std::unique_ptr<Socket> socket_; +}; + +} // namespace rtc + +#endif // RTC_BASE_ASYNC_TCP_SOCKET_H_ diff --git a/third_party/libwebrtc/rtc_base/async_tcp_socket_unittest.cc b/third_party/libwebrtc/rtc_base/async_tcp_socket_unittest.cc new file mode 100644 index 0000000000..af82238a37 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/async_tcp_socket_unittest.cc @@ -0,0 +1,47 @@ +/* + * 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 "rtc_base/async_tcp_socket.h" + +#include <memory> +#include <string> + +#include "rtc_base/gunit.h" +#include "rtc_base/virtual_socket_server.h" + +namespace rtc { + +class AsyncTCPSocketTest : public ::testing::Test, public sigslot::has_slots<> { + public: + AsyncTCPSocketTest() + : vss_(new rtc::VirtualSocketServer()), + socket_(vss_->CreateSocket(SOCK_STREAM)), + tcp_socket_(new AsyncTCPSocket(socket_, true)), + ready_to_send_(false) { + tcp_socket_->SignalReadyToSend.connect(this, + &AsyncTCPSocketTest::OnReadyToSend); + } + + void OnReadyToSend(rtc::AsyncPacketSocket* socket) { ready_to_send_ = true; } + + protected: + std::unique_ptr<VirtualSocketServer> vss_; + Socket* socket_; + std::unique_ptr<AsyncTCPSocket> tcp_socket_; + bool ready_to_send_; +}; + +TEST_F(AsyncTCPSocketTest, OnWriteEvent) { + EXPECT_FALSE(ready_to_send_); + socket_->SignalWriteEvent(socket_); + EXPECT_TRUE(ready_to_send_); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/async_udp_socket.cc b/third_party/libwebrtc/rtc_base/async_udp_socket.cc new file mode 100644 index 0000000000..af7ae56fb6 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/async_udp_socket.cc @@ -0,0 +1,147 @@ +/* + * 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 "rtc_base/async_udp_socket.h" + + +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" +#include "rtc_base/network/sent_packet.h" +#include "rtc_base/time_utils.h" +#include "system_wrappers/include/field_trial.h" + +namespace rtc { + +// Returns true if the experiement "WebRTC-SCM-Timestamp" is explicitly +// disabled. +static bool IsScmTimeStampExperimentDisabled() { + return webrtc::field_trial::IsDisabled("WebRTC-SCM-Timestamp"); +} + +AsyncUDPSocket* AsyncUDPSocket::Create(Socket* socket, + const SocketAddress& bind_address) { + std::unique_ptr<Socket> owned_socket(socket); + if (socket->Bind(bind_address) < 0) { + RTC_LOG(LS_ERROR) << "Bind() failed with error " << socket->GetError(); + return nullptr; + } + return new AsyncUDPSocket(owned_socket.release()); +} + +AsyncUDPSocket* AsyncUDPSocket::Create(SocketFactory* factory, + const SocketAddress& bind_address) { + Socket* socket = factory->CreateSocket(bind_address.family(), SOCK_DGRAM); + if (!socket) + return nullptr; + return Create(socket, bind_address); +} + +AsyncUDPSocket::AsyncUDPSocket(Socket* socket) : socket_(socket) { + sequence_checker_.Detach(); + // The socket should start out readable but not writable. + socket_->SignalReadEvent.connect(this, &AsyncUDPSocket::OnReadEvent); + socket_->SignalWriteEvent.connect(this, &AsyncUDPSocket::OnWriteEvent); +} + +SocketAddress AsyncUDPSocket::GetLocalAddress() const { + return socket_->GetLocalAddress(); +} + +SocketAddress AsyncUDPSocket::GetRemoteAddress() const { + return socket_->GetRemoteAddress(); +} + +int AsyncUDPSocket::Send(const void* pv, + size_t cb, + const rtc::PacketOptions& options) { + rtc::SentPacket sent_packet(options.packet_id, rtc::TimeMillis(), + options.info_signaled_after_sent); + CopySocketInformationToPacketInfo(cb, *this, false, &sent_packet.info); + int ret = socket_->Send(pv, cb); + SignalSentPacket(this, sent_packet); + return ret; +} + +int AsyncUDPSocket::SendTo(const void* pv, + size_t cb, + const SocketAddress& addr, + const rtc::PacketOptions& options) { + rtc::SentPacket sent_packet(options.packet_id, rtc::TimeMillis(), + options.info_signaled_after_sent); + CopySocketInformationToPacketInfo(cb, *this, true, &sent_packet.info); + int ret = socket_->SendTo(pv, cb, addr); + SignalSentPacket(this, sent_packet); + return ret; +} + +int AsyncUDPSocket::Close() { + return socket_->Close(); +} + +AsyncUDPSocket::State AsyncUDPSocket::GetState() const { + return STATE_BOUND; +} + +int AsyncUDPSocket::GetOption(Socket::Option opt, int* value) { + return socket_->GetOption(opt, value); +} + +int AsyncUDPSocket::SetOption(Socket::Option opt, int value) { + return socket_->SetOption(opt, value); +} + +int AsyncUDPSocket::GetError() const { + return socket_->GetError(); +} + +void AsyncUDPSocket::SetError(int error) { + return socket_->SetError(error); +} + +void AsyncUDPSocket::OnReadEvent(Socket* socket) { + RTC_DCHECK(socket_.get() == socket); + RTC_DCHECK_RUN_ON(&sequence_checker_); + + SocketAddress remote_addr; + int64_t timestamp = -1; + int len = socket_->RecvFrom(buf_, BUF_SIZE, &remote_addr, ×tamp); + + if (len < 0) { + // An error here typically means we got an ICMP error in response to our + // send datagram, indicating the remote address was unreachable. + // When doing ICE, this kind of thing will often happen. + // TODO: Do something better like forwarding the error to the user. + SocketAddress local_addr = socket_->GetLocalAddress(); + RTC_LOG(LS_INFO) << "AsyncUDPSocket[" << local_addr.ToSensitiveString() + << "] receive failed with error " << socket_->GetError(); + return; + } + if (timestamp == -1) { + // Timestamp from socket is not available. + timestamp = TimeMicros(); + } else { + if (!socket_time_offset_) { + socket_time_offset_ = + !IsScmTimeStampExperimentDisabled() ? TimeMicros() - timestamp : 0; + } + timestamp += *socket_time_offset_; + } + + // TODO: Make sure that we got all of the packet. + // If we did not, then we should resize our buffer to be large enough. + SignalReadPacket(this, buf_, static_cast<size_t>(len), remote_addr, + timestamp); +} + +void AsyncUDPSocket::OnWriteEvent(Socket* socket) { + SignalReadyToSend(this); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/async_udp_socket.h b/third_party/libwebrtc/rtc_base/async_udp_socket.h new file mode 100644 index 0000000000..4198b25c4d --- /dev/null +++ b/third_party/libwebrtc/rtc_base/async_udp_socket.h @@ -0,0 +1,78 @@ +/* + * 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 RTC_BASE_ASYNC_UDP_SOCKET_H_ +#define RTC_BASE_ASYNC_UDP_SOCKET_H_ + +#include <stddef.h> + +#include <cstdint> +#include <memory> + +#include "absl/types/optional.h" +#include "api/sequence_checker.h" +#include "rtc_base/async_packet_socket.h" +#include "rtc_base/socket.h" +#include "rtc_base/socket_address.h" +#include "rtc_base/socket_factory.h" +#include "rtc_base/system/no_unique_address.h" +#include "rtc_base/thread_annotations.h" + +namespace rtc { + +// Provides the ability to receive packets asynchronously. Sends are not +// buffered since it is acceptable to drop packets under high load. +class AsyncUDPSocket : public AsyncPacketSocket { + public: + // Binds `socket` and creates AsyncUDPSocket for it. Takes ownership + // of `socket`. Returns null if bind() fails (`socket` is destroyed + // in that case). + static AsyncUDPSocket* Create(Socket* socket, + const SocketAddress& bind_address); + // Creates a new socket for sending asynchronous UDP packets using an + // asynchronous socket from the given factory. + static AsyncUDPSocket* Create(SocketFactory* factory, + const SocketAddress& bind_address); + explicit AsyncUDPSocket(Socket* socket); + ~AsyncUDPSocket() = default; + + SocketAddress GetLocalAddress() const override; + SocketAddress GetRemoteAddress() const override; + int Send(const void* pv, + size_t cb, + const rtc::PacketOptions& options) override; + int SendTo(const void* pv, + size_t cb, + const SocketAddress& addr, + const rtc::PacketOptions& options) override; + int Close() override; + + State GetState() const override; + int GetOption(Socket::Option opt, int* value) override; + int SetOption(Socket::Option opt, int value) override; + int GetError() const override; + void SetError(int error) override; + + private: + // Called when the underlying socket is ready to be read from. + void OnReadEvent(Socket* socket); + // Called when the underlying socket is ready to send. + void OnWriteEvent(Socket* socket); + + RTC_NO_UNIQUE_ADDRESS webrtc::SequenceChecker sequence_checker_; + std::unique_ptr<Socket> socket_; + static constexpr int BUF_SIZE = 64 * 1024; + char buf_[BUF_SIZE] RTC_GUARDED_BY(sequence_checker_); + absl::optional<int64_t> socket_time_offset_ RTC_GUARDED_BY(sequence_checker_); +}; + +} // namespace rtc + +#endif // RTC_BASE_ASYNC_UDP_SOCKET_H_ diff --git a/third_party/libwebrtc/rtc_base/async_udp_socket_unittest.cc b/third_party/libwebrtc/rtc_base/async_udp_socket_unittest.cc new file mode 100644 index 0000000000..7df1ca0a46 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/async_udp_socket_unittest.cc @@ -0,0 +1,50 @@ +/* + * 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 "rtc_base/async_udp_socket.h" + +#include <memory> +#include <string> + +#include "rtc_base/gunit.h" +#include "rtc_base/physical_socket_server.h" +#include "rtc_base/virtual_socket_server.h" + +namespace rtc { + +class AsyncUdpSocketTest : public ::testing::Test, public sigslot::has_slots<> { + public: + AsyncUdpSocketTest() + : pss_(new rtc::PhysicalSocketServer), + vss_(new rtc::VirtualSocketServer(pss_.get())), + socket_(vss_->CreateSocket(SOCK_DGRAM)), + udp_socket_(new AsyncUDPSocket(socket_)), + ready_to_send_(false) { + udp_socket_->SignalReadyToSend.connect(this, + &AsyncUdpSocketTest::OnReadyToSend); + } + + void OnReadyToSend(rtc::AsyncPacketSocket* socket) { ready_to_send_ = true; } + + protected: + std::unique_ptr<PhysicalSocketServer> pss_; + std::unique_ptr<VirtualSocketServer> vss_; + Socket* socket_; + std::unique_ptr<AsyncUDPSocket> udp_socket_; + bool ready_to_send_; +}; + +TEST_F(AsyncUdpSocketTest, OnWriteEvent) { + EXPECT_FALSE(ready_to_send_); + socket_->SignalWriteEvent(socket_); + EXPECT_TRUE(ready_to_send_); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/audio_format_to_string_gn/moz.build b/third_party/libwebrtc/rtc_base/audio_format_to_string_gn/moz.build new file mode 100644 index 0000000000..62b75c06ce --- /dev/null +++ b/third_party/libwebrtc/rtc_base/audio_format_to_string_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/rtc_base/strings/audio_format_to_string.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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("audio_format_to_string_gn") diff --git a/third_party/libwebrtc/rtc_base/base64_unittest.cc b/third_party/libwebrtc/rtc_base/base64_unittest.cc new file mode 100644 index 0000000000..6722a1f5d9 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/base64_unittest.cc @@ -0,0 +1,1454 @@ +/* + * Copyright 2011 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 "rtc_base/third_party/base64/base64.h" + +#include <stdio.h> +#include <string.h> + +#include <algorithm> + +#include "rtc_base/logging.h" +#include "rtc_base/test_base64.h" +#include "test/gtest.h" + +namespace rtc { +namespace { + +static struct { + size_t plain_length; + const char* plaintext; + const char* cyphertext; +} base64_tests[] = { + + // Basic bit patterns; + // values obtained with "echo -n '...' | uuencode -m test" + + {1, "\000", "AA=="}, + {1, "\001", "AQ=="}, + {1, "\002", "Ag=="}, + {1, "\004", "BA=="}, + {1, "\010", "CA=="}, + {1, "\020", "EA=="}, + {1, "\040", "IA=="}, + {1, "\100", "QA=="}, + {1, "\200", "gA=="}, + + {1, "\377", "/w=="}, + {1, "\376", "/g=="}, + {1, "\375", "/Q=="}, + {1, "\373", "+w=="}, + {1, "\367", "9w=="}, + {1, "\357", "7w=="}, + {1, "\337", "3w=="}, + {1, "\277", "vw=="}, + {1, "\177", "fw=="}, + {2, "\000\000", "AAA="}, + {2, "\000\001", "AAE="}, + {2, "\000\002", "AAI="}, + {2, "\000\004", "AAQ="}, + {2, "\000\010", "AAg="}, + {2, "\000\020", "ABA="}, + {2, "\000\040", "ACA="}, + {2, "\000\100", "AEA="}, + {2, "\000\200", "AIA="}, + {2, "\001\000", "AQA="}, + {2, "\002\000", "AgA="}, + {2, "\004\000", "BAA="}, + {2, "\010\000", "CAA="}, + {2, "\020\000", "EAA="}, + {2, "\040\000", "IAA="}, + {2, "\100\000", "QAA="}, + {2, "\200\000", "gAA="}, + + {2, "\377\377", "//8="}, + {2, "\377\376", "//4="}, + {2, "\377\375", "//0="}, + {2, "\377\373", "//s="}, + {2, "\377\367", "//c="}, + {2, "\377\357", "/+8="}, + {2, "\377\337", "/98="}, + {2, "\377\277", "/78="}, + {2, "\377\177", "/38="}, + {2, "\376\377", "/v8="}, + {2, "\375\377", "/f8="}, + {2, "\373\377", "+/8="}, + {2, "\367\377", "9/8="}, + {2, "\357\377", "7/8="}, + {2, "\337\377", "3/8="}, + {2, "\277\377", "v/8="}, + {2, "\177\377", "f/8="}, + + {3, "\000\000\000", "AAAA"}, + {3, "\000\000\001", "AAAB"}, + {3, "\000\000\002", "AAAC"}, + {3, "\000\000\004", "AAAE"}, + {3, "\000\000\010", "AAAI"}, + {3, "\000\000\020", "AAAQ"}, + {3, "\000\000\040", "AAAg"}, + {3, "\000\000\100", "AABA"}, + {3, "\000\000\200", "AACA"}, + {3, "\000\001\000", "AAEA"}, + {3, "\000\002\000", "AAIA"}, + {3, "\000\004\000", "AAQA"}, + {3, "\000\010\000", "AAgA"}, + {3, "\000\020\000", "ABAA"}, + {3, "\000\040\000", "ACAA"}, + {3, "\000\100\000", "AEAA"}, + {3, "\000\200\000", "AIAA"}, + {3, "\001\000\000", "AQAA"}, + {3, "\002\000\000", "AgAA"}, + {3, "\004\000\000", "BAAA"}, + {3, "\010\000\000", "CAAA"}, + {3, "\020\000\000", "EAAA"}, + {3, "\040\000\000", "IAAA"}, + {3, "\100\000\000", "QAAA"}, + {3, "\200\000\000", "gAAA"}, + + {3, "\377\377\377", "////"}, + {3, "\377\377\376", "///+"}, + {3, "\377\377\375", "///9"}, + {3, "\377\377\373", "///7"}, + {3, "\377\377\367", "///3"}, + {3, "\377\377\357", "///v"}, + {3, "\377\377\337", "///f"}, + {3, "\377\377\277", "//+/"}, + {3, "\377\377\177", "//9/"}, + {3, "\377\376\377", "//7/"}, + {3, "\377\375\377", "//3/"}, + {3, "\377\373\377", "//v/"}, + {3, "\377\367\377", "//f/"}, + {3, "\377\357\377", "/+//"}, + {3, "\377\337\377", "/9//"}, + {3, "\377\277\377", "/7//"}, + {3, "\377\177\377", "/3//"}, + {3, "\376\377\377", "/v//"}, + {3, "\375\377\377", "/f//"}, + {3, "\373\377\377", "+///"}, + {3, "\367\377\377", "9///"}, + {3, "\357\377\377", "7///"}, + {3, "\337\377\377", "3///"}, + {3, "\277\377\377", "v///"}, + {3, "\177\377\377", "f///"}, + + // Random numbers: values obtained with + // + // #! /bin/bash + // dd bs=$1 count=1 if=/dev/random of=/tmp/bar.random + // od -N $1 -t o1 /tmp/bar.random + // uuencode -m test < /tmp/bar.random + // + // where $1 is the number of bytes (2, 3) + + {2, "\243\361", "o/E="}, + {2, "\024\167", "FHc="}, + {2, "\313\252", "y6o="}, + {2, "\046\041", "JiE="}, + {2, "\145\236", "ZZ4="}, + {2, "\254\325", "rNU="}, + {2, "\061\330", "Mdg="}, + {2, "\245\032", "pRo="}, + {2, "\006\000", "BgA="}, + {2, "\375\131", "/Vk="}, + {2, "\303\210", "w4g="}, + {2, "\040\037", "IB8="}, + {2, "\261\372", "sfo="}, + {2, "\335\014", "3Qw="}, + {2, "\233\217", "m48="}, + {2, "\373\056", "+y4="}, + {2, "\247\232", "p5o="}, + {2, "\107\053", "Rys="}, + {2, "\204\077", "hD8="}, + {2, "\276\211", "vok="}, + {2, "\313\110", "y0g="}, + {2, "\363\376", "8/4="}, + {2, "\251\234", "qZw="}, + {2, "\103\262", "Q7I="}, + {2, "\142\312", "Yso="}, + {2, "\067\211", "N4k="}, + {2, "\220\001", "kAE="}, + {2, "\152\240", "aqA="}, + {2, "\367\061", "9zE="}, + {2, "\133\255", "W60="}, + {2, "\176\035", "fh0="}, + {2, "\032\231", "Gpk="}, + + {3, "\013\007\144", "Cwdk"}, + {3, "\030\112\106", "GEpG"}, + {3, "\047\325\046", "J9Um"}, + {3, "\310\160\022", "yHAS"}, + {3, "\131\100\237", "WUCf"}, + {3, "\064\342\134", "NOJc"}, + {3, "\010\177\004", "CH8E"}, + {3, "\345\147\205", "5WeF"}, + {3, "\300\343\360", "wOPw"}, + {3, "\061\240\201", "MaCB"}, + {3, "\225\333\044", "ldsk"}, + {3, "\215\137\352", "jV/q"}, + {3, "\371\147\160", "+Wdw"}, + {3, "\030\320\051", "GNAp"}, + {3, "\044\174\241", "JHyh"}, + {3, "\260\127\037", "sFcf"}, + {3, "\111\045\033", "SSUb"}, + {3, "\202\114\107", "gkxH"}, + {3, "\057\371\042", "L/ki"}, + {3, "\223\247\244", "k6ek"}, + {3, "\047\216\144", "J45k"}, + {3, "\203\070\327", "gzjX"}, + {3, "\247\140\072", "p2A6"}, + {3, "\124\115\116", "VE1O"}, + {3, "\157\162\050", "b3Io"}, + {3, "\357\223\004", "75ME"}, + {3, "\052\117\156", "Kk9u"}, + {3, "\347\154\000", "52wA"}, + {3, "\303\012\142", "wwpi"}, + {3, "\060\035\362", "MB3y"}, + {3, "\130\226\361", "WJbx"}, + {3, "\173\013\071", "ews5"}, + {3, "\336\004\027", "3gQX"}, + {3, "\357\366\234", "7/ac"}, + {3, "\353\304\111", "68RJ"}, + {3, "\024\264\131", "FLRZ"}, + {3, "\075\114\251", "PUyp"}, + {3, "\315\031\225", "zRmV"}, + {3, "\154\201\276", "bIG+"}, + {3, "\200\066\072", "gDY6"}, + {3, "\142\350\267", "Yui3"}, + {3, "\033\000\166", "GwB2"}, + {3, "\210\055\077", "iC0/"}, + {3, "\341\037\124", "4R9U"}, + {3, "\161\103\152", "cUNq"}, + {3, "\270\142\131", "uGJZ"}, + {3, "\337\076\074", "3z48"}, + {3, "\375\106\362", "/Uby"}, + {3, "\227\301\127", "l8FX"}, + {3, "\340\002\234", "4AKc"}, + {3, "\121\064\033", "UTQb"}, + {3, "\157\134\143", "b1xj"}, + {3, "\247\055\327", "py3X"}, + {3, "\340\142\005", "4GIF"}, + {3, "\060\260\143", "MLBj"}, + {3, "\075\203\170", "PYN4"}, + {3, "\143\160\016", "Y3AO"}, + {3, "\313\013\063", "ywsz"}, + {3, "\174\236\135", "fJ5d"}, + {3, "\103\047\026", "QycW"}, + {3, "\365\005\343", "9QXj"}, + {3, "\271\160\223", "uXCT"}, + {3, "\362\255\172", "8q16"}, + {3, "\113\012\015", "SwoN"}, + + // various lengths, generated by this python script: + // + // from string import lowercase as lc + // for i in range(27): + // print '{ %2d, "%s",%s "%s" },' % (i, lc[:i], ' ' * (26-i), + // lc[:i].encode('base64').strip()) + + {0, "abcdefghijklmnopqrstuvwxyz", ""}, + {1, "abcdefghijklmnopqrstuvwxyz", "YQ=="}, + {2, "abcdefghijklmnopqrstuvwxyz", "YWI="}, + {3, "abcdefghijklmnopqrstuvwxyz", "YWJj"}, + {4, "abcdefghijklmnopqrstuvwxyz", "YWJjZA=="}, + {5, "abcdefghijklmnopqrstuvwxyz", "YWJjZGU="}, + {6, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVm"}, + {7, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZw=="}, + {8, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2g="}, + {9, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hp"}, + {10, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpag=="}, + {11, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpams="}, + {12, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpamts"}, + {13, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpamtsbQ=="}, + {14, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpamtsbW4="}, + {15, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpamtsbW5v"}, + {16, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpamtsbW5vcA=="}, + {17, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpamtsbW5vcHE="}, + {18, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpamtsbW5vcHFy"}, + {19, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpamtsbW5vcHFycw=="}, + {20, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpamtsbW5vcHFyc3Q="}, + {21, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1"}, + {22, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dg=="}, + {23, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnc="}, + {24, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4"}, + {25, "abcdefghijklmnopqrstuvwxy", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eQ=="}, + {26, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo="}, +}; +#if 0 +static struct { + const char* plaintext; + const char* cyphertext; +} base64_strings[] = { + + // The first few Google quotes + // Cyphertext created with "uuencode - GNU sharutils 4.2.1" + { + "Everyone! We're teetering on the brink of disaster." + " - Sergey Brin, 6/24/99, regarding the company's state " + "after the unleashing of Netscape/Google search", + + "RXZlcnlvbmUhICBXZSdyZSB0ZWV0ZXJpbmcgb24gdGhlIGJyaW5rIG9mIGRp" + "c2FzdGVyLiAtIFNlcmdleSBCcmluLCA2LzI0Lzk5LCByZWdhcmRpbmcgdGhl" + "IGNvbXBhbnkncyBzdGF0ZSBhZnRlciB0aGUgdW5sZWFzaGluZyBvZiBOZXRz" + "Y2FwZS9Hb29nbGUgc2VhcmNo" }, + + { + "I'm not sure why we're still alive, but we seem to be." + " - Larry Page, 6/24/99, while hiding in the kitchenette " + "during the Netscape traffic overflow", + + "SSdtIG5vdCBzdXJlIHdoeSB3ZSdyZSBzdGlsbCBhbGl2ZSwgYnV0IHdlIHNl" + "ZW0gdG8gYmUuIC0gTGFycnkgUGFnZSwgNi8yNC85OSwgd2hpbGUgaGlkaW5n" + "IGluIHRoZSBraXRjaGVuZXR0ZSBkdXJpbmcgdGhlIE5ldHNjYXBlIHRyYWZm" + "aWMgb3ZlcmZsb3c" }, + + { + "I think kids want porn." + " - Sergey Brin, 6/99, on why Google shouldn't prioritize a " + "filtered search for children and families", + + "SSB0aGluayBraWRzIHdhbnQgcG9ybi4gLSBTZXJnZXkgQnJpbiwgNi85OSwg" + "b24gd2h5IEdvb2dsZSBzaG91bGRuJ3QgcHJpb3JpdGl6ZSBhIGZpbHRlcmVk" + "IHNlYXJjaCBmb3IgY2hpbGRyZW4gYW5kIGZhbWlsaWVz" }, +}; +#endif +// Compare bytes 0..len-1 of x and y. If not equal, abort with verbose error +// message showing position and numeric value that differed. +// Handles embedded nulls just like any other byte. +// Only added because string.compare() in gcc-3.3.3 seems to misbehave with +// embedded nulls. +// TODO: switch back to string.compare() if/when gcc is fixed +#define EXPECT_EQ_ARRAY(len, x, y, msg) \ + for (size_t j = 0; j < len; ++j) { \ + if (x[j] != y[j]) { \ + RTC_LOG(LS_ERROR) << "" #x << " != " #y << " byte " << j \ + << " msg: " << msg; \ + } \ + } + +size_t Base64Escape(const unsigned char* src, + size_t szsrc, + char* dest, + size_t szdest) { + std::string escaped; + Base64::EncodeFromArray((const char*)src, szsrc, &escaped); + memcpy(dest, escaped.data(), std::min(escaped.size(), szdest)); + return escaped.size(); +} + +size_t Base64Unescape(const char* src, + size_t szsrc, + char* dest, + size_t szdest) { + std::string unescaped; + EXPECT_TRUE( + Base64::DecodeFromArray(src, szsrc, Base64::DO_LAX, &unescaped, nullptr)); + memcpy(dest, unescaped.data(), std::min(unescaped.size(), szdest)); + return unescaped.size(); +} + +size_t Base64Unescape(const char* src, size_t szsrc, std::string* s) { + EXPECT_TRUE(Base64::DecodeFromArray(src, szsrc, Base64::DO_LAX, s, nullptr)); + return s->size(); +} + +TEST(Base64, EncodeDecodeBattery) { + RTC_LOG(LS_VERBOSE) << "Testing base-64"; + + size_t i; + + // Check the short strings; this tests the math (and boundaries) + for (i = 0; i < sizeof(base64_tests) / sizeof(base64_tests[0]); ++i) { + char encode_buffer[100]; + size_t encode_length; + char decode_buffer[100]; + size_t decode_length; + size_t cypher_length; + + RTC_LOG(LS_VERBOSE) << "B64: " << base64_tests[i].cyphertext; + + const unsigned char* unsigned_plaintext = + reinterpret_cast<const unsigned char*>(base64_tests[i].plaintext); + + cypher_length = strlen(base64_tests[i].cyphertext); + + // The basic escape function: + memset(encode_buffer, 0, sizeof(encode_buffer)); + encode_length = + Base64Escape(unsigned_plaintext, base64_tests[i].plain_length, + encode_buffer, sizeof(encode_buffer)); + // Is it of the expected length? + EXPECT_EQ(encode_length, cypher_length); + + // Is it the expected encoded value? + EXPECT_STREQ(encode_buffer, base64_tests[i].cyphertext); + + // If we encode it into a buffer of exactly the right length... + memset(encode_buffer, 0, sizeof(encode_buffer)); + encode_length = + Base64Escape(unsigned_plaintext, base64_tests[i].plain_length, + encode_buffer, cypher_length); + // Is it still of the expected length? + EXPECT_EQ(encode_length, cypher_length); + + // And is the value still correct? (i.e., not losing the last byte) + EXPECT_STREQ(encode_buffer, base64_tests[i].cyphertext); + + // If we decode it back: + memset(decode_buffer, 0, sizeof(decode_buffer)); + decode_length = Base64Unescape(encode_buffer, cypher_length, decode_buffer, + sizeof(decode_buffer)); + + // Is it of the expected length? + EXPECT_EQ(decode_length, base64_tests[i].plain_length); + + // Is it the expected decoded value? + EXPECT_EQ(0, + memcmp(decode_buffer, base64_tests[i].plaintext, decode_length)); + + // Our decoder treats the padding '=' characters at the end as + // optional. If encode_buffer has any, run some additional + // tests that fiddle with them. + char* first_equals = strchr(encode_buffer, '='); + if (first_equals) { + // How many equals signs does the string start with? + int equals = (*(first_equals + 1) == '=') ? 2 : 1; + + // Try chopping off the equals sign(s) entirely. The decoder + // should still be okay with this. + std::string decoded2("this junk should also be ignored"); + *first_equals = '\0'; + EXPECT_NE(0U, Base64Unescape(encode_buffer, first_equals - encode_buffer, + &decoded2)); + EXPECT_EQ(decoded2.size(), base64_tests[i].plain_length); + EXPECT_EQ_ARRAY(decoded2.size(), decoded2.data(), + base64_tests[i].plaintext, i); + + size_t len; + + // try putting some extra stuff after the equals signs, or in between them + if (equals == 2) { + snprintf(first_equals, 6, " = = "); + len = first_equals - encode_buffer + 5; + } else { + snprintf(first_equals, 6, " = "); + len = first_equals - encode_buffer + 3; + } + decoded2.assign("this junk should be ignored"); + EXPECT_NE(0U, Base64Unescape(encode_buffer, len, &decoded2)); + EXPECT_EQ(decoded2.size(), base64_tests[i].plain_length); + EXPECT_EQ_ARRAY(decoded2.size(), decoded2, base64_tests[i].plaintext, i); + } + } +} + +// here's a weird case: a giant base64 encoded stream which broke our base64 +// decoding. Let's test it explicitly. +const char SpecificTest[] = + "/9j/4AAQSkZJRgABAgEASABIAAD/" + "4Q0HRXhpZgAATU0AKgAAAAgADAEOAAIAAAAgAAAAngEPAAI\n" + "AAAAFAAAAvgEQAAIAAAAJAAAAwwESAAMAAAABAAEAAAEaAAUAAAABAAAAzAEbAAUAAAABAAAA1" + "A\n" + "EoAAMAAAABAAIAAAExAAIAAAAUAAAA3AEyAAIAAAAUAAAA8AE8AAIAAAAQAAABBAITAAMAAAAB" + "A\n" + "AIAAIdpAAQAAAABAAABFAAAAsQgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgAFNPTlk" + "A\n" + "RFNDLVAyMDAAAAAASAAAAAEAAABIAAAAAUFkb2JlIFBob3Rvc2hvcCA3LjAAMjAwNzowMTozMC" + "A\n" + "yMzoxMDowNABNYWMgT1MgWCAxMC40LjgAAByCmgAFAAAAAQAAAmqCnQAFAAAAAQAAAnKIIgADA" + "A\n" + "AAAQACAACIJwADAAAAAQBkAACQAAAHAAAABDAyMjCQAwACAAAAFAAAAnqQBAACAAAAFAAAAo6R" + "A\n" + "QAHAAAABAECAwCRAgAFAAAAAQAAAqKSBAAKAAAAAQAAAqqSBQAFAAAAAQAAArKSBwADAAAAAQA" + "F\n" + "AACSCAADAAAAAQAAAACSCQADAAAAAQAPAACSCgAFAAAAAQAAArqgAAAHAAAABDAxMDCgAQADAA" + "A\n" + "AAf//" + "AACgAgAEAAAAAQAAAGSgAwAEAAAAAQAAAGSjAAAHAAAAAQMAAACjAQAHAAAAAQEAAACkAQ\n" + "ADAAAAAQAAAACkAgADAAAAAQAAAACkAwADAAAAAQAAAACkBgADAAAAAQAAAACkCAADAAAAAQAA" + "A\n" + "ACkCQADAAAAAQAAAACkCgADAAAAAQAAAAAAAAAAAAAACgAAAZAAAAAcAAAACjIwMDc6MDE6MjA" + "g\n" + "MjM6MDU6NTIAMjAwNzowMToyMCAyMzowNTo1MgAAAAAIAAAAAQAAAAAAAAAKAAAAMAAAABAAAA" + "B\n" + "PAAAACgAAAAYBAwADAAAAAQAGAAABGgAFAAAAAQAAAxIBGwAFAAAAAQAAAxoBKAADAAAAAQACA" + "A\n" + "ACAQAEAAAAAQAAAyICAgAEAAAAAQAACd0AAAAAAAAASAAAAAEAAABIAAAAAf/Y/" + "+AAEEpGSUYAA\n" + "QIBAEgASAAA/+0ADEFkb2JlX0NNAAL/7gAOQWRvYmUAZIAAAAAB/" + "9sAhAAMCAgICQgMCQkMEQsK\n" + "CxEVDwwMDxUYExMVExMYEQwMDAwMDBEMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMAQ0LCw" + "0\n" + "ODRAODhAUDg4OFBQODg4OFBEMDAwMDBERDAwMDAwMEQwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMD" + "A\n" + "wMDAz/wAARCABkAGQDASIAAhEBAxEB/90ABAAH/" + "8QBPwAAAQUBAQEBAQEAAAAAAAAAAwABAgQFB\n" + "gcICQoLAQABBQEBAQEBAQAAAAAAAAABAAIDBAUGBwgJCgsQAAEEAQMCBAIFBwYIBQMMMwEAAhE" + "D\n" + "BCESMQVBUWETInGBMgYUkaGxQiMkFVLBYjM0coLRQwclklPw4fFjczUWorKDJkSTVGRFwqN0Nh" + "f\n" + "SVeJl8rOEw9N14/" + "NGJ5SkhbSVxNTk9KW1xdXl9VZmdoaWprbG1ub2N0dXZ3eHl6e3x9fn9xEAAg\n" + "IBAgQEAwQFBgcHBgU1AQACEQMhMRIEQVFhcSITBTKBkRShsUIjwVLR8DMkYuFygpJDUxVjczTx" + "J\n" + "QYWorKDByY1wtJEk1SjF2RFVTZ0ZeLys4TD03Xj80aUpIW0lcTU5PSltcXV5fVWZnaGlqa2xtb" + "m\n" + "9ic3R1dnd4eXp7fH/" + "9oADAMBAAIRAxEAPwDy7bKNTUXNLz9EaJPDWMjxH4ozhtpYwaACT8ShaaW\n" + "bW0uEc9/JFfjj0Q4Hk/PRDxwX7y47W9z/" + "AN9Cv4+O3ILK2DcRqT2CaSvEbcl1Jbz37KG1dBldLo\n" + "qaS4l9xGjG9v6yoDAdYIaIjUk+AREgo4y5sapirb8Yl0NHHdKvBNm4yA1o5Pc+" + "SPEFvCWqB3HZF\n" + "Hj2SbWQ/" + "afGFP0bHP8ATY0uc4w1o1JPkkimGiS2KvqlnmBkOZQTyydzgPMM9v8A0lp4v1Nx9gF1\n" + "tpdqJaGtH/S3I0i3lISXW/8AMqnd/O2bfg2eUkqVYf/" + "Q8zuncO4Bj7lZ+n7f5Mj5KsJcY8NUZ4d\n" + "uEDVo1HkeU0rg3Om4H2rabCWUN7DQuK1n5FWKW4uCwG92gDRJBS6exhxmMboQI+" + "Cv4WFTQ42Bs2\n" + "fvnkkqEmy2YxoMMbpVzaz6jt+RbpHZs8lzkHqrasKkYOKP0jgDfZ4N/" + "wDM1tNrcWfSPmRyq9uNV\n" + "DnFg2s97i7UkjxKVrq0eVz3spZsja+ASDzwsh9jnOk/" + "JFzb3XZD3v1c4yT8UACTCniKDUnKz5Nj\n" + "G33XV1DV73BrT8dF23SejV4zg9g33cOsPb+SxVvqv9ViwNy8vS0iWs/" + "daf8A0Y5dpTi1sADGxCR\n" + "K1o0YBEmInlXWYbDBcDLdPJXa8f71Yrx2jnUoAqLnfZK5hJaW2vdwEk5a/wD/0fN6Ia/" + "e76IiVf\n" + "xavUL7CPpnT4LNbYXAVjuQt/AqDmNYO/" + "Kjnoy4hr5J8SwMhrRMaeSvbsxrfUazcOw4UX0Cisem2\n" + "SBoD4+" + "Kz8nC6llbSLCRrubJA8kwUWbUDa29X1PMa7aQWjuDC0MXMdbDbhI7eazBiUfZ6GOYRe1s\n" + "WvGgJ8Vbw2+m4Bx9s6JpNHuuGo1FF53r/" + "SHYua61gLse0lzXeBP5rkvqx0o5vVWz7WY49QkiQSP\n" + "oN/tLoevW/ogxv0HA7tJ0AnhT+pdDGYVl/wCdcTPkGn2NU0JWNWvlgAbHV6fEqdu2gR/" + "r2WlWwt\n" + "AA5VXAEsLXTqJafArQY5rRr9LiPBJiZsZCI1pJjxCi0j4oncSICSkWwzwkjeaSch//" + "0vO7sP7Lm\n" + "enO9ogtd5FbPT3Q5pCpZVc4ld3Lmn3O8j9EI2BYdunKjOobMQIyI+rusc2wx4d0eutwGnHh/" + "uQc\n" + "Ha7ladj6mVANGvcqOgz0Go7HJ12/GEHcwvB/dPY6ImbbaMaASGuIBjkN7qofs9Ubg9g7OI9p/" + "t/\n" + "RTSmhTHr0v6eSz6UgCPP2/wAVu9Ex2V49dVY2iACB4BZeVXQ/" + "AJ3gzGnnOi2+kACpru8flUsNmt\n" + "zHRf6xfWCnoeAfTh2ZaQKazx/" + "Ke7+QxcKz61fWA2uuObaC4zGhaPJrXBL64ZFmR124O09ENraPK\n" + "N3/AH5GqxIrZVUyp2K2vfdkENsDnxuex9m4Ox9n82xSgNd9D+p/XR1npgseR9ppOy4Dx/NfH/" + "CL\n" + "oQJGunmvMv8AFq3KHVcq3HkYQbD2nuSf0I/rMavSg6TLjLigQhJ7Z58v9QkmlsTOqSCn/" + "9PzL7R\n" + "d6Qq3n0wZ2zotXpT9xLfFYvkr/S7jXeB8E0jRkhKpC3q8LcJ/kmCrTnkuAPCq4do9Q/" + "ytVbuAeY\n" + "Gg5lQybQK+" + "82GBqEQUA1kOHPYf3LLsoyN36G5w8iUfHxepbXE2l0cApALgLHzBq9UxhTXU5hMC1\n" + "ktnSCup6S4Ctk+C5XqVGcaHPfuiuHkeTTuWz0+9zaKiH6CC0/yXBSQ2a/" + "MxojV57634rq+v2PLY\n" + "be1r2nsYG13/" + "AFKxbfCBMcr0brGAzrGEwCG31ncx0SfBzf7S4+zoHUWWsJq3hz9oLfcBH77R9H+\n" + "0pA13u/qPgDp/Q6ri39JlfpXkDx+h/" + "msWn1L6wdO6bSbcrIbU2Q0xLnSe21kuVejJspbVS5+4bd\n" + "ocBAkD/orG+tP1ar67Wy7GtZTm1SCXfRsb+a18fRe38x6SG3/44H1Z3f0y2I+l6DoSXD/" + "8xPrDs\n" + "3enVu3bdnqN3R+//USSVo//" + "1PLohhce+gRWS0Nsby3lRgFkKxQyW7SgUh3em5Tbq2uB9wWw1wey\n" + "J1XGV2XYdm5k7e4WzidXY9oMwo5RZ4T6Hd1ixwfp96PWbAJBVTHzK7O6Ky5oJB1HZMqmUEFlkG" + "y\n" + "xpa4zI1Hkq31dy7bMN9BAc3HeWAnnbyxEycmuup1jiAGglZ31PyrmZ9tQg1WtNj54EHR3/" + "S2qTH\n" + "1Yc5GgD1FFtzPdWGkd2AyflogZmRmsz6PSrbXbdo+" + "txOrP337f3fzVo15DK2uyrTtqpBOnBKx6b\n" + "7MjJsz7tHWOAYP3WD6LU6cqGjFCNl1MmvLcxv6YtDTLSAqP27LrdtYHXFnJZI+" + "Tp3MWg68OpDPv\n" + "UMUM2lkQBoouKQ6swjE9Nml+1sz1PW+z6xt27zuj+skrX2ZvqR5z8kkuOfdPt43/1fMm/" + "grFG6f\n" + "Lss9JA7JG7tnZs/SfJUrfS3foJ9TvHCopJsV8nWx/t24bJn8Fo/5TjWJXMJIS+i+G36TsZ/" + "7Q9P\n" + "8ATfzfeOFofVSZv2/zvt+O3X/v65dJPjt/BiyfN1/wn0zre79nVej/ADG8ep4x2/" + "6Srjd6TdviF\n" + "52ko8m6/Ht9X1KnftEo+POwxzK8mSTF46vrH6T1/OEl5Okkl//Z/" + "+0uHFBob3Rvc2hvcCAzLjAA\n" + "OEJJTQQEAAAAAAArHAIAAAIAAhwCeAAfICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA" + "A\n" + "4QklNBCUAAAAAABD7Caa9B0wqNp2P4sxXqayFOEJJTQPqAAAAAB2wPD94bWwgdmVyc2lvbj0iM" + "S\n" + "4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPCFET0NUWVBFIHBsaXN0IFBVQkxJQyAiLS8vQXBwbGUg" + "Q\n" + "29tcHV0ZXIvL0RURCBQTElTVCAxLjAvL0VOIiAiaHR0cDovL3d3dy5hcHBsZS5jb20vRFREcy9" + "Q\n" + "cm9wZXJ0eUxpc3QtMS4wLmR0ZCI+" + "CjxwbGlzdCB2ZXJzaW9uPSIxLjAiPgo8ZGljdD4KCTxrZXk\n" + "+Y29tLmFwcGxlLnByaW50LlBhZ2VGb3JtYXQuUE1Ib3Jpem9udGFsUmVzPC9rZXk+" + "Cgk8ZGljdD\n" + "4KCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQuY3JlYXRvcjwva2V5PgoJCTxzdHJpbmc+" + "Y\n" + "29tLmFwcGxlLnByaW50aW5nbWFuYWdlcjwvc3RyaW5nPgoJCTxrZXk+" + "Y29tLmFwcGxlLnByaW50\n" + "LnRpY2tldC5pdGVtQXJyYXk8L2tleT4KCQk8YXJyYXk+" + "CgkJCTxkaWN0PgoJCQkJPGtleT5jb20\n" + "uYXBwbGUucHJpbnQuUGFnZUZvcm1hdC5QTUhvcml6b250YWxSZXM8L2tleT4KCQkJCTxyZWFsP" + "j\n" + "cyPC9yZWFsPgoJCQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0LmNsaWVudDwva2V5PgoJ" + "C\n" + "QkJPHN0cmluZz5jb20uYXBwbGUucHJpbnRpbmdtYW5hZ2VyPC9zdHJpbmc+" + "CgkJCQk8a2V5PmNv\n" + "bS5hcHBsZS5wcmludC50aWNrZXQubW9kRGF0ZTwva2V5PgoJCQkJPGRhdGU+" + "MjAwNy0wMS0zMFQ\n" + "yMjowODo0MVo8L2RhdGU+" + "CgkJCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQuc3RhdGVGbG\n" + "FnPC9rZXk+CgkJCQk8aW50ZWdlcj4wPC9pbnRlZ2VyPgoJCQk8L2RpY3Q+" + "CgkJPC9hcnJheT4KC\n" + "TwvZGljdD4KCTxrZXk+" + "Y29tLmFwcGxlLnByaW50LlBhZ2VGb3JtYXQuUE1PcmllbnRhdGlvbjwv\n" + "a2V5PgoJPGRpY3Q+" + "CgkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0LmNyZWF0b3I8L2tleT4\n" + "KCQk8c3RyaW5nPmNvbS5hcHBsZS5wcmludGluZ21hbmFnZXI8L3N0cmluZz4KCQk8a2V5PmNvb" + "S\n" + "5hcHBsZS5wcmludC50aWNrZXQuaXRlbUFycmF5PC9rZXk+" + "CgkJPGFycmF5PgoJCQk8ZGljdD4KC\n" + "QkJCTxrZXk+" + "Y29tLmFwcGxlLnByaW50LlBhZ2VGb3JtYXQuUE1PcmllbnRhdGlvbjwva2V5PgoJ\n" + "CQkJPGludGVnZXI+MTwvaW50ZWdlcj4KCQkJCTxrZXk+" + "Y29tLmFwcGxlLnByaW50LnRpY2tldC5\n" + "jbGllbnQ8L2tleT4KCQkJCTxzdHJpbmc+" + "Y29tLmFwcGxlLnByaW50aW5nbWFuYWdlcjwvc3RyaW\n" + "5nPgoJCQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0Lm1vZERhdGU8L2tleT4KCQkJCTxk" + "Y\n" + "XRlPjIwMDctMDEtMzBUMjI6MDg6NDFaPC9kYXRlPgoJCQkJPGtleT5jb20uYXBwbGUucHJpbnQ" + "u\n" + "dGlja2V0LnN0YXRlRmxhZzwva2V5PgoJCQkJPGludGVnZXI+" + "MDwvaW50ZWdlcj4KCQkJPC9kaWN\n" + "0PgoJCTwvYXJyYXk+Cgk8L2RpY3Q+" + "Cgk8a2V5PmNvbS5hcHBsZS5wcmludC5QYWdlRm9ybWF0Ll\n" + "BNU2NhbGluZzwva2V5PgoJPGRpY3Q+" + "CgkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0LmNyZ\n" + "WF0b3I8L2tleT4KCQk8c3RyaW5nPmNvbS5hcHBsZS5wcmludGluZ21hbmFnZXI8L3N0cmluZz4" + "K\n" + "CQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQuaXRlbUFycmF5PC9rZXk+" + "CgkJPGFycmF5Pgo\n" + "JCQk8ZGljdD4KCQkJCTxrZXk+" + "Y29tLmFwcGxlLnByaW50LlBhZ2VGb3JtYXQuUE1TY2FsaW5nPC\n" + "9rZXk+" + "CgkJCQk8cmVhbD4xPC9yZWFsPgoJCQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0L\n" + "mNsaWVudDwva2V5PgoJCQkJPHN0cmluZz5jb20uYXBwbGUucHJpbnRpbmdtYW5hZ2VyPC9zdHJ" + "p\n" + "bmc+" + "CgkJCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQubW9kRGF0ZTwva2V5PgoJCQkJPGR\n" + "hdGU+MjAwNy0wMS0zMFQyMjowODo0MVo8L2RhdGU+" + "CgkJCQk8a2V5PmNvbS5hcHBsZS5wcmludC\n" + "50aWNrZXQuc3RhdGVGbGFnPC9rZXk+" + "CgkJCQk8aW50ZWdlcj4wPC9pbnRlZ2VyPgoJCQk8L2RpY\n" + "3Q+CgkJPC9hcnJheT4KCTwvZGljdD4KCTxrZXk+" + "Y29tLmFwcGxlLnByaW50LlBhZ2VGb3JtYXQu\n" + "UE1WZXJ0aWNhbFJlczwva2V5PgoJPGRpY3Q+" + "CgkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V\n" + "0LmNyZWF0b3I8L2tleT4KCQk8c3RyaW5nPmNvbS5hcHBsZS5wcmludGluZ21hbmFnZXI8L3N0c" + "m\n" + "luZz4KCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQuaXRlbUFycmF5PC9rZXk+" + "CgkJPGFyc\n" + "mF5PgoJCQk8ZGljdD4KCQkJCTxrZXk+" + "Y29tLmFwcGxlLnByaW50LlBhZ2VGb3JtYXQuUE1WZXJ0\n" + "aWNhbFJlczwva2V5PgoJCQkJPHJlYWw+NzI8L3JlYWw+" + "CgkJCQk8a2V5PmNvbS5hcHBsZS5wcml\n" + "udC50aWNrZXQuY2xpZW50PC9rZXk+" + "CgkJCQk8c3RyaW5nPmNvbS5hcHBsZS5wcmludGluZ21hbm\n" + "FnZXI8L3N0cmluZz4KCQkJCTxrZXk+" + "Y29tLmFwcGxlLnByaW50LnRpY2tldC5tb2REYXRlPC9rZ\n" + "Xk+CgkJCQk8ZGF0ZT4yMDA3LTAxLTMwVDIyOjA4OjQxWjwvZGF0ZT4KCQkJCTxrZXk+" + "Y29tLmFw\n" + "cGxlLnByaW50LnRpY2tldC5zdGF0ZUZsYWc8L2tleT4KCQkJCTxpbnRlZ2VyPjA8L2ludGVnZX" + "I\n" + "+CgkJCTwvZGljdD4KCQk8L2FycmF5PgoJPC9kaWN0PgoJPGtleT5jb20uYXBwbGUucHJpbnQuU" + "G\n" + "FnZUZvcm1hdC5QTVZlcnRpY2FsU2NhbGluZzwva2V5PgoJPGRpY3Q+" + "CgkJPGtleT5jb20uYXBwb\n" + "GUucHJpbnQudGlja2V0LmNyZWF0b3I8L2tleT4KCQk8c3RyaW5nPmNvbS5hcHBsZS5wcmludGl" + "u\n" + "Z21hbmFnZXI8L3N0cmluZz4KCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQuaXRlbUFycm" + "F\n" + "5PC9rZXk+CgkJPGFycmF5PgoJCQk8ZGljdD4KCQkJCTxrZXk+" + "Y29tLmFwcGxlLnByaW50LlBhZ2\n" + "VGb3JtYXQuUE1WZXJ0aWNhbFNjYWxpbmc8L2tleT4KCQkJCTxyZWFsPjE8L3JlYWw+" + "CgkJCQk8a\n" + "2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQuY2xpZW50PC9rZXk+" + "CgkJCQk8c3RyaW5nPmNvbS5h\n" + "cHBsZS5wcmludGluZ21hbmFnZXI8L3N0cmluZz4KCQkJCTxrZXk+" + "Y29tLmFwcGxlLnByaW50LnR\n" + "pY2tldC5tb2REYXRlPC9rZXk+" + "CgkJCQk8ZGF0ZT4yMDA3LTAxLTMwVDIyOjA4OjQxWjwvZGF0ZT\n" + "4KCQkJCTxrZXk+" + "Y29tLmFwcGxlLnByaW50LnRpY2tldC5zdGF0ZUZsYWc8L2tleT4KCQkJCTxpb\n" + "nRlZ2VyPjA8L2ludGVnZXI+" + "CgkJCTwvZGljdD4KCQk8L2FycmF5PgoJPC9kaWN0PgoJPGtleT5j\n" + "b20uYXBwbGUucHJpbnQuc3ViVGlja2V0LnBhcGVyX2luZm9fdGlja2V0PC9rZXk+" + "Cgk8ZGljdD4\n" + "KCQk8a2V5PmNvbS5hcHBsZS5wcmludC5QYWdlRm9ybWF0LlBNQWRqdXN0ZWRQYWdlUmVjdDwva" + "2\n" + "V5PgoJCTxkaWN0PgoJCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQuY3JlYXRvcjwva2V5" + "P\n" + "goJCQk8c3RyaW5nPmNvbS5hcHBsZS5wcmludGluZ21hbmFnZXI8L3N0cmluZz4KCQkJPGtleT5" + "j\n" + "b20uYXBwbGUucHJpbnQudGlja2V0Lml0ZW1BcnJheTwva2V5PgoJCQk8YXJyYXk+" + "CgkJCQk8ZGl\n" + "jdD4KCQkJCQk8a2V5PmNvbS5hcHBsZS5wcmludC5QYWdlRm9ybWF0LlBNQWRqdXN0ZWRQYWdlU" + "m\n" + "VjdDwva2V5PgoJCQkJCTxhcnJheT4KCQkJCQkJPHJlYWw+" + "MC4wPC9yZWFsPgoJCQkJCQk8cmVhb\n" + "D4wLjA8L3JlYWw+CgkJCQkJCTxyZWFsPjczNDwvcmVhbD4KCQkJCQkJPHJlYWw+" + "NTc2PC9yZWFs\n" + "PgoJCQkJCTwvYXJyYXk+" + "CgkJCQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0LmNsaWVudDw\n" + "va2V5PgoJCQkJCTxzdHJpbmc+" + "Y29tLmFwcGxlLnByaW50aW5nbWFuYWdlcjwvc3RyaW5nPgoJCQ\n" + "kJCTxrZXk+Y29tLmFwcGxlLnByaW50LnRpY2tldC5tb2REYXRlPC9rZXk+CgkJCQkJPGRhdGU+" + "M\n" + "jAwNy0wMS0zMFQyMjowODo0MVo8L2RhdGU+" + "CgkJCQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlj\n" + "a2V0LnN0YXRlRmxhZzwva2V5PgoJCQkJCTxpbnRlZ2VyPjA8L2ludGVnZXI+" + "CgkJCQk8L2RpY3Q\n" + "+CgkJCTwvYXJyYXk+CgkJPC9kaWN0PgoJCTxrZXk+" + "Y29tLmFwcGxlLnByaW50LlBhZ2VGb3JtYX\n" + "QuUE1BZGp1c3RlZFBhcGVyUmVjdDwva2V5PgoJCTxkaWN0PgoJCQk8a2V5PmNvbS5hcHBsZS5w" + "c\n" + "mludC50aWNrZXQuY3JlYXRvcjwva2V5PgoJCQk8c3RyaW5nPmNvbS5hcHBsZS5wcmludGluZ21" + "h\n" + "bmFnZXI8L3N0cmluZz4KCQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0Lml0ZW1BcnJheT" + "w\n" + "va2V5PgoJCQk8YXJyYXk+" + "CgkJCQk8ZGljdD4KCQkJCQk8a2V5PmNvbS5hcHBsZS5wcmludC5QYW\n" + "dlRm9ybWF0LlBNQWRqdXN0ZWRQYXBlclJlY3Q8L2tleT4KCQkJCQk8YXJyYXk+" + "CgkJCQkJCTxyZ\n" + "WFsPi0xODwvcmVhbD4KCQkJCQkJPHJlYWw+" + "LTE4PC9yZWFsPgoJCQkJCQk8cmVhbD43NzQ8L3Jl\n" + "YWw+CgkJCQkJCTxyZWFsPjU5NDwvcmVhbD4KCQkJCQk8L2FycmF5PgoJCQkJCTxrZXk+" + "Y29tLmF\n" + "wcGxlLnByaW50LnRpY2tldC5jbGllbnQ8L2tleT4KCQkJCQk8c3RyaW5nPmNvbS5hcHBsZS5wc" + "m\n" + "ludGluZ21hbmFnZXI8L3N0cmluZz4KCQkJCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQu" + "b\n" + "W9kRGF0ZTwva2V5PgoJCQkJCTxkYXRlPjIwMDctMDEtMzBUMjI6MDg6NDFaPC9kYXRlPgoJCQk" + "J\n" + "CTxrZXk+" + "Y29tLmFwcGxlLnByaW50LnRpY2tldC5zdGF0ZUZsYWc8L2tleT4KCQkJCQk8aW50ZWd\n" + "lcj4wPC9pbnRlZ2VyPgoJCQkJPC9kaWN0PgoJCQk8L2FycmF5PgoJCTwvZGljdD4KCQk8a2V5P" + "m\n" + "NvbS5hcHBsZS5wcmludC5QYXBlckluZm8uUE1QYXBlck5hbWU8L2tleT4KCQk8ZGljdD4KCQkJ" + "P\n" + "GtleT5jb20uYXBwbGUucHJpbnQudGlja2V0LmNyZWF0b3I8L2tleT4KCQkJPHN0cmluZz5jb20" + "u\n" + "YXBwbGUucHJpbnQucG0uUG9zdFNjcmlwdDwvc3RyaW5nPgoJCQk8a2V5PmNvbS5hcHBsZS5wcm" + "l\n" + "udC50aWNrZXQuaXRlbUFycmF5PC9rZXk+" + "CgkJCTxhcnJheT4KCQkJCTxkaWN0PgoJCQkJCTxrZX\n" + "k+" + "Y29tLmFwcGxlLnByaW50LlBhcGVySW5mby5QTVBhcGVyTmFtZTwva2V5PgoJCQkJCTxzdHJpb" + "\n" + "mc+bmEtbGV0dGVyPC9zdHJpbmc+" + "CgkJCQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0LmNs\n" + "aWVudDwva2V5PgoJCQkJCTxzdHJpbmc+" + "Y29tLmFwcGxlLnByaW50LnBtLlBvc3RTY3JpcHQ8L3N\n" + "0cmluZz4KCQkJCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQubW9kRGF0ZTwva2V5PgoJC" + "Q\n" + "kJCTxkYXRlPjIwMDMtMDctMDFUMTc6NDk6MzZaPC9kYXRlPgoJCQkJCTxrZXk+" + "Y29tLmFwcGxlL\n" + "nByaW50LnRpY2tldC5zdGF0ZUZsYWc8L2tleT4KCQkJCQk8aW50ZWdlcj4xPC9pbnRlZ2VyPgo" + "J\n" + "CQkJPC9kaWN0PgoJCQk8L2FycmF5PgoJCTwvZGljdD4KCQk8a2V5PmNvbS5hcHBsZS5wcmludC" + "5\n" + "QYXBlckluZm8uUE1VbmFkanVzdGVkUGFnZVJlY3Q8L2tleT4KCQk8ZGljdD4KCQkJPGtleT5jb" + "2\n" + "0uYXBwbGUucHJpbnQudGlja2V0LmNyZWF0b3I8L2tleT4KCQkJPHN0cmluZz5jb20uYXBwbGUu" + "c\n" + "HJpbnQucG0uUG9zdFNjcmlwdDwvc3RyaW5nPgoJCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWN" + "r\n" + "ZXQuaXRlbUFycmF5PC9rZXk+CgkJCTxhcnJheT4KCQkJCTxkaWN0PgoJCQkJCTxrZXk+" + "Y29tLmF\n" + "wcGxlLnByaW50LlBhcGVySW5mby5QTVVuYWRqdXN0ZWRQYWdlUmVjdDwva2V5PgoJCQkJCTxhc" + "n\n" + "JheT4KCQkJCQkJPHJlYWw+MC4wPC9yZWFsPgoJCQkJCQk8cmVhbD4wLjA8L3JlYWw+" + "CgkJCQkJC\n" + "TxyZWFsPjczNDwvcmVhbD4KCQkJCQkJPHJlYWw+NTc2PC9yZWFsPgoJCQkJCTwvYXJyYXk+" + "CgkJ\n" + "CQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0LmNsaWVudDwva2V5PgoJCQkJCTxzdHJpbm" + "c\n" + "+Y29tLmFwcGxlLnByaW50aW5nbWFuYWdlcjwvc3RyaW5nPgoJCQkJCTxrZXk+" + "Y29tLmFwcGxlLn\n" + "ByaW50LnRpY2tldC5tb2REYXRlPC9rZXk+CgkJCQkJPGRhdGU+" + "MjAwNy0wMS0zMFQyMjowODo0M\n" + "Vo8L2RhdGU+" + "CgkJCQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0LnN0YXRlRmxhZzwva2V5\n" + "PgoJCQkJCTxpbnRlZ2VyPjA8L2ludGVnZXI+CgkJCQk8L2RpY3Q+CgkJCTwvYXJyYXk+" + "CgkJPC9\n" + "kaWN0PgoJCTxrZXk+" + "Y29tLmFwcGxlLnByaW50LlBhcGVySW5mby5QTVVuYWRqdXN0ZWRQYXBlcl\n" + "JlY3Q8L2tleT4KCQk8ZGljdD4KCQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0LmNyZWF0" + "b\n" + "3I8L2tleT4KCQkJPHN0cmluZz5jb20uYXBwbGUucHJpbnQucG0uUG9zdFNjcmlwdDwvc3RyaW5" + "n\n" + "PgoJCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQuaXRlbUFycmF5PC9rZXk+" + "CgkJCTxhcnJ\n" + "heT4KCQkJCTxkaWN0PgoJCQkJCTxrZXk+" + "Y29tLmFwcGxlLnByaW50LlBhcGVySW5mby5QTVVuYW\n" + "RqdXN0ZWRQYXBlclJlY3Q8L2tleT4KCQkJCQk8YXJyYXk+" + "CgkJCQkJCTxyZWFsPi0xODwvcmVhb\n" + "D4KCQkJCQkJPHJlYWw+LTE4PC9yZWFsPgoJCQkJCQk8cmVhbD43NzQ8L3JlYWw+" + "CgkJCQkJCTxy\n" + "ZWFsPjU5NDwvcmVhbD4KCQkJCQk8L2FycmF5PgoJCQkJCTxrZXk+" + "Y29tLmFwcGxlLnByaW50LnR\n" + "pY2tldC5jbGllbnQ8L2tleT4KCQkJCQk8c3RyaW5nPmNvbS5hcHBsZS5wcmludGluZ21hbmFnZ" + "X\n" + "I8L3N0cmluZz4KCQkJCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQubW9kRGF0ZTwva2V5" + "P\n" + "goJCQkJCTxkYXRlPjIwMDctMDEtMzBUMjI6MDg6NDFaPC9kYXRlPgoJCQkJCTxrZXk+" + "Y29tLmFw\n" + "cGxlLnByaW50LnRpY2tldC5zdGF0ZUZsYWc8L2tleT4KCQkJCQk8aW50ZWdlcj4wPC9pbnRlZ2" + "V\n" + "yPgoJCQkJPC9kaWN0PgoJCQk8L2FycmF5PgoJCTwvZGljdD4KCQk8a2V5PmNvbS5hcHBsZS5wc" + "m\n" + "ludC5QYXBlckluZm8ucHBkLlBNUGFwZXJOYW1lPC9rZXk+CgkJPGRpY3Q+CgkJCTxrZXk+" + "Y29tL\n" + "mFwcGxlLnByaW50LnRpY2tldC5jcmVhdG9yPC9rZXk+CgkJCTxzdHJpbmc+" + "Y29tLmFwcGxlLnBy\n" + "aW50LnBtLlBvc3RTY3JpcHQ8L3N0cmluZz4KCQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2" + "V\n" + "0Lml0ZW1BcnJheTwva2V5PgoJCQk8YXJyYXk+" + "CgkJCQk8ZGljdD4KCQkJCQk8a2V5PmNvbS5hcH\n" + "BsZS5wcmludC5QYXBlckluZm8ucHBkLlBNUGFwZXJOYW1lPC9rZXk+" + "CgkJCQkJPHN0cmluZz5VU\n" + "yBMZXR0ZXI8L3N0cmluZz4KCQkJCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQuY2xpZW5" + "0\n" + "PC9rZXk+" + "CgkJCQkJPHN0cmluZz5jb20uYXBwbGUucHJpbnQucG0uUG9zdFNjcmlwdDwvc3RyaW5\n" + "nPgoJCQkJCTxrZXk+Y29tLmFwcGxlLnByaW50LnRpY2tldC5tb2REYXRlPC9rZXk+" + "CgkJCQkJPG\n" + "RhdGU+MjAwMy0wNy0wMVQxNzo0OTozNlo8L2RhdGU+" + "CgkJCQkJPGtleT5jb20uYXBwbGUucHJpb\n" + "nQudGlja2V0LnN0YXRlRmxhZzwva2V5PgoJCQkJCTxpbnRlZ2VyPjE8L2ludGVnZXI+" + "CgkJCQk8\n" + "L2RpY3Q+CgkJCTwvYXJyYXk+CgkJPC9kaWN0PgoJCTxrZXk+" + "Y29tLmFwcGxlLnByaW50LnRpY2t\n" + "ldC5BUElWZXJzaW9uPC9rZXk+CgkJPHN0cmluZz4wMC4yMDwvc3RyaW5nPgoJCTxrZXk+" + "Y29tLm\n" + "FwcGxlLnByaW50LnRpY2tldC5wcml2YXRlTG9jazwva2V5PgoJCTxmYWxzZS8+" + "CgkJPGtleT5jb\n" + "20uYXBwbGUucHJpbnQudGlja2V0LnR5cGU8L2tleT4KCQk8c3RyaW5nPmNvbS5hcHBsZS5wcml" + "u\n" + "dC5QYXBlckluZm9UaWNrZXQ8L3N0cmluZz4KCTwvZGljdD4KCTxrZXk+" + "Y29tLmFwcGxlLnByaW5\n" + "0LnRpY2tldC5BUElWZXJzaW9uPC9rZXk+Cgk8c3RyaW5nPjAwLjIwPC9zdHJpbmc+" + "Cgk8a2V5Pm\n" + "NvbS5hcHBsZS5wcmludC50aWNrZXQucHJpdmF0ZUxvY2s8L2tleT4KCTxmYWxzZS8+" + "Cgk8a2V5P\n" + "mNvbS5hcHBsZS5wcmludC50aWNrZXQudHlwZTwva2V5PgoJPHN0cmluZz5jb20uYXBwbGUucHJ" + "p\n" + "bnQuUGFnZUZvcm1hdFRpY2tldDwvc3RyaW5nPgo8L2RpY3Q+CjwvcGxpc3Q+" + "CjhCSU0D6QAAAAA\n" + "AeAADAAAASABIAAAAAALeAkD/7v/uAwYCUgNnBSgD/" + "AACAAAASABIAAAAAALYAigAAQAAAGQAAA\n" + "ABAAMDAwAAAAF//" + "wABAAEAAAAAAAAAAAAAAABoCAAZAZAAAAAAACAAAAAAAAAAAAAAAAAAAAAAA\n" + "AAAAAAAAAAAADhCSU0D7QAAAAAAEABIAAAAAQABAEgAAAABAAE4QklNBCYAAAAAAA4AAAAAAAA" + "A\n" + "AAAAP4AAADhCSU0EDQAAAAAABAAAAB44QklNBBkAAAAAAAQAAAAeOEJJTQPzAAAAAAAJAAAAAA" + "A\n" + "AAAABADhCSU0ECgAAAAAAAQAAOEJJTScQAAAAAAAKAAEAAAAAAAAAAThCSU0D9QAAAAAASAAvZ" + "m\n" + "YAAQBsZmYABgAAAAAAAQAvZmYAAQChmZoABgAAAAAAAQAyAAAAAQBaAAAABgAAAAAAAQA1AAAA" + "A\n" + "QAtAAAABgAAAAAAAThCSU0D+AAAAAAAcAAA/////////////////////////////wPoAAAAAP/" + "/\n" + "//////////////////////////8D6AAAAAD/////////////////////////////A+gAAAAA//" + "/\n" + "//////////////////////////" + "wPoAAA4QklNBAgAAAAAABAAAAABAAACQAAAAkAAAAAAOEJJTQ\n" + "QeAAAAAAAEAAAAADhCSU0EGgAAAAADRQAAAAYAAAAAAAAAAAAAAGQAAABkAAAACABEAFMAQwAw" + "A\n" + "DIAMwAyADUAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAGQAAABkAAAAAAAAAAA" + "A\n" + "AAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAEAAAAAAABudWxsAAAAAgAAAAZib3VuZH" + "N\n" + "PYmpjAAAAAQAAAAAAAFJjdDEAAAAEAAAAAFRvcCBsb25nAAAAAAAAAABMZWZ0bG9uZwAAAAAAA" + "A\n" + "AAQnRvbWxvbmcAAABkAAAAAFJnaHRsb25nAAAAZAAAAAZzbGljZXNWbExzAAAAAU9iamMAAAAB" + "A\n" + "AAAAAAFc2xpY2UAAAASAAAAB3NsaWNlSURsb25nAAAAAAAAAAdncm91cElEbG9uZwAAAAAAAAA" + "G\n" + "b3JpZ2luZW51bQAAAAxFU2xpY2VPcmlnaW4AAAANYXV0b0dlbmVyYXRlZAAAAABUeXBlZW51bQ" + "A\n" + "AAApFU2xpY2VUeXBlAAAAAEltZyAAAAAGYm91bmRzT2JqYwAAAAEAAAAAAABSY3QxAAAABAAAA" + "A\n" + "BUb3AgbG9uZwAAAAAAAAAATGVmdGxvbmcAAAAAAAAAAEJ0b21sb25nAAAAZAAAAABSZ2h0bG9u" + "Z\n" + "wAAAGQAAAADdXJsVEVYVAAAAAEAAAAAAABudWxsVEVYVAAAAAEAAAAAAABNc2dlVEVYVAAAAAE" + "A\n" + "AAAAAAZhbHRUYWdURVhUAAAAAQAAAAAADmNlbGxUZXh0SXNIVE1MYm9vbAEAAAAIY2VsbFRleH" + "R\n" + "URVhUAAAAAQAAAAAACWhvcnpBbGlnbmVudW0AAAAPRVNsaWNlSG9yekFsaWduAAAAB2RlZmF1b" + "H\n" + "QAAAAJdmVydEFsaWduZW51bQAAAA9FU2xpY2VWZXJ0QWxpZ24AAAAHZGVmYXVsdAAAAAtiZ0Nv" + "b\n" + "G9yVHlwZWVudW0AAAARRVNsaWNlQkdDb2xvclR5cGUAAAAATm9uZQAAAAl0b3BPdXRzZXRsb25" + "n\n" + "AAAAAAAAAApsZWZ0T3V0c2V0bG9uZwAAAAAAAAAMYm90dG9tT3V0c2V0bG9uZwAAAAAAAAALcm" + "l\n" + "naHRPdXRzZXRsb25nAAAAAAA4QklNBBEAAAAAAAEBADhCSU0EFAAAAAAABAAAAAE4QklNBAwAA" + "A\n" + "AACfkAAAABAAAAZAAAAGQAAAEsAAB1MAAACd0AGAAB/9j/4AAQSkZJRgABAgEASABIAAD/" + "7QAMQ\n" + "WRvYmVfQ00AAv/uAA5BZG9iZQBkgAAAAAH/" + "2wCEAAwICAgJCAwJCQwRCwoLERUPDAwPFRgTExUT\n" + "ExgRDAwMDAwMEQwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwBDQsLDQ4NEA4OEBQODg4UFA" + "4\n" + "ODg4UEQwMDAwMEREMDAwMDAwRDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDP/" + "AABEIAGQAZA\n" + "MBIgACEQEDEQH/3QAEAAf/xAE/" + "AAABBQEBAQEBAQAAAAAAAAADAAECBAUGBwgJCgsBAAEFAQEBA\n" + "QEBAAAAAAAAAAEAAgMEBQYHCAkKCxAAAQQBAwIEAgUHBggFAwwzAQACEQMEIRIxBUFRYRMicYE" + "y\n" + "BhSRobFCIyQVUsFiMzRygtFDByWSU/" + "Dh8WNzNRaisoMmRJNUZEXCo3Q2F9JV4mXys4TD03Xj80Y\n" + "nlKSFtJXE1OT0pbXF1eX1VmZ2hpamtsbW5vY3R1dnd4eXp7fH1+" + "f3EQACAgECBAQDBAUGBwcGBT\n" + "UBAAIRAyExEgRBUWFxIhMFMoGRFKGxQiPBUtHwMyRi4XKCkkNTFWNzNPElBhaisoMHJjXC0kST" + "V\n" + "KMXZEVVNnRl4vKzhMPTdePzRpSkhbSVxNTk9KW1xdXl9VZmdoaWprbG1ub2JzdHV2d3h5ent8f" + "/\n" + "2gAMAwEAAhEDEQA/" + "APLtso1NRc0vP0Rok8NYyPEfijOG2ljBoAJPxKFppZtbS4Rz38kV+OPRDge\n" + "T89EPHBfvLjtb3P8A30K/j47cgsrYNxGpPYJpK8RtyXUlvPfsobV0GV0uippLiX3EaMb2/" + "rKgMB\n" + "1ghoiNST4BESCjjLmxqmKtvxiXQ0cd0q8E2bjIDWjk9z5I8QW8JaoHcdkUePZJtZD9p8YU/" + "Rsc/\n" + "wBNjS5zjDWjUk+SSKYaJLYq+qWeYGQ5lBPLJ3OA8wz2/wDSWni/" + "U3H2AXW2l2oloa0f9LcjSLeU\n" + "hJdb/wAyqd387Zt+DZ5SSpVh/9DzO6dw7gGPuVn6ft/" + "kyPkqwlxjw1Rnh24QNWjUeR5TSuDc6bg\n" + "fatpsJZQ3sNC4rWfkVYpbi4LAb3aANEkFLp7GHGYxuhAj4K/" + "hYVNDjYGzZ++eSSoSbLZjGgwxul\n" + "XNrPqO35FukdmzyXOQeqtqwqRg4o/SOAN9ng3/" + "AMzW02txZ9I+ZHKr241UOcWDaz3uLtSSPEpWu\n" + "rR5XPeylmyNr4BIPPCyH2Oc6T8kXNvddkPe/" + "VzjJPxQAJMKeIoNScrPk2MbfddXUNXvcGtPx0Xb\n" + "dJ6NXjOD2Dfdw6w9v5LFW+q/1WLA3Ly9LSJaz91p/" + "wDRjl2lOLWwAMbEJErWjRgESYieVdZhsMF\n" + "wMt08ldrx/vVivHaOdSgCoud9krmElpba93ASTlr/AP/R83ohr97voiJV/" + "Fq9QvsI+mdPgs1thc\n" + "BWO5C38CoOY1g78qOejLiGvknxLAyGtExp5K9uzGt9RrNw7DhRfQKKx6bZIGgPj4rPycLqWVtI" + "s\n" + "JGu5skDyTBRZtQNrb1fU8xrtpBaO4MLQxcx1sNuEjt5rMGJR9noY5hF7Wxa8aAnxVvDb6bgHH2" + "z\n" + "omk0e64ajUUXnev9Idi5rrWAux7SXNd4E/muS+rHSjm9VbPtZjj1CSJBI+g3+0uh69b+iDG/" + "QcD\n" + "u0nQCeFP6l0MZhWX/" + "AJ1xM+QafY1TQlY1a+WABsdXp8Sp27aBH+vZaVbC0ADlVcASwtdOolp8Ct\n" + "BjmtGv0uI8EmJmxkIjWkmPEKLSPiidxIgJKRbDPCSN5pJyH//S87uw/" + "suZ6c72iC13kVs9PdDmk\n" + "KllVziV3cuafc7yP0QjYFh26cqM6hsxAjIj6u6xzbDHh3R663AaceH+" + "5BwdruVp2PqZUA0a9yo6\n" + "DPQajscnXb8YQdzC8H909joiZttoxoBIa4gGOQ3uqh+z1RuD2Ds4j2n+39FNKaFMevS/" + "p5LPpSA\n" + "I8/b/ABW70THZXj11VjaIAIHgFl5VdD8AneDMaec6Lb6QAKmu7x+VSw2a3MdF/" + "rF9YKeh4B9OHZ\n" + "lpAprPH8p7v5DFwrPrV9YDa645toLjMaFo8mtcEvrhkWZHXbg7T0Q2to8o3f8AfkarEitlVTKn" + "Y\n" + "ra992QQ2wOfG57H2bg7H2fzbFKA130P6n9dHWemCx5H2mk7LgPH818f8IuhAka6ea8y/" + "wAWrcod\n" + "VyrceRhBsPae5J/Qj+sxq9KDpMuMuKBCEntnny/1CSaWxM6pIKf/0/" + "MvtF3pCrefTBnbOi1elP3\n" + "Et8Vi+Sv9LuNd4HwTSNGSEqkLerwtwn+SYKtOeS4A8Krh2j1D/" + "K1Vu4B5gaDmVDJtAr7zYYGoRB\n" + "QDWQ4c9h/" + "csuyjI3fobnDyJR8fF6ltcTaXRwCkAuAsfMGr1TGFNdTmEwLWS2dIK6npLgK2T4Lle\n" + "pUZxoc9+6K4eR5NO5bPT73NoqIfoILT/JcFJDZr8zGiNXnvrfiur6/" + "Y8tht7WvaexgbXf8AUrFt\n" + "8IExyvRusYDOsYTAIbfWdzHRJ8HN/" + "tLj7OgdRZawmreHP2gt9wEfvtH0f7SkDXe7+o+AOn9DquL\n" + "f0mV+leQPH6H+axafUvrB07ptJtyshtTZDTEudJ7bWS5V6MmyltVLn7ht2hwECQP+isb60/" + "Vqvr\n" + "tbLsa1lObVIJd9Gxv5rXx9F7fzHpIbf/jgfVnd/TLYj6XoOhJcP/zE+sOzd6dW7dt2eo3dH7/" + "9R\n" + "JJWj//" + "U8uiGFx76BFZLQ2xvLeVGAWQrFDJbtKBSHd6blNura4H3BbDXB7InVcZXZdh2bmTt7hbO\n" + "J1dj2gzCjlFnhPod3WLHB+" + "n3o9ZsAkFVMfMrs7orLmgkHUdkyqZQQWWQbLGlrjMjUeSrfV3Ltsw\n" + "30EBzcd5YCedvLETJya66nWOIAaCVnfU/" + "KuZn21CDVa02PngQdHf9LapMfVhzkaAPUUW3M91YaR\n" + "3YDJ+WiBmZGazPo9Kttdt2j63E6s/fft/d/NWjXkMra7KtO2qkE6cErHpvsyMmzPu0dY4Bg/" + "dYP\n" + "otTpyoaMUI2XUya8tzG/pi0NMtICo/" + "bsut21gdcWclkj5OncxaDrw6kM+9QxQzaWRAGii4pDqzC\n" + "MT02aX7WzPU9b7PrG3bvO6P6yStfZm+pHnPySS4590+3jf/" + "V8yb+CsUbp8uyz0kDskbu2dmz9J8\n" + "lSt9Ld+gn1O8cKikmxXydbH+3bhsmfwWj/lONYlcwkhL6L4bfpOxn/tD0/wBN/N944Wh9VJm/" + "b/\n" + "O+347df+/rl0k+O38GLJ83X/CfTOt7v2dV6P8AMbx6njHb/" + "pKuN3pN2+IXnaSjybr8e31fUqd+0\n" + "Sj487DHMryZJMXjq+sfpPX84SXk6SSX/" + "9kAOEJJTQQhAAAAAABVAAAAAQEAAAAPAEEAZABvAGIA\n" + "ZQAgAFAAaABvAHQAbwBzAGgAbwBwAAAAEwBBAGQAbwBiAGUAIABQAGgAbwB0AG8AcwBoAG8AcA" + "A\n" + "gADcALgAwAAAAAQA4QklNBAYAAAAAAAcABQAAAAEBAP/" + "hFWdodHRwOi8vbnMuYWRvYmUuY29tL3\n" + "hhcC8xLjAvADw/eHBhY2tldCBiZWdpbj0n77u/" + "JyBpZD0nVzVNME1wQ2VoaUh6cmVTek5UY3prY\n" + "zlkJz8+Cjw/YWRvYmUteGFwLWZpbHRlcnMgZXNjPSJDUiI/" + "Pgo8eDp4YXBtZXRhIHhtbG5zOng9\n" + "J2Fkb2JlOm5zOm1ldGEvJyB4OnhhcHRrPSdYTVAgdG9vbGtpdCAyLjguMi0zMywgZnJhbWV3b3" + "J\n" + "rIDEuNSc+" + "CjxyZGY6UkRGIHhtbG5zOnJkZj0naHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi\n" + "1yZGYtc3ludGF4LW5zIycgeG1sbnM6aVg9J2h0dHA6Ly9ucy5hZG9iZS5jb20vaVgvMS4wLyc+" + "C\n" + "gogPHJkZjpEZXNjcmlwdGlvbiBhYm91dD0ndXVpZDoyMmQwMmIwYS1iMjQ5LTExZGItOGFmOC0" + "5\n" + "MWQ1NDAzZjkyZjknCiAgeG1sbnM6cGRmPSdodHRwOi8vbnMuYWRvYmUuY29tL3BkZi8xLjMvJz" + "4\n" + "KICA8IS0tIHBkZjpTdWJqZWN0IGlzIGFsaWFzZWQgLS0+" + "CiA8L3JkZjpEZXNjcmlwdGlvbj4KCi\n" + "A8cmRmOkRlc2NyaXB0aW9uIGFib3V0PSd1dWlkOjIyZDAyYjBhLWIyNDktMTFkYi04YWY4LTkx" + "Z\n" + "DU0MDNmOTJmOScKICB4bWxuczpwaG90b3Nob3A9J2h0dHA6Ly9ucy5hZG9iZS5jb20vcGhvdG9" + "z\n" + "aG9wLzEuMC8nPgogIDwhLS0gcGhvdG9zaG9wOkNhcHRpb24gaXMgYWxpYXNlZCAtLT4KIDwvcm" + "R\n" + "mOkRlc2NyaXB0aW9uPgoKIDxyZGY6RGVzY3JpcHRpb24gYWJvdXQ9J3V1aWQ6MjJkMDJiMGEtY" + "j\n" + "I0OS0xMWRiLThhZjgtOTFkNTQwM2Y5MmY5JwogIHhtbG5zOnhhcD0naHR0cDovL25zLmFkb2Jl" + "L\n" + "mNvbS94YXAvMS4wLyc+" + "CiAgPCEtLSB4YXA6RGVzY3JpcHRpb24gaXMgYWxpYXNlZCAtLT4KIDwv\n" + "cmRmOkRlc2NyaXB0aW9uPgoKIDxyZGY6RGVzY3JpcHRpb24gYWJvdXQ9J3V1aWQ6MjJkMDJiMG" + "E\n" + "tYjI0OS0xMWRiLThhZjgtOTFkNTQwM2Y5MmY5JwogIHhtbG5zOnhhcE1NPSdodHRwOi8vbnMuY" + "W\n" + "RvYmUuY29tL3hhcC8xLjAvbW0vJz4KICA8eGFwTU06RG9jdW1lbnRJRD5hZG9iZTpkb2NpZDpw" + "a\n" + "G90b3Nob3A6MjJkMDJiMDYtYjI0OS0xMWRiLThhZjgtOTFkNTQwM2Y5MmY5PC94YXBNTTpEb2N" + "1\n" + "bWVudElEPgogPC9yZGY6RGVzY3JpcHRpb24+" + "CgogPHJkZjpEZXNjcmlwdGlvbiBhYm91dD0ndXV\n" + "pZDoyMmQwMmIwYS1iMjQ5LTExZGItOGFmOC05MWQ1NDAzZjkyZjknCiAgeG1sbnM6ZGM9J2h0d" + "H\n" + "A6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvJz4KICA8ZGM6ZGVzY3JpcHRpb24+" + "CiAgIDxyZ\n" + "GY6QWx0PgogICAgPHJkZjpsaSB4bWw6bGFuZz0neC1kZWZhdWx0Jz4gICAgICAgICAgICAgICA" + "g\n" + "ICAgICAgICAgICAgICAgPC9yZGY6bGk+" + "CiAgIDwvcmRmOkFsdD4KICA8L2RjOmRlc2NyaXB0aW9\n" + "uPgogPC9yZGY6RGVzY3JpcHRpb24+Cgo8L3JkZjpSREY+" + "CjwveDp4YXBtZXRhPgogICAgICAgIC\n" + "AgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg" + "I\n" + "CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICA" + "g\n" + "ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC" + "A\n" + "gICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI" + "C\n" + "AgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg" + "I\n" + "CAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA" + "g\n" + "ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC" + "A\n" + "gCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI" + "C\n" + "AgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAg" + "I\n" + "CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA" + "g\n" + "ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgIC" + "A\n" + "gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI" + "C\n" + "AgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg" + "I\n" + "CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA" + "g\n" + "ICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC" + "A\n" + "gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI" + "A\n" + "ogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg" + "I\n" + "CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICA" + "g\n" + "ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC" + "A\n" + "gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgI" + "C\n" + "AgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg" + "I\n" + "CAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA" + "g\n" + "ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC" + "A\n" + "gICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI" + "C\n" + "AgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAK" + "I\n" + "CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA" + "g\n" + "ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgIC" + "A\n" + "gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI" + "C\n" + "AgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAg" + "I\n" + "CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA" + "g\n" + "ICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC" + "A\n" + "gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI" + "C\n" + "AgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg" + "I\n" + "CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiA" + "g\n" + "ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC" + "A\n" + "gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgI" + "C\n" + "AgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg" + "I\n" + "CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICA" + "g\n" + "ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC" + "A\n" + "gICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI" + "C\n" + "AgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg" + "I\n" + "CAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA" + "g\n" + "ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogIC" + "A\n" + "gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI" + "C\n" + "AgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAg" + "I\n" + "CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA" + "g\n" + "ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgIC" + "A\n" + "gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI" + "C\n" + "AgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg" + "I\n" + "CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA" + "g\n" + "ICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC" + "A\n" + "gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgI" + "C\n" + "AgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg" + "I\n" + "CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICA" + "g\n" + "ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC" + "A\n" + "gICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgI" + "C\n" + "AgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg" + "I\n" + "CAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA" + "g\n" + "ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC" + "A\n" + "gICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI" + "C\n" + "AgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAg" + "I\n" + "CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA" + "g\n" + "ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgIC" + "A\n" + "gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI" + "C\n" + "AgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAg" + "I\n" + "CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA" + "g\n" + "ICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC" + "A\n" + "gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI" + "C\n" + "AgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg" + "I\n" + "CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICA" + "g\n" + "ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC" + "A\n" + "gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgI" + "C\n" + "AgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKPD94cGFja2V0IGVuZD0ndyc/" + "P\n" + "v/uAA5BZG9iZQBkQAAAAAH/" + "2wCEAAQDAwMDAwQDAwQGBAMEBgcFBAQFBwgGBgcGBggKCAkJCQkI\n" + "CgoMDAwMDAoMDAwMDAwMDAwMDAwMDAwMDAwMDAwBBAUFCAcIDwoKDxQODg4UFA4ODg4UEQwMDA" + "w\n" + "MEREMDAwMDAwRDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDP/" + "AABEIAGQAZAMBEQACEQEDEQ\n" + "H/3QAEAA3/" + "xAGiAAAABwEBAQEBAAAAAAAAAAAEBQMCBgEABwgJCgsBAAICAwEBAQEBAAAAAAAAA\n" + "AEAAgMEBQYHCAkKCxAAAgEDAwIEAgYHAwQCBgJzAQIDEQQABSESMUFRBhNhInGBFDKRoQcVsUI" + "j\n" + "wVLR4TMWYvAkcoLxJUM0U5KismNzwjVEJ5OjszYXVGR0w9LiCCaDCQoYGYSURUaktFbTVSga8u" + "P\n" + "zxNTk9GV1hZWltcXV5fVmdoaWprbG1ub2N0dXZ3eHl6e3x9fn9zhIWGh4iJiouMjY6PgpOUlZa" + "X\n" + "mJmam5ydnp+" + "So6SlpqeoqaqrrK2ur6EQACAgECAwUFBAUGBAgDA20BAAIRAwQhEjFBBVETYSIGc\n" + "YGRMqGx8BTB0eEjQhVSYnLxMyQ0Q4IWklMlomOywgdz0jXiRIMXVJMICQoYGSY2RRonZHRVN/" + "Kj\n" + "s8MoKdPj84SUpLTE1OT0ZXWFlaW1xdXl9UZWZnaGlqa2xtbm9kdXZ3eHl6e3x9fn9zhIWGh4iJ" + "i\n" + "ouMjY6Pg5SVlpeYmZqbnJ2en5KjpKWmp6ipqqusra6vr/2gAMAwEAAhEDEQA/" + "APBnplwPAdR+GB\n" + "KY6dYtNG1w39yh4+xb+zIksgEfFaRSSoIx8f7RPRRkSWQimM+lRmwWVXFWYigHxUUVoMiJM+" + "Fj0\n" + "tg0RBegLE0Wu+3c+GTBazFCGI7HtSp9slbFYYzyoBsegw2hY1Afl3wqqRqahk+" + "0tDgKpgu4DAUU\n" + "+HY+GRS2ePiMKtUB3G+KGuONq//" + "Q8OzpFbW5WnxMop4k9crG5ZnZNJkEOn21utVRYw7HxZtz+OR\n" + "vdsrZ2lRtci4aVxFEQA0neg/" + "ZXxJpTITNNuOFss0vSotYNvZ2qGRkPKSTqiU8Sdqk5SZU5Ix8XJ\n" + "NNZ8k6bp8TtM73OputUtYq0Unux/" + "hkRkJOzZLCAN2KR+VpbtSkCBaDnIzdlWu59u+XeJTjeASk8\n" + "+juZOESEAVqx8BvU/" + "PJibScTrTy09560hkWOGFd2YgFnPQKD19zhOSkxw2l8Vm6XAiYb8gg+k5O\n" + "9mnhoon9H3cs5s7WF5pp29OGGMFndyaAKBuTiEEPQLD8h/" + "NDmNdYlttNkYjlbFjcXCr3LLH8II8\n" + "C2WUGviZvon/OPWkm3RNSv72SYllMkKxQRV67CQMSKYQAxMkR/" + "wBC56d61P0heel4cYuVOXWvTp\n" + "h4Qjjf/9Hw5qBYyISaqjBV+QpvkAzKcki4HomnIxck/" + "wBhtlR2bhunvlDywddMUl4zW+kQ9FQ8X\n" + "nfuSewrtmPkycPvc/" + "DhMhvyegXOrWWhmLQPKlsj6xIAiLCoZkY96nv7npmJvI2XOjQFMl0fyRqM\n" + "NoxvZvrGt33wlATwiMnVnY1LEdSfuyXF3KIDmUu88w2XlnTl8raAlb2ZFfVL0jdYRtQnxc7BfD" + "C\n" + "OaJR7nm3me5tdOtjbMvp3ZRXkV6chVQRX79hmVjgZG+" + "jgZ5jHGhzecXF5LPL6jEjstSSaDM51Ka\n" + "6MZ9S1C0sEBe8uZo4YCBXdjxGw60wEWyEqfUHkT8vLXRJFuLdTcaqfhlvWUErtukZ3ABPUjIXT" + "E\n" + "m3rGmeV2Tk5UKz/AG/E/wAcgZKya20C3b02kjYtH8AqCygbkUH0nLYlgUb+gbWtPbpXt/" + "n2ybB/\n" + "/9Lw4oaVxGd+PxH3qBkGaY3KyiSP01IkiUclH8sg+LKydm6INvZvKsFu+" + "kWtvD8LRoFNRup6moO\n" + "aqd277HsGW+XPLmn6XM17FF6l7vW4fd2Zuu+" + "RFls2tmUNrLJb7TSBertGQGqetDkxE0na0pvtHs\n" + "QkszWyiGAG5laYlnkeMVHJj8sA5rPk+SvMepTalqlxd3B5zTOXdj/" + "MxqafLpm5xioh5nPK5kpRG\n" + "pkcKAST0A6k5NpfUP5K/ki1ssHmHzF+71KRQ8Nud/Qibb/kYw6/" + "yjbrXISlSH07YaHbWyxx2kXE\n" + "KACB2zHJtLI7XSelBRvH2xCpvaaTDHXkOTVBPcUG2479RlsdmJVPRtvV+ylenQ0y62FP/" + "9PxRpo\n" + "WG5FxKKxKFDA+GVS5NsebLdFsRePc3siVW4f4QR0QVAGYeSXR2unhtZ6s60K6jt+MMSFwtF2+" + "xX\n" + "wr7eGUGLlRPQMsE2vxQm7itxKg3VCfT2+" + "nb8cDYaCDtfOXmCCcROrQrUhkkCHYn6emRMqZxjbLd\n" + "F1+W/" + "4xajHzjNCtQKMffETWUdngX5p+QZ9A8xS6hbo0ui37NNDPT7DOalHpsCD08Rmyw5ARTpdV\n" + "gIPEF35MeRn80ed4S5EdrpKm9kZ15K0iH92hB7Me/tmS60vt/" + "QrCYyekiBdgSTXcjqV9q9MokFD\n" + "N7S3aFVVR8RoK9zldqndvAY6nffr/AGYQqLhjdpCoIAZW22HavU/LJBUP9WblX0xTw7fOmWsX/" + "9\n" + "Tw7FdvMqWkQ3Z1qfED+mQIbI77PX/" + "LFis9vBajZm2Y+x65rMh3t30Bsze400aVaIbSLk6r8CMRT\n" + "l/" + "NmOcllnGDD9Y8uecNfEEiXrMgDGWAyGOOu5WlB+" + "vMrHODTlxZCdjsyFdB006VpVtLasurQxBL\n" + "64WiLI4/" + "aFT1ANOXemV5piR2b9NiljB4yyHy9CLOVI5GJhB+CvXY9R8xmINzs5HNZ+Z96BZpbxA\n" + "fVJo39UFefwopYgL4nMiMd2qZoIn/AJx00u3t/" + "Lt7qpp9Yv5GLf5MUTERqfbvmzBeezjd9H+VlL\n" + "wSQzBqsvOGQD7L12rXsemPNxmXQSxxIPU2nFV4HYqR1xEUWj4ZAxBryr2G+" + "J2VGDZlLrxUH6KZA\n" + "Fkqb15VFelfwy+2FP8A/" + "9Xxlf6AdA182Yk9eFeLxSjoVfcfSMo4uIOfkweFOnpvlWYrLEwNFAA+\n" + "nMOYdrhFvQLeSO7coBXiK8iKiv07Zj8Ac4QtNrW1njUcKcT+yAR/" + "xGmR4WcsStLpTuPU9IFaEsV\n" + "BP3k4m2AgBzSwyQNcIwNTE1aI3wnam9O2Ug7s5Ckk/" + "NDndeVXa2H78MqqV6jmeBp9+ZWKXqDjZ4\n" + "+gvVvy30qCy0qzsLRBCnBI2VdgUTqPvOZ7y+Q7pz+bn5q6d+VflZxZlJ/" + "NN4ypptk5qtB9qRwDX\n" + "gn/AAx2y2ItpfKFv+eH5qNeTajJ5ovVaVywSqvEtTUKqupAA6D2y0BNPtv/AJx//" + "M5PzL8mJeXT\n" + "L+ndPf6rqarSpkAqsnEAAeoN6DpkJRYci9lROSgSUUH9o9K5Tw0ztfSHnXkOtK9q+PHwydq//" + "9b\n" + "yxrVoZNBtNSA5zRMPXmH8j0CLXuBmHE+" + "qneamHpEuqYeV7pzFVTRgQK5XMNmnlb1vyyY5QA1OwJ\n" + "+eUF2seTOLu5s7azVIVAkpVn/" + "hhnIALG73Yz5jvb1dICqzpDNIqyFD8SxH7R28cxibZCiWOsdJs\n" + "PTM6XNstPhnkjIhcHuJBVfvOCiUSn0TfWrTTLjyw8guA/PifTO3xcxxA8a5ZAbimvJP0m3p/" + "kFF\n" + "WxhmpWQJ9NW3zZPHz5vlb/nIDVbrWfzO1RJhxGnpDaRL/" + "khA1T7ktmSOTAJhZaAUtLawsbayl8v\n" + "xWi3Gpay0cF3HPcFRJJHJMXVrcJ8UaAFG5LWjF8tAYW9H/wCcOo9bTzxrt/" + "owkTyksZW5gkIKvI\n" + "7k26nvyReRJHyyBWT7dWQyOWlbnK2526e1O1MqIUFE84uPLkOdK9RXI0E2/wD/1/DA1bURZLY/" + "W\n" + "ZDZqwb0eXw7dMgIi7bjllVXsz7yNcfWC0Vd3Ip92Y2UOz0cnsPlwyx8xQ/" + "u24sMxCadoJp9LOXk\n" + "VX/" + "uwRUE0BI8cokbLMyoKouHu2MaKGXw7fLDwgoGSkbHpaNZyLLHRSKcFFQQRvUdMlwUFOQyLzr\n" + "ztpCaba6fPau4ijv4OURY8AjVFKV7ZZiO+7Vnh6XvXkSWNbW2WTb92KDxIFMzwHlZc3zX+" + "fuizW\n" + "f5p3ty8XGDU4YLmCQiisyII3+4rvl8UB5ffEghRGvOm7AbnvWvjk1fen/" + "ONPldPKP5aWOpPCfr2\n" + "uE31y6q2wbaMEn+VAMDSdyzrzj+avlHyTp0l/r2rxWFuHWJuIeacu4qFCRgsajfBwsty89/" + "6Gr/\n" + "ACa9an+JL/hSnrfoubhXwpXpjwhaL//" + "Q8E1AqtcAZMs8l6i1nqMa1oSVP0VynKLDmaWdSfQXl69\n" + "jF1Jv8MhDb5rpB3AO7INRRLhhGp4R05FgaGvTMU8200xS70zVDMRp2pTIOvBmB3PgQP15kxIcn" + "D\n" + "LH/" + "EEz0rRvOJhldr9pQtCqyd6VrShGTqw5d4ARv9jHfOGl+ZJNMluLkyenaFbiRdqFYW5nrWuwO\n" + "MKB5MdSMRxnhlu9N8p6lLFpti63FUjCtFJTrDKvse2bEDZ4XJ9RZB+YPli2/" + "Mjy5bxoUi1a0YS2\n" + "85UOwIXiy9jRu+TBppfOF1+V3m22vrdpNPM8cs/oo0VJlUqQPjValR3+IZNNvtLS9Yu9Mi0/" + "TJr\n" + "kyp6QhWVVCIWRATsKBemwwFrDzT87fybs/" + "wA1bW21PRb+DTvNlgGSRp6iC8i3KJJx+y6n7D0Pwm\n" + "hxBZXT55/6Fi/Nf0PW+qWXq+t6X1X67F6vD/ftK04V/wBl344U8b//" + "0fBapxheVh9ocV+nviqY2\n" + "/qQJDew/" + "bioWHiuQ8m0bbvaPKGtQ6jaxSo9JloCK75gZI0Xb4sgkHo8MouoAvP94BsRmGY7uWJU\n" + "gzbypOQpNOvIdK4Nw2WCE2tXulTkjEEbdafgclxMhFBas93dwyQzsWDghlJFONKHJCZtjOFBJf" + "y\n" + "j1y9vPL9zpbIs0WkXL2sUjA8hDXlGCRXtt07ZuYvL5KJeo6bfajbkzWkcToR8dqshZ6in2fhNK" + "/\n" + "PDTUlXmHVvMdr5o0v9H2kdrqGpfu7m0nkY87Uf7tkKAU4/" + "s03ynLkEBbfihx7dGT6va67LbRMNR\n" + "aKOBuUTKgIBXoK1BOYR1M3aQ0mOt9yxUeZNdtJhFapLqMluSXkg5oxJrUMW5KevQ9MmNXXNqOi" + "H\n" + "Rr/Hmv8A1r9I/oj95w+r+j9Yf1+NP5+nXtTD+dF8tkfkOlv/0vC3ph7f0/" + "alcVTbS4A8QibuKb5\n" + "RI05EBYRFpdX3ly79a2qYCavH/" + "EY7TCYyMD5PSdD8+wXUSn1ArDqOhBzFlipz4ZwWbaV5htbsgF\n" + "qg9crMXKErGyYwajFGzxyHlGSePbbwyqg5UZlCaxrFpaWU95LIqrEjMAT4Dp9OShGy1ZslBhv/" + "A\n" + "Dj9rd/a+aL+xUK+m38L3d0HrxRo2HFtu5D8c27y8t30raarbWkU+u6g4gsNORn+EcUaSh2Pc0/" + "4\n" + "lgtAjezzbT9SutY1i782al8Nxdyotqh6xWybIg+jc5q8s+I27bFDgFPQp9RE+nrag70+" + "L6crrZu\n" + "4jajokdv6LW/Dii1Wo61PXKQN3KPK0L+h4/rnD/K5V78a5LhXxd3/0/" + "DMXXtwxVNtL9Xkaf3f7N\n" + "etfbKMjdjtkZ9D6ufrlK0+HpX8coF9HJ26sXvfqXrf7i/U+uften/d/" + "wCyrmQL6uOav0pvpP8Ai\n" + "b1F+rV59+vH6a5XLhcjH4nRmY/xpxHP0/UptWvT6Mx/RbmjxWK+aP8AFf1M/" + "pCv1Kvxen9inavf\n" + "MrFwXtzcLUeLXq5Mv/I3nz1b0v8AjofuKVry9KrUpTanOlf9jmQ68va/zH9b/COn/o7/" + "AI431mP\n" + "65SvLh+zWvbl9rMfNfC34K4kmj9T6lD6FKclp/DNYXZx5srsPrHor6nXvkgxTPS/" + "U+rv6dPU5mt\n" + "fngFN5ulv+l/pL/Lp/scerHo//2Q==\n"; + +static std::string gCommandLine; + +TEST(Base64, LargeSample) { + RTC_LOG(LS_VERBOSE) << "Testing specific base64 file"; + + char unescaped[64 * 1024]; + + // unescape that massive blob above + size_t size = Base64Unescape(SpecificTest, sizeof(SpecificTest), unescaped, + sizeof(unescaped)); + + EXPECT_EQ(size, sizeof(testbase64)); + EXPECT_EQ(0, memcmp(testbase64, unescaped, sizeof(testbase64))); +} + +bool DecodeTest(const char* encoded, + size_t expect_unparsed, + const char* decoded, + Base64::DecodeFlags flags) { + std::string result; + size_t consumed = 0, encoded_len = strlen(encoded); + bool success = + Base64::DecodeFromArray(encoded, encoded_len, flags, &result, &consumed); + size_t unparsed = encoded_len - consumed; + EXPECT_EQ(expect_unparsed, unparsed) + << "\"" << encoded << "\" -> \"" << decoded << "\""; + EXPECT_STREQ(decoded, result.c_str()); + return success; +} + +#define Flags(x, y, z) \ + Base64::DO_PARSE_##x | Base64::DO_PAD_##y | Base64::DO_TERM_##z + +TEST(Base64, DecodeParseOptions) { + // Trailing whitespace + EXPECT_TRUE(DecodeTest("YWJjZA== ", 1, "abcd", Flags(STRICT, YES, CHAR))); + EXPECT_TRUE(DecodeTest("YWJjZA== ", 0, "abcd", Flags(WHITE, YES, CHAR))); + EXPECT_TRUE(DecodeTest("YWJjZA== ", 0, "abcd", Flags(ANY, YES, CHAR))); + + // Embedded whitespace + EXPECT_FALSE(DecodeTest("YWJjZA= =", 3, "abcd", Flags(STRICT, YES, CHAR))); + EXPECT_TRUE(DecodeTest("YWJjZA= =", 0, "abcd", Flags(WHITE, YES, CHAR))); + EXPECT_TRUE(DecodeTest("YWJjZA= =", 0, "abcd", Flags(ANY, YES, CHAR))); + + // Embedded non-base64 characters + EXPECT_FALSE(DecodeTest("YWJjZA=*=", 3, "abcd", Flags(STRICT, YES, CHAR))); + EXPECT_FALSE(DecodeTest("YWJjZA=*=", 3, "abcd", Flags(WHITE, YES, CHAR))); + EXPECT_TRUE(DecodeTest("YWJjZA=*=", 0, "abcd", Flags(ANY, YES, CHAR))); + + // Unexpected padding characters + EXPECT_FALSE(DecodeTest("YW=JjZA==", 7, "a", Flags(STRICT, YES, CHAR))); + EXPECT_FALSE(DecodeTest("YW=JjZA==", 7, "a", Flags(WHITE, YES, CHAR))); + EXPECT_TRUE(DecodeTest("YW=JjZA==", 0, "abcd", Flags(ANY, YES, CHAR))); +} + +TEST(Base64, DecodePadOptions) { + // Padding + EXPECT_TRUE(DecodeTest("YWJjZA==", 0, "abcd", Flags(STRICT, YES, CHAR))); + EXPECT_TRUE(DecodeTest("YWJjZA==", 0, "abcd", Flags(STRICT, ANY, CHAR))); + EXPECT_TRUE(DecodeTest("YWJjZA==", 2, "abcd", Flags(STRICT, NO, CHAR))); + + // Incomplete padding + EXPECT_FALSE(DecodeTest("YWJjZA=", 1, "abcd", Flags(STRICT, YES, CHAR))); + EXPECT_TRUE(DecodeTest("YWJjZA=", 1, "abcd", Flags(STRICT, ANY, CHAR))); + EXPECT_TRUE(DecodeTest("YWJjZA=", 1, "abcd", Flags(STRICT, NO, CHAR))); + + // No padding + EXPECT_FALSE(DecodeTest("YWJjZA", 0, "abcd", Flags(STRICT, YES, CHAR))); + EXPECT_TRUE(DecodeTest("YWJjZA", 0, "abcd", Flags(STRICT, ANY, CHAR))); + EXPECT_TRUE(DecodeTest("YWJjZA", 0, "abcd", Flags(STRICT, NO, CHAR))); +} + +TEST(Base64, DecodeTerminateOptions) { + // Complete quantum + EXPECT_TRUE(DecodeTest("YWJj", 0, "abc", Flags(STRICT, NO, BUFFER))); + EXPECT_TRUE(DecodeTest("YWJj", 0, "abc", Flags(STRICT, NO, CHAR))); + EXPECT_TRUE(DecodeTest("YWJj", 0, "abc", Flags(STRICT, NO, ANY))); + + // Complete quantum with trailing data + EXPECT_FALSE(DecodeTest("YWJj*", 1, "abc", Flags(STRICT, NO, BUFFER))); + EXPECT_TRUE(DecodeTest("YWJj*", 1, "abc", Flags(STRICT, NO, CHAR))); + EXPECT_TRUE(DecodeTest("YWJj*", 1, "abc", Flags(STRICT, NO, ANY))); + + // Incomplete quantum + EXPECT_FALSE(DecodeTest("YWJ", 0, "ab", Flags(STRICT, NO, BUFFER))); + EXPECT_FALSE(DecodeTest("YWJ", 0, "ab", Flags(STRICT, NO, CHAR))); + EXPECT_TRUE(DecodeTest("YWJ", 0, "ab", Flags(STRICT, NO, ANY))); +} + +TEST(Base64, GetNextBase64Char) { + // The table looks like this: + // "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" + char next_char; + EXPECT_TRUE(Base64::GetNextBase64Char('A', &next_char)); + EXPECT_EQ('B', next_char); + EXPECT_TRUE(Base64::GetNextBase64Char('Z', &next_char)); + EXPECT_EQ('a', next_char); + EXPECT_TRUE(Base64::GetNextBase64Char('/', &next_char)); + EXPECT_EQ('A', next_char); + EXPECT_FALSE(Base64::GetNextBase64Char('&', &next_char)); + EXPECT_FALSE(Base64::GetNextBase64Char('Z', nullptr)); +} + +} // namespace +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/bit_buffer.cc b/third_party/libwebrtc/rtc_base/bit_buffer.cc new file mode 100644 index 0000000000..fd57e136b4 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/bit_buffer.cc @@ -0,0 +1,230 @@ +/* + * Copyright 2015 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 "rtc_base/bit_buffer.h" + +#include <algorithm> +#include <limits> + +#include "absl/numeric/bits.h" +#include "absl/strings/string_view.h" +#include "rtc_base/checks.h" + +namespace { + +// Returns the highest byte of `val` in a uint8_t. +uint8_t HighestByte(uint64_t val) { + return static_cast<uint8_t>(val >> 56); +} + +// Returns the result of writing partial data from `source`, of +// `source_bit_count` size in the highest bits, to `target` at +// `target_bit_offset` from the highest bit. +uint8_t WritePartialByte(uint8_t source, + size_t source_bit_count, + uint8_t target, + size_t target_bit_offset) { + RTC_DCHECK(target_bit_offset < 8); + RTC_DCHECK(source_bit_count < 9); + RTC_DCHECK(source_bit_count <= (8 - target_bit_offset)); + // Generate a mask for just the bits we're going to overwrite, so: + uint8_t mask = + // The number of bits we want, in the most significant bits... + static_cast<uint8_t>(0xFF << (8 - source_bit_count)) + // ...shifted over to the target offset from the most signficant bit. + >> target_bit_offset; + + // We want the target, with the bits we'll overwrite masked off, or'ed with + // the bits from the source we want. + return (target & ~mask) | (source >> target_bit_offset); +} + +} // namespace + +namespace rtc { + +BitBufferWriter::BitBufferWriter(uint8_t* bytes, size_t byte_count) + : writable_bytes_(bytes), + byte_count_(byte_count), + byte_offset_(), + bit_offset_() { + RTC_DCHECK(static_cast<uint64_t>(byte_count_) <= + std::numeric_limits<uint32_t>::max()); +} + +uint64_t BitBufferWriter::RemainingBitCount() const { + return (static_cast<uint64_t>(byte_count_) - byte_offset_) * 8 - bit_offset_; +} + +bool BitBufferWriter::ConsumeBytes(size_t byte_count) { + return ConsumeBits(byte_count * 8); +} + +bool BitBufferWriter::ConsumeBits(size_t bit_count) { + if (bit_count > RemainingBitCount()) { + return false; + } + + byte_offset_ += (bit_offset_ + bit_count) / 8; + bit_offset_ = (bit_offset_ + bit_count) % 8; + return true; +} + +void BitBufferWriter::GetCurrentOffset(size_t* out_byte_offset, + size_t* out_bit_offset) { + RTC_CHECK(out_byte_offset != nullptr); + RTC_CHECK(out_bit_offset != nullptr); + *out_byte_offset = byte_offset_; + *out_bit_offset = bit_offset_; +} + +bool BitBufferWriter::Seek(size_t byte_offset, size_t bit_offset) { + if (byte_offset > byte_count_ || bit_offset > 7 || + (byte_offset == byte_count_ && bit_offset > 0)) { + return false; + } + byte_offset_ = byte_offset; + bit_offset_ = bit_offset; + return true; +} + +bool BitBufferWriter::WriteUInt8(uint8_t val) { + return WriteBits(val, sizeof(uint8_t) * 8); +} + +bool BitBufferWriter::WriteUInt16(uint16_t val) { + return WriteBits(val, sizeof(uint16_t) * 8); +} + +bool BitBufferWriter::WriteUInt32(uint32_t val) { + return WriteBits(val, sizeof(uint32_t) * 8); +} + +bool BitBufferWriter::WriteBits(uint64_t val, size_t bit_count) { + if (bit_count > RemainingBitCount()) { + return false; + } + size_t total_bits = bit_count; + + // For simplicity, push the bits we want to read from val to the highest bits. + val <<= (sizeof(uint64_t) * 8 - bit_count); + + uint8_t* bytes = writable_bytes_ + byte_offset_; + + // The first byte is relatively special; the bit offset to write to may put us + // in the middle of the byte, and the total bit count to write may require we + // save the bits at the end of the byte. + size_t remaining_bits_in_current_byte = 8 - bit_offset_; + size_t bits_in_first_byte = + std::min(bit_count, remaining_bits_in_current_byte); + *bytes = WritePartialByte(HighestByte(val), bits_in_first_byte, *bytes, + bit_offset_); + if (bit_count <= remaining_bits_in_current_byte) { + // Nothing left to write, so quit early. + return ConsumeBits(total_bits); + } + + // Subtract what we've written from the bit count, shift it off the value, and + // write the remaining full bytes. + val <<= bits_in_first_byte; + bytes++; + bit_count -= bits_in_first_byte; + while (bit_count >= 8) { + *bytes++ = HighestByte(val); + val <<= 8; + bit_count -= 8; + } + + // Last byte may also be partial, so write the remaining bits from the top of + // val. + if (bit_count > 0) { + *bytes = WritePartialByte(HighestByte(val), bit_count, *bytes, 0); + } + + // All done! Consume the bits we've written. + return ConsumeBits(total_bits); +} + +bool BitBufferWriter::WriteNonSymmetric(uint32_t val, uint32_t num_values) { + RTC_DCHECK_LT(val, num_values); + RTC_DCHECK_LE(num_values, uint32_t{1} << 31); + if (num_values == 1) { + // When there is only one possible value, it requires zero bits to store it. + // But WriteBits doesn't support writing zero bits. + return true; + } + size_t count_bits = absl::bit_width(num_values); + uint32_t num_min_bits_values = (uint32_t{1} << count_bits) - num_values; + + return val < num_min_bits_values + ? WriteBits(val, count_bits - 1) + : WriteBits(val + num_min_bits_values, count_bits); +} + +size_t BitBufferWriter::SizeNonSymmetricBits(uint32_t val, + uint32_t num_values) { + RTC_DCHECK_LT(val, num_values); + RTC_DCHECK_LE(num_values, uint32_t{1} << 31); + size_t count_bits = absl::bit_width(num_values); + uint32_t num_min_bits_values = (uint32_t{1} << count_bits) - num_values; + + return val < num_min_bits_values ? (count_bits - 1) : count_bits; +} + +bool BitBufferWriter::WriteExponentialGolomb(uint32_t val) { + // We don't support reading UINT32_MAX, because it doesn't fit in a uint32_t + // when encoded, so don't support writing it either. + if (val == std::numeric_limits<uint32_t>::max()) { + return false; + } + uint64_t val_to_encode = static_cast<uint64_t>(val) + 1; + + // We need to write bit_width(val+1) 0s and then val+1. Since val (as a + // uint64_t) has leading zeros, we can just write the total golomb encoded + // size worth of bits, knowing the value will appear last. + return WriteBits(val_to_encode, absl::bit_width(val_to_encode) * 2 - 1); +} + +bool BitBufferWriter::WriteSignedExponentialGolomb(int32_t val) { + if (val == 0) { + return WriteExponentialGolomb(0); + } else if (val > 0) { + uint32_t signed_val = val; + return WriteExponentialGolomb((signed_val * 2) - 1); + } else { + if (val == std::numeric_limits<int32_t>::min()) + return false; // Not supported, would cause overflow. + uint32_t signed_val = -val; + return WriteExponentialGolomb(signed_val * 2); + } +} + +bool BitBufferWriter::WriteLeb128(uint64_t val) { + bool success = true; + do { + uint8_t byte = static_cast<uint8_t>(val & 0x7f); + val >>= 7; + if (val > 0) { + byte |= 0x80; + } + success &= WriteUInt8(byte); + } while (val > 0); + return success; +} + +bool BitBufferWriter::WriteString(absl::string_view data) { + bool success = true; + for (char c : data) { + success &= WriteUInt8(c); + } + return success; +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/bit_buffer.h b/third_party/libwebrtc/rtc_base/bit_buffer.h new file mode 100644 index 0000000000..fe50b2b76e --- /dev/null +++ b/third_party/libwebrtc/rtc_base/bit_buffer.h @@ -0,0 +1,100 @@ +/* + * Copyright 2015 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 RTC_BASE_BIT_BUFFER_H_ +#define RTC_BASE_BIT_BUFFER_H_ + +#include <stddef.h> // For size_t. +#include <stdint.h> // For integer types. + +#include "absl/strings/string_view.h" +#include "api/units/data_size.h" + +namespace rtc { + +// A BitBuffer API for write operations. Supports symmetric write APIs to the +// reading APIs of BitstreamReader. +// Sizes/counts specify bits/bytes, for clarity. +// Byte order is assumed big-endian/network. +class BitBufferWriter { + public: + static constexpr webrtc::DataSize kMaxLeb128Length = + webrtc::DataSize::Bytes(10); + + // Constructs a bit buffer for the writable buffer of `bytes`. + BitBufferWriter(uint8_t* bytes, size_t byte_count); + + BitBufferWriter(const BitBufferWriter&) = delete; + BitBufferWriter& operator=(const BitBufferWriter&) = delete; + + // Gets the current offset, in bytes/bits, from the start of the buffer. The + // bit offset is the offset into the current byte, in the range [0,7]. + void GetCurrentOffset(size_t* out_byte_offset, size_t* out_bit_offset); + + // The remaining bits in the byte buffer. + uint64_t RemainingBitCount() const; + + // Moves current position `byte_count` bytes forward. Returns false if + // there aren't enough bytes left in the buffer. + bool ConsumeBytes(size_t byte_count); + // Moves current position `bit_count` bits forward. Returns false if + // there aren't enough bits left in the buffer. + bool ConsumeBits(size_t bit_count); + + // Sets the current offset to the provied byte/bit offsets. The bit + // offset is from the given byte, in the range [0,7]. + bool Seek(size_t byte_offset, size_t bit_offset); + + // Writes byte-sized values from the buffer. Returns false if there isn't + // enough data left for the specified type. + bool WriteUInt8(uint8_t val); + bool WriteUInt16(uint16_t val); + bool WriteUInt32(uint32_t val); + + // Writes bit-sized values to the buffer. Returns false if there isn't enough + // room left for the specified number of bits. + bool WriteBits(uint64_t val, size_t bit_count); + + // Writes value in range [0, num_values - 1] + // See ReadNonSymmetric documentation for the format, + // Call SizeNonSymmetricBits to get number of bits needed to store the value. + // Returns false if there isn't enough room left for the value. + bool WriteNonSymmetric(uint32_t val, uint32_t num_values); + // Returns number of bits required to store `val` with NonSymmetric encoding. + static size_t SizeNonSymmetricBits(uint32_t val, uint32_t num_values); + + // Writes the exponential golomb encoded version of the supplied value. + // Returns false if there isn't enough room left for the value. + bool WriteExponentialGolomb(uint32_t val); + // Writes the signed exponential golomb version of the supplied value. + // Signed exponential golomb values are just the unsigned values mapped to the + // sequence 0, 1, -1, 2, -2, etc. in order. + bool WriteSignedExponentialGolomb(int32_t val); + + // Writes the Leb128 encoded value. + bool WriteLeb128(uint64_t val); + + // Writes the string as bytes of data. + bool WriteString(absl::string_view data); + + private: + // The buffer, as a writable array. + uint8_t* const writable_bytes_; + // The total size of `bytes_`. + const size_t byte_count_; + // The current offset, in bytes, from the start of `bytes_`. + size_t byte_offset_; + // The current offset, in bits, into the current byte. + size_t bit_offset_; +}; + +} // namespace rtc + +#endif // RTC_BASE_BIT_BUFFER_H_ diff --git a/third_party/libwebrtc/rtc_base/bit_buffer_gn/moz.build b/third_party/libwebrtc/rtc_base/bit_buffer_gn/moz.build new file mode 100644 index 0000000000..a4a4e8c6e4 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/bit_buffer_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/rtc_base/bit_buffer.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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("bit_buffer_gn") diff --git a/third_party/libwebrtc/rtc_base/bit_buffer_unittest.cc b/third_party/libwebrtc/rtc_base/bit_buffer_unittest.cc new file mode 100644 index 0000000000..7dfe0c808d --- /dev/null +++ b/third_party/libwebrtc/rtc_base/bit_buffer_unittest.cc @@ -0,0 +1,256 @@ +/* + * Copyright 2015 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 "rtc_base/bit_buffer.h" + +#include <limits> + +#include "api/array_view.h" +#include "rtc_base/arraysize.h" +#include "rtc_base/bitstream_reader.h" +#include "rtc_base/byte_buffer.h" +#include "test/gmock.h" +#include "test/gtest.h" + +namespace rtc { + +using ::testing::ElementsAre; +using ::webrtc::BitstreamReader; + +TEST(BitBufferWriterTest, ConsumeBits) { + uint8_t bytes[64] = {0}; + BitBufferWriter buffer(bytes, 32); + uint64_t total_bits = 32 * 8; + EXPECT_EQ(total_bits, buffer.RemainingBitCount()); + EXPECT_TRUE(buffer.ConsumeBits(3)); + total_bits -= 3; + EXPECT_EQ(total_bits, buffer.RemainingBitCount()); + EXPECT_TRUE(buffer.ConsumeBits(3)); + total_bits -= 3; + EXPECT_EQ(total_bits, buffer.RemainingBitCount()); + EXPECT_TRUE(buffer.ConsumeBits(15)); + total_bits -= 15; + EXPECT_EQ(total_bits, buffer.RemainingBitCount()); + EXPECT_TRUE(buffer.ConsumeBits(37)); + total_bits -= 37; + EXPECT_EQ(total_bits, buffer.RemainingBitCount()); + + EXPECT_FALSE(buffer.ConsumeBits(32 * 8)); + EXPECT_EQ(total_bits, buffer.RemainingBitCount()); +} + +TEST(BitBufferWriterDeathTest, SetOffsetValues) { + uint8_t bytes[4] = {0}; + BitBufferWriter buffer(bytes, 4); + + size_t byte_offset, bit_offset; + // Bit offsets are [0,7]. + EXPECT_TRUE(buffer.Seek(0, 0)); + EXPECT_TRUE(buffer.Seek(0, 7)); + buffer.GetCurrentOffset(&byte_offset, &bit_offset); + EXPECT_EQ(0u, byte_offset); + EXPECT_EQ(7u, bit_offset); + EXPECT_FALSE(buffer.Seek(0, 8)); + buffer.GetCurrentOffset(&byte_offset, &bit_offset); + EXPECT_EQ(0u, byte_offset); + EXPECT_EQ(7u, bit_offset); + // Byte offsets are [0,length]. At byte offset length, the bit offset must be + // 0. + EXPECT_TRUE(buffer.Seek(0, 0)); + EXPECT_TRUE(buffer.Seek(2, 4)); + buffer.GetCurrentOffset(&byte_offset, &bit_offset); + EXPECT_EQ(2u, byte_offset); + EXPECT_EQ(4u, bit_offset); + EXPECT_TRUE(buffer.Seek(4, 0)); + EXPECT_FALSE(buffer.Seek(5, 0)); + buffer.GetCurrentOffset(&byte_offset, &bit_offset); + EXPECT_EQ(4u, byte_offset); + EXPECT_EQ(0u, bit_offset); + EXPECT_FALSE(buffer.Seek(4, 1)); + +// Disable death test on Android because it relies on fork() and doesn't play +// nicely. +#if GTEST_HAS_DEATH_TEST +#if !defined(WEBRTC_ANDROID) + // Passing a null out parameter is death. + EXPECT_DEATH(buffer.GetCurrentOffset(&byte_offset, nullptr), ""); +#endif +#endif +} + +TEST(BitBufferWriterTest, + WriteNonSymmetricSameNumberOfBitsWhenNumValuesPowerOf2) { + uint8_t bytes[2] = {}; + BitBufferWriter writer(bytes, 2); + + ASSERT_EQ(writer.RemainingBitCount(), 16u); + EXPECT_TRUE(writer.WriteNonSymmetric(0xf, /*num_values=*/1 << 4)); + ASSERT_EQ(writer.RemainingBitCount(), 12u); + EXPECT_TRUE(writer.WriteNonSymmetric(0x3, /*num_values=*/1 << 4)); + ASSERT_EQ(writer.RemainingBitCount(), 8u); + EXPECT_TRUE(writer.WriteNonSymmetric(0xa, /*num_values=*/1 << 4)); + ASSERT_EQ(writer.RemainingBitCount(), 4u); + EXPECT_TRUE(writer.WriteNonSymmetric(0x0, /*num_values=*/1 << 4)); + ASSERT_EQ(writer.RemainingBitCount(), 0u); + + EXPECT_THAT(bytes, ElementsAre(0xf3, 0xa0)); +} + +TEST(BitBufferWriterTest, NonSymmetricReadsMatchesWrites) { + uint8_t bytes[2] = {}; + BitBufferWriter writer(bytes, 2); + + EXPECT_EQ(BitBufferWriter::SizeNonSymmetricBits(/*val=*/1, /*num_values=*/6), + 2u); + EXPECT_EQ(BitBufferWriter::SizeNonSymmetricBits(/*val=*/2, /*num_values=*/6), + 3u); + // Values [0, 1] can fit into two bit. + ASSERT_EQ(writer.RemainingBitCount(), 16u); + EXPECT_TRUE(writer.WriteNonSymmetric(/*val=*/0, /*num_values=*/6)); + ASSERT_EQ(writer.RemainingBitCount(), 14u); + EXPECT_TRUE(writer.WriteNonSymmetric(/*val=*/1, /*num_values=*/6)); + ASSERT_EQ(writer.RemainingBitCount(), 12u); + // Values [2, 5] require 3 bits. + EXPECT_TRUE(writer.WriteNonSymmetric(/*val=*/2, /*num_values=*/6)); + ASSERT_EQ(writer.RemainingBitCount(), 9u); + EXPECT_TRUE(writer.WriteNonSymmetric(/*val=*/3, /*num_values=*/6)); + ASSERT_EQ(writer.RemainingBitCount(), 6u); + EXPECT_TRUE(writer.WriteNonSymmetric(/*val=*/4, /*num_values=*/6)); + ASSERT_EQ(writer.RemainingBitCount(), 3u); + EXPECT_TRUE(writer.WriteNonSymmetric(/*val=*/5, /*num_values=*/6)); + ASSERT_EQ(writer.RemainingBitCount(), 0u); + + // Bit values are + // 00.01.100.101.110.111 = 00011001|01110111 = 0x19|77 + EXPECT_THAT(bytes, ElementsAre(0x19, 0x77)); + + BitstreamReader reader(bytes); + EXPECT_EQ(reader.ReadNonSymmetric(/*num_values=*/6), 0u); + EXPECT_EQ(reader.ReadNonSymmetric(/*num_values=*/6), 1u); + EXPECT_EQ(reader.ReadNonSymmetric(/*num_values=*/6), 2u); + EXPECT_EQ(reader.ReadNonSymmetric(/*num_values=*/6), 3u); + EXPECT_EQ(reader.ReadNonSymmetric(/*num_values=*/6), 4u); + EXPECT_EQ(reader.ReadNonSymmetric(/*num_values=*/6), 5u); + EXPECT_TRUE(reader.Ok()); +} + +TEST(BitBufferWriterTest, WriteNonSymmetricOnlyValueConsumesNoBits) { + uint8_t bytes[2] = {}; + BitBufferWriter writer(bytes, 2); + ASSERT_EQ(writer.RemainingBitCount(), 16u); + + EXPECT_TRUE(writer.WriteNonSymmetric(0, /*num_values=*/1)); + + EXPECT_EQ(writer.RemainingBitCount(), 16u); +} + +TEST(BitBufferWriterTest, SymmetricReadWrite) { + uint8_t bytes[16] = {0}; + BitBufferWriter buffer(bytes, 4); + + // Write some bit data at various sizes. + EXPECT_TRUE(buffer.WriteBits(0x2u, 3)); + EXPECT_TRUE(buffer.WriteBits(0x1u, 2)); + EXPECT_TRUE(buffer.WriteBits(0x53u, 7)); + EXPECT_TRUE(buffer.WriteBits(0x0u, 2)); + EXPECT_TRUE(buffer.WriteBits(0x1u, 1)); + EXPECT_TRUE(buffer.WriteBits(0x1ABCDu, 17)); + // That should be all that fits in the buffer. + EXPECT_FALSE(buffer.WriteBits(1, 1)); + + BitstreamReader reader(rtc::MakeArrayView(bytes, 4)); + EXPECT_EQ(reader.ReadBits(3), 0x2u); + EXPECT_EQ(reader.ReadBits(2), 0x1u); + EXPECT_EQ(reader.ReadBits(7), 0x53u); + EXPECT_EQ(reader.ReadBits(2), 0x0u); + EXPECT_EQ(reader.ReadBits(1), 0x1u); + EXPECT_EQ(reader.ReadBits(17), 0x1ABCDu); + // And there should be nothing left. + EXPECT_EQ(reader.RemainingBitCount(), 0); +} + +TEST(BitBufferWriterTest, SymmetricBytesMisaligned) { + uint8_t bytes[16] = {0}; + BitBufferWriter buffer(bytes, 16); + + // Offset 3, to get things misaligned. + EXPECT_TRUE(buffer.ConsumeBits(3)); + EXPECT_TRUE(buffer.WriteUInt8(0x12u)); + EXPECT_TRUE(buffer.WriteUInt16(0x3456u)); + EXPECT_TRUE(buffer.WriteUInt32(0x789ABCDEu)); + + BitstreamReader reader(bytes); + reader.ConsumeBits(3); + EXPECT_EQ(reader.Read<uint8_t>(), 0x12u); + EXPECT_EQ(reader.Read<uint16_t>(), 0x3456u); + EXPECT_EQ(reader.Read<uint32_t>(), 0x789ABCDEu); + EXPECT_TRUE(reader.Ok()); +} + +TEST(BitBufferWriterTest, SymmetricGolomb) { + char test_string[] = "my precious"; + uint8_t bytes[64] = {0}; + BitBufferWriter buffer(bytes, 64); + for (size_t i = 0; i < arraysize(test_string); ++i) { + EXPECT_TRUE(buffer.WriteExponentialGolomb(test_string[i])); + } + BitstreamReader reader(bytes); + for (size_t i = 0; i < arraysize(test_string); ++i) { + EXPECT_EQ(int64_t{reader.ReadExponentialGolomb()}, int64_t{test_string[i]}); + } + EXPECT_TRUE(reader.Ok()); +} + +TEST(BitBufferWriterTest, WriteClearsBits) { + uint8_t bytes[] = {0xFF, 0xFF}; + BitBufferWriter buffer(bytes, 2); + EXPECT_TRUE(buffer.ConsumeBits(3)); + EXPECT_TRUE(buffer.WriteBits(0, 1)); + EXPECT_EQ(0xEFu, bytes[0]); + EXPECT_TRUE(buffer.WriteBits(0, 3)); + EXPECT_EQ(0xE1u, bytes[0]); + EXPECT_TRUE(buffer.WriteBits(0, 2)); + EXPECT_EQ(0xE0u, bytes[0]); + EXPECT_EQ(0x7F, bytes[1]); +} + +TEST(BitBufferWriterTest, WriteLeb128) { + uint8_t small_number[2]; + BitBufferWriter small_buffer(small_number, sizeof(small_number)); + EXPECT_TRUE(small_buffer.WriteLeb128(129)); + EXPECT_THAT(small_number, ElementsAre(0x81, 0x01)); + + uint8_t large_number[10]; + BitBufferWriter large_buffer(large_number, sizeof(large_number)); + EXPECT_TRUE(large_buffer.WriteLeb128(std::numeric_limits<uint64_t>::max())); + EXPECT_THAT(large_number, ElementsAre(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x01)); +} + +TEST(BitBufferWriterTest, WriteLeb128TooSmallBuffer) { + uint8_t bytes[1]; + BitBufferWriter buffer(bytes, sizeof(bytes)); + EXPECT_FALSE(buffer.WriteLeb128(12345)); +} + +TEST(BitBufferWriterTest, WriteString) { + uint8_t buffer[2]; + BitBufferWriter writer(buffer, sizeof(buffer)); + EXPECT_TRUE(writer.WriteString("ab")); + EXPECT_THAT(buffer, ElementsAre('a', 'b')); +} + +TEST(BitBufferWriterTest, WriteStringTooSmallBuffer) { + uint8_t buffer[2]; + BitBufferWriter writer(buffer, sizeof(buffer)); + EXPECT_FALSE(writer.WriteString("abc")); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/bitrate_tracker.cc b/third_party/libwebrtc/rtc_base/bitrate_tracker.cc new file mode 100644 index 0000000000..340e444f24 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/bitrate_tracker.cc @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2023 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 "rtc_base/bitrate_tracker.h" + +#include "absl/types/optional.h" +#include "api/units/data_rate.h" +#include "api/units/timestamp.h" +#include "rtc_base/rate_statistics.h" + +namespace webrtc { + +BitrateTracker::BitrateTracker(TimeDelta max_window_size) + : impl_(max_window_size.ms(), RateStatistics::kBpsScale) {} + +absl::optional<DataRate> BitrateTracker::Rate(Timestamp now) const { + if (absl::optional<int64_t> rate = impl_.Rate(now.ms())) { + return DataRate::BitsPerSec(*rate); + } + return absl::nullopt; +} + +bool BitrateTracker::SetWindowSize(TimeDelta window_size, Timestamp now) { + return impl_.SetWindowSize(window_size.ms(), now.ms()); +} + +void BitrateTracker::Update(int64_t bytes, Timestamp now) { + impl_.Update(bytes, now.ms()); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/bitrate_tracker.h b/third_party/libwebrtc/rtc_base/bitrate_tracker.h new file mode 100644 index 0000000000..a54bd9a561 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/bitrate_tracker.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2023 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 RTC_BASE_BITRATE_TRACKER_H_ +#define RTC_BASE_BITRATE_TRACKER_H_ + +#include <stddef.h> +#include <stdint.h> + +#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" +#include "rtc_base/rate_statistics.h" +#include "rtc_base/system/rtc_export.h" + +namespace webrtc { +// Class to estimate bitrates over running window. +// Timestamps used in Update(), Rate() and SetWindowSize() must never +// decrease for two consecutive calls. +// This class is thread unsafe. +class RTC_EXPORT BitrateTracker { + public: + // max_window_sizes = Maximum window size for the rate estimation. + // Initial window size is set to this, but may be changed + // to something lower by calling SetWindowSize(). + explicit BitrateTracker(TimeDelta max_window_size); + + BitrateTracker(const BitrateTracker&) = default; + BitrateTracker(BitrateTracker&&) = default; + BitrateTracker& operator=(const BitrateTracker&) = delete; + BitrateTracker& operator=(BitrateTracker&&) = delete; + + ~BitrateTracker() = default; + + // Resets instance to original state. + void Reset() { impl_.Reset(); } + + // Updates bitrate with a new data point, moving averaging window as needed. + void Update(int64_t bytes, Timestamp now); + void Update(DataSize size, Timestamp now) { Update(size.bytes(), now); } + + // Returns bitrate, moving averaging window as needed. + // Returns nullopt when bitrate can't be measured. + absl::optional<DataRate> Rate(Timestamp now) const; + + // Update the size of the averaging window. The maximum allowed value for + // `window_size` is `max_window_size` as supplied in the constructor. + bool SetWindowSize(TimeDelta window_size, Timestamp now); + + private: + RateStatistics impl_; +}; +} // namespace webrtc + +#endif // RTC_BASE_BITRATE_TRACKER_H_ diff --git a/third_party/libwebrtc/rtc_base/bitrate_tracker_gn/moz.build b/third_party/libwebrtc/rtc_base/bitrate_tracker_gn/moz.build new file mode 100644 index 0000000000..8836b1e089 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/bitrate_tracker_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/rtc_base/bitrate_tracker.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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("bitrate_tracker_gn") diff --git a/third_party/libwebrtc/rtc_base/bitrate_tracker_unittest.cc b/third_party/libwebrtc/rtc_base/bitrate_tracker_unittest.cc new file mode 100644 index 0000000000..2129aebfdd --- /dev/null +++ b/third_party/libwebrtc/rtc_base/bitrate_tracker_unittest.cc @@ -0,0 +1,267 @@ +/* + * Copyright (c) 2023 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 "rtc_base/bitrate_tracker.h" + +#include <cstdlib> +#include <limits> + +#include "absl/types/optional.h" +#include "api/units/data_rate.h" +#include "api/units/time_delta.h" +#include "api/units/timestamp.h" +#include "test/gmock.h" +#include "test/gtest.h" + +namespace webrtc { +namespace { + +using ::testing::AllOf; +using ::testing::Ge; +using ::testing::Le; + +constexpr TimeDelta kWindow = TimeDelta::Millis(500); +constexpr TimeDelta kEpsilon = TimeDelta::Millis(1); + +TEST(BitrateTrackerTest, ReturnsNulloptInitially) { + Timestamp now = Timestamp::Seconds(12'345); + BitrateTracker stats(kWindow); + + EXPECT_EQ(stats.Rate(now), absl::nullopt); +} + +TEST(BitrateTrackerTest, ReturnsNulloptAfterSingleDataPoint) { + Timestamp now = Timestamp::Seconds(12'345); + BitrateTracker stats(kWindow); + + stats.Update(1'500, now); + now += TimeDelta::Millis(10); + + EXPECT_EQ(stats.Rate(now), absl::nullopt); +} + +TEST(BitrateTrackerTest, ReturnsRateAfterTwoMeasurements) { + Timestamp now = Timestamp::Seconds(12'345); + BitrateTracker stats(kWindow); + + stats.Update(1'500, now); + now += TimeDelta::Millis(10); + stats.Update(1'500, now); + + // One packet every 10ms would result in 1.2 Mbps, but until window is full, + // it could be treated as two packets in ~10ms window, measuring twice that + // bitrate. + EXPECT_THAT(stats.Rate(now), AllOf(Ge(DataRate::BitsPerSec(1'200'000)), + Le(DataRate::BitsPerSec(2'400'000)))); +} + +TEST(BitrateTrackerTest, MeasuresConstantRate) { + const Timestamp start = Timestamp::Seconds(12'345); + const TimeDelta kInterval = TimeDelta::Millis(10); + const DataSize kPacketSize = DataSize::Bytes(1'500); + const DataRate kConstantRate = kPacketSize / kInterval; + + Timestamp now = start; + BitrateTracker stats(kWindow); + + stats.Update(kPacketSize, now); + DataSize total_size = kPacketSize; + DataRate last_error = DataRate::PlusInfinity(); + for (TimeDelta i = TimeDelta::Zero(); i < kWindow; i += kInterval) { + SCOPED_TRACE(i); + now += kInterval; + total_size += kPacketSize; + stats.Update(kPacketSize, now); + + // Until window is full, bitrate is measured over a smaller window and might + // look larger than the constant rate. + absl::optional<DataRate> bitrate = stats.Rate(now); + ASSERT_THAT(bitrate, + AllOf(Ge(kConstantRate), Le(total_size / (now - start)))); + + // Expect the estimation error to decrease as the window is extended. + DataRate error = *bitrate - kConstantRate; + EXPECT_LE(error, last_error); + last_error = error; + } + + // Once window is full, bitrate measurment should be stable. + for (TimeDelta i = TimeDelta::Zero(); i < kInterval; + i += TimeDelta::Millis(1)) { + SCOPED_TRACE(i); + EXPECT_EQ(stats.Rate(now + i), kConstantRate); + } +} + +TEST(BitrateTrackerTest, IncreasingThenDecreasingBitrate) { + const DataSize kLargePacketSize = DataSize::Bytes(1'500); + const DataSize kSmallPacketSize = DataSize::Bytes(300); + const TimeDelta kLargeInterval = TimeDelta::Millis(10); + const TimeDelta kSmallInterval = TimeDelta::Millis(2); + + Timestamp now = Timestamp::Seconds(12'345); + BitrateTracker stats(kWindow); + + stats.Update(kLargePacketSize, now); + for (TimeDelta i = TimeDelta::Zero(); i < kWindow; i += kLargeInterval) { + SCOPED_TRACE(i); + now += kLargeInterval; + stats.Update(kLargePacketSize, now); + } + absl::optional<DataRate> last_bitrate = stats.Rate(now); + EXPECT_EQ(last_bitrate, kLargePacketSize / kLargeInterval); + + // Decrease bitrate with smaller measurments. + for (TimeDelta i = TimeDelta::Zero(); i < kWindow; i += kLargeInterval) { + SCOPED_TRACE(i); + now += kLargeInterval; + stats.Update(kSmallPacketSize, now); + + absl::optional<DataRate> bitrate = stats.Rate(now); + EXPECT_LT(bitrate, last_bitrate); + + last_bitrate = bitrate; + } + EXPECT_EQ(last_bitrate, kSmallPacketSize / kLargeInterval); + + // Increase bitrate with more frequent measurments. + for (TimeDelta i = TimeDelta::Zero(); i < kWindow; i += kSmallInterval) { + SCOPED_TRACE(i); + now += kSmallInterval; + stats.Update(kSmallPacketSize, now); + + absl::optional<DataRate> bitrate = stats.Rate(now); + EXPECT_GE(bitrate, last_bitrate); + + last_bitrate = bitrate; + } + EXPECT_EQ(last_bitrate, kSmallPacketSize / kSmallInterval); +} + +TEST(BitrateTrackerTest, ResetAfterSilence) { + const TimeDelta kInterval = TimeDelta::Millis(10); + const DataSize kPacketSize = DataSize::Bytes(1'500); + + Timestamp now = Timestamp::Seconds(12'345); + BitrateTracker stats(kWindow); + + // Feed data until window has been filled. + stats.Update(kPacketSize, now); + for (TimeDelta i = TimeDelta::Zero(); i < kWindow; i += kInterval) { + now += kInterval; + stats.Update(kPacketSize, now); + } + ASSERT_GT(stats.Rate(now), DataRate::Zero()); + + now += kWindow + kEpsilon; + // Silence over window size should trigger auto reset for coming sample. + EXPECT_EQ(stats.Rate(now), absl::nullopt); + stats.Update(kPacketSize, now); + // Single measurment after reset is not enough to estimate the rate. + EXPECT_EQ(stats.Rate(now), absl::nullopt); + + // Manual reset, add the same check again. + stats.Reset(); + EXPECT_EQ(stats.Rate(now), absl::nullopt); + now += kInterval; + stats.Update(kPacketSize, now); + EXPECT_EQ(stats.Rate(now), absl::nullopt); +} + +TEST(BitrateTrackerTest, HandlesChangingWindowSize) { + Timestamp now = Timestamp::Seconds(12'345); + BitrateTracker stats(kWindow); + + // Check window size is validated. + EXPECT_TRUE(stats.SetWindowSize(kWindow, now)); + EXPECT_FALSE(stats.SetWindowSize(kWindow + kEpsilon, now)); + EXPECT_FALSE(stats.SetWindowSize(TimeDelta::Zero(), now)); + EXPECT_TRUE(stats.SetWindowSize(kEpsilon, now)); + EXPECT_TRUE(stats.SetWindowSize(kWindow, now)); + + // Fill the buffer at a rate of 10 bytes per 10 ms (8 kbps). + const DataSize kValue = DataSize::Bytes(10); + const TimeDelta kInterval = TimeDelta::Millis(10); + for (TimeDelta i = TimeDelta::Zero(); i < kWindow; i += kInterval) { + now += kInterval; + stats.Update(kValue, now); + } + ASSERT_GT(stats.Rate(now), DataRate::BitsPerSec(8'000)); + + // Halve the window size, rate should stay the same. + EXPECT_TRUE(stats.SetWindowSize(kWindow / 2, now)); + EXPECT_EQ(stats.Rate(now), DataRate::BitsPerSec(8'000)); + + // Double the window size again, rate should stay the same. + // The window won't actually expand until new calls to the `Update`. + EXPECT_TRUE(stats.SetWindowSize(kWindow, now)); + EXPECT_EQ(stats.Rate(now), DataRate::BitsPerSec(8'000)); + + // Fill the now empty window half at twice the rate. + for (TimeDelta i = TimeDelta::Zero(); i < kWindow / 2; i += kInterval) { + now += kInterval; + stats.Update(2 * kValue, now); + } + + // Rate should have increased by 50%. + EXPECT_EQ(stats.Rate(now), DataRate::BitsPerSec(12'000)); +} + +TEST(BitrateTrackerTest, HandlesZeroCounts) { + const DataSize kPacketSize = DataSize::Bytes(1'500); + const TimeDelta kInterval = TimeDelta::Millis(10); + const Timestamp start = Timestamp::Seconds(12'345); + + Timestamp now = start; + BitrateTracker stats(kWindow); + + stats.Update(kPacketSize, now); + ASSERT_EQ(stats.Rate(now), absl::nullopt); + now += kInterval; + stats.Update(0, now); + absl::optional<DataRate> last_bitrate = stats.Rate(now); + EXPECT_GT(last_bitrate, DataRate::Zero()); + now += kInterval; + while (now < start + kWindow) { + SCOPED_TRACE(now - start); + stats.Update(0, now); + + absl::optional<DataRate> bitrate = stats.Rate(now); + EXPECT_GT(bitrate, DataRate::Zero()); + // As window expands, average bitrate decreases. + EXPECT_LT(bitrate, last_bitrate); + + last_bitrate = bitrate; + now += kInterval; + } + + // Initial kPacketSize should be outside the window now, so overall bitrate + // should be zero + EXPECT_EQ(stats.Rate(now), DataRate::Zero()); + + // Single measurment should be enough to get non zero rate. + stats.Update(kPacketSize, now); + EXPECT_EQ(stats.Rate(now), kPacketSize / kWindow); +} + +TEST(BitrateTrackerTest, ReturnsNulloptWhenOverflows) { + Timestamp now = Timestamp::Seconds(12'345); + BitrateTracker stats(kWindow); + + int64_t very_large_number = std::numeric_limits<int64_t>::max(); + stats.Update(very_large_number, now); + now += kEpsilon; + stats.Update(very_large_number, now); + + EXPECT_EQ(stats.Rate(now), absl::nullopt); +} + +} // namespace +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/bitstream_reader.cc b/third_party/libwebrtc/rtc_base/bitstream_reader.cc new file mode 100644 index 0000000000..3e1b94d8d4 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/bitstream_reader.cc @@ -0,0 +1,167 @@ +/* + * Copyright 2021 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 "rtc_base/bitstream_reader.h" + +#include <stdint.h> + +#include <limits> + +#include "absl/numeric/bits.h" +#include "rtc_base/checks.h" +#include "rtc_base/numerics/safe_conversions.h" + +namespace webrtc { + +uint64_t BitstreamReader::ReadBits(int bits) { + RTC_DCHECK_GE(bits, 0); + RTC_DCHECK_LE(bits, 64); + set_last_read_is_verified(false); + + if (remaining_bits_ < bits) { + remaining_bits_ -= bits; + return 0; + } + + int remaining_bits_in_first_byte = remaining_bits_ % 8; + remaining_bits_ -= bits; + if (bits < remaining_bits_in_first_byte) { + // Reading fewer bits than what's left in the current byte, just + // return the portion of this byte that is needed. + int offset = (remaining_bits_in_first_byte - bits); + return ((*bytes_) >> offset) & ((1 << bits) - 1); + } + + uint64_t result = 0; + if (remaining_bits_in_first_byte > 0) { + // Read all bits that were left in the current byte and consume that byte. + bits -= remaining_bits_in_first_byte; + uint8_t mask = (1 << remaining_bits_in_first_byte) - 1; + result = static_cast<uint64_t>(*bytes_ & mask) << bits; + ++bytes_; + } + + // Read as many full bytes as we can. + while (bits >= 8) { + bits -= 8; + result |= uint64_t{*bytes_} << bits; + ++bytes_; + } + // Whatever is left to read is smaller than a byte, so grab just the needed + // bits and shift them into the lowest bits. + if (bits > 0) { + result |= (*bytes_ >> (8 - bits)); + } + return result; +} + +int BitstreamReader::ReadBit() { + set_last_read_is_verified(false); + --remaining_bits_; + if (remaining_bits_ < 0) { + return 0; + } + + int bit_position = remaining_bits_ % 8; + if (bit_position == 0) { + // Read the last bit from current byte and move to the next byte. + return (*bytes_++) & 0x01; + } + + return (*bytes_ >> bit_position) & 0x01; +} + +void BitstreamReader::ConsumeBits(int bits) { + RTC_DCHECK_GE(bits, 0); + set_last_read_is_verified(false); + if (remaining_bits_ < bits) { + Invalidate(); + return; + } + + int remaining_bytes = (remaining_bits_ + 7) / 8; + remaining_bits_ -= bits; + int new_remaining_bytes = (remaining_bits_ + 7) / 8; + bytes_ += (remaining_bytes - new_remaining_bytes); +} + +uint32_t BitstreamReader::ReadNonSymmetric(uint32_t num_values) { + RTC_DCHECK_GT(num_values, 0); + RTC_DCHECK_LE(num_values, uint32_t{1} << 31); + + int width = absl::bit_width(num_values); + uint32_t num_min_bits_values = (uint32_t{1} << width) - num_values; + + uint64_t val = ReadBits(width - 1); + if (val < num_min_bits_values) { + return val; + } + return (val << 1) + ReadBit() - num_min_bits_values; +} + +uint32_t BitstreamReader::ReadExponentialGolomb() { + // Count the number of leading 0. + int zero_bit_count = 0; + while (ReadBit() == 0) { + if (++zero_bit_count >= 32) { + // Golob value won't fit into 32 bits of the return value. Fail the parse. + Invalidate(); + return 0; + } + } + + // The bit count of the value is the number of zeros + 1. + // However the first '1' was already read above. + return (uint32_t{1} << zero_bit_count) + + rtc::dchecked_cast<uint32_t>(ReadBits(zero_bit_count)) - 1; +} + +int BitstreamReader::ReadSignedExponentialGolomb() { + uint32_t unsigned_val = ReadExponentialGolomb(); + if ((unsigned_val & 1) == 0) { + return -static_cast<int>(unsigned_val / 2); + } else { + return (unsigned_val + 1) / 2; + } +} + +uint64_t BitstreamReader::ReadLeb128() { + uint64_t decoded = 0; + size_t i = 0; + uint8_t byte; + // A LEB128 value can in theory be arbitrarily large, but for convenience sake + // consider it invalid if it can't fit in an uint64_t. + do { + byte = Read<uint8_t>(); + decoded += + (static_cast<uint64_t>(byte & 0x7f) << static_cast<uint64_t>(7 * i)); + ++i; + } while (i < 10 && (byte & 0x80)); + + // The first 9 bytes represent the first 63 bits. The tenth byte can therefore + // not be larger than 1 as it would overflow an uint64_t. + if (i == 10 && byte > 1) { + Invalidate(); + } + + return Ok() ? decoded : 0; +} + +std::string BitstreamReader::ReadString(int num_bytes) { + std::string res; + res.reserve(num_bytes); + for (int i = 0; i < num_bytes; ++i) { + res += Read<uint8_t>(); + } + + return Ok() ? res : std::string(); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/bitstream_reader.h b/third_party/libwebrtc/rtc_base/bitstream_reader.h new file mode 100644 index 0000000000..c367b9dc9f --- /dev/null +++ b/third_party/libwebrtc/rtc_base/bitstream_reader.h @@ -0,0 +1,151 @@ +/* + * Copyright 2021 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 RTC_BASE_BITSTREAM_READER_H_ +#define RTC_BASE_BITSTREAM_READER_H_ + +#include <stdint.h> + +#include "absl/base/attributes.h" +#include "absl/strings/string_view.h" +#include "api/array_view.h" +#include "rtc_base/checks.h" +#include "rtc_base/numerics/safe_conversions.h" + +namespace webrtc { + +// A class to parse sequence of bits. Byte order is assumed big-endian/network. +// This class is optimized for successful parsing and binary size. +// Individual calls to `Read` and `ConsumeBits` never fail. Instead they may +// change the class state into 'failure state'. User of this class should verify +// parsing by checking if class is in that 'failure state' by calling `Ok`. +// That verification can be done once after multiple reads. +class BitstreamReader { + public: + explicit BitstreamReader( + rtc::ArrayView<const uint8_t> bytes ABSL_ATTRIBUTE_LIFETIME_BOUND); + explicit BitstreamReader( + absl::string_view bytes ABSL_ATTRIBUTE_LIFETIME_BOUND); + BitstreamReader(const BitstreamReader&) = default; + BitstreamReader& operator=(const BitstreamReader&) = default; + ~BitstreamReader(); + + // Return number of unread bits in the buffer, or negative number if there + // was a reading error. + int RemainingBitCount() const; + + // Returns `true` iff all calls to `Read` and `ConsumeBits` were successful. + bool Ok() const { return RemainingBitCount() >= 0; } + + // Sets `BitstreamReader` into the failure state. + void Invalidate() { remaining_bits_ = -1; } + + // Moves current read position forward. `bits` must be non-negative. + void ConsumeBits(int bits); + + // Reads single bit. Returns 0 or 1. + ABSL_MUST_USE_RESULT int ReadBit(); + + // Reads `bits` from the bitstream. `bits` must be in range [0, 64]. + // Returns an unsigned integer in range [0, 2^bits - 1]. + // On failure sets `BitstreamReader` into the failure state and returns 0. + ABSL_MUST_USE_RESULT uint64_t ReadBits(int bits); + + // Reads unsigned integer of fixed width. + template <typename T, + typename std::enable_if<std::is_unsigned<T>::value && + !std::is_same<T, bool>::value && + sizeof(T) <= 8>::type* = nullptr> + ABSL_MUST_USE_RESULT T Read() { + return rtc::dchecked_cast<T>(ReadBits(sizeof(T) * 8)); + } + + // Reads single bit as boolean. + template < + typename T, + typename std::enable_if<std::is_same<T, bool>::value>::type* = nullptr> + ABSL_MUST_USE_RESULT bool Read() { + return ReadBit() != 0; + } + + // Reads value in range [0, `num_values` - 1]. + // This encoding is similar to ReadBits(val, Ceil(Log2(num_values)), + // but reduces wastage incurred when encoding non-power of two value ranges + // Non symmetric values are encoded as: + // 1) n = bit_width(num_values) + // 2) k = (1 << n) - num_values + // Value v in range [0, k - 1] is encoded in (n-1) bits. + // Value v in range [k, num_values - 1] is encoded as (v+k) in n bits. + // https://aomediacodec.github.io/av1-spec/#nsn + uint32_t ReadNonSymmetric(uint32_t num_values); + + // Reads exponential golomb encoded value. + // On failure sets `BitstreamReader` into the failure state and returns + // unspecified value. + // Exponential golomb values are encoded as: + // 1) x = source val + 1 + // 2) In binary, write [bit_width(x) - 1] 0s, then x + // To decode, we count the number of leading 0 bits, read that many + 1 bits, + // and increment the result by 1. + // Fails the parsing if the value wouldn't fit in a uint32_t. + uint32_t ReadExponentialGolomb(); + + // Reads signed exponential golomb values at the current offset. Signed + // exponential golomb values are just the unsigned values mapped to the + // sequence 0, 1, -1, 2, -2, etc. in order. + // On failure sets `BitstreamReader` into the failure state and returns + // unspecified value. + int ReadSignedExponentialGolomb(); + + // Reads a LEB128 encoded value. The value will be considered invalid if it + // can't fit into a uint64_t. + uint64_t ReadLeb128(); + + std::string ReadString(int num_bytes); + + private: + void set_last_read_is_verified(bool value) const; + + // Next byte with at least one unread bit. + const uint8_t* bytes_; + + // Number of bits remained to read. + int remaining_bits_; + + // Unused in release mode. + mutable bool last_read_is_verified_ = true; +}; + +inline BitstreamReader::BitstreamReader(rtc::ArrayView<const uint8_t> bytes) + : bytes_(bytes.data()), remaining_bits_(bytes.size() * 8) {} + +inline BitstreamReader::BitstreamReader(absl::string_view bytes) + : bytes_(reinterpret_cast<const uint8_t*>(bytes.data())), + remaining_bits_(bytes.size() * 8) {} + +inline BitstreamReader::~BitstreamReader() { + RTC_DCHECK(last_read_is_verified_) << "Latest calls to Read or ConsumeBit " + "were not checked with Ok function."; +} + +inline void BitstreamReader::set_last_read_is_verified(bool value) const { +#ifdef RTC_DCHECK_IS_ON + last_read_is_verified_ = value; +#endif +} + +inline int BitstreamReader::RemainingBitCount() const { + set_last_read_is_verified(true); + return remaining_bits_; +} + +} // namespace webrtc + +#endif // RTC_BASE_BITSTREAM_READER_H_ diff --git a/third_party/libwebrtc/rtc_base/bitstream_reader_gn/moz.build b/third_party/libwebrtc/rtc_base/bitstream_reader_gn/moz.build new file mode 100644 index 0000000000..b6a5de1971 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/bitstream_reader_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/rtc_base/bitstream_reader.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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("bitstream_reader_gn") diff --git a/third_party/libwebrtc/rtc_base/bitstream_reader_unittest.cc b/third_party/libwebrtc/rtc_base/bitstream_reader_unittest.cc new file mode 100644 index 0000000000..46309b2a13 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/bitstream_reader_unittest.cc @@ -0,0 +1,373 @@ +/* + * Copyright 2021 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 "rtc_base/bitstream_reader.h" + +#include <stddef.h> +#include <stdint.h> + +#include <array> +#include <limits> + +#include "absl/numeric/bits.h" +#include "absl/types/optional.h" +#include "api/array_view.h" +#include "rtc_base/checks.h" +#include "test/gmock.h" +#include "test/gtest.h" + +namespace webrtc { +namespace { + +TEST(BitstreamReaderTest, InDebugModeRequiresToCheckOkStatusBeforeDestruction) { + const uint8_t bytes[32] = {}; + absl::optional<BitstreamReader> reader(absl::in_place, bytes); + + EXPECT_GE(reader->ReadBits(7), 0u); +#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(OS_ANDROID) + EXPECT_DEATH(reader = absl::nullopt, ""); +#endif + EXPECT_TRUE(reader->Ok()); + reader = absl::nullopt; +} + +TEST(BitstreamReaderTest, InDebugModeMayCheckRemainingBitsInsteadOfOkStatus) { + const uint8_t bytes[32] = {}; + absl::optional<BitstreamReader> reader(absl::in_place, bytes); + + EXPECT_GE(reader->ReadBit(), 0); +#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(OS_ANDROID) + EXPECT_DEATH(reader = absl::nullopt, ""); +#endif + EXPECT_GE(reader->RemainingBitCount(), 0); + reader = absl::nullopt; +} + +TEST(BitstreamReaderTest, ConsumeBits) { + const uint8_t bytes[32] = {}; + BitstreamReader reader(bytes); + + int total_bits = 32 * 8; + EXPECT_EQ(reader.RemainingBitCount(), total_bits); + reader.ConsumeBits(3); + total_bits -= 3; + EXPECT_EQ(reader.RemainingBitCount(), total_bits); + reader.ConsumeBits(3); + total_bits -= 3; + EXPECT_EQ(reader.RemainingBitCount(), total_bits); + reader.ConsumeBits(15); + total_bits -= 15; + EXPECT_EQ(reader.RemainingBitCount(), total_bits); + reader.ConsumeBits(67); + total_bits -= 67; + EXPECT_EQ(reader.RemainingBitCount(), total_bits); + EXPECT_TRUE(reader.Ok()); + + reader.ConsumeBits(32 * 8); + EXPECT_FALSE(reader.Ok()); + EXPECT_LT(reader.RemainingBitCount(), 0); +} + +TEST(BitstreamReaderTest, ConsumeLotsOfBits) { + const uint8_t bytes[1] = {}; + BitstreamReader reader(bytes); + + reader.ConsumeBits(std::numeric_limits<int>::max()); + reader.ConsumeBits(std::numeric_limits<int>::max()); + EXPECT_GE(reader.ReadBit(), 0); + EXPECT_FALSE(reader.Ok()); +} + +TEST(BitstreamReaderTest, ReadBit) { + const uint8_t bytes[] = {0b0100'0001, 0b1011'0001}; + BitstreamReader reader(bytes); + // First byte. + EXPECT_EQ(reader.ReadBit(), 0); + EXPECT_EQ(reader.ReadBit(), 1); + EXPECT_EQ(reader.ReadBit(), 0); + EXPECT_EQ(reader.ReadBit(), 0); + + EXPECT_EQ(reader.ReadBit(), 0); + EXPECT_EQ(reader.ReadBit(), 0); + EXPECT_EQ(reader.ReadBit(), 0); + EXPECT_EQ(reader.ReadBit(), 1); + + // Second byte. + EXPECT_EQ(reader.ReadBit(), 1); + EXPECT_EQ(reader.ReadBit(), 0); + EXPECT_EQ(reader.ReadBit(), 1); + EXPECT_EQ(reader.ReadBit(), 1); + + EXPECT_EQ(reader.ReadBit(), 0); + EXPECT_EQ(reader.ReadBit(), 0); + EXPECT_EQ(reader.ReadBit(), 0); + EXPECT_EQ(reader.ReadBit(), 1); + + EXPECT_TRUE(reader.Ok()); + // Try to read beyound the buffer. + EXPECT_EQ(reader.ReadBit(), 0); + EXPECT_FALSE(reader.Ok()); +} + +TEST(BitstreamReaderTest, ReadBoolConsumesSingleBit) { + const uint8_t bytes[] = {0b1010'1010}; + BitstreamReader reader(bytes); + ASSERT_EQ(reader.RemainingBitCount(), 8); + EXPECT_TRUE(reader.Read<bool>()); + EXPECT_EQ(reader.RemainingBitCount(), 7); +} + +TEST(BitstreamReaderTest, ReadBytesAligned) { + const uint8_t bytes[] = {0x0A, // + 0xBC, // + 0xDE, 0xF1, // + 0x23, 0x45, 0x67, 0x89}; + BitstreamReader reader(bytes); + EXPECT_EQ(reader.Read<uint8_t>(), 0x0Au); + EXPECT_EQ(reader.Read<uint8_t>(), 0xBCu); + EXPECT_EQ(reader.Read<uint16_t>(), 0xDEF1u); + EXPECT_EQ(reader.Read<uint32_t>(), 0x23456789u); + EXPECT_TRUE(reader.Ok()); +} + +TEST(BitstreamReaderTest, ReadBytesOffset4) { + const uint8_t bytes[] = {0x0A, 0xBC, 0xDE, 0xF1, 0x23, + 0x45, 0x67, 0x89, 0x0A}; + BitstreamReader reader(bytes); + reader.ConsumeBits(4); + + EXPECT_EQ(reader.Read<uint8_t>(), 0xABu); + EXPECT_EQ(reader.Read<uint8_t>(), 0xCDu); + EXPECT_EQ(reader.Read<uint16_t>(), 0xEF12u); + EXPECT_EQ(reader.Read<uint32_t>(), 0x34567890u); + EXPECT_TRUE(reader.Ok()); +} + +TEST(BitstreamReaderTest, ReadBytesOffset3) { + // The pattern we'll check against is counting down from 0b1111. It looks + // weird here because it's all offset by 3. + // Byte pattern is: + // 56701234 + // 0b00011111, + // 0b11011011, + // 0b10010111, + // 0b01010011, + // 0b00001110, + // 0b11001010, + // 0b10000110, + // 0b01000010 + // xxxxx <-- last 5 bits unused. + + // The bytes. It almost looks like counting down by two at a time, except the + // jump at 5->3->0, since that's when the high bit is turned off. + const uint8_t bytes[] = {0x1F, 0xDB, 0x97, 0x53, 0x0E, 0xCA, 0x86, 0x42}; + + BitstreamReader reader(bytes); + reader.ConsumeBits(3); + EXPECT_EQ(reader.Read<uint8_t>(), 0xFEu); + EXPECT_EQ(reader.Read<uint16_t>(), 0xDCBAu); + EXPECT_EQ(reader.Read<uint32_t>(), 0x98765432u); + EXPECT_TRUE(reader.Ok()); + + // 5 bits left unread. Not enough to read a uint8_t. + EXPECT_EQ(reader.RemainingBitCount(), 5); + EXPECT_EQ(reader.Read<uint8_t>(), 0); + EXPECT_FALSE(reader.Ok()); +} + +TEST(BitstreamReaderTest, ReadBits) { + const uint8_t bytes[] = {0b010'01'101, 0b0011'00'1'0}; + BitstreamReader reader(bytes); + EXPECT_EQ(reader.ReadBits(3), 0b010u); + EXPECT_EQ(reader.ReadBits(2), 0b01u); + EXPECT_EQ(reader.ReadBits(7), 0b101'0011u); + EXPECT_EQ(reader.ReadBits(2), 0b00u); + EXPECT_EQ(reader.ReadBits(1), 0b1u); + EXPECT_EQ(reader.ReadBits(1), 0b0u); + EXPECT_TRUE(reader.Ok()); + + EXPECT_EQ(reader.ReadBits(1), 0u); + EXPECT_FALSE(reader.Ok()); +} + +TEST(BitstreamReaderTest, ReadZeroBits) { + BitstreamReader reader(rtc::ArrayView<const uint8_t>(nullptr, 0)); + + EXPECT_EQ(reader.ReadBits(0), 0u); + EXPECT_TRUE(reader.Ok()); +} + +TEST(BitstreamReaderTest, ReadBitFromEmptyArray) { + BitstreamReader reader(rtc::ArrayView<const uint8_t>(nullptr, 0)); + + // Trying to read from the empty array shouldn't dereference the pointer, + // i.e. shouldn't crash. + EXPECT_EQ(reader.ReadBit(), 0); + EXPECT_FALSE(reader.Ok()); +} + +TEST(BitstreamReaderTest, ReadBitsFromEmptyArray) { + BitstreamReader reader(rtc::ArrayView<const uint8_t>(nullptr, 0)); + + // Trying to read from the empty array shouldn't dereference the pointer, + // i.e. shouldn't crash. + EXPECT_EQ(reader.ReadBits(1), 0u); + EXPECT_FALSE(reader.Ok()); +} + +TEST(BitstreamReaderTest, ReadBits64) { + const uint8_t bytes[] = {0x4D, 0x32, 0xAB, 0x54, 0x00, 0xFF, 0xFE, 0x01, + 0xAB, 0xCD, 0xEF, 0x01, 0x23, 0x45, 0x67, 0x89}; + BitstreamReader reader(bytes); + + EXPECT_EQ(reader.ReadBits(33), 0x4D32AB5400FFFE01u >> (64 - 33)); + + constexpr uint64_t kMask31Bits = (1ull << 32) - 1; + EXPECT_EQ(reader.ReadBits(31), 0x4D32AB5400FFFE01ull & kMask31Bits); + + EXPECT_EQ(reader.ReadBits(64), 0xABCDEF0123456789ull); + EXPECT_TRUE(reader.Ok()); + + // Nothing more to read. + EXPECT_EQ(reader.ReadBit(), 0); + EXPECT_FALSE(reader.Ok()); +} + +TEST(BitstreamReaderTest, CanPeekBitsUsingCopyConstructor) { + // BitstreamReader doesn't have peek function. To simulate it, user may use + // cheap BitstreamReader copy constructor. + const uint8_t bytes[] = {0x0A, 0xBC}; + BitstreamReader reader(bytes); + reader.ConsumeBits(4); + ASSERT_EQ(reader.RemainingBitCount(), 12); + + BitstreamReader peeker = reader; + EXPECT_EQ(peeker.ReadBits(8), 0xABu); + EXPECT_EQ(peeker.RemainingBitCount(), 4); + + EXPECT_EQ(reader.RemainingBitCount(), 12); + // Can resume reading from before peeker was created. + EXPECT_EQ(reader.ReadBits(4), 0xAu); + EXPECT_EQ(reader.RemainingBitCount(), 8); +} + +TEST(BitstreamReaderTest, + ReadNonSymmetricSameNumberOfBitsWhenNumValuesPowerOf2) { + const uint8_t bytes[2] = {0xf3, 0xa0}; + BitstreamReader reader(bytes); + + ASSERT_EQ(reader.RemainingBitCount(), 16); + EXPECT_EQ(reader.ReadNonSymmetric(/*num_values=*/1 << 4), 0xfu); + EXPECT_EQ(reader.ReadNonSymmetric(/*num_values=*/1 << 4), 0x3u); + EXPECT_EQ(reader.ReadNonSymmetric(/*num_values=*/1 << 4), 0xau); + EXPECT_EQ(reader.ReadNonSymmetric(/*num_values=*/1 << 4), 0x0u); + EXPECT_EQ(reader.RemainingBitCount(), 0); + EXPECT_TRUE(reader.Ok()); +} + +TEST(BitstreamReaderTest, ReadNonSymmetricOnlyValueConsumesZeroBits) { + const uint8_t bytes[2] = {}; + BitstreamReader reader(bytes); + + ASSERT_EQ(reader.RemainingBitCount(), 16); + EXPECT_EQ(reader.ReadNonSymmetric(/*num_values=*/1), 0u); + EXPECT_EQ(reader.RemainingBitCount(), 16); +} + +std::array<uint8_t, 8> GolombEncoded(uint32_t val) { + int val_width = absl::bit_width(val + 1); + int total_width = 2 * val_width - 1; + uint64_t representation = (uint64_t{val} + 1) << (64 - total_width); + std::array<uint8_t, 8> result; + for (int i = 0; i < 8; ++i) { + result[i] = representation >> (7 - i) * 8; + } + return result; +} + +TEST(BitstreamReaderTest, GolombUint32Values) { + // Test over the uint32_t range with a large enough step that the test doesn't + // take forever. Around 20,000 iterations should do. + const int kStep = std::numeric_limits<uint32_t>::max() / 20000; + for (uint32_t i = 0; i < std::numeric_limits<uint32_t>::max() - kStep; + i += kStep) { + std::array<uint8_t, 8> buffer = GolombEncoded(i); + BitstreamReader reader(buffer); + // Use assert instead of EXPECT to avoid spamming thousands of failed + // expectation when this test fails. + ASSERT_EQ(reader.ReadExponentialGolomb(), i); + EXPECT_TRUE(reader.Ok()); + } +} + +TEST(BitstreamReaderTest, SignedGolombValues) { + uint8_t golomb_bits[][1] = { + {0b1'0000000}, {0b010'00000}, {0b011'00000}, {0b00100'000}, {0b00111'000}, + }; + int expected[] = {0, 1, -1, 2, -3}; + for (size_t i = 0; i < sizeof(golomb_bits); ++i) { + BitstreamReader reader(golomb_bits[i]); + EXPECT_EQ(reader.ReadSignedExponentialGolomb(), expected[i]) + << "Mismatch in expected/decoded value for golomb_bits[" << i + << "]: " << static_cast<int>(golomb_bits[i][0]); + EXPECT_TRUE(reader.Ok()); + } +} + +TEST(BitstreamReaderTest, NoGolombOverread) { + const uint8_t bytes[] = {0x00, 0xFF, 0xFF}; + // Make sure the bit buffer correctly enforces byte length on golomb reads. + // If it didn't, the above buffer would be valid at 3 bytes. + BitstreamReader reader1(rtc::MakeArrayView(bytes, 1)); + // When parse fails, `ReadExponentialGolomb` may return any number. + reader1.ReadExponentialGolomb(); + EXPECT_FALSE(reader1.Ok()); + + BitstreamReader reader2(rtc::MakeArrayView(bytes, 2)); + reader2.ReadExponentialGolomb(); + EXPECT_FALSE(reader2.Ok()); + + BitstreamReader reader3(bytes); + // Golomb should have read 9 bits, so 0x01FF, and since it is golomb, the + // result is 0x01FF - 1 = 0x01FE. + EXPECT_EQ(reader3.ReadExponentialGolomb(), 0x01FEu); + EXPECT_TRUE(reader3.Ok()); +} + +TEST(BitstreamReaderTest, ReadLeb128) { + const uint8_t bytes[] = {0xFF, 0x7F}; + BitstreamReader reader(bytes); + EXPECT_EQ(reader.ReadLeb128(), 0x3FFFu); + EXPECT_TRUE(reader.Ok()); +} + +TEST(BitstreamReaderTest, ReadLeb128Large) { + const uint8_t max_uint64[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x1}; + BitstreamReader max_reader(max_uint64); + EXPECT_EQ(max_reader.ReadLeb128(), std::numeric_limits<uint64_t>::max()); + EXPECT_TRUE(max_reader.Ok()); + + const uint8_t overflow_unit64_t[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x2}; + BitstreamReader overflow_reader(overflow_unit64_t); + EXPECT_EQ(overflow_reader.ReadLeb128(), uint64_t{0}); + EXPECT_FALSE(overflow_reader.Ok()); +} + +TEST(BitstreamReaderTest, ReadLeb128NoEndByte) { + const uint8_t bytes[] = {0xFF, 0xFF}; + BitstreamReader reader(bytes); + EXPECT_EQ(reader.ReadLeb128(), uint64_t{0}); + EXPECT_FALSE(reader.Ok()); +} + +} // namespace +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/boringssl_certificate.cc b/third_party/libwebrtc/rtc_base/boringssl_certificate.cc new file mode 100644 index 0000000000..a866224496 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/boringssl_certificate.cc @@ -0,0 +1,412 @@ +/* + * 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. + */ + +#include "rtc_base/boringssl_certificate.h" + +#include "absl/strings/string_view.h" + +#if defined(WEBRTC_WIN) +// Must be included first before openssl headers. +#include "rtc_base/win32.h" // NOLINT +#endif // WEBRTC_WIN + +#include <openssl/asn1.h> +#include <openssl/bytestring.h> +#include <openssl/digest.h> +#include <openssl/evp.h> +#include <openssl/mem.h> +#include <openssl/pool.h> +#include <openssl/rand.h> +#include <time.h> + +#include <cstring> +#include <memory> +#include <utility> +#include <vector> + +#include "rtc_base/checks.h" +#include "rtc_base/helpers.h" +#include "rtc_base/logging.h" +#include "rtc_base/message_digest.h" +#include "rtc_base/openssl_digest.h" +#include "rtc_base/openssl_key_pair.h" +#include "rtc_base/openssl_utility.h" + +namespace rtc { +namespace { + +// List of OIDs of signature algorithms accepted by WebRTC. +// Taken from openssl/nid.h. +static const uint8_t kMD5WithRSA[] = {0x2b, 0x0e, 0x03, 0x02, 0x03}; +static const uint8_t kMD5WithRSAEncryption[] = {0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x04}; +static const uint8_t kECDSAWithSHA1[] = {0x2a, 0x86, 0x48, 0xce, + 0x3d, 0x04, 0x01}; +static const uint8_t kDSAWithSHA1[] = {0x2a, 0x86, 0x48, 0xce, + 0x38, 0x04, 0x03}; +static const uint8_t kDSAWithSHA1_2[] = {0x2b, 0x0e, 0x03, 0x02, 0x1b}; +static const uint8_t kSHA1WithRSA[] = {0x2b, 0x0e, 0x03, 0x02, 0x1d}; +static const uint8_t kSHA1WithRSAEncryption[] = {0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x05}; +static const uint8_t kECDSAWithSHA224[] = {0x2a, 0x86, 0x48, 0xce, + 0x3d, 0x04, 0x03, 0x01}; +static const uint8_t kSHA224WithRSAEncryption[] = {0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x0e}; +static const uint8_t kDSAWithSHA224[] = {0x60, 0x86, 0x48, 0x01, 0x65, + 0x03, 0x04, 0x03, 0x01}; +static const uint8_t kECDSAWithSHA256[] = {0x2a, 0x86, 0x48, 0xce, + 0x3d, 0x04, 0x03, 0x02}; +static const uint8_t kSHA256WithRSAEncryption[] = {0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x0b}; +static const uint8_t kDSAWithSHA256[] = {0x60, 0x86, 0x48, 0x01, 0x65, + 0x03, 0x04, 0x03, 0x02}; +static const uint8_t kECDSAWithSHA384[] = {0x2a, 0x86, 0x48, 0xce, + 0x3d, 0x04, 0x03, 0x03}; +static const uint8_t kSHA384WithRSAEncryption[] = {0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x0c}; +static const uint8_t kECDSAWithSHA512[] = {0x2a, 0x86, 0x48, 0xce, + 0x3d, 0x04, 0x03, 0x04}; +static const uint8_t kSHA512WithRSAEncryption[] = {0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x0d}; + +#if !defined(NDEBUG) +// Print a certificate to the log, for debugging. +static void PrintCert(BoringSSLCertificate* cert) { + // Since we're using CRYPTO_BUFFER, we can't use X509_print_ex, so we'll just + // print the PEM string. + RTC_DLOG(LS_VERBOSE) << "PEM representation of certificate:\n" + << cert->ToPEMString(); +} +#endif + +bool AddSHA256SignatureAlgorithm(CBB* cbb, KeyType key_type) { + // An AlgorithmIdentifier is described in RFC 5280, 4.1.1.2. + CBB sequence, oid, params; + if (!CBB_add_asn1(cbb, &sequence, CBS_ASN1_SEQUENCE) || + !CBB_add_asn1(&sequence, &oid, CBS_ASN1_OBJECT)) { + return false; + } + + switch (key_type) { + case KT_RSA: + if (!CBB_add_bytes(&oid, kSHA256WithRSAEncryption, + sizeof(kSHA256WithRSAEncryption)) || + !CBB_add_asn1(&sequence, ¶ms, CBS_ASN1_NULL)) { + return false; + } + break; + case KT_ECDSA: + if (!CBB_add_bytes(&oid, kECDSAWithSHA256, sizeof(kECDSAWithSHA256))) { + return false; + } + break; + default: + RTC_DCHECK_NOTREACHED(); + return false; + } + if (!CBB_flush(cbb)) { + return false; + } + return true; +} + +// Adds an X.509 Common Name to `cbb`. +bool AddCommonName(CBB* cbb, absl::string_view common_name) { + // See RFC 4519. + static const uint8_t kCommonName[] = {0x55, 0x04, 0x03}; + + if (common_name.empty()) { + RTC_LOG(LS_ERROR) << "Common name cannot be empty."; + return false; + } + + // See RFC 5280, section 4.1.2.4. + CBB rdns; + if (!CBB_add_asn1(cbb, &rdns, CBS_ASN1_SEQUENCE)) { + return false; + } + + CBB rdn, attr, type, value; + if (!CBB_add_asn1(&rdns, &rdn, CBS_ASN1_SET) || + !CBB_add_asn1(&rdn, &attr, CBS_ASN1_SEQUENCE) || + !CBB_add_asn1(&attr, &type, CBS_ASN1_OBJECT) || + !CBB_add_bytes(&type, kCommonName, sizeof(kCommonName)) || + !CBB_add_asn1(&attr, &value, CBS_ASN1_UTF8STRING) || + !CBB_add_bytes(&value, + reinterpret_cast<const uint8_t*>(common_name.data()), + common_name.size()) || + !CBB_flush(cbb)) { + return false; + } + + return true; +} + +bool AddTime(CBB* cbb, time_t time) { + bssl::UniquePtr<ASN1_TIME> asn1_time(ASN1_TIME_new()); + if (!asn1_time) { + return false; + } + + if (!ASN1_TIME_set(asn1_time.get(), time)) { + return false; + } + + unsigned tag; + switch (asn1_time->type) { + case V_ASN1_UTCTIME: + tag = CBS_ASN1_UTCTIME; + break; + case V_ASN1_GENERALIZEDTIME: + tag = CBS_ASN1_GENERALIZEDTIME; + break; + default: + return false; + } + + CBB child; + if (!CBB_add_asn1(cbb, &child, tag) || + !CBB_add_bytes(&child, asn1_time->data, asn1_time->length) || + !CBB_flush(cbb)) { + return false; + } + + return true; +} + +// Generate a self-signed certificate, with the public key from the +// given key pair. Caller is responsible for freeing the returned object. +static bssl::UniquePtr<CRYPTO_BUFFER> MakeCertificate( + EVP_PKEY* pkey, + const SSLIdentityParams& params) { + RTC_LOG(LS_INFO) << "Making certificate for " << params.common_name; + + // See RFC 5280, section 4.1. First, construct the TBSCertificate. + bssl::ScopedCBB cbb; + CBB tbs_cert, version, validity; + uint8_t* tbs_cert_bytes; + size_t tbs_cert_len; + uint64_t serial_number; + if (!CBB_init(cbb.get(), 64) || + !CBB_add_asn1(cbb.get(), &tbs_cert, CBS_ASN1_SEQUENCE) || + !CBB_add_asn1(&tbs_cert, &version, + CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0) || + !CBB_add_asn1_uint64(&version, 2) || + !RAND_bytes(reinterpret_cast<uint8_t*>(&serial_number), + sizeof(serial_number)) || + !CBB_add_asn1_uint64(&tbs_cert, serial_number) || + !AddSHA256SignatureAlgorithm(&tbs_cert, params.key_params.type()) || + !AddCommonName(&tbs_cert, params.common_name) || // issuer + !CBB_add_asn1(&tbs_cert, &validity, CBS_ASN1_SEQUENCE) || + !AddTime(&validity, params.not_before) || + !AddTime(&validity, params.not_after) || + !AddCommonName(&tbs_cert, params.common_name) || // subject + !EVP_marshal_public_key(&tbs_cert, pkey) || // subjectPublicKeyInfo + !CBB_finish(cbb.get(), &tbs_cert_bytes, &tbs_cert_len)) { + return nullptr; + } + + bssl::UniquePtr<uint8_t> delete_tbs_cert_bytes(tbs_cert_bytes); + + // Sign the TBSCertificate and write the entire certificate. + CBB cert, signature; + bssl::ScopedEVP_MD_CTX ctx; + uint8_t* sig_out; + size_t sig_len; + uint8_t* cert_bytes; + size_t cert_len; + if (!CBB_init(cbb.get(), tbs_cert_len) || + !CBB_add_asn1(cbb.get(), &cert, CBS_ASN1_SEQUENCE) || + !CBB_add_bytes(&cert, tbs_cert_bytes, tbs_cert_len) || + !AddSHA256SignatureAlgorithm(&cert, params.key_params.type()) || + !CBB_add_asn1(&cert, &signature, CBS_ASN1_BITSTRING) || + !CBB_add_u8(&signature, 0 /* no unused bits */) || + !EVP_DigestSignInit(ctx.get(), nullptr, EVP_sha256(), nullptr, pkey) || + // Compute the maximum signature length. + !EVP_DigestSign(ctx.get(), nullptr, &sig_len, tbs_cert_bytes, + tbs_cert_len) || + !CBB_reserve(&signature, &sig_out, sig_len) || + // Actually sign the TBSCertificate. + !EVP_DigestSign(ctx.get(), sig_out, &sig_len, tbs_cert_bytes, + tbs_cert_len) || + !CBB_did_write(&signature, sig_len) || + !CBB_finish(cbb.get(), &cert_bytes, &cert_len)) { + return nullptr; + } + bssl::UniquePtr<uint8_t> delete_cert_bytes(cert_bytes); + + RTC_LOG(LS_INFO) << "Returning certificate"; + return bssl::UniquePtr<CRYPTO_BUFFER>( + CRYPTO_BUFFER_new(cert_bytes, cert_len, openssl::GetBufferPool())); +} + +} // namespace + +BoringSSLCertificate::BoringSSLCertificate( + bssl::UniquePtr<CRYPTO_BUFFER> cert_buffer) + : cert_buffer_(std::move(cert_buffer)) { + RTC_DCHECK(cert_buffer_ != nullptr); +} + +std::unique_ptr<BoringSSLCertificate> BoringSSLCertificate::Generate( + OpenSSLKeyPair* key_pair, + const SSLIdentityParams& params) { + SSLIdentityParams actual_params(params); + if (actual_params.common_name.empty()) { + // Use a random string, arbitrarily 8 chars long. + actual_params.common_name = CreateRandomString(8); + } + bssl::UniquePtr<CRYPTO_BUFFER> cert_buffer = + MakeCertificate(key_pair->pkey(), actual_params); + if (!cert_buffer) { + openssl::LogSSLErrors("Generating certificate"); + return nullptr; + } + auto ret = std::make_unique<BoringSSLCertificate>(std::move(cert_buffer)); +#if !defined(NDEBUG) + PrintCert(ret.get()); +#endif + return ret; +} + +std::unique_ptr<BoringSSLCertificate> BoringSSLCertificate::FromPEMString( + absl::string_view pem_string) { + std::string der; + if (!SSLIdentity::PemToDer(kPemTypeCertificate, pem_string, &der)) { + return nullptr; + } + bssl::UniquePtr<CRYPTO_BUFFER> cert_buffer( + CRYPTO_BUFFER_new(reinterpret_cast<const uint8_t*>(der.c_str()), + der.length(), openssl::GetBufferPool())); + if (!cert_buffer) { + return nullptr; + } + return std::make_unique<BoringSSLCertificate>(std::move(cert_buffer)); +} + +#define OID_MATCHES(oid, oid_other) \ + (CBS_len(&oid) == sizeof(oid_other) && \ + 0 == memcmp(CBS_data(&oid), oid_other, sizeof(oid_other))) + +bool BoringSSLCertificate::GetSignatureDigestAlgorithm( + std::string* algorithm) const { + CBS oid; + if (!openssl::ParseCertificate(cert_buffer_.get(), &oid, nullptr)) { + RTC_LOG(LS_ERROR) << "Failed to parse certificate."; + return false; + } + if (OID_MATCHES(oid, kMD5WithRSA) || + OID_MATCHES(oid, kMD5WithRSAEncryption)) { + *algorithm = DIGEST_MD5; + return true; + } + if (OID_MATCHES(oid, kECDSAWithSHA1) || OID_MATCHES(oid, kDSAWithSHA1) || + OID_MATCHES(oid, kDSAWithSHA1_2) || OID_MATCHES(oid, kSHA1WithRSA) || + OID_MATCHES(oid, kSHA1WithRSAEncryption)) { + *algorithm = DIGEST_SHA_1; + return true; + } + if (OID_MATCHES(oid, kECDSAWithSHA224) || + OID_MATCHES(oid, kSHA224WithRSAEncryption) || + OID_MATCHES(oid, kDSAWithSHA224)) { + *algorithm = DIGEST_SHA_224; + return true; + } + if (OID_MATCHES(oid, kECDSAWithSHA256) || + OID_MATCHES(oid, kSHA256WithRSAEncryption) || + OID_MATCHES(oid, kDSAWithSHA256)) { + *algorithm = DIGEST_SHA_256; + return true; + } + if (OID_MATCHES(oid, kECDSAWithSHA384) || + OID_MATCHES(oid, kSHA384WithRSAEncryption)) { + *algorithm = DIGEST_SHA_384; + return true; + } + if (OID_MATCHES(oid, kECDSAWithSHA512) || + OID_MATCHES(oid, kSHA512WithRSAEncryption)) { + *algorithm = DIGEST_SHA_512; + return true; + } + // Unknown algorithm. There are several unhandled options that are less + // common and more complex. + RTC_LOG(LS_ERROR) << "Unknown signature algorithm."; + algorithm->clear(); + return false; +} + +bool BoringSSLCertificate::ComputeDigest(absl::string_view algorithm, + unsigned char* digest, + size_t size, + size_t* length) const { + return ComputeDigest(cert_buffer_.get(), algorithm, digest, size, length); +} + +bool BoringSSLCertificate::ComputeDigest(const CRYPTO_BUFFER* cert_buffer, + absl::string_view algorithm, + unsigned char* digest, + size_t size, + size_t* length) { + const EVP_MD* md = nullptr; + unsigned int n = 0; + if (!OpenSSLDigest::GetDigestEVP(algorithm, &md)) { + return false; + } + if (size < static_cast<size_t>(EVP_MD_size(md))) { + return false; + } + if (!EVP_Digest(CRYPTO_BUFFER_data(cert_buffer), + CRYPTO_BUFFER_len(cert_buffer), digest, &n, md, nullptr)) { + return false; + } + *length = n; + return true; +} + +BoringSSLCertificate::~BoringSSLCertificate() {} + +std::unique_ptr<SSLCertificate> BoringSSLCertificate::Clone() const { + return std::make_unique<BoringSSLCertificate>( + bssl::UpRef(cert_buffer_.get())); +} + +std::string BoringSSLCertificate::ToPEMString() const { + return SSLIdentity::DerToPem(kPemTypeCertificate, + CRYPTO_BUFFER_data(cert_buffer_.get()), + CRYPTO_BUFFER_len(cert_buffer_.get())); +} + +void BoringSSLCertificate::ToDER(Buffer* der_buffer) const { + der_buffer->SetData(CRYPTO_BUFFER_data(cert_buffer_.get()), + CRYPTO_BUFFER_len(cert_buffer_.get())); +} + +bool BoringSSLCertificate::operator==(const BoringSSLCertificate& other) const { + return CRYPTO_BUFFER_len(cert_buffer_.get()) == + CRYPTO_BUFFER_len(other.cert_buffer_.get()) && + 0 == memcmp(CRYPTO_BUFFER_data(cert_buffer_.get()), + CRYPTO_BUFFER_data(other.cert_buffer_.get()), + CRYPTO_BUFFER_len(cert_buffer_.get())); +} + +bool BoringSSLCertificate::operator!=(const BoringSSLCertificate& other) const { + return !(*this == other); +} + +int64_t BoringSSLCertificate::CertificateExpirationTime() const { + int64_t ret; + if (!openssl::ParseCertificate(cert_buffer_.get(), nullptr, &ret)) { + RTC_LOG(LS_ERROR) << "Failed to parse certificate."; + return -1; + } + return ret; +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/boringssl_certificate.h b/third_party/libwebrtc/rtc_base/boringssl_certificate.h new file mode 100644 index 0000000000..bd331686b7 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/boringssl_certificate.h @@ -0,0 +1,82 @@ +/* + * 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 RTC_BASE_BORINGSSL_CERTIFICATE_H_ +#define RTC_BASE_BORINGSSL_CERTIFICATE_H_ + +#include <openssl/ossl_typ.h> +#include <stddef.h> +#include <stdint.h> + +#include <memory> +#include <string> + +#include "absl/strings/string_view.h" +#include "rtc_base/buffer.h" +#include "rtc_base/ssl_certificate.h" +#include "rtc_base/ssl_identity.h" + +namespace rtc { + +class OpenSSLKeyPair; + +// BoringSSLCertificate encapsulates a BoringSSL CRYPTO_BUFFER object holding a +// certificate, which is also reference counted inside the BoringSSL library. +// This offers binary size and memory improvements over the OpenSSL X509 +// object. +class BoringSSLCertificate final : public SSLCertificate { + public: + explicit BoringSSLCertificate(bssl::UniquePtr<CRYPTO_BUFFER> cert_buffer); + + static std::unique_ptr<BoringSSLCertificate> Generate( + OpenSSLKeyPair* key_pair, + const SSLIdentityParams& params); + static std::unique_ptr<BoringSSLCertificate> FromPEMString( + absl::string_view pem_string); + + ~BoringSSLCertificate() override; + + BoringSSLCertificate(const BoringSSLCertificate&) = delete; + BoringSSLCertificate& operator=(const BoringSSLCertificate&) = delete; + + std::unique_ptr<SSLCertificate> Clone() const override; + + CRYPTO_BUFFER* cert_buffer() const { return cert_buffer_.get(); } + + std::string ToPEMString() const override; + void ToDER(Buffer* der_buffer) const override; + bool operator==(const BoringSSLCertificate& other) const; + bool operator!=(const BoringSSLCertificate& other) const; + + // Compute the digest of the certificate given `algorithm`. + bool ComputeDigest(absl::string_view algorithm, + unsigned char* digest, + size_t size, + size_t* length) const override; + + // Compute the digest of a certificate as a CRYPTO_BUFFER. + static bool ComputeDigest(const CRYPTO_BUFFER* cert_buffer, + absl::string_view algorithm, + unsigned char* digest, + size_t size, + size_t* length); + + bool GetSignatureDigestAlgorithm(std::string* algorithm) const override; + + int64_t CertificateExpirationTime() const override; + + private: + // A handle to the DER encoded certificate data. + bssl::UniquePtr<CRYPTO_BUFFER> cert_buffer_; +}; + +} // namespace rtc + +#endif // RTC_BASE_BORINGSSL_CERTIFICATE_H_ diff --git a/third_party/libwebrtc/rtc_base/boringssl_identity.cc b/third_party/libwebrtc/rtc_base/boringssl_identity.cc new file mode 100644 index 0000000000..a61524a679 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/boringssl_identity.cc @@ -0,0 +1,216 @@ +/* + * 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. + */ + +#include "rtc_base/boringssl_identity.h" + +#include <openssl/bio.h> +#include <openssl/err.h> +#include <openssl/pem.h> +#include <openssl/pool.h> +#include <stdint.h> +#include <string.h> + +#include <memory> +#include <utility> +#include <vector> + +#include "absl/memory/memory.h" +#include "absl/strings/string_view.h" +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" +#include "rtc_base/numerics/safe_conversions.h" +#include "rtc_base/openssl.h" +#include "rtc_base/openssl_utility.h" + +namespace rtc { + +BoringSSLIdentity::BoringSSLIdentity( + std::unique_ptr<OpenSSLKeyPair> key_pair, + std::unique_ptr<BoringSSLCertificate> certificate) + : key_pair_(std::move(key_pair)) { + RTC_DCHECK(key_pair_ != nullptr); + RTC_DCHECK(certificate != nullptr); + std::vector<std::unique_ptr<SSLCertificate>> certs; + certs.push_back(std::move(certificate)); + cert_chain_.reset(new SSLCertChain(std::move(certs))); +} + +BoringSSLIdentity::BoringSSLIdentity(std::unique_ptr<OpenSSLKeyPair> key_pair, + std::unique_ptr<SSLCertChain> cert_chain) + : key_pair_(std::move(key_pair)), cert_chain_(std::move(cert_chain)) { + RTC_DCHECK(key_pair_ != nullptr); + RTC_DCHECK(cert_chain_ != nullptr); +} + +BoringSSLIdentity::~BoringSSLIdentity() = default; + +std::unique_ptr<BoringSSLIdentity> BoringSSLIdentity::CreateInternal( + const SSLIdentityParams& params) { + auto key_pair = OpenSSLKeyPair::Generate(params.key_params); + if (key_pair) { + std::unique_ptr<BoringSSLCertificate> certificate( + BoringSSLCertificate::Generate(key_pair.get(), params)); + if (certificate != nullptr) { + return absl::WrapUnique( + new BoringSSLIdentity(std::move(key_pair), std::move(certificate))); + } + } + RTC_LOG(LS_ERROR) << "Identity generation failed."; + return nullptr; +} + +// static +std::unique_ptr<BoringSSLIdentity> BoringSSLIdentity::CreateWithExpiration( + absl::string_view common_name, + const KeyParams& key_params, + time_t certificate_lifetime) { + SSLIdentityParams params; + params.key_params = key_params; + params.common_name = std::string(common_name); + time_t now = time(nullptr); + params.not_before = now + kCertificateWindowInSeconds; + params.not_after = now + certificate_lifetime; + if (params.not_before > params.not_after) + return nullptr; + return CreateInternal(params); +} + +std::unique_ptr<BoringSSLIdentity> BoringSSLIdentity::CreateForTest( + const SSLIdentityParams& params) { + return CreateInternal(params); +} + +std::unique_ptr<SSLIdentity> BoringSSLIdentity::CreateFromPEMStrings( + absl::string_view private_key, + absl::string_view certificate) { + std::unique_ptr<BoringSSLCertificate> cert( + BoringSSLCertificate::FromPEMString(certificate)); + if (!cert) { + RTC_LOG(LS_ERROR) + << "Failed to create BoringSSLCertificate from PEM string."; + return nullptr; + } + + auto key_pair = OpenSSLKeyPair::FromPrivateKeyPEMString(private_key); + if (!key_pair) { + RTC_LOG(LS_ERROR) << "Failed to create key pair from PEM string."; + return nullptr; + } + + return absl::WrapUnique( + new BoringSSLIdentity(std::move(key_pair), std::move(cert))); +} + +std::unique_ptr<SSLIdentity> BoringSSLIdentity::CreateFromPEMChainStrings( + absl::string_view private_key, + absl::string_view certificate_chain) { + bssl::UniquePtr<BIO> bio( + BIO_new_mem_buf(certificate_chain.data(), + rtc::dchecked_cast<int>(certificate_chain.size()))); + if (!bio) { + return nullptr; + } + BIO_set_mem_eof_return(bio.get(), 0); + std::vector<std::unique_ptr<SSLCertificate>> certs; + while (true) { + char* name; + char* header; + unsigned char* data; + long len; // NOLINT + int ret = PEM_read_bio(bio.get(), &name, &header, &data, &len); + if (ret == 0) { + uint32_t err = ERR_peek_error(); + if (ERR_GET_LIB(err) == ERR_LIB_PEM && + ERR_GET_REASON(err) == PEM_R_NO_START_LINE) { + break; + } + RTC_LOG(LS_ERROR) << "Failed to parse certificate from PEM string."; + return nullptr; + } + bssl::UniquePtr<char> owned_name(name); + bssl::UniquePtr<char> owned_header(header); + bssl::UniquePtr<unsigned char> owned_data(data); + if (strcmp(owned_name.get(), PEM_STRING_X509) != 0) { + RTC_LOG(LS_ERROR) + << "Non-certificate found while parsing certificate chain: " + << owned_name.get(); + return nullptr; + } + bssl::UniquePtr<CRYPTO_BUFFER> crypto_buffer( + CRYPTO_BUFFER_new(data, len, openssl::GetBufferPool())); + if (!crypto_buffer) { + return nullptr; + } + certs.emplace_back(new BoringSSLCertificate(std::move(crypto_buffer))); + } + if (certs.empty()) { + RTC_LOG(LS_ERROR) << "Found no certificates in PEM string."; + return nullptr; + } + + auto key_pair = OpenSSLKeyPair::FromPrivateKeyPEMString(private_key); + if (!key_pair) { + RTC_LOG(LS_ERROR) << "Failed to create key pair from PEM string."; + return nullptr; + } + + return absl::WrapUnique(new BoringSSLIdentity( + std::move(key_pair), std::make_unique<SSLCertChain>(std::move(certs)))); +} + +const BoringSSLCertificate& BoringSSLIdentity::certificate() const { + return *static_cast<const BoringSSLCertificate*>(&cert_chain_->Get(0)); +} + +const SSLCertChain& BoringSSLIdentity::cert_chain() const { + return *cert_chain_.get(); +} + +std::unique_ptr<SSLIdentity> BoringSSLIdentity::CloneInternal() const { + // We cannot use std::make_unique here because the referenced + // BoringSSLIdentity constructor is private. + return absl::WrapUnique( + new BoringSSLIdentity(key_pair_->Clone(), cert_chain_->Clone())); +} + +bool BoringSSLIdentity::ConfigureIdentity(SSL_CTX* ctx) { + std::vector<CRYPTO_BUFFER*> cert_buffers; + for (size_t i = 0; i < cert_chain_->GetSize(); ++i) { + cert_buffers.push_back( + static_cast<const BoringSSLCertificate*>(&cert_chain_->Get(i)) + ->cert_buffer()); + } + // 1 is the documented success return code. + if (1 != SSL_CTX_set_chain_and_key(ctx, &cert_buffers[0], cert_buffers.size(), + key_pair_->pkey(), nullptr)) { + openssl::LogSSLErrors("Configuring key and certificate"); + return false; + } + return true; +} + +std::string BoringSSLIdentity::PrivateKeyToPEMString() const { + return key_pair_->PrivateKeyToPEMString(); +} + +std::string BoringSSLIdentity::PublicKeyToPEMString() const { + return key_pair_->PublicKeyToPEMString(); +} + +bool BoringSSLIdentity::operator==(const BoringSSLIdentity& other) const { + return *this->key_pair_ == *other.key_pair_ && + this->certificate() == other.certificate(); +} + +bool BoringSSLIdentity::operator!=(const BoringSSLIdentity& other) const { + return !(*this == other); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/boringssl_identity.h b/third_party/libwebrtc/rtc_base/boringssl_identity.h new file mode 100644 index 0000000000..ffc8812af2 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/boringssl_identity.h @@ -0,0 +1,77 @@ +/* + * 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 RTC_BASE_BORINGSSL_IDENTITY_H_ +#define RTC_BASE_BORINGSSL_IDENTITY_H_ + +#include <openssl/ossl_typ.h> + +#include <ctime> +#include <memory> +#include <string> + +#include "absl/strings/string_view.h" +#include "rtc_base/boringssl_certificate.h" +#include "rtc_base/openssl_key_pair.h" +#include "rtc_base/ssl_certificate.h" +#include "rtc_base/ssl_identity.h" + +namespace rtc { + +// Holds a keypair and certificate together, and a method to generate them +// consistently. Uses CRYPTO_BUFFER instead of X509, which offers binary size +// and memory improvements. +class BoringSSLIdentity final : public SSLIdentity { + public: + static std::unique_ptr<BoringSSLIdentity> CreateWithExpiration( + absl::string_view common_name, + const KeyParams& key_params, + time_t certificate_lifetime); + static std::unique_ptr<BoringSSLIdentity> CreateForTest( + const SSLIdentityParams& params); + static std::unique_ptr<SSLIdentity> CreateFromPEMStrings( + absl::string_view private_key, + absl::string_view certificate); + static std::unique_ptr<SSLIdentity> CreateFromPEMChainStrings( + absl::string_view private_key, + absl::string_view certificate_chain); + ~BoringSSLIdentity() override; + + BoringSSLIdentity(const BoringSSLIdentity&) = delete; + BoringSSLIdentity& operator=(const BoringSSLIdentity&) = delete; + + const BoringSSLCertificate& certificate() const override; + const SSLCertChain& cert_chain() const override; + + // Configure an SSL context object to use our key and certificate. + bool ConfigureIdentity(SSL_CTX* ctx); + + std::string PrivateKeyToPEMString() const override; + std::string PublicKeyToPEMString() const override; + bool operator==(const BoringSSLIdentity& other) const; + bool operator!=(const BoringSSLIdentity& other) const; + + private: + BoringSSLIdentity(std::unique_ptr<OpenSSLKeyPair> key_pair, + std::unique_ptr<BoringSSLCertificate> certificate); + BoringSSLIdentity(std::unique_ptr<OpenSSLKeyPair> key_pair, + std::unique_ptr<SSLCertChain> cert_chain); + std::unique_ptr<SSLIdentity> CloneInternal() const override; + + static std::unique_ptr<BoringSSLIdentity> CreateInternal( + const SSLIdentityParams& params); + + std::unique_ptr<OpenSSLKeyPair> key_pair_; + std::unique_ptr<SSLCertChain> cert_chain_; +}; + +} // namespace rtc + +#endif // RTC_BASE_BORINGSSL_IDENTITY_H_ diff --git a/third_party/libwebrtc/rtc_base/bounded_inline_vector.h b/third_party/libwebrtc/rtc_base/bounded_inline_vector.h new file mode 100644 index 0000000000..f8b7eb3d86 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/bounded_inline_vector.h @@ -0,0 +1,155 @@ +/* + * 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 RTC_BASE_BOUNDED_INLINE_VECTOR_H_ +#define RTC_BASE_BOUNDED_INLINE_VECTOR_H_ + +#include <stdint.h> + +#include <memory> +#include <type_traits> +#include <utility> + +#include "rtc_base/bounded_inline_vector_impl.h" +#include "rtc_base/checks.h" + +namespace webrtc { + +// A small std::vector-like type whose capacity is a compile-time constant. It +// stores all data inline and never heap allocates (beyond what its element type +// requires). Trying to grow it beyond its constant capacity is an error. +// +// TODO(bugs.webrtc.org/11391): Comparison operators. +// TODO(bugs.webrtc.org/11391): Methods for adding and deleting elements. +template <typename T, int fixed_capacity> +class BoundedInlineVector { + static_assert(!std::is_const<T>::value, "T may not be const"); + static_assert(fixed_capacity > 0, "Capacity must be strictly positive"); + + public: + using size_type = int; + using value_type = T; + using const_iterator = const T*; + + BoundedInlineVector() = default; + BoundedInlineVector(const BoundedInlineVector&) = default; + BoundedInlineVector(BoundedInlineVector&&) = default; + BoundedInlineVector& operator=(const BoundedInlineVector&) = default; + BoundedInlineVector& operator=(BoundedInlineVector&&) = default; + ~BoundedInlineVector() = default; + + // This constructor is implicit, to make it possible to write e.g. + // + // BoundedInlineVector<double, 7> x = {2.72, 3.14}; + // + // and + // + // BoundedInlineVector<double, 7> GetConstants() { + // return {2.72, 3.14}; + // } + template <typename... Ts, + typename std::enable_if_t< + bounded_inline_vector_impl::AllConvertible<T, Ts...>::value>* = + nullptr> + BoundedInlineVector(Ts&&... elements) // NOLINT(runtime/explicit) + : storage_(std::forward<Ts>(elements)...) { + static_assert(sizeof...(Ts) <= fixed_capacity, ""); + } + + template < + int other_capacity, + typename std::enable_if_t<other_capacity != fixed_capacity>* = nullptr> + BoundedInlineVector(const BoundedInlineVector<T, other_capacity>& other) { + RTC_DCHECK_LE(other.size(), fixed_capacity); + bounded_inline_vector_impl::CopyElements(other.data(), other.size(), + storage_.data, &storage_.size); + } + + template < + int other_capacity, + typename std::enable_if_t<other_capacity != fixed_capacity>* = nullptr> + BoundedInlineVector(BoundedInlineVector<T, other_capacity>&& other) { + RTC_DCHECK_LE(other.size(), fixed_capacity); + bounded_inline_vector_impl::MoveElements(other.data(), other.size(), + storage_.data, &storage_.size); + } + + template < + int other_capacity, + typename std::enable_if_t<other_capacity != fixed_capacity>* = nullptr> + BoundedInlineVector& operator=( + const BoundedInlineVector<T, other_capacity>& other) { + bounded_inline_vector_impl::DestroyElements(storage_.data, storage_.size); + RTC_DCHECK_LE(other.size(), fixed_capacity); + bounded_inline_vector_impl::CopyElements(other.data(), other.size(), + storage_.data, &storage_.size); + return *this; + } + + template < + int other_capacity, + typename std::enable_if_t<other_capacity != fixed_capacity>* = nullptr> + BoundedInlineVector& operator=( + BoundedInlineVector<T, other_capacity>&& other) { + bounded_inline_vector_impl::DestroyElements(storage_.data, storage_.size); + RTC_DCHECK_LE(other.size(), fixed_capacity); + bounded_inline_vector_impl::MoveElements(other.data(), other.size(), + storage_.data, &storage_.size); + return *this; + } + + bool empty() const { return storage_.size == 0; } + int size() const { return storage_.size; } + constexpr int capacity() const { return fixed_capacity; } + + // Resizes the BoundedInlineVector to the given size, which must not exceed + // its constant capacity. If the size is increased, the added elements are + // default constructed. + void resize(int new_size) { + RTC_DCHECK_GE(new_size, 0); + RTC_DCHECK_LE(new_size, fixed_capacity); + if (new_size > storage_.size) { + bounded_inline_vector_impl::DefaultInitializeElements( + storage_.data + storage_.size, new_size - storage_.size); + } else if (new_size < storage_.size) { + bounded_inline_vector_impl::DestroyElements(storage_.data + new_size, + storage_.size - new_size); + } + storage_.size = new_size; + } + + const T* data() const { return storage_.data; } + T* data() { return storage_.data; } + + const T& operator[](int index) const { + RTC_DCHECK_GE(index, 0); + RTC_DCHECK_LT(index, storage_.size); + return storage_.data[index]; + } + T& operator[](int index) { + RTC_DCHECK_GE(index, 0); + RTC_DCHECK_LT(index, storage_.size); + return storage_.data[index]; + } + + T* begin() { return storage_.data; } + T* end() { return storage_.data + storage_.size; } + const T* begin() const { return storage_.data; } + const T* end() const { return storage_.data + storage_.size; } + const T* cbegin() const { return storage_.data; } + const T* cend() const { return storage_.data + storage_.size; } + + private: + bounded_inline_vector_impl::Storage<T, fixed_capacity> storage_; +}; + +} // namespace webrtc + +#endif // RTC_BASE_BOUNDED_INLINE_VECTOR_H_ diff --git a/third_party/libwebrtc/rtc_base/bounded_inline_vector_impl.h b/third_party/libwebrtc/rtc_base/bounded_inline_vector_impl.h new file mode 100644 index 0000000000..3539ace5bc --- /dev/null +++ b/third_party/libwebrtc/rtc_base/bounded_inline_vector_impl.h @@ -0,0 +1,225 @@ +/* + * 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 RTC_BASE_BOUNDED_INLINE_VECTOR_IMPL_H_ +#define RTC_BASE_BOUNDED_INLINE_VECTOR_IMPL_H_ + +#include <stdint.h> + +#include <cstring> +#include <memory> +#include <type_traits> +#include <utility> + +namespace webrtc { +namespace bounded_inline_vector_impl { + +template <bool...> +struct BoolPack; + +// Tests if all its parameters (x0, x1, ..., xn) are true. The implementation +// checks whether (x0, x1, ..., xn, true) == (true, x0, x1, ..., xn), which is +// true iff true == x0 && x0 == x1 && x1 == x2 ... && xn-1 == xn && xn == true. +template <bool... Bs> +using AllTrue = std::is_same<BoolPack<Bs..., true>, BoolPack<true, Bs...>>; + +template <typename To, typename... Froms> +using AllConvertible = AllTrue<std::is_convertible<Froms, To>::value...>; + +// Initializes part of an uninitialized array. Unlike normal array +// initialization, does not zero the remaining array elements. Caller is +// responsible for ensuring that there is enough space in `data`. +template <typename T> +void InitializeElements(T* data) {} +template <typename T, typename U, typename... Us> +void InitializeElements(T* data, U&& element, Us&&... elements) { + // Placement new, because we construct a new object in uninitialized memory. + ::new (data) T(std::forward<U>(element)); + InitializeElements(data + 1, std::forward<Us>(elements)...); +} + +// Default initializes uninitialized array elements. +// TODO(kwiberg): Replace with std::uninitialized_default_construct_n() (C++17). +template <typename T> +void DefaultInitializeElements(T* data, int size) { + for (int i = 0; i < size; ++i) { + // Placement new, because we construct a new object in uninitialized memory. + ::new (&data[i]) T; + } +} + +// Copies from source to uninitialized destination. Caller is responsible for +// ensuring that there is enough space in `dst_data`. +template <typename T> +void CopyElements(const T* src_data, int src_size, T* dst_data, int* dst_size) { + if /*constexpr*/ (std::is_trivially_copy_constructible<T>::value) { + std::memcpy(dst_data, src_data, src_size * sizeof(T)); + } else { + std::uninitialized_copy_n(src_data, src_size, dst_data); + } + *dst_size = src_size; +} + +// Moves from source to uninitialized destination. Caller is responsible for +// ensuring that there is enough space in `dst_data`. +template <typename T> +void MoveElements(T* src_data, int src_size, T* dst_data, int* dst_size) { + if /*constexpr*/ (std::is_trivially_move_constructible<T>::value) { + std::memcpy(dst_data, src_data, src_size * sizeof(T)); + } else { + // TODO(kwiberg): Use std::uninitialized_move_n() instead (C++17). + for (int i = 0; i < src_size; ++i) { + // Placement new, because we create a new object in uninitialized + // memory. + ::new (&dst_data[i]) T(std::move(src_data[i])); + } + } + *dst_size = src_size; +} + +// Destroys elements, leaving them uninitialized. +template <typename T> +void DestroyElements(T* data, int size) { + if /*constexpr*/ (!std::is_trivially_destructible<T>::value) { + for (int i = 0; i < size; ++i) { + data[i].~T(); + } + } +} + +// If elements are trivial and the total capacity is at most this many bytes, +// copy everything instead of just the elements that are in use; this is more +// efficient, and makes BoundedInlineVector trivially copyable. +static constexpr int kSmallSize = 64; + +// Storage implementations. +// +// There are diferent Storage structs for diferent kinds of element types. The +// common contract is the following: +// +// * They have public `size` variables and `data` array members. +// +// * Their owner is responsible for enforcing the invariant that the first +// `size` elements in `data` are initialized, and the remaining elements are +// not initialized. +// +// * They implement default construction, construction with one or more +// elements, copy/move construction, copy/move assignment, and destruction; +// the owner must ensure that the invariant holds whenever these operations +// occur. + +// Storage implementation for nontrivial element types. +template <typename T, + int fixed_capacity, + bool is_trivial = std::is_trivial<T>::value, + bool is_small = (sizeof(T) * fixed_capacity <= kSmallSize)> +struct Storage { + static_assert(!std::is_trivial<T>::value, ""); + + template < + typename... Ts, + typename std::enable_if_t<AllConvertible<T, Ts...>::value>* = nullptr> + explicit Storage(Ts&&... elements) : size(sizeof...(Ts)) { + InitializeElements(data, std::forward<Ts>(elements)...); + } + + Storage(const Storage& other) { + CopyElements(other.data, other.size, data, &size); + } + + Storage(Storage&& other) { + MoveElements(other.data, other.size, data, &size); + } + + Storage& operator=(const Storage& other) { + if (this != &other) { + DestroyElements(data, size); + CopyElements(other.data, other.size, data, &size); + } + return *this; + } + + Storage& operator=(Storage&& other) { + DestroyElements(data, size); + size = 0; // Needed in case of self assignment. + MoveElements(other.data, other.size, data, &size); + return *this; + } + + ~Storage() { DestroyElements(data, size); } + + int size; + union { + // Since this array is in a union, we get to construct and destroy it + // manually. + T data[fixed_capacity]; // NOLINT(runtime/arrays) + }; +}; + +// Storage implementation for trivial element types when the capacity is small +// enough that we can cheaply copy everything. +template <typename T, int fixed_capacity> +struct Storage<T, fixed_capacity, /*is_trivial=*/true, /*is_small=*/true> { + static_assert(std::is_trivial<T>::value, ""); + static_assert(sizeof(T) * fixed_capacity <= kSmallSize, ""); + + template < + typename... Ts, + typename std::enable_if_t<AllConvertible<T, Ts...>::value>* = nullptr> + explicit Storage(Ts&&... elements) : size(sizeof...(Ts)) { + InitializeElements(data, std::forward<Ts>(elements)...); + } + + Storage(const Storage&) = default; + Storage& operator=(const Storage&) = default; + ~Storage() = default; + + int size; + T data[fixed_capacity]; // NOLINT(runtime/arrays) +}; + +// Storage implementation for trivial element types when the capacity is large +// enough that we want to avoid copying uninitialized elements. +template <typename T, int fixed_capacity> +struct Storage<T, fixed_capacity, /*is_trivial=*/true, /*is_small=*/false> { + static_assert(std::is_trivial<T>::value, ""); + static_assert(sizeof(T) * fixed_capacity > kSmallSize, ""); + + template < + typename... Ts, + typename std::enable_if_t<AllConvertible<T, Ts...>::value>* = nullptr> + explicit Storage(Ts&&... elements) : size(sizeof...(Ts)) { + InitializeElements(data, std::forward<Ts>(elements)...); + } + + Storage(const Storage& other) : size(other.size) { + std::memcpy(data, other.data, other.size * sizeof(T)); + } + + Storage& operator=(const Storage& other) { + if (this != &other) { + size = other.size; + std::memcpy(data, other.data, other.size * sizeof(T)); + } + return *this; + } + + ~Storage() = default; + + int size; + union { + T data[fixed_capacity]; // NOLINT(runtime/arrays) + }; +}; + +} // namespace bounded_inline_vector_impl +} // namespace webrtc + +#endif // RTC_BASE_BOUNDED_INLINE_VECTOR_IMPL_H_ diff --git a/third_party/libwebrtc/rtc_base/bounded_inline_vector_unittest.cc b/third_party/libwebrtc/rtc_base/bounded_inline_vector_unittest.cc new file mode 100644 index 0000000000..50cf2e3153 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/bounded_inline_vector_unittest.cc @@ -0,0 +1,133 @@ +/* + * 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. + */ + +#include "rtc_base/bounded_inline_vector.h" + +#include <memory> +#include <string> +#include <utility> + +#include "test/gmock.h" +#include "test/gtest.h" + +namespace webrtc { +namespace { + +using SmallTrivial = BoundedInlineVector<int, 2>; +using LargeTrivial = BoundedInlineVector<int, 200>; +using NonTrivial = BoundedInlineVector<std::string, 2>; +static_assert(std::is_trivially_copyable<SmallTrivial>::value, ""); +static_assert(!std::is_trivially_copyable<LargeTrivial>::value, ""); +static_assert(std::is_trivially_destructible<LargeTrivial>::value, ""); +static_assert(!std::is_trivially_copyable<NonTrivial>::value, ""); +static_assert(!std::is_trivially_destructible<NonTrivial>::value, ""); + +template <typename T> +class BoundedInlineVectorTestAllTypes : public ::testing::Test {}; + +using AllTypes = + ::testing::Types<int, // Scalar type. + std::pair<int, float>, // Trivial nonprimitive type. + std::unique_ptr<int>, // Move-only type. + std::string>; // Nontrivial copyable type. +TYPED_TEST_SUITE(BoundedInlineVectorTestAllTypes, AllTypes); + +template <typename T> +class BoundedInlineVectorTestCopyableTypes : public ::testing::Test {}; + +using CopyableTypes = ::testing::Types<int, std::pair<int, float>, std::string>; +TYPED_TEST_SUITE(BoundedInlineVectorTestCopyableTypes, CopyableTypes); + +TYPED_TEST(BoundedInlineVectorTestAllTypes, ConstructEmpty) { + BoundedInlineVector<TypeParam, 3> x; + EXPECT_EQ(x.size(), 0); + EXPECT_EQ(x.begin(), x.end()); + static_assert(x.capacity() == 3, ""); +} + +TYPED_TEST(BoundedInlineVectorTestAllTypes, ConstructNonempty) { + BoundedInlineVector<TypeParam, 3> x = {TypeParam(), TypeParam()}; + EXPECT_EQ(x.size(), 2); + static_assert(x.capacity() == 3, ""); +} + +TYPED_TEST(BoundedInlineVectorTestCopyableTypes, CopyConstruct) { + BoundedInlineVector<TypeParam, 3> x = {TypeParam(), TypeParam()}; + BoundedInlineVector<TypeParam, 2> y = x; + EXPECT_EQ(y.size(), 2); + static_assert(x.capacity() == 3, ""); + static_assert(y.capacity() == 2, ""); +} + +TYPED_TEST(BoundedInlineVectorTestCopyableTypes, CopyAssign) { + BoundedInlineVector<TypeParam, 3> x = {TypeParam(), TypeParam()}; + BoundedInlineVector<TypeParam, 2> y; + EXPECT_EQ(y.size(), 0); + y = x; + EXPECT_EQ(y.size(), 2); +} + +TYPED_TEST(BoundedInlineVectorTestAllTypes, MoveConstruct) { + BoundedInlineVector<TypeParam, 3> x = {TypeParam(), TypeParam()}; + BoundedInlineVector<TypeParam, 2> y = std::move(x); + EXPECT_EQ(y.size(), 2); + static_assert(x.capacity() == 3, ""); + static_assert(y.capacity() == 2, ""); +} + +TYPED_TEST(BoundedInlineVectorTestAllTypes, MoveAssign) { + BoundedInlineVector<TypeParam, 3> x = {TypeParam(), TypeParam()}; + BoundedInlineVector<TypeParam, 2> y; + EXPECT_EQ(y.size(), 0); + y = std::move(x); + EXPECT_EQ(y.size(), 2); +} + +TEST(BoundedInlineVectorTestOneType, Iteration) { + BoundedInlineVector<std::string, 4> sv{"one", "two", "three", "four"}; + std::string cat; + for (const auto& s : sv) { + cat += s; + } + EXPECT_EQ(cat, "onetwothreefour"); +} + +TEST(BoundedInlineVectorTestOneType, Indexing) { + BoundedInlineVector<double, 1> x = {3.14}; + EXPECT_EQ(x[0], 3.14); +} + +template <typename T, int capacity, typename... Ts> +BoundedInlineVector<T, capacity> Returns(Ts... values) { + return {std::forward<Ts>(values)...}; +} + +TYPED_TEST(BoundedInlineVectorTestAllTypes, Return) { + EXPECT_EQ((Returns<TypeParam, 3>().size()), 0); + EXPECT_EQ((Returns<TypeParam, 3>(TypeParam(), TypeParam()).size()), 2); +} + +TYPED_TEST(BoundedInlineVectorTestAllTypes, Resize) { + BoundedInlineVector<TypeParam, 17> x; + EXPECT_EQ(x.size(), 0); + x.resize(17); + EXPECT_EQ(x.size(), 17); + // Test one arbitrary element, mostly to give MSan a chance to scream. But if + // the type has a trivial default constructor we can't, because the element + // won't be initialized. + if (!std::is_trivially_default_constructible<TypeParam>::value) { + EXPECT_EQ(x[4], TypeParam()); + } + x.resize(2); + EXPECT_EQ(x.size(), 2); +} + +} // namespace +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/buffer.h b/third_party/libwebrtc/rtc_base/buffer.h new file mode 100644 index 0000000000..6663c687b8 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/buffer.h @@ -0,0 +1,452 @@ +/* + * 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 RTC_BASE_BUFFER_H_ +#define RTC_BASE_BUFFER_H_ + +#include <stdint.h> + +#include <algorithm> +#include <cstring> +#include <memory> +#include <type_traits> +#include <utility> + +#include "absl/strings/string_view.h" +#include "api/array_view.h" +#include "rtc_base/checks.h" +#include "rtc_base/type_traits.h" +#include "rtc_base/zero_memory.h" + +namespace rtc { + +namespace internal { + +// (Internal; please don't use outside this file.) Determines if elements of +// type U are compatible with a BufferT<T>. For most types, we just ignore +// top-level const and forbid top-level volatile and require T and U to be +// otherwise equal, but all byte-sized integers (notably char, int8_t, and +// uint8_t) are compatible with each other. (Note: We aim to get rid of this +// behavior, and treat all types the same.) +template <typename T, typename U> +struct BufferCompat { + static constexpr bool value = + !std::is_volatile<U>::value && + ((std::is_integral<T>::value && sizeof(T) == 1) + ? (std::is_integral<U>::value && sizeof(U) == 1) + : (std::is_same<T, typename std::remove_const<U>::type>::value)); +}; + +} // namespace internal + +// Basic buffer class, can be grown and shrunk dynamically. +// Unlike std::string/vector, does not initialize data when increasing size. +// If "ZeroOnFree" is true, any memory is explicitly cleared before releasing. +// The type alias "ZeroOnFreeBuffer" below should be used instead of setting +// "ZeroOnFree" in the template manually to "true". +template <typename T, bool ZeroOnFree = false> +class BufferT { + // We want T's destructor and default constructor to be trivial, i.e. perform + // no action, so that we don't have to touch the memory we allocate and + // deallocate. And we want T to be trivially copyable, so that we can copy T + // instances with std::memcpy. This is precisely the definition of a trivial + // type. + static_assert(std::is_trivial<T>::value, "T must be a trivial type."); + + // This class relies heavily on being able to mutate its data. + static_assert(!std::is_const<T>::value, "T may not be const"); + + public: + using value_type = T; + using const_iterator = const T*; + + // An empty BufferT. + BufferT() : size_(0), capacity_(0), data_(nullptr) { + RTC_DCHECK(IsConsistent()); + } + + // Disable copy construction and copy assignment, since copying a buffer is + // expensive enough that we want to force the user to be explicit about it. + BufferT(const BufferT&) = delete; + BufferT& operator=(const BufferT&) = delete; + + BufferT(BufferT&& buf) + : size_(buf.size()), + capacity_(buf.capacity()), + data_(std::move(buf.data_)) { + RTC_DCHECK(IsConsistent()); + buf.OnMovedFrom(); + } + + // Construct a buffer with the specified number of uninitialized elements. + explicit BufferT(size_t size) : BufferT(size, size) {} + + BufferT(size_t size, size_t capacity) + : size_(size), + capacity_(std::max(size, capacity)), + data_(capacity_ > 0 ? new T[capacity_] : nullptr) { + RTC_DCHECK(IsConsistent()); + } + + // Construct a buffer and copy the specified number of elements into it. + template <typename U, + typename std::enable_if< + internal::BufferCompat<T, U>::value>::type* = nullptr> + BufferT(const U* data, size_t size) : BufferT(data, size, size) {} + + template <typename U, + typename std::enable_if< + internal::BufferCompat<T, U>::value>::type* = nullptr> + BufferT(U* data, size_t size, size_t capacity) : BufferT(size, capacity) { + static_assert(sizeof(T) == sizeof(U), ""); + if (size > 0) { + RTC_DCHECK(data); + std::memcpy(data_.get(), data, size * sizeof(U)); + } + } + + // Construct a buffer from the contents of an array. + template <typename U, + size_t N, + typename std::enable_if< + internal::BufferCompat<T, U>::value>::type* = nullptr> + BufferT(U (&array)[N]) : BufferT(array, N) {} + + ~BufferT() { MaybeZeroCompleteBuffer(); } + + // Implicit conversion to absl::string_view if T is compatible with char. + template <typename U = T> + operator typename std::enable_if<internal::BufferCompat<U, char>::value, + absl::string_view>::type() const { + return absl::string_view(data<char>(), size()); + } + + // Get a pointer to the data. Just .data() will give you a (const) T*, but if + // T is a byte-sized integer, you may also use .data<U>() for any other + // byte-sized integer U. + template <typename U = T, + typename std::enable_if< + internal::BufferCompat<T, U>::value>::type* = nullptr> + const U* data() const { + RTC_DCHECK(IsConsistent()); + return reinterpret_cast<U*>(data_.get()); + } + + template <typename U = T, + typename std::enable_if< + internal::BufferCompat<T, U>::value>::type* = nullptr> + U* data() { + RTC_DCHECK(IsConsistent()); + return reinterpret_cast<U*>(data_.get()); + } + + bool empty() const { + RTC_DCHECK(IsConsistent()); + return size_ == 0; + } + + size_t size() const { + RTC_DCHECK(IsConsistent()); + return size_; + } + + size_t capacity() const { + RTC_DCHECK(IsConsistent()); + return capacity_; + } + + BufferT& operator=(BufferT&& buf) { + RTC_DCHECK(buf.IsConsistent()); + MaybeZeroCompleteBuffer(); + size_ = buf.size_; + capacity_ = buf.capacity_; + using std::swap; + swap(data_, buf.data_); + buf.data_.reset(); + buf.OnMovedFrom(); + return *this; + } + + bool operator==(const BufferT& buf) const { + RTC_DCHECK(IsConsistent()); + if (size_ != buf.size_) { + return false; + } + if (std::is_integral<T>::value) { + // Optimization. + return std::memcmp(data_.get(), buf.data_.get(), size_ * sizeof(T)) == 0; + } + for (size_t i = 0; i < size_; ++i) { + if (data_[i] != buf.data_[i]) { + return false; + } + } + return true; + } + + bool operator!=(const BufferT& buf) const { return !(*this == buf); } + + T& operator[](size_t index) { + RTC_DCHECK_LT(index, size_); + return data()[index]; + } + + T operator[](size_t index) const { + RTC_DCHECK_LT(index, size_); + return data()[index]; + } + + T* begin() { return data(); } + T* end() { return data() + size(); } + const T* begin() const { return data(); } + const T* end() const { return data() + size(); } + const T* cbegin() const { return data(); } + const T* cend() const { return data() + size(); } + + // The SetData functions replace the contents of the buffer. They accept the + // same input types as the constructors. + template <typename U, + typename std::enable_if< + internal::BufferCompat<T, U>::value>::type* = nullptr> + void SetData(const U* data, size_t size) { + RTC_DCHECK(IsConsistent()); + const size_t old_size = size_; + size_ = 0; + AppendData(data, size); + if (ZeroOnFree && size_ < old_size) { + ZeroTrailingData(old_size - size_); + } + } + + template <typename U, + size_t N, + typename std::enable_if< + internal::BufferCompat<T, U>::value>::type* = nullptr> + void SetData(const U (&array)[N]) { + SetData(array, N); + } + + template <typename W, + typename std::enable_if< + HasDataAndSize<const W, const T>::value>::type* = nullptr> + void SetData(const W& w) { + SetData(w.data(), w.size()); + } + + // Replaces the data in the buffer with at most `max_elements` of data, using + // the function `setter`, which should have the following signature: + // + // size_t setter(ArrayView<U> view) + // + // `setter` is given an appropriately typed ArrayView of length exactly + // `max_elements` that describes the area where it should write the data; it + // should return the number of elements actually written. (If it doesn't fill + // the whole ArrayView, it should leave the unused space at the end.) + template <typename U = T, + typename F, + typename std::enable_if< + internal::BufferCompat<T, U>::value>::type* = nullptr> + size_t SetData(size_t max_elements, F&& setter) { + RTC_DCHECK(IsConsistent()); + const size_t old_size = size_; + size_ = 0; + const size_t written = AppendData<U>(max_elements, std::forward<F>(setter)); + if (ZeroOnFree && size_ < old_size) { + ZeroTrailingData(old_size - size_); + } + return written; + } + + // The AppendData functions add data to the end of the buffer. They accept + // the same input types as the constructors. + template <typename U, + typename std::enable_if< + internal::BufferCompat<T, U>::value>::type* = nullptr> + void AppendData(const U* data, size_t size) { + if (size == 0) { + return; + } + RTC_DCHECK(data); + RTC_DCHECK(IsConsistent()); + const size_t new_size = size_ + size; + EnsureCapacityWithHeadroom(new_size, true); + static_assert(sizeof(T) == sizeof(U), ""); + std::memcpy(data_.get() + size_, data, size * sizeof(U)); + size_ = new_size; + RTC_DCHECK(IsConsistent()); + } + + template <typename U, + size_t N, + typename std::enable_if< + internal::BufferCompat<T, U>::value>::type* = nullptr> + void AppendData(const U (&array)[N]) { + AppendData(array, N); + } + + template <typename W, + typename std::enable_if< + HasDataAndSize<const W, const T>::value>::type* = nullptr> + void AppendData(const W& w) { + AppendData(w.data(), w.size()); + } + + template <typename U, + typename std::enable_if< + internal::BufferCompat<T, U>::value>::type* = nullptr> + void AppendData(const U& item) { + AppendData(&item, 1); + } + + // Appends at most `max_elements` to the end of the buffer, using the function + // `setter`, which should have the following signature: + // + // size_t setter(ArrayView<U> view) + // + // `setter` is given an appropriately typed ArrayView of length exactly + // `max_elements` that describes the area where it should write the data; it + // should return the number of elements actually written. (If it doesn't fill + // the whole ArrayView, it should leave the unused space at the end.) + template <typename U = T, + typename F, + typename std::enable_if< + internal::BufferCompat<T, U>::value>::type* = nullptr> + size_t AppendData(size_t max_elements, F&& setter) { + RTC_DCHECK(IsConsistent()); + const size_t old_size = size_; + SetSize(old_size + max_elements); + U* base_ptr = data<U>() + old_size; + size_t written_elements = setter(rtc::ArrayView<U>(base_ptr, max_elements)); + + RTC_CHECK_LE(written_elements, max_elements); + size_ = old_size + written_elements; + RTC_DCHECK(IsConsistent()); + return written_elements; + } + + // Sets the size of the buffer. If the new size is smaller than the old, the + // buffer contents will be kept but truncated; if the new size is greater, + // the existing contents will be kept and the new space will be + // uninitialized. + void SetSize(size_t size) { + const size_t old_size = size_; + EnsureCapacityWithHeadroom(size, true); + size_ = size; + if (ZeroOnFree && size_ < old_size) { + ZeroTrailingData(old_size - size_); + } + } + + // Ensure that the buffer size can be increased to at least capacity without + // further reallocation. (Of course, this operation might need to reallocate + // the buffer.) + void EnsureCapacity(size_t capacity) { + // Don't allocate extra headroom, since the user is asking for a specific + // capacity. + EnsureCapacityWithHeadroom(capacity, false); + } + + // Resets the buffer to zero size without altering capacity. Works even if the + // buffer has been moved from. + void Clear() { + MaybeZeroCompleteBuffer(); + size_ = 0; + RTC_DCHECK(IsConsistent()); + } + + // Swaps two buffers. Also works for buffers that have been moved from. + friend void swap(BufferT& a, BufferT& b) { + using std::swap; + swap(a.size_, b.size_); + swap(a.capacity_, b.capacity_); + swap(a.data_, b.data_); + } + + private: + void EnsureCapacityWithHeadroom(size_t capacity, bool extra_headroom) { + RTC_DCHECK(IsConsistent()); + if (capacity <= capacity_) + return; + + // If the caller asks for extra headroom, ensure that the new capacity is + // >= 1.5 times the old capacity. Any constant > 1 is sufficient to prevent + // quadratic behavior; as to why we pick 1.5 in particular, see + // https://github.com/facebook/folly/blob/master/folly/docs/FBVector.md and + // http://www.gahcep.com/cpp-internals-stl-vector-part-1/. + const size_t new_capacity = + extra_headroom ? std::max(capacity, capacity_ + capacity_ / 2) + : capacity; + + std::unique_ptr<T[]> new_data(new T[new_capacity]); + if (data_ != nullptr) { + std::memcpy(new_data.get(), data_.get(), size_ * sizeof(T)); + } + MaybeZeroCompleteBuffer(); + data_ = std::move(new_data); + capacity_ = new_capacity; + RTC_DCHECK(IsConsistent()); + } + + // Zero the complete buffer if template argument "ZeroOnFree" is true. + void MaybeZeroCompleteBuffer() { + if (ZeroOnFree && capacity_ > 0) { + // It would be sufficient to only zero "size_" elements, as all other + // methods already ensure that the unused capacity contains no sensitive + // data---but better safe than sorry. + ExplicitZeroMemory(data_.get(), capacity_ * sizeof(T)); + } + } + + // Zero the first "count" elements of unused capacity. + void ZeroTrailingData(size_t count) { + RTC_DCHECK(IsConsistent()); + RTC_DCHECK_LE(count, capacity_ - size_); + ExplicitZeroMemory(data_.get() + size_, count * sizeof(T)); + } + + // Precondition for all methods except Clear, operator= and the destructor. + // Postcondition for all methods except move construction and move + // assignment, which leave the moved-from object in a possibly inconsistent + // state. + bool IsConsistent() const { + return (data_ || capacity_ == 0) && capacity_ >= size_; + } + + // Called when *this has been moved from. Conceptually it's a no-op, but we + // can mutate the state slightly to help subsequent sanity checks catch bugs. + void OnMovedFrom() { + RTC_DCHECK(!data_); // Our heap block should have been stolen. +#if RTC_DCHECK_IS_ON + // Ensure that *this is always inconsistent, to provoke bugs. + size_ = 1; + capacity_ = 0; +#else + // Make *this consistent and empty. Shouldn't be necessary, but better safe + // than sorry. + size_ = 0; + capacity_ = 0; +#endif + } + + size_t size_; + size_t capacity_; + std::unique_ptr<T[]> data_; +}; + +// By far the most common sort of buffer. +using Buffer = BufferT<uint8_t>; + +// A buffer that zeros memory before releasing it. +template <typename T> +using ZeroOnFreeBuffer = BufferT<T, true>; + +} // namespace rtc + +#endif // RTC_BASE_BUFFER_H_ diff --git a/third_party/libwebrtc/rtc_base/buffer_gn/moz.build b/third_party/libwebrtc/rtc_base/buffer_gn/moz.build new file mode 100644 index 0000000000..cb5a45ce58 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/buffer_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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("buffer_gn") diff --git a/third_party/libwebrtc/rtc_base/buffer_queue.cc b/third_party/libwebrtc/rtc_base/buffer_queue.cc new file mode 100644 index 0000000000..7879e933c7 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/buffer_queue.cc @@ -0,0 +1,85 @@ +/* + * Copyright 2015 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 "rtc_base/buffer_queue.h" + +#include <stdint.h> +#include <string.h> + +#include <algorithm> + +namespace rtc { + +BufferQueue::BufferQueue(size_t capacity, size_t default_size) + : capacity_(capacity), default_size_(default_size) {} + +BufferQueue::~BufferQueue() { + RTC_DCHECK_RUN_ON(&sequence_checker_); + for (Buffer* buffer : queue_) + delete buffer; + for (Buffer* buffer : free_list_) + delete buffer; +} + +size_t BufferQueue::size() const { + RTC_DCHECK_RUN_ON(&sequence_checker_); + return queue_.size(); +} + +void BufferQueue::Clear() { + RTC_DCHECK_RUN_ON(&sequence_checker_); + while (!queue_.empty()) { + free_list_.push_back(queue_.front()); + queue_.pop_front(); + } +} + +bool BufferQueue::ReadFront(void* buffer, size_t bytes, size_t* bytes_read) { + RTC_DCHECK_RUN_ON(&sequence_checker_); + if (queue_.empty()) + return false; + + Buffer* packet = queue_.front(); + queue_.pop_front(); + + bytes = std::min(bytes, packet->size()); + memcpy(buffer, packet->data(), bytes); + + if (bytes_read) + *bytes_read = bytes; + + free_list_.push_back(packet); + return true; +} + +bool BufferQueue::WriteBack(const void* buffer, + size_t bytes, + size_t* bytes_written) { + RTC_DCHECK_RUN_ON(&sequence_checker_); + if (queue_.size() == capacity_) + return false; + + Buffer* packet; + if (!free_list_.empty()) { + packet = free_list_.back(); + free_list_.pop_back(); + } else { + packet = new Buffer(bytes, default_size_); + } + + packet->SetData(static_cast<const uint8_t*>(buffer), bytes); + if (bytes_written) + *bytes_written = bytes; + + queue_.push_back(packet); + return true; +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/buffer_queue.h b/third_party/libwebrtc/rtc_base/buffer_queue.h new file mode 100644 index 0000000000..b018e160a1 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/buffer_queue.h @@ -0,0 +1,70 @@ +/* + * Copyright 2015 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 RTC_BASE_BUFFER_QUEUE_H_ +#define RTC_BASE_BUFFER_QUEUE_H_ + +#include <stddef.h> + +#include <deque> +#include <vector> + +#include "api/sequence_checker.h" +#include "rtc_base/buffer.h" +#include "rtc_base/system/no_unique_address.h" +#include "rtc_base/thread_annotations.h" + +namespace rtc { + +class BufferQueue final { + public: + // Creates a buffer queue with a given capacity and default buffer size. + BufferQueue(size_t capacity, size_t default_size); + ~BufferQueue(); + + BufferQueue(const BufferQueue&) = delete; + BufferQueue& operator=(const BufferQueue&) = delete; + + // Return number of queued buffers. + size_t size() const; + + // Clear the BufferQueue by moving all Buffers from `queue_` to `free_list_`. + void Clear(); + + // ReadFront will only read one buffer at a time and will truncate buffers + // that don't fit in the passed memory. + // Returns true unless no data could be returned. + bool ReadFront(void* data, size_t bytes, size_t* bytes_read); + + // WriteBack always writes either the complete memory or nothing. + // Returns true unless no data could be written. + bool WriteBack(const void* data, size_t bytes, size_t* bytes_written); + + bool is_writable() const { + RTC_DCHECK_RUN_ON(&sequence_checker_); + return queue_.size() < capacity_; + } + + bool is_readable() const { + RTC_DCHECK_RUN_ON(&sequence_checker_); + return !queue_.empty(); + } + + private: + RTC_NO_UNIQUE_ADDRESS webrtc::SequenceChecker sequence_checker_; + const size_t capacity_; + const size_t default_size_; + std::deque<Buffer*> queue_ RTC_GUARDED_BY(sequence_checker_); + std::vector<Buffer*> free_list_ RTC_GUARDED_BY(sequence_checker_); +}; + +} // namespace rtc + +#endif // RTC_BASE_BUFFER_QUEUE_H_ diff --git a/third_party/libwebrtc/rtc_base/buffer_queue_unittest.cc b/third_party/libwebrtc/rtc_base/buffer_queue_unittest.cc new file mode 100644 index 0000000000..2a2f8cc4db --- /dev/null +++ b/third_party/libwebrtc/rtc_base/buffer_queue_unittest.cc @@ -0,0 +1,89 @@ +/* + * Copyright 2015 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 "rtc_base/buffer_queue.h" + +#include <string.h> + +#include "test/gtest.h" + +namespace rtc { + +TEST(BufferQueueTest, TestAll) { + const size_t kSize = 16; + const char in[kSize * 2 + 1] = "0123456789ABCDEFGHIJKLMNOPQRSTUV"; + char out[kSize * 2]; + size_t bytes; + BufferQueue queue1(1, kSize); + BufferQueue queue2(2, kSize); + + // The queue is initially empty. + EXPECT_EQ(0u, queue1.size()); + EXPECT_FALSE(queue1.ReadFront(out, kSize, &bytes)); + + // A write should succeed. + EXPECT_TRUE(queue1.WriteBack(in, kSize, &bytes)); + EXPECT_EQ(kSize, bytes); + EXPECT_EQ(1u, queue1.size()); + + // The queue is full now (only one buffer allowed). + EXPECT_FALSE(queue1.WriteBack(in, kSize, &bytes)); + EXPECT_EQ(1u, queue1.size()); + + // Reading previously written buffer. + EXPECT_TRUE(queue1.ReadFront(out, kSize, &bytes)); + EXPECT_EQ(kSize, bytes); + EXPECT_EQ(0, memcmp(in, out, kSize)); + + // The queue is empty again now. + EXPECT_FALSE(queue1.ReadFront(out, kSize, &bytes)); + EXPECT_EQ(0u, queue1.size()); + + // Reading only returns available data. + EXPECT_TRUE(queue1.WriteBack(in, kSize, &bytes)); + EXPECT_EQ(kSize, bytes); + EXPECT_EQ(1u, queue1.size()); + EXPECT_TRUE(queue1.ReadFront(out, kSize * 2, &bytes)); + EXPECT_EQ(kSize, bytes); + EXPECT_EQ(0, memcmp(in, out, kSize)); + EXPECT_EQ(0u, queue1.size()); + + // Reading maintains buffer boundaries. + EXPECT_TRUE(queue2.WriteBack(in, kSize / 2, &bytes)); + EXPECT_EQ(1u, queue2.size()); + EXPECT_TRUE(queue2.WriteBack(in + kSize / 2, kSize / 2, &bytes)); + EXPECT_EQ(2u, queue2.size()); + EXPECT_TRUE(queue2.ReadFront(out, kSize, &bytes)); + EXPECT_EQ(kSize / 2, bytes); + EXPECT_EQ(0, memcmp(in, out, kSize / 2)); + EXPECT_EQ(1u, queue2.size()); + EXPECT_TRUE(queue2.ReadFront(out, kSize, &bytes)); + EXPECT_EQ(kSize / 2, bytes); + EXPECT_EQ(0, memcmp(in + kSize / 2, out, kSize / 2)); + EXPECT_EQ(0u, queue2.size()); + + // Reading truncates buffers. + EXPECT_TRUE(queue2.WriteBack(in, kSize / 2, &bytes)); + EXPECT_EQ(1u, queue2.size()); + EXPECT_TRUE(queue2.WriteBack(in + kSize / 2, kSize / 2, &bytes)); + EXPECT_EQ(2u, queue2.size()); + // Read first packet partially in too-small buffer. + EXPECT_TRUE(queue2.ReadFront(out, kSize / 4, &bytes)); + EXPECT_EQ(kSize / 4, bytes); + EXPECT_EQ(0, memcmp(in, out, kSize / 4)); + EXPECT_EQ(1u, queue2.size()); + // Remainder of first packet is truncated, reading starts with next packet. + EXPECT_TRUE(queue2.ReadFront(out, kSize, &bytes)); + EXPECT_EQ(kSize / 2, bytes); + EXPECT_EQ(0, memcmp(in + kSize / 2, out, kSize / 2)); + EXPECT_EQ(0u, queue2.size()); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/buffer_unittest.cc b/third_party/libwebrtc/rtc_base/buffer_unittest.cc new file mode 100644 index 0000000000..b56118afde --- /dev/null +++ b/third_party/libwebrtc/rtc_base/buffer_unittest.cc @@ -0,0 +1,548 @@ +/* + * 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 "rtc_base/buffer.h" + +#include <cstdint> +#include <utility> + +#include "absl/strings/string_view.h" +#include "api/array_view.h" +#include "test/gmock.h" +#include "test/gtest.h" + +namespace rtc { + +namespace { + +using ::testing::ElementsAre; +using ::testing::ElementsAreArray; + +// clang-format off +const uint8_t kTestData[] = {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, + 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf}; +// clang-format on + +void TestBuf(const Buffer& b1, size_t size, size_t capacity) { + EXPECT_EQ(b1.size(), size); + EXPECT_EQ(b1.capacity(), capacity); +} + +} // namespace + +TEST(BufferTest, TestConstructEmpty) { + TestBuf(Buffer(), 0, 0); + TestBuf(Buffer(Buffer()), 0, 0); + TestBuf(Buffer(0), 0, 0); + + // We can't use a literal 0 for the first argument, because C++ will allow + // that to be considered a null pointer, which makes the call ambiguous. + TestBuf(Buffer(0 + 0, 10), 0, 10); + + TestBuf(Buffer(kTestData, 0), 0, 0); + TestBuf(Buffer(kTestData, 0, 20), 0, 20); +} + +TEST(BufferTest, TestConstructData) { + Buffer buf(kTestData, 7); + EXPECT_EQ(buf.size(), 7u); + EXPECT_EQ(buf.capacity(), 7u); + EXPECT_FALSE(buf.empty()); + EXPECT_EQ(0, memcmp(buf.data(), kTestData, 7)); +} + +TEST(BufferTest, TestConstructDataWithCapacity) { + Buffer buf(kTestData, 7, 14); + EXPECT_EQ(buf.size(), 7u); + EXPECT_EQ(buf.capacity(), 14u); + EXPECT_FALSE(buf.empty()); + EXPECT_EQ(0, memcmp(buf.data(), kTestData, 7)); +} + +TEST(BufferTest, TestConstructArray) { + Buffer buf(kTestData); + EXPECT_EQ(buf.size(), 16u); + EXPECT_EQ(buf.capacity(), 16u); + EXPECT_FALSE(buf.empty()); + EXPECT_EQ(0, memcmp(buf.data(), kTestData, 16)); +} + +TEST(BufferTest, TestStringViewConversion) { + Buffer buf(kTestData); + absl::string_view view = buf; + EXPECT_EQ(view, + absl::string_view(reinterpret_cast<const char*>(kTestData), 16u)); +} + +TEST(BufferTest, TestSetData) { + Buffer buf(kTestData + 4, 7); + buf.SetData(kTestData, 9); + EXPECT_EQ(buf.size(), 9u); + EXPECT_EQ(buf.capacity(), 7u * 3 / 2); + EXPECT_FALSE(buf.empty()); + EXPECT_EQ(0, memcmp(buf.data(), kTestData, 9)); + Buffer buf2; + buf2.SetData(buf); + EXPECT_EQ(buf.size(), 9u); + EXPECT_EQ(buf.capacity(), 7u * 3 / 2); + EXPECT_EQ(0, memcmp(buf.data(), kTestData, 9)); +} + +TEST(BufferTest, TestAppendData) { + Buffer buf(kTestData + 4, 3); + buf.AppendData(kTestData + 10, 2); + const int8_t exp[] = {0x4, 0x5, 0x6, 0xa, 0xb}; + EXPECT_EQ(buf, Buffer(exp)); + Buffer buf2; + buf2.AppendData(buf); + buf2.AppendData(rtc::ArrayView<uint8_t>(buf)); + const int8_t exp2[] = {0x4, 0x5, 0x6, 0xa, 0xb, 0x4, 0x5, 0x6, 0xa, 0xb}; + EXPECT_EQ(buf2, Buffer(exp2)); +} + +TEST(BufferTest, TestSetAndAppendWithUnknownArg) { + struct TestDataContainer { + size_t size() const { return 3; } + const uint8_t* data() const { return kTestData; } + }; + Buffer buf; + buf.SetData(TestDataContainer()); + EXPECT_EQ(3u, buf.size()); + EXPECT_EQ(Buffer(kTestData, 3), buf); + EXPECT_THAT(buf, ElementsAre(0, 1, 2)); + buf.AppendData(TestDataContainer()); + EXPECT_EQ(6u, buf.size()); + EXPECT_EQ(0, memcmp(buf.data(), kTestData, 3)); + EXPECT_EQ(0, memcmp(buf.data() + 3, kTestData, 3)); + EXPECT_THAT(buf, ElementsAre(0, 1, 2, 0, 1, 2)); +} + +TEST(BufferTest, TestSetSizeSmaller) { + Buffer buf; + buf.SetData(kTestData, 15); + buf.SetSize(10); + EXPECT_EQ(buf.size(), 10u); + EXPECT_EQ(buf.capacity(), 15u); // Hasn't shrunk. + EXPECT_FALSE(buf.empty()); + EXPECT_EQ(buf, Buffer(kTestData, 10)); +} + +TEST(BufferTest, TestSetSizeLarger) { + Buffer buf; + buf.SetData(kTestData, 15); + EXPECT_EQ(buf.size(), 15u); + EXPECT_EQ(buf.capacity(), 15u); + EXPECT_FALSE(buf.empty()); + buf.SetSize(20); + EXPECT_EQ(buf.size(), 20u); + EXPECT_EQ(buf.capacity(), 15u * 3 / 2); // Has grown. + EXPECT_FALSE(buf.empty()); + EXPECT_EQ(0, memcmp(buf.data(), kTestData, 15)); +} + +TEST(BufferTest, TestEnsureCapacitySmaller) { + Buffer buf(kTestData); + const char* data = buf.data<char>(); + buf.EnsureCapacity(4); + EXPECT_EQ(buf.capacity(), 16u); // Hasn't shrunk. + EXPECT_EQ(buf.data<char>(), data); // No reallocation. + EXPECT_FALSE(buf.empty()); + EXPECT_EQ(buf, Buffer(kTestData)); +} + +TEST(BufferTest, TestEnsureCapacityLarger) { + Buffer buf(kTestData, 5); + buf.EnsureCapacity(10); + const int8_t* data = buf.data<int8_t>(); + EXPECT_EQ(buf.capacity(), 10u); + buf.AppendData(kTestData + 5, 5); + EXPECT_EQ(buf.data<int8_t>(), data); // No reallocation. + EXPECT_FALSE(buf.empty()); + EXPECT_EQ(buf, Buffer(kTestData, 10)); +} + +TEST(BufferTest, TestMoveConstruct) { + Buffer buf1(kTestData, 3, 40); + const uint8_t* data = buf1.data(); + Buffer buf2(std::move(buf1)); + EXPECT_EQ(buf2.size(), 3u); + EXPECT_EQ(buf2.capacity(), 40u); + EXPECT_EQ(buf2.data(), data); + EXPECT_FALSE(buf2.empty()); + buf1.Clear(); + EXPECT_EQ(buf1.size(), 0u); + EXPECT_EQ(buf1.capacity(), 0u); + EXPECT_EQ(buf1.data(), nullptr); + EXPECT_TRUE(buf1.empty()); +} + +TEST(BufferTest, TestMoveAssign) { + Buffer buf1(kTestData, 3, 40); + const uint8_t* data = buf1.data(); + Buffer buf2(kTestData); + buf2 = std::move(buf1); + EXPECT_EQ(buf2.size(), 3u); + EXPECT_EQ(buf2.capacity(), 40u); + EXPECT_EQ(buf2.data(), data); + EXPECT_FALSE(buf2.empty()); + buf1.Clear(); + EXPECT_EQ(buf1.size(), 0u); + EXPECT_EQ(buf1.capacity(), 0u); + EXPECT_EQ(buf1.data(), nullptr); + EXPECT_TRUE(buf1.empty()); +} + +TEST(BufferTest, TestMoveAssignSelf) { + // Move self-assignment isn't required to produce a meaningful state, but + // should not leave the object in an inconsistent state. (Such inconsistent + // state could be caught by the DCHECKs and/or by the leak checker.) We need + // to be sneaky when testing this; if we're doing a too-obvious + // move-assign-to-self, clang's -Wself-move triggers at compile time. + Buffer buf(kTestData, 3, 40); + Buffer* buf_ptr = &buf; + buf = std::move(*buf_ptr); +} + +TEST(BufferTest, TestSwap) { + Buffer buf1(kTestData, 3); + Buffer buf2(kTestData, 6, 40); + uint8_t* data1 = buf1.data(); + uint8_t* data2 = buf2.data(); + using std::swap; + swap(buf1, buf2); + EXPECT_EQ(buf1.size(), 6u); + EXPECT_EQ(buf1.capacity(), 40u); + EXPECT_EQ(buf1.data(), data2); + EXPECT_FALSE(buf1.empty()); + EXPECT_EQ(buf2.size(), 3u); + EXPECT_EQ(buf2.capacity(), 3u); + EXPECT_EQ(buf2.data(), data1); + EXPECT_FALSE(buf2.empty()); +} + +TEST(BufferTest, TestClear) { + Buffer buf; + buf.SetData(kTestData, 15); + EXPECT_EQ(buf.size(), 15u); + EXPECT_EQ(buf.capacity(), 15u); + EXPECT_FALSE(buf.empty()); + const char* data = buf.data<char>(); + buf.Clear(); + EXPECT_EQ(buf.size(), 0u); + EXPECT_EQ(buf.capacity(), 15u); // Hasn't shrunk. + EXPECT_EQ(buf.data<char>(), data); // No reallocation. + EXPECT_TRUE(buf.empty()); +} + +TEST(BufferTest, TestLambdaSetAppend) { + auto setter = [](rtc::ArrayView<uint8_t> av) { + for (int i = 0; i != 15; ++i) + av[i] = kTestData[i]; + return 15; + }; + + Buffer buf1; + buf1.SetData(kTestData, 15); + buf1.AppendData(kTestData, 15); + + Buffer buf2; + EXPECT_EQ(buf2.SetData(15, setter), 15u); + EXPECT_EQ(buf2.AppendData(15, setter), 15u); + EXPECT_EQ(buf1, buf2); + EXPECT_EQ(buf1.capacity(), buf2.capacity()); + EXPECT_FALSE(buf1.empty()); + EXPECT_FALSE(buf2.empty()); +} + +TEST(BufferTest, TestLambdaSetAppendSigned) { + auto setter = [](rtc::ArrayView<int8_t> av) { + for (int i = 0; i != 15; ++i) + av[i] = kTestData[i]; + return 15; + }; + + Buffer buf1; + buf1.SetData(kTestData, 15); + buf1.AppendData(kTestData, 15); + + Buffer buf2; + EXPECT_EQ(buf2.SetData<int8_t>(15, setter), 15u); + EXPECT_EQ(buf2.AppendData<int8_t>(15, setter), 15u); + EXPECT_EQ(buf1, buf2); + EXPECT_EQ(buf1.capacity(), buf2.capacity()); + EXPECT_FALSE(buf1.empty()); + EXPECT_FALSE(buf2.empty()); +} + +TEST(BufferTest, TestLambdaAppendEmpty) { + auto setter = [](rtc::ArrayView<uint8_t> av) { + for (int i = 0; i != 15; ++i) + av[i] = kTestData[i]; + return 15; + }; + + Buffer buf1; + buf1.SetData(kTestData, 15); + + Buffer buf2; + EXPECT_EQ(buf2.AppendData(15, setter), 15u); + EXPECT_EQ(buf1, buf2); + EXPECT_EQ(buf1.capacity(), buf2.capacity()); + EXPECT_FALSE(buf1.empty()); + EXPECT_FALSE(buf2.empty()); +} + +TEST(BufferTest, TestLambdaAppendPartial) { + auto setter = [](rtc::ArrayView<uint8_t> av) { + for (int i = 0; i != 7; ++i) + av[i] = kTestData[i]; + return 7; + }; + + Buffer buf; + EXPECT_EQ(buf.AppendData(15, setter), 7u); + EXPECT_EQ(buf.size(), 7u); // Size is exactly what we wrote. + EXPECT_GE(buf.capacity(), 7u); // Capacity is valid. + EXPECT_NE(buf.data<char>(), nullptr); // Data is actually stored. + EXPECT_FALSE(buf.empty()); +} + +TEST(BufferTest, TestMutableLambdaSetAppend) { + uint8_t magic_number = 17; + auto setter = [magic_number](rtc::ArrayView<uint8_t> av) mutable { + for (int i = 0; i != 15; ++i) { + av[i] = magic_number; + ++magic_number; + } + return 15; + }; + + EXPECT_EQ(magic_number, 17); + + Buffer buf; + EXPECT_EQ(buf.SetData(15, setter), 15u); + EXPECT_EQ(buf.AppendData(15, setter), 15u); + EXPECT_EQ(buf.size(), 30u); // Size is exactly what we wrote. + EXPECT_GE(buf.capacity(), 30u); // Capacity is valid. + EXPECT_NE(buf.data<char>(), nullptr); // Data is actually stored. + EXPECT_FALSE(buf.empty()); + + for (uint8_t i = 0; i != buf.size(); ++i) { + EXPECT_EQ(buf.data()[i], magic_number + i); + } +} + +TEST(BufferTest, TestBracketRead) { + Buffer buf(kTestData, 7); + EXPECT_EQ(buf.size(), 7u); + EXPECT_EQ(buf.capacity(), 7u); + EXPECT_NE(buf.data(), nullptr); + EXPECT_FALSE(buf.empty()); + + for (size_t i = 0; i != 7u; ++i) { + EXPECT_EQ(buf[i], kTestData[i]); + } +} + +TEST(BufferTest, TestBracketReadConst) { + Buffer buf(kTestData, 7); + EXPECT_EQ(buf.size(), 7u); + EXPECT_EQ(buf.capacity(), 7u); + EXPECT_NE(buf.data(), nullptr); + EXPECT_FALSE(buf.empty()); + + const Buffer& cbuf = buf; + + for (size_t i = 0; i != 7u; ++i) { + EXPECT_EQ(cbuf[i], kTestData[i]); + } +} + +TEST(BufferTest, TestBracketWrite) { + Buffer buf(7); + EXPECT_EQ(buf.size(), 7u); + EXPECT_EQ(buf.capacity(), 7u); + EXPECT_NE(buf.data(), nullptr); + EXPECT_FALSE(buf.empty()); + + for (size_t i = 0; i != 7u; ++i) { + buf[i] = kTestData[i]; + } + + EXPECT_THAT(buf, ElementsAreArray(kTestData, 7)); +} + +TEST(BufferTest, TestBeginEnd) { + const Buffer cbuf(kTestData); + Buffer buf(kTestData); + auto* b1 = cbuf.begin(); + for (auto& x : buf) { + EXPECT_EQ(*b1, x); + ++b1; + ++x; + } + EXPECT_EQ(cbuf.end(), b1); + auto* b2 = buf.begin(); + for (auto& y : cbuf) { + EXPECT_EQ(*b2, y + 1); + ++b2; + } + EXPECT_EQ(buf.end(), b2); +} + +TEST(BufferTest, TestInt16) { + static constexpr int16_t test_data[] = {14, 15, 16, 17, 18}; + BufferT<int16_t> buf(test_data); + EXPECT_EQ(buf.size(), 5u); + EXPECT_EQ(buf.capacity(), 5u); + EXPECT_NE(buf.data(), nullptr); + EXPECT_FALSE(buf.empty()); + EXPECT_THAT(buf, ElementsAreArray(test_data)); + BufferT<int16_t> buf2(test_data); + EXPECT_EQ(buf, buf2); + buf2[0] = 9; + EXPECT_NE(buf, buf2); +} + +TEST(BufferTest, TestFloat) { + static constexpr float test_data[] = {14, 15, 16, 17, 18}; + BufferT<float> buf; + EXPECT_EQ(buf.size(), 0u); + EXPECT_EQ(buf.capacity(), 0u); + EXPECT_EQ(buf.data(), nullptr); + EXPECT_TRUE(buf.empty()); + buf.SetData(test_data); + EXPECT_EQ(buf.size(), 5u); + EXPECT_EQ(buf.capacity(), 5u); + EXPECT_NE(buf.data(), nullptr); + EXPECT_FALSE(buf.empty()); + float* p1 = buf.data(); + while (buf.data() == p1) { + buf.AppendData(test_data); + } + EXPECT_EQ(buf.size(), buf.capacity()); + EXPECT_GT(buf.size(), 5u); + EXPECT_EQ(buf.size() % 5, 0u); + EXPECT_NE(buf.data(), nullptr); + for (size_t i = 0; i != buf.size(); ++i) { + EXPECT_EQ(test_data[i % 5], buf[i]); + } +} + +TEST(BufferTest, TestStruct) { + struct BloodStone { + bool blood; + const char* stone; + }; + BufferT<BloodStone> buf(4); + EXPECT_EQ(buf.size(), 4u); + EXPECT_EQ(buf.capacity(), 4u); + EXPECT_NE(buf.data(), nullptr); + EXPECT_FALSE(buf.empty()); + BufferT<BloodStone*> buf2(4); + for (size_t i = 0; i < buf2.size(); ++i) { + buf2[i] = &buf[i]; + } + static const char kObsidian[] = "obsidian"; + buf2[2]->stone = kObsidian; + EXPECT_EQ(kObsidian, buf[2].stone); +} + +TEST(BufferDeathTest, DieOnUseAfterMove) { + Buffer buf(17); + Buffer buf2 = std::move(buf); + EXPECT_EQ(buf2.size(), 17u); +#if RTC_DCHECK_IS_ON +#if GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID) + EXPECT_DEATH(buf.empty(), ""); +#endif +#else + EXPECT_TRUE(buf.empty()); +#endif +} + +TEST(ZeroOnFreeBufferTest, TestZeroOnSetData) { + ZeroOnFreeBuffer<uint8_t> buf(kTestData, 7); + const uint8_t* old_data = buf.data(); + const size_t old_capacity = buf.capacity(); + const size_t old_size = buf.size(); + constexpr size_t offset = 1; + buf.SetData(kTestData + offset, 2); + // Sanity checks to make sure the underlying heap memory was not reallocated. + EXPECT_EQ(old_data, buf.data()); + EXPECT_EQ(old_capacity, buf.capacity()); + // The first two elements have been overwritten, and the remaining five have + // been zeroed. + EXPECT_EQ(kTestData[offset], buf[0]); + EXPECT_EQ(kTestData[offset + 1], buf[1]); + for (size_t i = 2; i < old_size; i++) { + EXPECT_EQ(0, old_data[i]); + } +} + +TEST(ZeroOnFreeBufferTest, TestZeroOnSetDataFromSetter) { + static constexpr size_t offset = 1; + const auto setter = [](rtc::ArrayView<uint8_t> av) { + for (int i = 0; i != 2; ++i) + av[i] = kTestData[offset + i]; + return 2; + }; + + ZeroOnFreeBuffer<uint8_t> buf(kTestData, 7); + const uint8_t* old_data = buf.data(); + const size_t old_capacity = buf.capacity(); + const size_t old_size = buf.size(); + buf.SetData(2, setter); + // Sanity checks to make sure the underlying heap memory was not reallocated. + EXPECT_EQ(old_data, buf.data()); + EXPECT_EQ(old_capacity, buf.capacity()); + // The first two elements have been overwritten, and the remaining five have + // been zeroed. + EXPECT_EQ(kTestData[offset], buf[0]); + EXPECT_EQ(kTestData[offset + 1], buf[1]); + for (size_t i = 2; i < old_size; i++) { + EXPECT_EQ(0, old_data[i]); + } +} + +TEST(ZeroOnFreeBufferTest, TestZeroOnSetSize) { + ZeroOnFreeBuffer<uint8_t> buf(kTestData, 7); + const uint8_t* old_data = buf.data(); + const size_t old_capacity = buf.capacity(); + const size_t old_size = buf.size(); + buf.SetSize(2); + // Sanity checks to make sure the underlying heap memory was not reallocated. + EXPECT_EQ(old_data, buf.data()); + EXPECT_EQ(old_capacity, buf.capacity()); + // The first two elements have not been modified and the remaining five have + // been zeroed. + EXPECT_EQ(kTestData[0], buf[0]); + EXPECT_EQ(kTestData[1], buf[1]); + for (size_t i = 2; i < old_size; i++) { + EXPECT_EQ(0, old_data[i]); + } +} + +TEST(ZeroOnFreeBufferTest, TestZeroOnClear) { + ZeroOnFreeBuffer<uint8_t> buf(kTestData, 7); + const uint8_t* old_data = buf.data(); + const size_t old_capacity = buf.capacity(); + const size_t old_size = buf.size(); + buf.Clear(); + // Sanity checks to make sure the underlying heap memory was not reallocated. + EXPECT_EQ(old_data, buf.data()); + EXPECT_EQ(old_capacity, buf.capacity()); + // The underlying memory was not released but cleared. + for (size_t i = 0; i < old_size; i++) { + EXPECT_EQ(0, old_data[i]); + } +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/byte_buffer.cc b/third_party/libwebrtc/rtc_base/byte_buffer.cc new file mode 100644 index 0000000000..e1278337a4 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/byte_buffer.cc @@ -0,0 +1,160 @@ +/* + * 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 "rtc_base/byte_buffer.h" + +#include <string.h> + +namespace rtc { + +ByteBufferWriter::ByteBufferWriter() : ByteBufferWriterT() {} + +ByteBufferWriter::ByteBufferWriter(const char* bytes, size_t len) + : ByteBufferWriterT(bytes, len) {} + +ByteBufferReader::ByteBufferReader(const char* bytes, size_t len) { + Construct(bytes, len); +} + +ByteBufferReader::ByteBufferReader(const char* bytes) { + Construct(bytes, strlen(bytes)); +} + +ByteBufferReader::ByteBufferReader(const Buffer& buf) { + Construct(buf.data<char>(), buf.size()); +} + +ByteBufferReader::ByteBufferReader(const ByteBufferWriter& buf) { + Construct(buf.Data(), buf.Length()); +} + +void ByteBufferReader::Construct(const char* bytes, size_t len) { + bytes_ = bytes; + size_ = len; + start_ = 0; + end_ = len; +} + +bool ByteBufferReader::ReadUInt8(uint8_t* val) { + if (!val) + return false; + + return ReadBytes(reinterpret_cast<char*>(val), 1); +} + +bool ByteBufferReader::ReadUInt16(uint16_t* val) { + if (!val) + return false; + + uint16_t v; + if (!ReadBytes(reinterpret_cast<char*>(&v), 2)) { + return false; + } else { + *val = NetworkToHost16(v); + return true; + } +} + +bool ByteBufferReader::ReadUInt24(uint32_t* val) { + if (!val) + return false; + + uint32_t v = 0; + char* read_into = reinterpret_cast<char*>(&v); + ++read_into; + + if (!ReadBytes(read_into, 3)) { + return false; + } else { + *val = NetworkToHost32(v); + return true; + } +} + +bool ByteBufferReader::ReadUInt32(uint32_t* val) { + if (!val) + return false; + + uint32_t v; + if (!ReadBytes(reinterpret_cast<char*>(&v), 4)) { + return false; + } else { + *val = NetworkToHost32(v); + return true; + } +} + +bool ByteBufferReader::ReadUInt64(uint64_t* val) { + if (!val) + return false; + + uint64_t v; + if (!ReadBytes(reinterpret_cast<char*>(&v), 8)) { + return false; + } else { + *val = NetworkToHost64(v); + return true; + } +} + +bool ByteBufferReader::ReadUVarint(uint64_t* val) { + if (!val) { + return false; + } + // Integers are deserialized 7 bits at a time, with each byte having a + // continuation byte (msb=1) if there are more bytes to be read. + uint64_t v = 0; + for (int i = 0; i < 64; i += 7) { + char byte; + if (!ReadBytes(&byte, 1)) { + return false; + } + // Read the first 7 bits of the byte, then offset by bits read so far. + v |= (static_cast<uint64_t>(byte) & 0x7F) << i; + // True if the msb is not a continuation byte. + if (static_cast<uint64_t>(byte) < 0x80) { + *val = v; + return true; + } + } + return false; +} + +bool ByteBufferReader::ReadString(std::string* val, size_t len) { + if (!val) + return false; + + if (len > Length()) { + return false; + } else { + val->append(bytes_ + start_, len); + start_ += len; + return true; + } +} + +bool ByteBufferReader::ReadBytes(char* val, size_t len) { + if (len > Length()) { + return false; + } else { + memcpy(val, bytes_ + start_, len); + start_ += len; + return true; + } +} + +bool ByteBufferReader::Consume(size_t size) { + if (size > Length()) + return false; + start_ += size; + return true; +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/byte_buffer.h b/third_party/libwebrtc/rtc_base/byte_buffer.h new file mode 100644 index 0000000000..9bcbb838aa --- /dev/null +++ b/third_party/libwebrtc/rtc_base/byte_buffer.h @@ -0,0 +1,173 @@ +/* + * 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 RTC_BASE_BYTE_BUFFER_H_ +#define RTC_BASE_BYTE_BUFFER_H_ + +#include <stddef.h> +#include <stdint.h> + +#include <string> + +#include "absl/strings/string_view.h" +#include "rtc_base/buffer.h" +#include "rtc_base/byte_order.h" + +// Reads/Writes from/to buffer using network byte order (big endian) +namespace rtc { + +template <class BufferClassT> +class ByteBufferWriterT { + public: + ByteBufferWriterT() { Construct(nullptr, kDefaultCapacity); } + ByteBufferWriterT(const char* bytes, size_t len) { Construct(bytes, len); } + + ByteBufferWriterT(const ByteBufferWriterT&) = delete; + ByteBufferWriterT& operator=(const ByteBufferWriterT&) = delete; + + const char* Data() const { return buffer_.data(); } + size_t Length() const { return buffer_.size(); } + size_t Capacity() const { return buffer_.capacity(); } + + // Write value to the buffer. Resizes the buffer when it is + // neccessary. + void WriteUInt8(uint8_t val) { + WriteBytes(reinterpret_cast<const char*>(&val), 1); + } + void WriteUInt16(uint16_t val) { + uint16_t v = HostToNetwork16(val); + WriteBytes(reinterpret_cast<const char*>(&v), 2); + } + void WriteUInt24(uint32_t val) { + uint32_t v = HostToNetwork32(val); + char* start = reinterpret_cast<char*>(&v); + ++start; + WriteBytes(start, 3); + } + void WriteUInt32(uint32_t val) { + uint32_t v = HostToNetwork32(val); + WriteBytes(reinterpret_cast<const char*>(&v), 4); + } + void WriteUInt64(uint64_t val) { + uint64_t v = HostToNetwork64(val); + WriteBytes(reinterpret_cast<const char*>(&v), 8); + } + // Serializes an unsigned varint in the format described by + // https://developers.google.com/protocol-buffers/docs/encoding#varints + // with the caveat that integers are 64-bit, not 128-bit. + void WriteUVarint(uint64_t val) { + while (val >= 0x80) { + // Write 7 bits at a time, then set the msb to a continuation byte + // (msb=1). + char byte = static_cast<char>(val) | 0x80; + WriteBytes(&byte, 1); + val >>= 7; + } + char last_byte = static_cast<char>(val); + WriteBytes(&last_byte, 1); + } + void WriteString(absl::string_view val) { + WriteBytes(val.data(), val.size()); + } + void WriteBytes(const char* val, size_t len) { buffer_.AppendData(val, len); } + + // Reserves the given number of bytes and returns a char* that can be written + // into. Useful for functions that require a char* buffer and not a + // ByteBufferWriter. + char* ReserveWriteBuffer(size_t len) { + buffer_.SetSize(buffer_.size() + len); + return buffer_.data(); + } + + // Resize the buffer to the specified `size`. + void Resize(size_t size) { buffer_.SetSize(size); } + + // Clears the contents of the buffer. After this, Length() will be 0. + void Clear() { buffer_.Clear(); } + + private: + static constexpr size_t kDefaultCapacity = 4096; + + void Construct(const char* bytes, size_t size) { + if (bytes) { + buffer_.AppendData(bytes, size); + } else { + buffer_.EnsureCapacity(size); + } + } + + BufferClassT buffer_; + + // There are sensible ways to define these, but they aren't needed in our code + // base. +}; + +class ByteBufferWriter : public ByteBufferWriterT<BufferT<char>> { + public: + ByteBufferWriter(); + ByteBufferWriter(const char* bytes, size_t len); + + ByteBufferWriter(const ByteBufferWriter&) = delete; + ByteBufferWriter& operator=(const ByteBufferWriter&) = delete; +}; + +// The ByteBufferReader references the passed data, i.e. the pointer must be +// valid during the lifetime of the reader. +class ByteBufferReader { + public: + ByteBufferReader(const char* bytes, size_t len); + + // Initializes buffer from a zero-terminated string. + explicit ByteBufferReader(const char* bytes); + + explicit ByteBufferReader(const Buffer& buf); + + explicit ByteBufferReader(const ByteBufferWriter& buf); + + ByteBufferReader(const ByteBufferReader&) = delete; + ByteBufferReader& operator=(const ByteBufferReader&) = delete; + + // Returns start of unprocessed data. + const char* Data() const { return bytes_ + start_; } + // Returns number of unprocessed bytes. + size_t Length() const { return end_ - start_; } + + // Read a next value from the buffer. Return false if there isn't + // enough data left for the specified type. + bool ReadUInt8(uint8_t* val); + bool ReadUInt16(uint16_t* val); + bool ReadUInt24(uint32_t* val); + bool ReadUInt32(uint32_t* val); + bool ReadUInt64(uint64_t* val); + bool ReadUVarint(uint64_t* val); + bool ReadBytes(char* val, size_t len); + + // Appends next `len` bytes from the buffer to `val`. Returns false + // if there is less than `len` bytes left. + bool ReadString(std::string* val, size_t len); + + // Moves current position `size` bytes forward. Returns false if + // there is less than `size` bytes left in the buffer. Consume doesn't + // permanently remove data, so remembered read positions are still valid + // after this call. + bool Consume(size_t size); + + protected: + void Construct(const char* bytes, size_t size); + + const char* bytes_; + size_t size_; + size_t start_; + size_t end_; +}; + +} // namespace rtc + +#endif // RTC_BASE_BYTE_BUFFER_H_ diff --git a/third_party/libwebrtc/rtc_base/byte_buffer_gn/moz.build b/third_party/libwebrtc/rtc_base/byte_buffer_gn/moz.build new file mode 100644 index 0000000000..b093b72f1f --- /dev/null +++ b/third_party/libwebrtc/rtc_base/byte_buffer_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/rtc_base/byte_buffer.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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("byte_buffer_gn") diff --git a/third_party/libwebrtc/rtc_base/byte_buffer_unittest.cc b/third_party/libwebrtc/rtc_base/byte_buffer_unittest.cc new file mode 100644 index 0000000000..4f8043c98f --- /dev/null +++ b/third_party/libwebrtc/rtc_base/byte_buffer_unittest.cc @@ -0,0 +1,250 @@ +/* + * 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 "rtc_base/byte_buffer.h" + +#include <string.h> + +#include "rtc_base/arraysize.h" +#include "rtc_base/byte_order.h" +#include "test/gtest.h" + +namespace rtc { + +TEST(ByteBufferTest, TestByteOrder) { + uint16_t n16 = 1; + uint32_t n32 = 1; + uint64_t n64 = 1; + + EXPECT_EQ(n16, NetworkToHost16(HostToNetwork16(n16))); + EXPECT_EQ(n32, NetworkToHost32(HostToNetwork32(n32))); + EXPECT_EQ(n64, NetworkToHost64(HostToNetwork64(n64))); + + if (IsHostBigEndian()) { + // The host is the network (big) endian. + EXPECT_EQ(n16, HostToNetwork16(n16)); + EXPECT_EQ(n32, HostToNetwork32(n32)); + EXPECT_EQ(n64, HostToNetwork64(n64)); + + // GetBE converts big endian to little endian here. + EXPECT_EQ(n16 >> 8, GetBE16(&n16)); + EXPECT_EQ(n32 >> 24, GetBE32(&n32)); + EXPECT_EQ(n64 >> 56, GetBE64(&n64)); + } else { + // The host is little endian. + EXPECT_NE(n16, HostToNetwork16(n16)); + EXPECT_NE(n32, HostToNetwork32(n32)); + EXPECT_NE(n64, HostToNetwork64(n64)); + + // GetBE converts little endian to big endian here. + EXPECT_EQ(GetBE16(&n16), HostToNetwork16(n16)); + EXPECT_EQ(GetBE32(&n32), HostToNetwork32(n32)); + EXPECT_EQ(GetBE64(&n64), HostToNetwork64(n64)); + + // GetBE converts little endian to big endian here. + EXPECT_EQ(n16 << 8, GetBE16(&n16)); + EXPECT_EQ(n32 << 24, GetBE32(&n32)); + EXPECT_EQ(n64 << 56, GetBE64(&n64)); + } +} + +TEST(ByteBufferTest, TestBufferLength) { + ByteBufferWriter buffer; + size_t size = 0; + EXPECT_EQ(size, buffer.Length()); + + buffer.WriteUInt8(1); + ++size; + EXPECT_EQ(size, buffer.Length()); + + buffer.WriteUInt16(1); + size += 2; + EXPECT_EQ(size, buffer.Length()); + + buffer.WriteUInt24(1); + size += 3; + EXPECT_EQ(size, buffer.Length()); + + buffer.WriteUInt32(1); + size += 4; + EXPECT_EQ(size, buffer.Length()); + + buffer.WriteUInt64(1); + size += 8; + EXPECT_EQ(size, buffer.Length()); +} + +TEST(ByteBufferTest, TestReadWriteBuffer) { + ByteBufferWriter buffer; + ByteBufferReader read_buf(nullptr, 0); + uint8_t ru8; + EXPECT_FALSE(read_buf.ReadUInt8(&ru8)); + + // Write and read uint8_t. + uint8_t wu8 = 1; + buffer.WriteUInt8(wu8); + ByteBufferReader read_buf1(buffer.Data(), buffer.Length()); + EXPECT_TRUE(read_buf1.ReadUInt8(&ru8)); + EXPECT_EQ(wu8, ru8); + EXPECT_EQ(0U, read_buf1.Length()); + buffer.Clear(); + + // Write and read uint16_t. + uint16_t wu16 = (1 << 8) + 1; + buffer.WriteUInt16(wu16); + ByteBufferReader read_buf2(buffer.Data(), buffer.Length()); + uint16_t ru16; + EXPECT_TRUE(read_buf2.ReadUInt16(&ru16)); + EXPECT_EQ(wu16, ru16); + EXPECT_EQ(0U, read_buf2.Length()); + buffer.Clear(); + + // Write and read uint24. + uint32_t wu24 = (3 << 16) + (2 << 8) + 1; + buffer.WriteUInt24(wu24); + ByteBufferReader read_buf3(buffer.Data(), buffer.Length()); + uint32_t ru24; + EXPECT_TRUE(read_buf3.ReadUInt24(&ru24)); + EXPECT_EQ(wu24, ru24); + EXPECT_EQ(0U, read_buf3.Length()); + buffer.Clear(); + + // Write and read uint32_t. + uint32_t wu32 = (4 << 24) + (3 << 16) + (2 << 8) + 1; + buffer.WriteUInt32(wu32); + ByteBufferReader read_buf4(buffer.Data(), buffer.Length()); + uint32_t ru32; + EXPECT_TRUE(read_buf4.ReadUInt32(&ru32)); + EXPECT_EQ(wu32, ru32); + EXPECT_EQ(0U, read_buf3.Length()); + buffer.Clear(); + + // Write and read uint64_t. + uint32_t another32 = (8 << 24) + (7 << 16) + (6 << 8) + 5; + uint64_t wu64 = (static_cast<uint64_t>(another32) << 32) + wu32; + buffer.WriteUInt64(wu64); + ByteBufferReader read_buf5(buffer.Data(), buffer.Length()); + uint64_t ru64; + EXPECT_TRUE(read_buf5.ReadUInt64(&ru64)); + EXPECT_EQ(wu64, ru64); + EXPECT_EQ(0U, read_buf5.Length()); + buffer.Clear(); + + // Write and read string. + std::string write_string("hello"); + buffer.WriteString(write_string); + ByteBufferReader read_buf6(buffer.Data(), buffer.Length()); + std::string read_string; + EXPECT_TRUE(read_buf6.ReadString(&read_string, write_string.size())); + EXPECT_EQ(write_string, read_string); + EXPECT_EQ(0U, read_buf6.Length()); + buffer.Clear(); + + // Write and read bytes + char write_bytes[] = "foo"; + buffer.WriteBytes(write_bytes, 3); + ByteBufferReader read_buf7(buffer.Data(), buffer.Length()); + char read_bytes[3]; + EXPECT_TRUE(read_buf7.ReadBytes(read_bytes, 3)); + for (int i = 0; i < 3; ++i) { + EXPECT_EQ(write_bytes[i], read_bytes[i]); + } + EXPECT_EQ(0U, read_buf7.Length()); + buffer.Clear(); + + // Write and read reserved buffer space + char* write_dst = buffer.ReserveWriteBuffer(3); + memcpy(write_dst, write_bytes, 3); + ByteBufferReader read_buf8(buffer.Data(), buffer.Length()); + memset(read_bytes, 0, 3); + EXPECT_TRUE(read_buf8.ReadBytes(read_bytes, 3)); + for (int i = 0; i < 3; ++i) { + EXPECT_EQ(write_bytes[i], read_bytes[i]); + } + EXPECT_EQ(0U, read_buf8.Length()); + buffer.Clear(); + + // Write and read in order. + buffer.WriteUInt8(wu8); + buffer.WriteUInt16(wu16); + buffer.WriteUInt24(wu24); + buffer.WriteUInt32(wu32); + buffer.WriteUInt64(wu64); + ByteBufferReader read_buf9(buffer.Data(), buffer.Length()); + EXPECT_TRUE(read_buf9.ReadUInt8(&ru8)); + EXPECT_EQ(wu8, ru8); + EXPECT_TRUE(read_buf9.ReadUInt16(&ru16)); + EXPECT_EQ(wu16, ru16); + EXPECT_TRUE(read_buf9.ReadUInt24(&ru24)); + EXPECT_EQ(wu24, ru24); + EXPECT_TRUE(read_buf9.ReadUInt32(&ru32)); + EXPECT_EQ(wu32, ru32); + EXPECT_TRUE(read_buf9.ReadUInt64(&ru64)); + EXPECT_EQ(wu64, ru64); + EXPECT_EQ(0U, read_buf9.Length()); + buffer.Clear(); +} + +TEST(ByteBufferTest, TestReadWriteUVarint) { + ByteBufferWriter write_buffer; + size_t size = 0; + EXPECT_EQ(size, write_buffer.Length()); + + write_buffer.WriteUVarint(1u); + ++size; + EXPECT_EQ(size, write_buffer.Length()); + + write_buffer.WriteUVarint(2u); + ++size; + EXPECT_EQ(size, write_buffer.Length()); + + write_buffer.WriteUVarint(27u); + ++size; + EXPECT_EQ(size, write_buffer.Length()); + + write_buffer.WriteUVarint(149u); + size += 2; + EXPECT_EQ(size, write_buffer.Length()); + + write_buffer.WriteUVarint(68719476736u); + size += 6; + EXPECT_EQ(size, write_buffer.Length()); + + ByteBufferReader read_buffer(write_buffer.Data(), write_buffer.Length()); + EXPECT_EQ(size, read_buffer.Length()); + uint64_t val1, val2, val3, val4, val5; + + ASSERT_TRUE(read_buffer.ReadUVarint(&val1)); + EXPECT_EQ(1u, val1); + --size; + EXPECT_EQ(size, read_buffer.Length()); + + ASSERT_TRUE(read_buffer.ReadUVarint(&val2)); + EXPECT_EQ(2u, val2); + --size; + EXPECT_EQ(size, read_buffer.Length()); + + ASSERT_TRUE(read_buffer.ReadUVarint(&val3)); + EXPECT_EQ(27u, val3); + --size; + EXPECT_EQ(size, read_buffer.Length()); + + ASSERT_TRUE(read_buffer.ReadUVarint(&val4)); + EXPECT_EQ(149u, val4); + size -= 2; + EXPECT_EQ(size, read_buffer.Length()); + + ASSERT_TRUE(read_buffer.ReadUVarint(&val5)); + EXPECT_EQ(68719476736u, val5); + size -= 6; + EXPECT_EQ(size, read_buffer.Length()); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/byte_order.h b/third_party/libwebrtc/rtc_base/byte_order.h new file mode 100644 index 0000000000..382511daeb --- /dev/null +++ b/third_party/libwebrtc/rtc_base/byte_order.h @@ -0,0 +1,214 @@ +/* + * 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 RTC_BASE_BYTE_ORDER_H_ +#define RTC_BASE_BYTE_ORDER_H_ + +#include <stdint.h> + +#include <cstring> + +#if defined(WEBRTC_POSIX) && !defined(__native_client__) +#include <arpa/inet.h> +#endif + +#include "rtc_base/system/arch.h" + +#if defined(WEBRTC_MAC) +#include <libkern/OSByteOrder.h> + +#define htobe16(v) OSSwapHostToBigInt16(v) +#define htobe32(v) OSSwapHostToBigInt32(v) +#define htobe64(v) OSSwapHostToBigInt64(v) +#define be16toh(v) OSSwapBigToHostInt16(v) +#define be32toh(v) OSSwapBigToHostInt32(v) +#define be64toh(v) OSSwapBigToHostInt64(v) + +#define htole16(v) OSSwapHostToLittleInt16(v) +#define htole32(v) OSSwapHostToLittleInt32(v) +#define htole64(v) OSSwapHostToLittleInt64(v) +#define le16toh(v) OSSwapLittleToHostInt16(v) +#define le32toh(v) OSSwapLittleToHostInt32(v) +#define le64toh(v) OSSwapLittleToHostInt64(v) + +#elif defined(WEBRTC_WIN) || defined(__native_client__) + +#if defined(WEBRTC_WIN) +#include <stdlib.h> +#include <winsock2.h> +#else +#include <netinet/in.h> +#endif // defined(WEBRTC_WIN) + +#if defined(WEBRTC_ARCH_LITTLE_ENDIAN) +#define htobe16(v) htons(v) +#define htobe32(v) htonl(v) +#define be16toh(v) ntohs(v) +#define be32toh(v) ntohl(v) +#define htole16(v) (v) +#define htole32(v) (v) +#define htole64(v) (v) +#define le16toh(v) (v) +#define le32toh(v) (v) +#define le64toh(v) (v) +#if defined(WEBRTC_WIN) +#define htobe64(v) _byteswap_uint64(v) +#define be64toh(v) _byteswap_uint64(v) +#endif // defined(WEBRTC_WIN) +#if defined(__native_client__) +#define htobe64(v) __builtin_bswap64(v) +#define be64toh(v) __builtin_bswap64(v) +#endif // defined(__native_client__) + +#elif defined(WEBRTC_ARCH_BIG_ENDIAN) +#define htobe16(v) (v) +#define htobe32(v) (v) +#define be16toh(v) (v) +#define be32toh(v) (v) +#define htole16(v) __builtin_bswap16(v) +#define htole32(v) __builtin_bswap32(v) +#define htole64(v) __builtin_bswap64(v) +#define le16toh(v) __builtin_bswap16(v) +#define le32toh(v) __builtin_bswap32(v) +#define le64toh(v) __builtin_bswap64(v) +#if defined(WEBRTC_WIN) +#define htobe64(v) (v) +#define be64toh(v) (v) +#endif // defined(WEBRTC_WIN) +#if defined(__native_client__) +#define htobe64(v) (v) +#define be64toh(v) (v) +#endif // defined(__native_client__) +#else +#error WEBRTC_ARCH_BIG_ENDIAN or WEBRTC_ARCH_LITTLE_ENDIAN must be defined. +#endif // defined(WEBRTC_ARCH_LITTLE_ENDIAN) + +#elif defined(WEBRTC_BSD) && !defined(__OpenBSD__) +#include <sys/endian.h> +#elif defined(WEBRTC_POSIX) +#include <endian.h> +#else +#error "Missing byte order functions for this arch." +#endif // defined(WEBRTC_MAC) + +namespace rtc { + +// Reading and writing of little and big-endian numbers from memory + +inline void Set8(void* memory, size_t offset, uint8_t v) { + static_cast<uint8_t*>(memory)[offset] = v; +} + +inline uint8_t Get8(const void* memory, size_t offset) { + return static_cast<const uint8_t*>(memory)[offset]; +} + +inline void SetBE16(void* memory, uint16_t v) { + uint16_t val = htobe16(v); + memcpy(memory, &val, sizeof(val)); +} + +inline void SetBE32(void* memory, uint32_t v) { + uint32_t val = htobe32(v); + memcpy(memory, &val, sizeof(val)); +} + +inline void SetBE64(void* memory, uint64_t v) { + uint64_t val = htobe64(v); + memcpy(memory, &val, sizeof(val)); +} + +inline uint16_t GetBE16(const void* memory) { + uint16_t val; + memcpy(&val, memory, sizeof(val)); + return be16toh(val); +} + +inline uint32_t GetBE32(const void* memory) { + uint32_t val; + memcpy(&val, memory, sizeof(val)); + return be32toh(val); +} + +inline uint64_t GetBE64(const void* memory) { + uint64_t val; + memcpy(&val, memory, sizeof(val)); + return be64toh(val); +} + +inline void SetLE16(void* memory, uint16_t v) { + uint16_t val = htole16(v); + memcpy(memory, &val, sizeof(val)); +} + +inline void SetLE32(void* memory, uint32_t v) { + uint32_t val = htole32(v); + memcpy(memory, &val, sizeof(val)); +} + +inline void SetLE64(void* memory, uint64_t v) { + uint64_t val = htole64(v); + memcpy(memory, &val, sizeof(val)); +} + +inline uint16_t GetLE16(const void* memory) { + uint16_t val; + memcpy(&val, memory, sizeof(val)); + return le16toh(val); +} + +inline uint32_t GetLE32(const void* memory) { + uint32_t val; + memcpy(&val, memory, sizeof(val)); + return le32toh(val); +} + +inline uint64_t GetLE64(const void* memory) { + uint64_t val; + memcpy(&val, memory, sizeof(val)); + return le64toh(val); +} + +// Check if the current host is big endian. +inline bool IsHostBigEndian() { +#if defined(WEBRTC_ARCH_BIG_ENDIAN) + return true; +#else + return false; +#endif +} + +inline uint16_t HostToNetwork16(uint16_t n) { + return htobe16(n); +} + +inline uint32_t HostToNetwork32(uint32_t n) { + return htobe32(n); +} + +inline uint64_t HostToNetwork64(uint64_t n) { + return htobe64(n); +} + +inline uint16_t NetworkToHost16(uint16_t n) { + return be16toh(n); +} + +inline uint32_t NetworkToHost32(uint32_t n) { + return be32toh(n); +} + +inline uint64_t NetworkToHost64(uint64_t n) { + return be64toh(n); +} + +} // namespace rtc + +#endif // RTC_BASE_BYTE_ORDER_H_ diff --git a/third_party/libwebrtc/rtc_base/byte_order_gn/moz.build b/third_party/libwebrtc/rtc_base/byte_order_gn/moz.build new file mode 100644 index 0000000000..21ea639dd4 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/byte_order_gn/moz.build @@ -0,0 +1,205 @@ +# 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("byte_order_gn") diff --git a/third_party/libwebrtc/rtc_base/byte_order_unittest.cc b/third_party/libwebrtc/rtc_base/byte_order_unittest.cc new file mode 100644 index 0000000000..0db230f3ec --- /dev/null +++ b/third_party/libwebrtc/rtc_base/byte_order_unittest.cc @@ -0,0 +1,83 @@ +/* + * Copyright 2012 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 "rtc_base/byte_order.h" + +#include <stdint.h> + +#include "test/gtest.h" + +namespace rtc { + +// Test memory set functions put values into memory in expected order. +TEST(ByteOrderTest, TestSet) { + uint8_t buf[8] = {0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u}; + Set8(buf, 0, 0xfb); + Set8(buf, 1, 0x12); + EXPECT_EQ(0xfb, buf[0]); + EXPECT_EQ(0x12, buf[1]); + SetBE16(buf, 0x1234); + EXPECT_EQ(0x12, buf[0]); + EXPECT_EQ(0x34, buf[1]); + SetLE16(buf, 0x1234); + EXPECT_EQ(0x34, buf[0]); + EXPECT_EQ(0x12, buf[1]); + SetBE32(buf, 0x12345678); + EXPECT_EQ(0x12, buf[0]); + EXPECT_EQ(0x34, buf[1]); + EXPECT_EQ(0x56, buf[2]); + EXPECT_EQ(0x78, buf[3]); + SetLE32(buf, 0x12345678); + EXPECT_EQ(0x78, buf[0]); + EXPECT_EQ(0x56, buf[1]); + EXPECT_EQ(0x34, buf[2]); + EXPECT_EQ(0x12, buf[3]); + SetBE64(buf, UINT64_C(0x0123456789abcdef)); + EXPECT_EQ(0x01, buf[0]); + EXPECT_EQ(0x23, buf[1]); + EXPECT_EQ(0x45, buf[2]); + EXPECT_EQ(0x67, buf[3]); + EXPECT_EQ(0x89, buf[4]); + EXPECT_EQ(0xab, buf[5]); + EXPECT_EQ(0xcd, buf[6]); + EXPECT_EQ(0xef, buf[7]); + SetLE64(buf, UINT64_C(0x0123456789abcdef)); + EXPECT_EQ(0xef, buf[0]); + EXPECT_EQ(0xcd, buf[1]); + EXPECT_EQ(0xab, buf[2]); + EXPECT_EQ(0x89, buf[3]); + EXPECT_EQ(0x67, buf[4]); + EXPECT_EQ(0x45, buf[5]); + EXPECT_EQ(0x23, buf[6]); + EXPECT_EQ(0x01, buf[7]); +} + +// Test memory get functions get values from memory in expected order. +TEST(ByteOrderTest, TestGet) { + uint8_t buf[8]; + buf[0] = 0x01u; + buf[1] = 0x23u; + buf[2] = 0x45u; + buf[3] = 0x67u; + buf[4] = 0x89u; + buf[5] = 0xabu; + buf[6] = 0xcdu; + buf[7] = 0xefu; + EXPECT_EQ(0x01u, Get8(buf, 0)); + EXPECT_EQ(0x23u, Get8(buf, 1)); + EXPECT_EQ(0x0123u, GetBE16(buf)); + EXPECT_EQ(0x2301u, GetLE16(buf)); + EXPECT_EQ(0x01234567u, GetBE32(buf)); + EXPECT_EQ(0x67452301u, GetLE32(buf)); + EXPECT_EQ(UINT64_C(0x0123456789abcdef), GetBE64(buf)); + EXPECT_EQ(UINT64_C(0xefcdab8967452301), GetLE64(buf)); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/callback_list.cc b/third_party/libwebrtc/rtc_base/callback_list.cc new file mode 100644 index 0000000000..c452c79b38 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/callback_list.cc @@ -0,0 +1,121 @@ +/* + * 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. + */ + +#include "rtc_base/callback_list.h" + +#include "rtc_base/checks.h" + +namespace webrtc { +namespace callback_list_impl { + +CallbackListReceivers::CallbackListReceivers() = default; + +CallbackListReceivers::~CallbackListReceivers() { + RTC_CHECK(!send_in_progress_); +} + +void CallbackListReceivers::RemoveReceivers(const void* removal_tag) { + RTC_DCHECK(removal_tag); + + // We divide the receivers_ vector into three regions: from right to left, the + // "keep" region, the "todo" region, and the "remove" region. The "todo" + // region initially covers the whole vector. + size_t first_todo = 0; // First element of the "todo" + // region. + size_t first_remove = receivers_.size(); // First element of the "remove" + // region. + + // Loop until the "todo" region is empty. + while (first_todo != first_remove) { + if (receivers_[first_todo].removal_tag != removal_tag) { + // The first element of the "todo" region should be kept. Move the + // "keep"/"todo" boundary. + ++first_todo; + } else if (receivers_[first_remove - 1].removal_tag == removal_tag) { + // The last element of the "todo" region should be removed. Move the + // "todo"/"remove" boundary. + if (send_in_progress_) { + // Tag this receiver for removal, which will be done when `ForEach` + // has completed. + receivers_[first_remove - 1].removal_tag = pending_removal_tag(); + } + --first_remove; + } else if (!send_in_progress_) { + // The first element of the "todo" region should be removed, and the last + // element of the "todo" region should be kept. Swap them, and then shrink + // the "todo" region from both ends. + RTC_DCHECK_NE(first_todo, first_remove - 1); + using std::swap; + swap(receivers_[first_todo], receivers_[first_remove - 1]); + RTC_DCHECK_NE(receivers_[first_todo].removal_tag, removal_tag); + ++first_todo; + RTC_DCHECK_EQ(receivers_[first_remove - 1].removal_tag, removal_tag); + --first_remove; + } + } + + if (!send_in_progress_) { + // Discard the remove region. + receivers_.resize(first_remove); + } +} + +void CallbackListReceivers::Foreach( + rtc::FunctionView<void(UntypedFunction&)> fv) { + RTC_CHECK(!send_in_progress_); + bool removals_detected = false; + send_in_progress_ = true; + for (auto& r : receivers_) { + RTC_DCHECK_NE(r.removal_tag, pending_removal_tag()); + fv(r.function); + if (r.removal_tag == pending_removal_tag()) { + removals_detected = true; + } + } + send_in_progress_ = false; + if (removals_detected) { + RemoveReceivers(pending_removal_tag()); + } +} + +template void CallbackListReceivers::AddReceiver( + const void*, + UntypedFunction::TrivialUntypedFunctionArgs<1>); +template void CallbackListReceivers::AddReceiver( + const void*, + UntypedFunction::TrivialUntypedFunctionArgs<2>); +template void CallbackListReceivers::AddReceiver( + const void*, + UntypedFunction::TrivialUntypedFunctionArgs<3>); +template void CallbackListReceivers::AddReceiver( + const void*, + UntypedFunction::TrivialUntypedFunctionArgs<4>); +template void CallbackListReceivers::AddReceiver( + const void*, + UntypedFunction::NontrivialUntypedFunctionArgs); +template void CallbackListReceivers::AddReceiver( + const void*, + UntypedFunction::FunctionPointerUntypedFunctionArgs); + +template void CallbackListReceivers::AddReceiver( + UntypedFunction::TrivialUntypedFunctionArgs<1>); +template void CallbackListReceivers::AddReceiver( + UntypedFunction::TrivialUntypedFunctionArgs<2>); +template void CallbackListReceivers::AddReceiver( + UntypedFunction::TrivialUntypedFunctionArgs<3>); +template void CallbackListReceivers::AddReceiver( + UntypedFunction::TrivialUntypedFunctionArgs<4>); +template void CallbackListReceivers::AddReceiver( + UntypedFunction::NontrivialUntypedFunctionArgs); +template void CallbackListReceivers::AddReceiver( + UntypedFunction::FunctionPointerUntypedFunctionArgs); + +} // namespace callback_list_impl +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/callback_list.h b/third_party/libwebrtc/rtc_base/callback_list.h new file mode 100644 index 0000000000..a9d71a6562 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/callback_list.h @@ -0,0 +1,223 @@ +/* + * 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 RTC_BASE_CALLBACK_LIST_H_ +#define RTC_BASE_CALLBACK_LIST_H_ + +#include <utility> +#include <vector> + +#include "api/function_view.h" +#include "rtc_base/checks.h" +#include "rtc_base/system/assume.h" +#include "rtc_base/system/inline.h" +#include "rtc_base/system/rtc_export.h" +#include "rtc_base/untyped_function.h" + +namespace webrtc { +namespace callback_list_impl { + +class RTC_EXPORT CallbackListReceivers { + public: + CallbackListReceivers(); + CallbackListReceivers(const CallbackListReceivers&) = delete; + CallbackListReceivers& operator=(const CallbackListReceivers&) = delete; + CallbackListReceivers(CallbackListReceivers&&) = delete; + CallbackListReceivers& operator=(CallbackListReceivers&&) = delete; + ~CallbackListReceivers(); + + template <typename UntypedFunctionArgsT> + RTC_NO_INLINE void AddReceiver(const void* removal_tag, + UntypedFunctionArgsT args) { + RTC_CHECK(!send_in_progress_); + RTC_DCHECK(removal_tag != nullptr); + receivers_.push_back({removal_tag, UntypedFunction::Create(args)}); + } + + template <typename UntypedFunctionArgsT> + RTC_NO_INLINE void AddReceiver(UntypedFunctionArgsT args) { + RTC_CHECK(!send_in_progress_); + receivers_.push_back({nullptr, UntypedFunction::Create(args)}); + } + + void RemoveReceivers(const void* removal_tag); + + void Foreach(rtc::FunctionView<void(UntypedFunction&)> fv); + + private: + // Special protected pointer value that's used as a removal_tag for + // receivers that want to unsubscribe from within a callback. + // Note we could use `&receivers_` too, but since it's the first member + // variable of the class, its address will be the same as the instance + // CallbackList instance, so we take an extra step to avoid collision. + const void* pending_removal_tag() const { return &send_in_progress_; } + + struct Callback { + const void* removal_tag; + UntypedFunction function; + }; + + std::vector<Callback> receivers_; + bool send_in_progress_ = false; +}; + +extern template void CallbackListReceivers::AddReceiver( + const void*, + UntypedFunction::TrivialUntypedFunctionArgs<1>); +extern template void CallbackListReceivers::AddReceiver( + const void*, + UntypedFunction::TrivialUntypedFunctionArgs<2>); +extern template void CallbackListReceivers::AddReceiver( + const void*, + UntypedFunction::TrivialUntypedFunctionArgs<3>); +extern template void CallbackListReceivers::AddReceiver( + const void*, + UntypedFunction::TrivialUntypedFunctionArgs<4>); +extern template void CallbackListReceivers::AddReceiver( + const void*, + UntypedFunction::NontrivialUntypedFunctionArgs); +extern template void CallbackListReceivers::AddReceiver( + const void*, + UntypedFunction::FunctionPointerUntypedFunctionArgs); + +extern template void CallbackListReceivers::AddReceiver( + UntypedFunction::TrivialUntypedFunctionArgs<1>); +extern template void CallbackListReceivers::AddReceiver( + UntypedFunction::TrivialUntypedFunctionArgs<2>); +extern template void CallbackListReceivers::AddReceiver( + UntypedFunction::TrivialUntypedFunctionArgs<3>); +extern template void CallbackListReceivers::AddReceiver( + UntypedFunction::TrivialUntypedFunctionArgs<4>); +extern template void CallbackListReceivers::AddReceiver( + UntypedFunction::NontrivialUntypedFunctionArgs); +extern template void CallbackListReceivers::AddReceiver( + UntypedFunction::FunctionPointerUntypedFunctionArgs); + +} // namespace callback_list_impl + +// A collection of receivers (callable objects) that can be called all at once. +// Optimized for minimal binary size. The template arguments dictate what +// signature the callbacks must have; for example, a CallbackList<int, float> +// will require callbacks with signature void(int, float). +// +// CallbackList is neither copyable nor movable (could easily be made movable if +// necessary). Callbacks must be movable, but need not be copyable. +// +// Usage example: +// +// // Declaration (usually a member variable). +// CallbackList<int, float> foo_; +// +// // Register callbacks. This can be done zero or more times. The +// // callbacks must accept the arguments types listed in the CallbackList's +// // template argument list, and must return void. +// foo_.AddReceiver([...](int a, float b) {...}); // Lambda. +// foo_.AddReceiver(SomeFunction); // Function pointer. +// +// // Call the zero or more receivers, one after the other. +// foo_.Send(17, 3.14); +// +// Callback lifetime considerations +// -------------------------------- +// +// CallbackList::AddReceiver() takes ownership of the given callback by moving +// it in place. The callback can be any callable object; in particular, it may +// have a nontrivial destructor, which will be run when the CallbackList is +// destroyed. The callback may thus access data via any type of smart pointer, +// expressing e.g. unique, shared, or weak ownership. Of course, if the data is +// guaranteed to outlive the callback, a plain raw pointer can be used. +// +// Take care when trying to have the callback own reference-counted data. The +// CallbackList will keep the callback alive, and the callback will keep its +// data alive, so as usual with reference-counted ownership, keep an eye out for +// cycles! +// +// Thread safety +// ------------- +// +// Like most C++ types, CallbackList is thread compatible: it's not safe to +// access it concurrently from multiple threads, but it can be made safe if it +// is protected by a mutex, for example. +// +// Excercise some care when deciding what mutexes to hold when you call +// CallbackList::Send(). In particular, do not hold mutexes that callbacks may +// need to grab. If a larger object has a CallbackList member and a single mutex +// that protects all of its data members, this may e.g. make it necessary to +// protect its CallbackList with a separate mutex; otherwise, there will be a +// deadlock if the callbacks try to access the object. +// +// CallbackList as a class data member +// ----------------------------------- +// +// CallbackList is a normal C++ data type, and should be private when it is a +// data member of a class. For thread safety reasons (see above), it is likely +// best to not have an accessor for the entire CallbackList, and instead only +// allow callers to add callbacks: +// +// template <typename F> +// void AddFooCallback(F&& callback) { +// // Maybe grab a mutex here? +// foo_callbacks_.AddReceiver(std::forward<F>(callback)); +// } +// +template <typename... ArgT> +class CallbackList { + public: + CallbackList() = default; + CallbackList(const CallbackList&) = delete; + CallbackList& operator=(const CallbackList&) = delete; + CallbackList(CallbackList&&) = delete; + CallbackList& operator=(CallbackList&&) = delete; + + // Adds a new receiver. The receiver (a callable object or a function pointer) + // must be movable, but need not be copyable. Its call signature should be + // `void(ArgT...)`. The removal tag is a pointer to an arbitrary object that + // you own, and that will stay alive until the CallbackList is gone, or until + // all receivers using it as a removal tag have been removed; you can use it + // to remove the receiver. + template <typename F> + void AddReceiver(const void* removal_tag, F&& f) { + receivers_.AddReceiver( + removal_tag, + UntypedFunction::PrepareArgs<void(ArgT...)>(std::forward<F>(f))); + } + + // Adds a new receiver with no removal tag. + template <typename F> + void AddReceiver(F&& f) { + receivers_.AddReceiver( + UntypedFunction::PrepareArgs<void(ArgT...)>(std::forward<F>(f))); + } + + // Removes all receivers that were added with the given removal tag. + void RemoveReceivers(const void* removal_tag) { + receivers_.RemoveReceivers(removal_tag); + } + + // Calls all receivers with the given arguments. While the Send is in + // progress, no method calls are allowed; specifically, this means that the + // callbacks may not do anything with this CallbackList instance. + // + // Note: Receivers are called serially, but not necessarily in the same order + // they were added. + template <typename... ArgU> + void Send(ArgU&&... args) { + receivers_.Foreach([&](UntypedFunction& f) { + f.Call<void(ArgT...)>(std::forward<ArgU>(args)...); + }); + } + + private: + callback_list_impl::CallbackListReceivers receivers_; +}; + +} // namespace webrtc + +#endif // RTC_BASE_CALLBACK_LIST_H_ diff --git a/third_party/libwebrtc/rtc_base/callback_list_unittest.cc b/third_party/libwebrtc/rtc_base/callback_list_unittest.cc new file mode 100644 index 0000000000..86c2009fe3 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/callback_list_unittest.cc @@ -0,0 +1,270 @@ +/* + * 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. + */ +#include "rtc_base/callback_list.h" + +#include <string> +#include <type_traits> + +#include "api/function_view.h" +#include "test/gtest.h" + +namespace webrtc { +namespace { + +TEST(CallbackList, NoReceiverSingleMessageTest) { + CallbackList<std::string> c; + + c.Send("message"); +} + +TEST(CallbackList, MultipleParameterMessageTest) { + CallbackList<const std::string&, std::string, std::string&&, int, int*, + std::string&> + c; + std::string str = "messege"; + int i = 10; + + c.Send(str, "message1", "message0", 123, &i, str); +} + +TEST(CallbackList, NoParameterMessageTest) { + CallbackList<> c; + + c.Send(); +} + +TEST(CallbackList, ReferenceTest) { + CallbackList<int&> c; + int index = 1; + + c.AddReceiver([](int& index) { index++; }); + c.Send(index); + + EXPECT_EQ(index, 2); +} + +enum State { + kNew, + kChecking, +}; + +TEST(CallbackList, SingleEnumValueTest) { + CallbackList<State> c; + State s1 = kNew; + int index = 0; + + c.AddReceiver([&index](State s) { index++; }); + c.Send(s1); + + EXPECT_EQ(index, 1); +} + +TEST(CallbackList, SingleEnumReferenceTest) { + CallbackList<State&> c; + State s = kNew; + + c.AddReceiver([](State& s) { s = kChecking; }); + c.Send(s); + + EXPECT_EQ(s, kChecking); +} + +TEST(CallbackList, ConstReferenceTest) { + CallbackList<int&> c; + int i = 0; + int index = 1; + + c.AddReceiver([&i](const int& index) { i = index; }); + c.Send(index); + + EXPECT_EQ(i, 1); +} + +TEST(CallbackList, PointerTest) { + CallbackList<int*> c; + int index = 1; + + c.AddReceiver([](int* index) { (*index)++; }); + c.Send(&index); + + EXPECT_EQ(index, 2); +} + +TEST(CallbackList, CallByValue) { + CallbackList<int> c; + int x = 17; + + c.AddReceiver([&x](int n) { x += n; }); + int y = 89; + c.Send(y); + + EXPECT_EQ(x, 106); +} + +void PlusOne(int& a) { + a++; +} + +TEST(CallbackList, FunctionPtrTest) { + CallbackList<int&> c; + int index = 1; + + c.AddReceiver(PlusOne); + c.Send(index); + + EXPECT_EQ(index, 2); +} + +struct LargeNonTrivial { + int a[17]; + + LargeNonTrivial() = default; + LargeNonTrivial(LargeNonTrivial&& m) {} + ~LargeNonTrivial() = default; + + void operator()(int& b) { b = 1; } +}; + +TEST(CallbackList, LargeNonTrivialTest) { + CallbackList<int&> c; + int i = 0; + static_assert(sizeof(LargeNonTrivial) > UntypedFunction::kInlineStorageSize, + ""); + c.AddReceiver(LargeNonTrivial()); + c.Send(i); + + EXPECT_EQ(i, 1); +} + +struct LargeTrivial { + int a[17]; + void operator()(int& x) { x = 1; } +}; + +TEST(CallbackList, LargeTrivial) { + CallbackList<int&> c; + LargeTrivial lt; + int i = 0; + + static_assert(sizeof(lt) > UntypedFunction::kInlineStorageSize, ""); + c.AddReceiver(lt); + c.Send(i); + + EXPECT_EQ(i, 1); +} + +struct OnlyNonTriviallyConstructible { + OnlyNonTriviallyConstructible() = default; + OnlyNonTriviallyConstructible(OnlyNonTriviallyConstructible&& m) {} + + void operator()(int& a) { a = 1; } +}; + +TEST(CallbackList, OnlyNonTriviallyMoveConstructible) { + CallbackList<int&> c; + int i = 0; + + c.AddReceiver(OnlyNonTriviallyConstructible()); + c.Send(i); + + EXPECT_EQ(i, 1); +} + +TEST(CallbackList, MultipleReceiverSendTest) { + CallbackList<int&> c; + std::function<void(int&)> plus = PlusOne; + int index = 1; + + c.AddReceiver(plus); + c.AddReceiver([](int& i) { i--; }); + c.AddReceiver(plus); + c.AddReceiver(plus); + c.Send(index); + c.Send(index); + + EXPECT_EQ(index, 5); +} + +class A { + public: + void increment(int& i) const { i++; } +}; + +TEST(CallbackList, MemberFunctionTest) { + CallbackList<int&> c; + A a; + int index = 1; + + c.AddReceiver([&a](int& i) { a.increment(i); }); + c.Send(index); + + EXPECT_EQ(index, 2); +} + +// todo(glahiru): Add a test case to catch some error for Karl's first fix + +TEST(CallbackList, RemoveOneReceiver) { + int removal_tag[2]; + CallbackList<> c; + int accumulator = 0; + c.AddReceiver([&accumulator] { accumulator += 1; }); + c.AddReceiver(&removal_tag[0], [&accumulator] { accumulator += 10; }); + c.AddReceiver(&removal_tag[1], [&accumulator] { accumulator += 100; }); + c.Send(); + EXPECT_EQ(accumulator, 111); + c.RemoveReceivers(&removal_tag[0]); + c.Send(); + EXPECT_EQ(accumulator, 212); +} + +TEST(CallbackList, RemoveZeroReceivers) { + int removal_tag[3]; + CallbackList<> c; + int accumulator = 0; + c.AddReceiver([&accumulator] { accumulator += 1; }); + c.AddReceiver(&removal_tag[0], [&accumulator] { accumulator += 10; }); + c.AddReceiver(&removal_tag[1], [&accumulator] { accumulator += 100; }); + c.Send(); + EXPECT_EQ(accumulator, 111); + c.RemoveReceivers(&removal_tag[2]); + c.Send(); + EXPECT_EQ(accumulator, 222); +} + +TEST(CallbackList, RemoveManyReceivers) { + int removal_tag; + CallbackList<> c; + int accumulator = 0; + c.AddReceiver([&accumulator] { accumulator += 1; }); + c.AddReceiver(&removal_tag, [&accumulator] { accumulator += 10; }); + c.AddReceiver([&accumulator] { accumulator += 100; }); + c.AddReceiver(&removal_tag, [&accumulator] { accumulator += 1000; }); + c.Send(); + EXPECT_EQ(accumulator, 1111); + c.RemoveReceivers(&removal_tag); + c.Send(); + EXPECT_EQ(accumulator, 1212); +} + +TEST(CallbackList, RemoveFromSend) { + int removal_tag = 0; + CallbackList<> c; + c.AddReceiver(&removal_tag, [&] { + c.RemoveReceivers(&removal_tag); + // Do after RemoveReceivers to make sure the lambda is still valid. + ++removal_tag; + }); + c.Send(); + c.Send(); + EXPECT_EQ(removal_tag, 1); +} + +} // namespace +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/checks.cc b/third_party/libwebrtc/rtc_base/checks.cc new file mode 100644 index 0000000000..e732a2659d --- /dev/null +++ b/third_party/libwebrtc/rtc_base/checks.cc @@ -0,0 +1,240 @@ +/* + * Copyright 2006 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. + */ + +// Most of this was borrowed (with minor modifications) from V8's and Chromium's +// src/base/logging.cc. + +#include <cstdarg> +#include <cstdio> +#include <cstdlib> + +#include "absl/strings/string_view.h" + +#if defined(WEBRTC_ANDROID) +#define RTC_LOG_TAG_ANDROID "rtc" +#include <android/log.h> // NOLINT +#endif + +#if defined(WEBRTC_WIN) +#include <windows.h> +#endif + +#if defined(WEBRTC_WIN) +#define LAST_SYSTEM_ERROR (::GetLastError()) +#elif defined(__native_client__) && __native_client__ +#define LAST_SYSTEM_ERROR (0) +#elif defined(WEBRTC_POSIX) +#include <errno.h> +#define LAST_SYSTEM_ERROR (errno) +#endif // WEBRTC_WIN + +#include "rtc_base/checks.h" + +namespace { + +#if defined(__GNUC__) +__attribute__((__format__(__printf__, 2, 3))) +#endif +void AppendFormat(std::string* s, const char* fmt, ...) { + va_list args, copy; + va_start(args, fmt); + va_copy(copy, args); + const int predicted_length = std::vsnprintf(nullptr, 0, fmt, copy); + va_end(copy); + + if (predicted_length > 0) { + const size_t size = s->size(); + s->resize(size + predicted_length); + // Pass "+ 1" to vsnprintf to include space for the '\0'. + std::vsnprintf(&((*s)[size]), predicted_length + 1, fmt, args); + } + va_end(args); +} +} // namespace + +namespace rtc { +namespace webrtc_checks_impl { + +#if !defined(WEBRTC_CHROMIUM_BUILD) +RTC_NORETURN void WriteFatalLog(absl::string_view output) { +#if defined(WEBRTC_ANDROID) + std::string output_str(output); + __android_log_print(ANDROID_LOG_ERROR, RTC_LOG_TAG_ANDROID, "%s\n", + output_str.c_str()); +#endif + fflush(stdout); + fwrite(output.data(), output.size(), 1, stderr); + fflush(stderr); +#if defined(WEBRTC_WIN) + DebugBreak(); +#endif + abort(); +} + +RTC_NORETURN void WriteFatalLog(const char* file, + int line, + absl::string_view output) { + WriteFatalLog(output); +} + +#endif // !defined(WEBRTC_CHROMIUM_BUILD) + +#if RTC_CHECK_MSG_ENABLED +// Reads one argument from args, appends it to s and advances fmt. +// Returns true iff an argument was sucessfully parsed. +bool ParseArg(va_list* args, const CheckArgType** fmt, std::string* s) { + if (**fmt == CheckArgType::kEnd) + return false; + + switch (**fmt) { + case CheckArgType::kInt: + AppendFormat(s, "%d", va_arg(*args, int)); + break; + case CheckArgType::kLong: + AppendFormat(s, "%ld", va_arg(*args, long)); + break; + case CheckArgType::kLongLong: + AppendFormat(s, "%lld", va_arg(*args, long long)); + break; + case CheckArgType::kUInt: + AppendFormat(s, "%u", va_arg(*args, unsigned)); + break; + case CheckArgType::kULong: + AppendFormat(s, "%lu", va_arg(*args, unsigned long)); + break; + case CheckArgType::kULongLong: + AppendFormat(s, "%llu", va_arg(*args, unsigned long long)); + break; + case CheckArgType::kDouble: + AppendFormat(s, "%g", va_arg(*args, double)); + break; + case CheckArgType::kLongDouble: + AppendFormat(s, "%Lg", va_arg(*args, long double)); + break; + case CheckArgType::kCharP: + s->append(va_arg(*args, const char*)); + break; + case CheckArgType::kStdString: + s->append(*va_arg(*args, const std::string*)); + break; + case CheckArgType::kStringView: { + const absl::string_view sv = *va_arg(*args, const absl::string_view*); + s->append(sv.data(), sv.size()); + break; + } + case CheckArgType::kVoidP: + AppendFormat(s, "%p", va_arg(*args, const void*)); + break; + default: + s->append("[Invalid CheckArgType]"); + return false; + } + (*fmt)++; + return true; +} + +RTC_NORETURN void FatalLog(const char* file, + int line, + const char* message, + const CheckArgType* fmt, + ...) { + va_list args; + va_start(args, fmt); + + std::string s; + AppendFormat(&s, + "\n\n" + "#\n" + "# Fatal error in: %s, line %d\n" + "# last system error: %u\n" + "# Check failed: %s", + file, line, LAST_SYSTEM_ERROR, message); + + if (*fmt == CheckArgType::kCheckOp) { + // This log message was generated by RTC_CHECK_OP, so we have to complete + // the error message using the operands that have been passed as the first + // two arguments. + fmt++; + + std::string s1, s2; + if (ParseArg(&args, &fmt, &s1) && ParseArg(&args, &fmt, &s2)) + AppendFormat(&s, " (%s vs. %s)\n# ", s1.c_str(), s2.c_str()); + } else { + s.append("\n# "); + } + + // Append all the user-supplied arguments to the message. + while (ParseArg(&args, &fmt, &s)) + ; + + va_end(args); + + WriteFatalLog(file, line, s); +} +#else // RTC_CHECK_MSG_ENABLED +RTC_NORETURN void FatalLog(const char* file, int line) { + std::string s; + AppendFormat(&s, + "\n\n" + "#\n" + "# Fatal error in: %s, line %d\n" + "# last system error: %u\n" + "# Check failed.\n" + "# ", + file, line, LAST_SYSTEM_ERROR); + WriteFatalLog(file, line, s); +} +#endif // RTC_CHECK_MSG_ENABLED + +#if RTC_DCHECK_IS_ON + +RTC_NORETURN void UnreachableCodeReached(const char* file, int line) { + std::string s; + AppendFormat(&s, + "\n\n" + "#\n" + "# Unreachable code reached: %s, line %d\n" + "# last system error: %u\n" + "# ", + file, line, LAST_SYSTEM_ERROR); + WriteFatalLog(file, line, s); +} + +#else // !RTC_DCHECK_IS_ON + +RTC_NORETURN void UnreachableCodeReached() { + std::string s; + AppendFormat(&s, + "\n\n" + "#\n" + "# Unreachable code reached (file and line unknown)\n" + "# last system error: %u\n" + "# ", + LAST_SYSTEM_ERROR); + WriteFatalLog(s); +} + +#endif // !RTC_DCHECK_IS_ON + +} // namespace webrtc_checks_impl +} // namespace rtc + +// Function to call from the C version of the RTC_CHECK and RTC_DCHECK macros. +RTC_NORETURN void rtc_FatalMessage(const char* file, + int line, + const char* msg) { +#if RTC_CHECK_MSG_ENABLED + static constexpr rtc::webrtc_checks_impl::CheckArgType t[] = { + rtc::webrtc_checks_impl::CheckArgType::kEnd}; + rtc::webrtc_checks_impl::FatalLog(file, line, msg, t); +#else + rtc::webrtc_checks_impl::FatalLog(file, line); +#endif +} diff --git a/third_party/libwebrtc/rtc_base/checks.h b/third_party/libwebrtc/rtc_base/checks.h new file mode 100644 index 0000000000..99fee97d0a --- /dev/null +++ b/third_party/libwebrtc/rtc_base/checks.h @@ -0,0 +1,520 @@ +/* + * Copyright 2006 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 RTC_BASE_CHECKS_H_ +#define RTC_BASE_CHECKS_H_ + +// If you for some reson need to know if DCHECKs are on, test the value of +// RTC_DCHECK_IS_ON. (Test its value, not if it's defined; it'll always be +// defined, to either a true or a false value.) +#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON) +#define RTC_DCHECK_IS_ON 1 +#else +#define RTC_DCHECK_IS_ON 0 +#endif + +// Annotate a function that will not return control flow to the caller. +#if defined(_MSC_VER) +#define RTC_NORETURN __declspec(noreturn) +#elif defined(__GNUC__) +#define RTC_NORETURN __attribute__((__noreturn__)) +#else +#define RTC_NORETURN +#endif + +#ifdef __cplusplus +extern "C" { +#endif +RTC_NORETURN void rtc_FatalMessage(const char* file, int line, const char* msg); +#ifdef __cplusplus +} // extern "C" +#endif + +#ifdef RTC_DISABLE_CHECK_MSG +#define RTC_CHECK_MSG_ENABLED 0 +#else +#define RTC_CHECK_MSG_ENABLED 1 +#endif + +#if RTC_CHECK_MSG_ENABLED +#define RTC_CHECK_EVAL_MESSAGE(message) message +#else +#define RTC_CHECK_EVAL_MESSAGE(message) "" +#endif + +#ifdef __cplusplus +// C++ version. + +#include <string> + +#include "absl/meta/type_traits.h" +#include "absl/strings/string_view.h" +#include "api/scoped_refptr.h" +#include "rtc_base/numerics/safe_compare.h" +#include "rtc_base/system/inline.h" +#include "rtc_base/system/rtc_export.h" + +// The macros here print a message to stderr and abort under various +// conditions. All will accept additional stream messages. For example: +// RTC_DCHECK_EQ(foo, bar) << "I'm printed when foo != bar."; +// +// - RTC_CHECK(x) is an assertion that x is always true, and that if it isn't, +// it's better to terminate the process than to continue. During development, +// the reason that it's better to terminate might simply be that the error +// handling code isn't in place yet; in production, the reason might be that +// the author of the code truly believes that x will always be true, but that +// they recognizes that if they are wrong, abrupt and unpleasant process +// termination is still better than carrying on with the assumption violated. +// +// RTC_CHECK always evaluates its argument, so it's OK for x to have side +// effects. +// +// - RTC_DCHECK(x) is the same as RTC_CHECK(x)---an assertion that x is always +// true---except that x will only be evaluated in debug builds; in production +// builds, x is simply assumed to be true. This is useful if evaluating x is +// expensive and the expected cost of failing to detect the violated +// assumption is acceptable. You should not handle cases where a production +// build fails to spot a violated condition, even those that would result in +// crashes. If the code needs to cope with the error, make it cope, but don't +// call RTC_DCHECK; if the condition really can't occur, but you'd sleep +// better at night knowing that the process will suicide instead of carrying +// on in case you were wrong, use RTC_CHECK instead of RTC_DCHECK. +// +// RTC_DCHECK only evaluates its argument in debug builds, so if x has visible +// side effects, you need to write e.g. +// bool w = x; RTC_DCHECK(w); +// +// - RTC_CHECK_EQ, _NE, _GT, ..., and RTC_DCHECK_EQ, _NE, _GT, ... are +// specialized variants of RTC_CHECK and RTC_DCHECK that print prettier +// messages if the condition doesn't hold. Prefer them to raw RTC_CHECK and +// RTC_DCHECK. +// +// - RTC_FATAL() aborts unconditionally. + +namespace rtc { +namespace webrtc_checks_impl { +enum class CheckArgType : int8_t { + kEnd = 0, + kInt, + kLong, + kLongLong, + kUInt, + kULong, + kULongLong, + kDouble, + kLongDouble, + kCharP, + kStdString, + kStringView, + kVoidP, + + // kCheckOp doesn't represent an argument type. Instead, it is sent as the + // first argument from RTC_CHECK_OP to make FatalLog use the next two + // arguments to build the special CHECK_OP error message + // (the "a == b (1 vs. 2)" bit). + kCheckOp, +}; + +// These two functions are public so they can be overridden from +// webrtc_overrides in chromium. +RTC_NORETURN void WriteFatalLog(const char* file, + int line, + absl::string_view output); +RTC_NORETURN void WriteFatalLog(absl::string_view output); + +#if RTC_CHECK_MSG_ENABLED +RTC_NORETURN RTC_EXPORT void FatalLog(const char* file, + int line, + const char* message, + const CheckArgType* fmt, + ...); +#else +RTC_NORETURN RTC_EXPORT void FatalLog(const char* file, int line); +#endif + +// Wrapper for log arguments. Only ever make values of this type with the +// MakeVal() functions. +template <CheckArgType N, typename T> +struct Val { + static constexpr CheckArgType Type() { return N; } + T GetVal() const { return val; } + T val; +}; + +// Case for when we need to construct a temp string and then print that. +// (We can't use Val<CheckArgType::kStdString, const std::string*> +// because we need somewhere to store the temp string.) +struct ToStringVal { + static constexpr CheckArgType Type() { return CheckArgType::kStdString; } + const std::string* GetVal() const { return &val; } + std::string val; +}; + +inline Val<CheckArgType::kInt, int> MakeVal(int x) { + return {x}; +} +inline Val<CheckArgType::kLong, long> MakeVal(long x) { + return {x}; +} +inline Val<CheckArgType::kLongLong, long long> MakeVal(long long x) { + return {x}; +} +inline Val<CheckArgType::kUInt, unsigned int> MakeVal(unsigned int x) { + return {x}; +} +inline Val<CheckArgType::kULong, unsigned long> MakeVal(unsigned long x) { + return {x}; +} +inline Val<CheckArgType::kULongLong, unsigned long long> MakeVal( + unsigned long long x) { + return {x}; +} + +inline Val<CheckArgType::kDouble, double> MakeVal(double x) { + return {x}; +} +inline Val<CheckArgType::kLongDouble, long double> MakeVal(long double x) { + return {x}; +} + +inline Val<CheckArgType::kCharP, const char*> MakeVal(const char* x) { + return {x}; +} +inline Val<CheckArgType::kStdString, const std::string*> MakeVal( + const std::string& x) { + return {&x}; +} +inline Val<CheckArgType::kStringView, const absl::string_view*> MakeVal( + const absl::string_view& x) { + return {&x}; +} + +inline Val<CheckArgType::kVoidP, const void*> MakeVal(const void* x) { + return {x}; +} + +template <typename T> +inline Val<CheckArgType::kVoidP, const void*> MakeVal( + const rtc::scoped_refptr<T>& p) { + return {p.get()}; +} + +// The enum class types are not implicitly convertible to arithmetic types. +template <typename T, + absl::enable_if_t<std::is_enum<T>::value && + !std::is_arithmetic<T>::value>* = nullptr> +inline decltype(MakeVal(std::declval<absl::underlying_type_t<T>>())) MakeVal( + T x) { + return {static_cast<absl::underlying_type_t<T>>(x)}; +} + +template <typename T, decltype(ToLogString(std::declval<T>()))* = nullptr> +ToStringVal MakeVal(const T& x) { + return {ToLogString(x)}; +} + +// Ephemeral type that represents the result of the logging << operator. +template <typename... Ts> +class LogStreamer; + +// Base case: Before the first << argument. +template <> +class LogStreamer<> final { + public: + template <typename U, + typename V = decltype(MakeVal(std::declval<U>())), + absl::enable_if_t<std::is_arithmetic<U>::value || + std::is_enum<U>::value>* = nullptr> + RTC_FORCE_INLINE LogStreamer<V> operator<<(U arg) const { + return LogStreamer<V>(MakeVal(arg), this); + } + + template <typename U, + typename V = decltype(MakeVal(std::declval<U>())), + absl::enable_if_t<!std::is_arithmetic<U>::value && + !std::is_enum<U>::value>* = nullptr> + RTC_FORCE_INLINE LogStreamer<V> operator<<(const U& arg) const { + return LogStreamer<V>(MakeVal(arg), this); + } + +#if RTC_CHECK_MSG_ENABLED + template <typename... Us> + RTC_NORETURN RTC_FORCE_INLINE static void Call(const char* file, + const int line, + const char* message, + const Us&... args) { + static constexpr CheckArgType t[] = {Us::Type()..., CheckArgType::kEnd}; + FatalLog(file, line, message, t, args.GetVal()...); + } + + template <typename... Us> + RTC_NORETURN RTC_FORCE_INLINE static void CallCheckOp(const char* file, + const int line, + const char* message, + const Us&... args) { + static constexpr CheckArgType t[] = {CheckArgType::kCheckOp, Us::Type()..., + CheckArgType::kEnd}; + FatalLog(file, line, message, t, args.GetVal()...); + } +#else + template <typename... Us> + RTC_NORETURN RTC_FORCE_INLINE static void Call(const char* file, + const int line) { + FatalLog(file, line); + } +#endif +}; + +// Inductive case: We've already seen at least one << argument. The most recent +// one had type `T`, and the earlier ones had types `Ts`. +template <typename T, typename... Ts> +class LogStreamer<T, Ts...> final { + public: + RTC_FORCE_INLINE LogStreamer(T arg, const LogStreamer<Ts...>* prior) + : arg_(arg), prior_(prior) {} + + template <typename U, + typename V = decltype(MakeVal(std::declval<U>())), + absl::enable_if_t<std::is_arithmetic<U>::value || + std::is_enum<U>::value>* = nullptr> + RTC_FORCE_INLINE LogStreamer<V, T, Ts...> operator<<(U arg) const { + return LogStreamer<V, T, Ts...>(MakeVal(arg), this); + } + + template <typename U, + typename V = decltype(MakeVal(std::declval<U>())), + absl::enable_if_t<!std::is_arithmetic<U>::value && + !std::is_enum<U>::value>* = nullptr> + RTC_FORCE_INLINE LogStreamer<V, T, Ts...> operator<<(const U& arg) const { + return LogStreamer<V, T, Ts...>(MakeVal(arg), this); + } + +#if RTC_CHECK_MSG_ENABLED + template <typename... Us> + RTC_NORETURN RTC_FORCE_INLINE void Call(const char* file, + const int line, + const char* message, + const Us&... args) const { + prior_->Call(file, line, message, arg_, args...); + } + + template <typename... Us> + RTC_NORETURN RTC_FORCE_INLINE void CallCheckOp(const char* file, + const int line, + const char* message, + const Us&... args) const { + prior_->CallCheckOp(file, line, message, arg_, args...); + } +#else + template <typename... Us> + RTC_NORETURN RTC_FORCE_INLINE void Call(const char* file, + const int line) const { + prior_->Call(file, line); + } +#endif + + private: + // The most recent argument. + T arg_; + + // Earlier arguments. + const LogStreamer<Ts...>* prior_; +}; + +template <bool isCheckOp> +class FatalLogCall final { + public: + FatalLogCall(const char* file, int line, const char* message) + : file_(file), line_(line), message_(message) {} + + // This can be any binary operator with precedence lower than <<. + template <typename... Ts> + RTC_NORETURN RTC_FORCE_INLINE void operator&( + const LogStreamer<Ts...>& streamer) { +#if RTC_CHECK_MSG_ENABLED + isCheckOp ? streamer.CallCheckOp(file_, line_, message_) + : streamer.Call(file_, line_, message_); +#else + streamer.Call(file_, line_); +#endif + } + + private: + const char* file_; + int line_; + const char* message_; +}; + +#if RTC_DCHECK_IS_ON + +// Be helpful, and include file and line in the RTC_CHECK_NOTREACHED error +// message. +#define RTC_UNREACHABLE_FILE_AND_LINE_CALL_ARGS __FILE__, __LINE__ +RTC_NORETURN RTC_EXPORT void UnreachableCodeReached(const char* file, int line); + +#else + +// Be mindful of binary size, and don't include file and line in the +// RTC_CHECK_NOTREACHED error message. +#define RTC_UNREACHABLE_FILE_AND_LINE_CALL_ARGS +RTC_NORETURN RTC_EXPORT void UnreachableCodeReached(); + +#endif + +} // namespace webrtc_checks_impl + +// The actual stream used isn't important. We reference `ignored` in the code +// but don't evaluate it; this is to avoid "unused variable" warnings (we do so +// in a particularly convoluted way with an extra ?: because that appears to be +// the simplest construct that keeps Visual Studio from complaining about +// condition being unused). +#define RTC_EAT_STREAM_PARAMETERS(ignored) \ + (true ? true : ((void)(ignored), true)) \ + ? static_cast<void>(0) \ + : ::rtc::webrtc_checks_impl::FatalLogCall<false>("", 0, "") & \ + ::rtc::webrtc_checks_impl::LogStreamer<>() + +// Call RTC_EAT_STREAM_PARAMETERS with an argument that fails to compile if +// values of the same types as `a` and `b` can't be compared with the given +// operation, and that would evaluate `a` and `b` if evaluated. +#define RTC_EAT_STREAM_PARAMETERS_OP(op, a, b) \ + RTC_EAT_STREAM_PARAMETERS(((void)::rtc::Safe##op(a, b))) + +// RTC_CHECK dies with a fatal error if condition is not true. It is *not* +// controlled by NDEBUG or anything else, so the check will be executed +// regardless of compilation mode. +// +// We make sure RTC_CHECK et al. always evaluates `condition`, as +// doing RTC_CHECK(FunctionWithSideEffect()) is a common idiom. +// +// RTC_CHECK_OP is a helper macro for binary operators. +// Don't use this macro directly in your code, use RTC_CHECK_EQ et al below. +#if RTC_CHECK_MSG_ENABLED +#define RTC_CHECK(condition) \ + (condition) ? static_cast<void>(0) \ + : ::rtc::webrtc_checks_impl::FatalLogCall<false>( \ + __FILE__, __LINE__, #condition) & \ + ::rtc::webrtc_checks_impl::LogStreamer<>() + +#define RTC_CHECK_OP(name, op, val1, val2) \ + ::rtc::Safe##name((val1), (val2)) \ + ? static_cast<void>(0) \ + : ::rtc::webrtc_checks_impl::FatalLogCall<true>( \ + __FILE__, __LINE__, #val1 " " #op " " #val2) & \ + ::rtc::webrtc_checks_impl::LogStreamer<>() << (val1) << (val2) +#else +#define RTC_CHECK(condition) \ + (condition) ? static_cast<void>(0) \ + : true ? ::rtc::webrtc_checks_impl::FatalLogCall<false>(__FILE__, __LINE__, \ + "") & \ + ::rtc::webrtc_checks_impl::LogStreamer<>() \ + : ::rtc::webrtc_checks_impl::FatalLogCall<false>("", 0, "") & \ + ::rtc::webrtc_checks_impl::LogStreamer<>() + +#define RTC_CHECK_OP(name, op, val1, val2) \ + ::rtc::Safe##name((val1), (val2)) ? static_cast<void>(0) \ + : true ? ::rtc::webrtc_checks_impl::FatalLogCall<true>(__FILE__, __LINE__, \ + "") & \ + ::rtc::webrtc_checks_impl::LogStreamer<>() \ + : ::rtc::webrtc_checks_impl::FatalLogCall<false>("", 0, "") & \ + ::rtc::webrtc_checks_impl::LogStreamer<>() +#endif + +#define RTC_CHECK_EQ(val1, val2) RTC_CHECK_OP(Eq, ==, val1, val2) +#define RTC_CHECK_NE(val1, val2) RTC_CHECK_OP(Ne, !=, val1, val2) +#define RTC_CHECK_LE(val1, val2) RTC_CHECK_OP(Le, <=, val1, val2) +#define RTC_CHECK_LT(val1, val2) RTC_CHECK_OP(Lt, <, val1, val2) +#define RTC_CHECK_GE(val1, val2) RTC_CHECK_OP(Ge, >=, val1, val2) +#define RTC_CHECK_GT(val1, val2) RTC_CHECK_OP(Gt, >, val1, val2) + +// The RTC_DCHECK macro is equivalent to RTC_CHECK except that it only generates +// code in debug builds. It does reference the condition parameter in all cases, +// though, so callers won't risk getting warnings about unused variables. +#if RTC_DCHECK_IS_ON +#define RTC_DCHECK(condition) RTC_CHECK(condition) +#define RTC_DCHECK_EQ(v1, v2) RTC_CHECK_EQ(v1, v2) +#define RTC_DCHECK_NE(v1, v2) RTC_CHECK_NE(v1, v2) +#define RTC_DCHECK_LE(v1, v2) RTC_CHECK_LE(v1, v2) +#define RTC_DCHECK_LT(v1, v2) RTC_CHECK_LT(v1, v2) +#define RTC_DCHECK_GE(v1, v2) RTC_CHECK_GE(v1, v2) +#define RTC_DCHECK_GT(v1, v2) RTC_CHECK_GT(v1, v2) +#else +#define RTC_DCHECK(condition) RTC_EAT_STREAM_PARAMETERS(condition) +#define RTC_DCHECK_EQ(v1, v2) RTC_EAT_STREAM_PARAMETERS_OP(Eq, v1, v2) +#define RTC_DCHECK_NE(v1, v2) RTC_EAT_STREAM_PARAMETERS_OP(Ne, v1, v2) +#define RTC_DCHECK_LE(v1, v2) RTC_EAT_STREAM_PARAMETERS_OP(Le, v1, v2) +#define RTC_DCHECK_LT(v1, v2) RTC_EAT_STREAM_PARAMETERS_OP(Lt, v1, v2) +#define RTC_DCHECK_GE(v1, v2) RTC_EAT_STREAM_PARAMETERS_OP(Ge, v1, v2) +#define RTC_DCHECK_GT(v1, v2) RTC_EAT_STREAM_PARAMETERS_OP(Gt, v1, v2) +#endif + +#define RTC_UNREACHABLE_CODE_HIT false +#define RTC_DCHECK_NOTREACHED() RTC_DCHECK(RTC_UNREACHABLE_CODE_HIT) + +// Kills the process with an error message. Never returns. Use when you wish to +// assert that a point in the code is never reached. +#define RTC_CHECK_NOTREACHED() \ + do { \ + ::rtc::webrtc_checks_impl::UnreachableCodeReached( \ + RTC_UNREACHABLE_FILE_AND_LINE_CALL_ARGS); \ + } while (0) + +#define RTC_FATAL() \ + ::rtc::webrtc_checks_impl::FatalLogCall<false>(__FILE__, __LINE__, \ + "FATAL()") & \ + ::rtc::webrtc_checks_impl::LogStreamer<>() + +// Performs the integer division a/b and returns the result. CHECKs that the +// remainder is zero. +template <typename T> +inline T CheckedDivExact(T a, T b) { + RTC_CHECK_EQ(a % b, 0) << a << " is not evenly divisible by " << b; + return a / b; +} + +} // namespace rtc + +#else // __cplusplus not defined +// C version. Lacks many features compared to the C++ version, but usage +// guidelines are the same. + +#define RTC_CHECK(condition) \ + do { \ + if (!(condition)) { \ + rtc_FatalMessage(__FILE__, __LINE__, \ + RTC_CHECK_EVAL_MESSAGE("CHECK failed: " #condition)); \ + } \ + } while (0) + +#define RTC_CHECK_EQ(a, b) RTC_CHECK((a) == (b)) +#define RTC_CHECK_NE(a, b) RTC_CHECK((a) != (b)) +#define RTC_CHECK_LE(a, b) RTC_CHECK((a) <= (b)) +#define RTC_CHECK_LT(a, b) RTC_CHECK((a) < (b)) +#define RTC_CHECK_GE(a, b) RTC_CHECK((a) >= (b)) +#define RTC_CHECK_GT(a, b) RTC_CHECK((a) > (b)) + +#define RTC_DCHECK(condition) \ + do { \ + if (RTC_DCHECK_IS_ON && !(condition)) { \ + rtc_FatalMessage(__FILE__, __LINE__, \ + RTC_CHECK_EVAL_MESSAGE("DCHECK failed: " #condition)); \ + } \ + } while (0) + +#define RTC_DCHECK_EQ(a, b) RTC_DCHECK((a) == (b)) +#define RTC_DCHECK_NE(a, b) RTC_DCHECK((a) != (b)) +#define RTC_DCHECK_LE(a, b) RTC_DCHECK((a) <= (b)) +#define RTC_DCHECK_LT(a, b) RTC_DCHECK((a) < (b)) +#define RTC_DCHECK_GE(a, b) RTC_DCHECK((a) >= (b)) +#define RTC_DCHECK_GT(a, b) RTC_DCHECK((a) > (b)) + +#endif // __cplusplus + +#endif // RTC_BASE_CHECKS_H_ diff --git a/third_party/libwebrtc/rtc_base/checks_gn/moz.build b/third_party/libwebrtc/rtc_base/checks_gn/moz.build new file mode 100644 index 0000000000..f2ef2e2a78 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/checks_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/rtc_base/checks.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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("checks_gn") diff --git a/third_party/libwebrtc/rtc_base/checks_unittest.cc b/third_party/libwebrtc/rtc_base/checks_unittest.cc new file mode 100644 index 0000000000..95deba9f1c --- /dev/null +++ b/third_party/libwebrtc/rtc_base/checks_unittest.cc @@ -0,0 +1,73 @@ +/* + * 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 "rtc_base/checks.h" + +#include "test/gtest.h" + +TEST(ChecksTest, ExpressionNotEvaluatedWhenCheckPassing) { + int i = 0; + RTC_CHECK(true) << "i=" << ++i; + RTC_CHECK_EQ(i, 0) << "Previous check passed, but i was incremented!"; +} + +#if GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID) +TEST(ChecksDeathTest, Checks) { +#if RTC_CHECK_MSG_ENABLED + EXPECT_DEATH(RTC_FATAL() << "message", + "\n\n#\n" + "# Fatal error in: \\S+, line \\w+\n" + "# last system error: \\w+\n" + "# Check failed: FATAL\\(\\)\n" + "# message"); + + int a = 1, b = 2; + EXPECT_DEATH(RTC_CHECK_EQ(a, b) << 1 << 2u, + "\n\n#\n" + "# Fatal error in: \\S+, line \\w+\n" + "# last system error: \\w+\n" + "# Check failed: a == b \\(1 vs. 2\\)\n" + "# 12"); + RTC_CHECK_EQ(5, 5); + + RTC_CHECK(true) << "Shouldn't crash" << 1; + EXPECT_DEATH(RTC_CHECK(false) << "Hi there!", + "\n\n#\n" + "# Fatal error in: \\S+, line \\w+\n" + "# last system error: \\w+\n" + "# Check failed: false\n" + "# Hi there!"); +#else + EXPECT_DEATH(RTC_FATAL() << "message", + "\n\n#\n" + "# Fatal error in: \\S+, line \\w+\n" + "# last system error: \\w+\n" + "# Check failed.\n" + "# "); + + int a = 1, b = 2; + EXPECT_DEATH(RTC_CHECK_EQ(a, b) << 1 << 2u, + "\n\n#\n" + "# Fatal error in: \\S+, line \\w+\n" + "# last system error: \\w+\n" + "# Check failed.\n" + "# "); + RTC_CHECK_EQ(5, 5); + + RTC_CHECK(true) << "Shouldn't crash" << 1; + EXPECT_DEATH(RTC_CHECK(false) << "Hi there!", + "\n\n#\n" + "# Fatal error in: \\S+, line \\w+\n" + "# last system error: \\w+\n" + "# Check failed.\n" + "# "); +#endif // RTC_CHECK_MSG_ENABLED +} +#endif // GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID) diff --git a/third_party/libwebrtc/rtc_base/compile_assert_c.h b/third_party/libwebrtc/rtc_base/compile_assert_c.h new file mode 100644 index 0000000000..db2e4a8116 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/compile_assert_c.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2012 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 RTC_BASE_COMPILE_ASSERT_C_H_ +#define RTC_BASE_COMPILE_ASSERT_C_H_ + +// Use this macro to verify at compile time that certain restrictions are met. +// The argument is the boolean expression to evaluate. +// Example: +// RTC_COMPILE_ASSERT(sizeof(foo) < 128); +// Note: In C++, use static_assert instead! +#define RTC_COMPILE_ASSERT(expression) \ + switch (0) { \ + case 0: \ + case expression:; \ + } + +#endif // RTC_BASE_COMPILE_ASSERT_C_H_ diff --git a/third_party/libwebrtc/rtc_base/compile_assert_c_gn/moz.build b/third_party/libwebrtc/rtc_base/compile_assert_c_gn/moz.build new file mode 100644 index 0000000000..9f6999032d --- /dev/null +++ b/third_party/libwebrtc/rtc_base/compile_assert_c_gn/moz.build @@ -0,0 +1,205 @@ +# 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("compile_assert_c_gn") diff --git a/third_party/libwebrtc/rtc_base/containers/BUILD.gn b/third_party/libwebrtc/rtc_base/containers/BUILD.gn new file mode 100644 index 0000000000..621b6122a3 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/containers/BUILD.gn @@ -0,0 +1,56 @@ +# Copyright (c) 2021 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("flat_containers_internal") { + sources = [ + "flat_tree.cc", + "flat_tree.h", + "identity.h", + "invoke.h", + "move_only_int.h", + ] + deps = [ + "..:checks", + "../system:no_unique_address", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/algorithm:container" ] + visibility = [ ":*" ] +} + +rtc_source_set("flat_set") { + sources = [ "flat_set.h" ] + deps = [ ":flat_containers_internal" ] +} + +rtc_source_set("flat_map") { + sources = [ "flat_map.h" ] + deps = [ + ":flat_containers_internal", + "..:checks", + ] +} + +rtc_library("unittests") { + testonly = true + sources = [ + "flat_map_unittest.cc", + "flat_set_unittest.cc", + "flat_tree_unittest.cc", + ] + deps = [ + ":flat_containers_internal", + ":flat_map", + ":flat_set", + "../../test:test_support", + "//testing/gmock:gmock", + "//testing/gtest:gtest", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/algorithm:container" ] +} diff --git a/third_party/libwebrtc/rtc_base/containers/flat_containers_internal_gn/moz.build b/third_party/libwebrtc/rtc_base/containers/flat_containers_internal_gn/moz.build new file mode 100644 index 0000000000..8fd59a6ce2 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/containers/flat_containers_internal_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/rtc_base/containers/flat_tree.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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("flat_containers_internal_gn") diff --git a/third_party/libwebrtc/rtc_base/containers/flat_map.h b/third_party/libwebrtc/rtc_base/containers/flat_map.h new file mode 100644 index 0000000000..d1f757f669 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/containers/flat_map.h @@ -0,0 +1,374 @@ +/* + * Copyright (c) 2021 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 implementation is borrowed from Chromium. + +#ifndef RTC_BASE_CONTAINERS_FLAT_MAP_H_ +#define RTC_BASE_CONTAINERS_FLAT_MAP_H_ + +#include <functional> +#include <tuple> +#include <utility> +#include <vector> + +#include "rtc_base/checks.h" +#include "rtc_base/containers/flat_tree.h" // IWYU pragma: export + +namespace webrtc { + +namespace flat_containers_internal { + +// An implementation of the flat_tree GetKeyFromValue template parameter that +// extracts the key as the first element of a pair. +struct GetFirst { + template <class Key, class Mapped> + constexpr const Key& operator()(const std::pair<Key, Mapped>& p) const { + return p.first; + } +}; + +} // namespace flat_containers_internal + +// flat_map is a container with a std::map-like interface that stores its +// contents in a sorted container, by default a vector. +// +// Its implementation mostly tracks the corresponding standardization proposal +// https://wg21.link/P0429, except that the storage of keys and values is not +// split. +// +// PROS +// +// - Good memory locality. +// - Low overhead, especially for smaller maps. +// - Performance is good for more workloads than you might expect (see +// //base/containers/README.md in Chromium repository) +// - Supports C++14 map interface. +// +// CONS +// +// - Inserts and removals are O(n). +// +// IMPORTANT NOTES +// +// - Iterators are invalidated across mutations. This means that the following +// line of code has undefined behavior since adding a new element could +// resize the container, invalidating all iterators: +// container["new element"] = it.second; +// - If possible, construct a flat_map in one operation by inserting into +// a container and moving that container into the flat_map constructor. +// +// QUICK REFERENCE +// +// Most of the core functionality is inherited from flat_tree. Please see +// flat_tree.h for more details for most of these functions. As a quick +// reference, the functions available are: +// +// Constructors (inputs need not be sorted): +// flat_map(const flat_map&); +// flat_map(flat_map&&); +// flat_map(InputIterator first, InputIterator last, +// const Compare& compare = Compare()); +// flat_map(const container_type& items, +// const Compare& compare = Compare()); +// flat_map(container_type&& items, +// const Compare& compare = Compare()); // Re-use storage. +// flat_map(std::initializer_list<value_type> ilist, +// const Compare& comp = Compare()); +// +// Constructors (inputs need to be sorted): +// flat_map(sorted_unique_t, +// InputIterator first, InputIterator last, +// const Compare& compare = Compare()); +// flat_map(sorted_unique_t, +// const container_type& items, +// const Compare& compare = Compare()); +// flat_map(sorted_unique_t, +// container_type&& items, +// const Compare& compare = Compare()); // Re-use storage. +// flat_map(sorted_unique_t, +// std::initializer_list<value_type> ilist, +// const Compare& comp = Compare()); +// +// Assignment functions: +// flat_map& operator=(const flat_map&); +// flat_map& operator=(flat_map&&); +// flat_map& operator=(initializer_list<value_type>); +// +// Memory management functions: +// void reserve(size_t); +// size_t capacity() const; +// void shrink_to_fit(); +// +// Size management functions: +// void clear(); +// size_t size() const; +// size_t max_size() const; +// bool empty() const; +// +// Iterator functions: +// iterator begin(); +// const_iterator begin() const; +// const_iterator cbegin() const; +// iterator end(); +// const_iterator end() const; +// const_iterator cend() const; +// reverse_iterator rbegin(); +// const reverse_iterator rbegin() const; +// const_reverse_iterator crbegin() const; +// reverse_iterator rend(); +// const_reverse_iterator rend() const; +// const_reverse_iterator crend() const; +// +// Insert and accessor functions: +// mapped_type& operator[](const key_type&); +// mapped_type& operator[](key_type&&); +// mapped_type& at(const K&); +// const mapped_type& at(const K&) const; +// pair<iterator, bool> insert(const value_type&); +// pair<iterator, bool> insert(value_type&&); +// iterator insert(const_iterator hint, const value_type&); +// iterator insert(const_iterator hint, value_type&&); +// void insert(InputIterator first, InputIterator last); +// pair<iterator, bool> insert_or_assign(K&&, M&&); +// iterator insert_or_assign(const_iterator hint, K&&, M&&); +// pair<iterator, bool> emplace(Args&&...); +// iterator emplace_hint(const_iterator, Args&&...); +// pair<iterator, bool> try_emplace(K&&, Args&&...); +// iterator try_emplace(const_iterator hint, K&&, Args&&...); + +// Underlying type functions: +// container_type extract() &&; +// void replace(container_type&&); +// +// Erase functions: +// iterator erase(iterator); +// iterator erase(const_iterator); +// iterator erase(const_iterator first, const_iterator& last); +// template <class K> size_t erase(const K& key); +// +// Comparators (see std::map documentation). +// key_compare key_comp() const; +// value_compare value_comp() const; +// +// Search functions: +// template <typename K> size_t count(const K&) const; +// template <typename K> iterator find(const K&); +// template <typename K> const_iterator find(const K&) const; +// template <typename K> bool contains(const K&) const; +// template <typename K> pair<iterator, iterator> equal_range(const K&); +// template <typename K> iterator lower_bound(const K&); +// template <typename K> const_iterator lower_bound(const K&) const; +// template <typename K> iterator upper_bound(const K&); +// template <typename K> const_iterator upper_bound(const K&) const; +// +// General functions: +// void swap(flat_map&); +// +// Non-member operators: +// bool operator==(const flat_map&, const flat_map); +// bool operator!=(const flat_map&, const flat_map); +// bool operator<(const flat_map&, const flat_map); +// bool operator>(const flat_map&, const flat_map); +// bool operator>=(const flat_map&, const flat_map); +// bool operator<=(const flat_map&, const flat_map); +// +template <class Key, + class Mapped, + class Compare = std::less<>, + class Container = std::vector<std::pair<Key, Mapped>>> +class flat_map : public ::webrtc::flat_containers_internal::flat_tree< + Key, + flat_containers_internal::GetFirst, + Compare, + Container> { + private: + using tree = typename ::webrtc::flat_containers_internal:: + flat_tree<Key, flat_containers_internal::GetFirst, Compare, Container>; + + public: + using key_type = typename tree::key_type; + using mapped_type = Mapped; + using value_type = typename tree::value_type; + using reference = typename Container::reference; + using const_reference = typename Container::const_reference; + using size_type = typename Container::size_type; + using difference_type = typename Container::difference_type; + using iterator = typename tree::iterator; + using const_iterator = typename tree::const_iterator; + using reverse_iterator = typename tree::reverse_iterator; + using const_reverse_iterator = typename tree::const_reverse_iterator; + using container_type = typename tree::container_type; + + // -------------------------------------------------------------------------- + // Lifetime and assignments. + // + // Note: we explicitly bring operator= in because otherwise + // flat_map<...> x; + // x = {...}; + // Would first create a flat_map and then move assign it. This most likely + // would be optimized away but still affects our debug builds. + + using tree::tree; + using tree::operator=; + + // Out-of-bound calls to at() will CHECK. + template <class K> + mapped_type& at(const K& key); + template <class K> + const mapped_type& at(const K& key) const; + + // -------------------------------------------------------------------------- + // Map-specific insert operations. + // + // Normal insert() functions are inherited from flat_tree. + // + // Assume that every operation invalidates iterators and references. + // Insertion of one element can take O(size). + + mapped_type& operator[](const key_type& key); + mapped_type& operator[](key_type&& key); + + template <class K, class M> + std::pair<iterator, bool> insert_or_assign(K&& key, M&& obj); + template <class K, class M> + iterator insert_or_assign(const_iterator hint, K&& key, M&& obj); + + template <class K, class... Args> + std::enable_if_t<std::is_constructible<key_type, K&&>::value, + std::pair<iterator, bool>> + try_emplace(K&& key, Args&&... args); + + template <class K, class... Args> + std::enable_if_t<std::is_constructible<key_type, K&&>::value, iterator> + try_emplace(const_iterator hint, K&& key, Args&&... args); + + // -------------------------------------------------------------------------- + // General operations. + // + // Assume that swap invalidates iterators and references. + + void swap(flat_map& other) noexcept; + + friend void swap(flat_map& lhs, flat_map& rhs) noexcept { lhs.swap(rhs); } +}; + +// ---------------------------------------------------------------------------- +// Lookups. + +template <class Key, class Mapped, class Compare, class Container> +template <class K> +auto flat_map<Key, Mapped, Compare, Container>::at(const K& key) + -> mapped_type& { + iterator found = tree::find(key); + RTC_CHECK(found != tree::end()); + return found->second; +} + +template <class Key, class Mapped, class Compare, class Container> +template <class K> +auto flat_map<Key, Mapped, Compare, Container>::at(const K& key) const + -> const mapped_type& { + const_iterator found = tree::find(key); + RTC_CHECK(found != tree::cend()); + return found->second; +} + +// ---------------------------------------------------------------------------- +// Insert operations. + +template <class Key, class Mapped, class Compare, class Container> +auto flat_map<Key, Mapped, Compare, Container>::operator[](const key_type& key) + -> mapped_type& { + iterator found = tree::lower_bound(key); + if (found == tree::end() || tree::key_comp()(key, found->first)) + found = tree::unsafe_emplace(found, key, mapped_type()); + return found->second; +} + +template <class Key, class Mapped, class Compare, class Container> +auto flat_map<Key, Mapped, Compare, Container>::operator[](key_type&& key) + -> mapped_type& { + iterator found = tree::lower_bound(key); + if (found == tree::end() || tree::key_comp()(key, found->first)) + found = tree::unsafe_emplace(found, std::move(key), mapped_type()); + return found->second; +} + +template <class Key, class Mapped, class Compare, class Container> +template <class K, class M> +auto flat_map<Key, Mapped, Compare, Container>::insert_or_assign(K&& key, + M&& obj) + -> std::pair<iterator, bool> { + auto result = + tree::emplace_key_args(key, std::forward<K>(key), std::forward<M>(obj)); + if (!result.second) + result.first->second = std::forward<M>(obj); + return result; +} + +template <class Key, class Mapped, class Compare, class Container> +template <class K, class M> +auto flat_map<Key, Mapped, Compare, Container>::insert_or_assign( + const_iterator hint, + K&& key, + M&& obj) -> iterator { + auto result = tree::emplace_hint_key_args(hint, key, std::forward<K>(key), + std::forward<M>(obj)); + if (!result.second) + result.first->second = std::forward<M>(obj); + return result.first; +} + +template <class Key, class Mapped, class Compare, class Container> +template <class K, class... Args> +auto flat_map<Key, Mapped, Compare, Container>::try_emplace(K&& key, + Args&&... args) + -> std::enable_if_t<std::is_constructible<key_type, K&&>::value, + std::pair<iterator, bool>> { + return tree::emplace_key_args( + key, std::piecewise_construct, + std::forward_as_tuple(std::forward<K>(key)), + std::forward_as_tuple(std::forward<Args>(args)...)); +} + +template <class Key, class Mapped, class Compare, class Container> +template <class K, class... Args> +auto flat_map<Key, Mapped, Compare, Container>::try_emplace(const_iterator hint, + K&& key, + Args&&... args) + -> std::enable_if_t<std::is_constructible<key_type, K&&>::value, iterator> { + return tree::emplace_hint_key_args( + hint, key, std::piecewise_construct, + std::forward_as_tuple(std::forward<K>(key)), + std::forward_as_tuple(std::forward<Args>(args)...)) + .first; +} + +// ---------------------------------------------------------------------------- +// General operations. + +template <class Key, class Mapped, class Compare, class Container> +void flat_map<Key, Mapped, Compare, Container>::swap(flat_map& other) noexcept { + tree::swap(other); +} + +// Erases all elements that match predicate. It has O(size) complexity. +// +// flat_map<int, Timestamp> last_times; +// ... +// EraseIf(last_times, +// [&](const auto& element) { return now - element.second > kLimit; }); + +// NOLINTNEXTLINE(misc-unused-using-decls) +using ::webrtc::flat_containers_internal::EraseIf; + +} // namespace webrtc + +#endif // RTC_BASE_CONTAINERS_FLAT_MAP_H_ diff --git a/third_party/libwebrtc/rtc_base/containers/flat_map_gn/moz.build b/third_party/libwebrtc/rtc_base/containers/flat_map_gn/moz.build new file mode 100644 index 0000000000..164aae2969 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/containers/flat_map_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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("flat_map_gn") diff --git a/third_party/libwebrtc/rtc_base/containers/flat_map_unittest.cc b/third_party/libwebrtc/rtc_base/containers/flat_map_unittest.cc new file mode 100644 index 0000000000..98846a0206 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/containers/flat_map_unittest.cc @@ -0,0 +1,455 @@ +/* + * Copyright (c) 2021 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 implementation is borrowed from Chromium. + +#include "rtc_base/containers/flat_map.h" + +#include <algorithm> +#include <string> +#include <type_traits> +#include <vector> + +#include "rtc_base/containers/move_only_int.h" +#include "test/gmock.h" +#include "test/gtest.h" + +// A flat_map is basically a interface to flat_tree. So several basic +// operations are tested to make sure things are set up properly, but the bulk +// of the tests are in flat_tree_unittests.cc. + +using ::testing::ElementsAre; + +namespace webrtc { + +namespace { + +struct Unsortable { + int value; +}; + +bool operator==(const Unsortable& lhs, const Unsortable& rhs) { + return lhs.value == rhs.value; +} + +bool operator<(const Unsortable& lhs, const Unsortable& rhs) = delete; +bool operator<=(const Unsortable& lhs, const Unsortable& rhs) = delete; +bool operator>(const Unsortable& lhs, const Unsortable& rhs) = delete; +bool operator>=(const Unsortable& lhs, const Unsortable& rhs) = delete; + +TEST(FlatMap, IncompleteType) { + struct A { + using Map = flat_map<A, A>; + int data; + Map set_with_incomplete_type; + Map::iterator it; + Map::const_iterator cit; + + // We do not declare operator< because clang complains that it's unused. + }; + + A a; +} + +TEST(FlatMap, RangeConstructor) { + flat_map<int, int>::value_type input_vals[] = { + {1, 1}, {1, 2}, {1, 3}, {2, 1}, {2, 2}, {2, 3}, {3, 1}, {3, 2}, {3, 3}}; + + flat_map<int, int> first(std::begin(input_vals), std::end(input_vals)); + EXPECT_THAT(first, ElementsAre(std::make_pair(1, 1), std::make_pair(2, 1), + std::make_pair(3, 1))); +} + +TEST(FlatMap, MoveConstructor) { + using pair = std::pair<MoveOnlyInt, MoveOnlyInt>; + + flat_map<MoveOnlyInt, MoveOnlyInt> original; + original.insert(pair(MoveOnlyInt(1), MoveOnlyInt(1))); + original.insert(pair(MoveOnlyInt(2), MoveOnlyInt(2))); + original.insert(pair(MoveOnlyInt(3), MoveOnlyInt(3))); + original.insert(pair(MoveOnlyInt(4), MoveOnlyInt(4))); + + flat_map<MoveOnlyInt, MoveOnlyInt> moved(std::move(original)); + + EXPECT_EQ(1U, moved.count(MoveOnlyInt(1))); + EXPECT_EQ(1U, moved.count(MoveOnlyInt(2))); + EXPECT_EQ(1U, moved.count(MoveOnlyInt(3))); + EXPECT_EQ(1U, moved.count(MoveOnlyInt(4))); +} + +TEST(FlatMap, VectorConstructor) { + using IntPair = std::pair<int, int>; + using IntMap = flat_map<int, int>; + std::vector<IntPair> vect{{1, 1}, {1, 2}, {2, 1}}; + IntMap map(std::move(vect)); + EXPECT_THAT(map, ElementsAre(IntPair(1, 1), IntPair(2, 1))); +} + +TEST(FlatMap, InitializerListConstructor) { + flat_map<int, int> cont( + {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}, {1, 2}, {10, 10}, {8, 8}}); + EXPECT_THAT(cont, ElementsAre(std::make_pair(1, 1), std::make_pair(2, 2), + std::make_pair(3, 3), std::make_pair(4, 4), + std::make_pair(5, 5), std::make_pair(8, 8), + std::make_pair(10, 10))); +} + +TEST(FlatMap, SortedRangeConstructor) { + using PairType = std::pair<int, Unsortable>; + using MapType = flat_map<int, Unsortable>; + MapType::value_type input_vals[] = {{1, {1}}, {2, {1}}, {3, {1}}}; + MapType map(sorted_unique, std::begin(input_vals), std::end(input_vals)); + EXPECT_THAT( + map, ElementsAre(PairType(1, {1}), PairType(2, {1}), PairType(3, {1}))); +} + +TEST(FlatMap, SortedCopyFromVectorConstructor) { + using PairType = std::pair<int, Unsortable>; + using MapType = flat_map<int, Unsortable>; + std::vector<PairType> vect{{1, {1}}, {2, {1}}}; + MapType map(sorted_unique, vect); + EXPECT_THAT(map, ElementsAre(PairType(1, {1}), PairType(2, {1}))); +} + +TEST(FlatMap, SortedMoveFromVectorConstructor) { + using PairType = std::pair<int, Unsortable>; + using MapType = flat_map<int, Unsortable>; + std::vector<PairType> vect{{1, {1}}, {2, {1}}}; + MapType map(sorted_unique, std::move(vect)); + EXPECT_THAT(map, ElementsAre(PairType(1, {1}), PairType(2, {1}))); +} + +TEST(FlatMap, SortedInitializerListConstructor) { + using PairType = std::pair<int, Unsortable>; + flat_map<int, Unsortable> map( + sorted_unique, + {{1, {1}}, {2, {2}}, {3, {3}}, {4, {4}}, {5, {5}}, {8, {8}}, {10, {10}}}); + EXPECT_THAT(map, + ElementsAre(PairType(1, {1}), PairType(2, {2}), PairType(3, {3}), + PairType(4, {4}), PairType(5, {5}), PairType(8, {8}), + PairType(10, {10}))); +} + +TEST(FlatMap, InitializerListAssignment) { + flat_map<int, int> cont; + cont = {{1, 1}, {2, 2}}; + EXPECT_THAT(cont, ElementsAre(std::make_pair(1, 1), std::make_pair(2, 2))); +} + +TEST(FlatMap, InsertFindSize) { + flat_map<int, int> s; + s.insert(std::make_pair(1, 1)); + s.insert(std::make_pair(1, 1)); + s.insert(std::make_pair(2, 2)); + + EXPECT_EQ(2u, s.size()); + EXPECT_EQ(std::make_pair(1, 1), *s.find(1)); + EXPECT_EQ(std::make_pair(2, 2), *s.find(2)); + EXPECT_EQ(s.end(), s.find(7)); +} + +TEST(FlatMap, CopySwap) { + flat_map<int, int> original; + original.insert({1, 1}); + original.insert({2, 2}); + EXPECT_THAT(original, + ElementsAre(std::make_pair(1, 1), std::make_pair(2, 2))); + + flat_map<int, int> copy(original); + EXPECT_THAT(copy, ElementsAre(std::make_pair(1, 1), std::make_pair(2, 2))); + + copy.erase(copy.begin()); + copy.insert({10, 10}); + EXPECT_THAT(copy, ElementsAre(std::make_pair(2, 2), std::make_pair(10, 10))); + + original.swap(copy); + EXPECT_THAT(original, + ElementsAre(std::make_pair(2, 2), std::make_pair(10, 10))); + EXPECT_THAT(copy, ElementsAre(std::make_pair(1, 1), std::make_pair(2, 2))); +} + +// operator[](const Key&) +TEST(FlatMap, SubscriptConstKey) { + flat_map<std::string, int> m; + + // Default construct elements that don't exist yet. + int& s = m["a"]; + EXPECT_EQ(0, s); + EXPECT_EQ(1u, m.size()); + + // The returned mapped reference should refer into the map. + s = 22; + EXPECT_EQ(22, m["a"]); + + // Overwrite existing elements. + m["a"] = 44; + EXPECT_EQ(44, m["a"]); +} + +// operator[](Key&&) +TEST(FlatMap, SubscriptMoveOnlyKey) { + flat_map<MoveOnlyInt, int> m; + + // Default construct elements that don't exist yet. + int& s = m[MoveOnlyInt(1)]; + EXPECT_EQ(0, s); + EXPECT_EQ(1u, m.size()); + + // The returned mapped reference should refer into the map. + s = 22; + EXPECT_EQ(22, m[MoveOnlyInt(1)]); + + // Overwrite existing elements. + m[MoveOnlyInt(1)] = 44; + EXPECT_EQ(44, m[MoveOnlyInt(1)]); +} + +// Mapped& at(const Key&) +// const Mapped& at(const Key&) const +TEST(FlatMap, AtFunction) { + flat_map<int, std::string> m = {{1, "a"}, {2, "b"}}; + + // Basic Usage. + EXPECT_EQ("a", m.at(1)); + EXPECT_EQ("b", m.at(2)); + + // Const reference works. + const std::string& const_ref = std::as_const(m).at(1); + EXPECT_EQ("a", const_ref); + + // Reference works, can operate on the string. + m.at(1)[0] = 'x'; + EXPECT_EQ("x", m.at(1)); + + // Out-of-bounds will CHECK. + EXPECT_DEATH_IF_SUPPORTED(m.at(-1), ""); + EXPECT_DEATH_IF_SUPPORTED({ m.at(-1)[0] = 'z'; }, ""); + + // Heterogeneous look-up works. + flat_map<std::string, int> m2 = {{"a", 1}, {"b", 2}}; + EXPECT_EQ(1, m2.at(absl::string_view("a"))); + EXPECT_EQ(2, std::as_const(m2).at(absl::string_view("b"))); +} + +// insert_or_assign(K&&, M&&) +TEST(FlatMap, InsertOrAssignMoveOnlyKey) { + flat_map<MoveOnlyInt, MoveOnlyInt> m; + + // Initial insertion should return an iterator to the element and set the + // second pair member to `true`. The inserted key and value should be moved + // from. + MoveOnlyInt key(1); + MoveOnlyInt val(22); + auto result = m.insert_or_assign(std::move(key), std::move(val)); + EXPECT_EQ(1, result.first->first.data()); + EXPECT_EQ(22, result.first->second.data()); + EXPECT_TRUE(result.second); + EXPECT_EQ(1u, m.size()); + EXPECT_EQ(0, key.data()); // moved from + EXPECT_EQ(0, val.data()); // moved from + + // Second call with same key should result in an assignment, overwriting the + // old value. Assignment should be indicated by setting the second pair member + // to `false`. Only the inserted value should be moved from, the key should be + // left intact. + key = MoveOnlyInt(1); + val = MoveOnlyInt(44); + result = m.insert_or_assign(std::move(key), std::move(val)); + EXPECT_EQ(1, result.first->first.data()); + EXPECT_EQ(44, result.first->second.data()); + EXPECT_FALSE(result.second); + EXPECT_EQ(1u, m.size()); + EXPECT_EQ(1, key.data()); // not moved from + EXPECT_EQ(0, val.data()); // moved from + + // Check that random insertion results in sorted range. + flat_map<MoveOnlyInt, int> map; + for (int i : {3, 1, 5, 6, 8, 7, 0, 9, 4, 2}) { + map.insert_or_assign(MoveOnlyInt(i), i); + EXPECT_TRUE(absl::c_is_sorted(map)); + } +} + +// insert_or_assign(const_iterator hint, K&&, M&&) +TEST(FlatMap, InsertOrAssignMoveOnlyKeyWithHint) { + flat_map<MoveOnlyInt, MoveOnlyInt> m; + + // Initial insertion should return an iterator to the element. The inserted + // key and value should be moved from. + MoveOnlyInt key(1); + MoveOnlyInt val(22); + auto result = m.insert_or_assign(m.end(), std::move(key), std::move(val)); + EXPECT_EQ(1, result->first.data()); + EXPECT_EQ(22, result->second.data()); + EXPECT_EQ(1u, m.size()); + EXPECT_EQ(0, key.data()); // moved from + EXPECT_EQ(0, val.data()); // moved from + + // Second call with same key should result in an assignment, overwriting the + // old value. Only the inserted value should be moved from, the key should be + // left intact. + key = MoveOnlyInt(1); + val = MoveOnlyInt(44); + result = m.insert_or_assign(m.end(), std::move(key), std::move(val)); + EXPECT_EQ(1, result->first.data()); + EXPECT_EQ(44, result->second.data()); + EXPECT_EQ(1u, m.size()); + EXPECT_EQ(1, key.data()); // not moved from + EXPECT_EQ(0, val.data()); // moved from + + // Check that random insertion results in sorted range. + flat_map<MoveOnlyInt, int> map; + for (int i : {3, 1, 5, 6, 8, 7, 0, 9, 4, 2}) { + map.insert_or_assign(map.end(), MoveOnlyInt(i), i); + EXPECT_TRUE(absl::c_is_sorted(map)); + } +} + +// try_emplace(K&&, Args&&...) +TEST(FlatMap, TryEmplaceMoveOnlyKey) { + flat_map<MoveOnlyInt, std::pair<MoveOnlyInt, MoveOnlyInt>> m; + + // Trying to emplace into an empty map should succeed. Insertion should return + // an iterator to the element and set the second pair member to `true`. The + // inserted key and value should be moved from. + MoveOnlyInt key(1); + MoveOnlyInt val1(22); + MoveOnlyInt val2(44); + // Test piecewise construction of mapped_type. + auto result = m.try_emplace(std::move(key), std::move(val1), std::move(val2)); + EXPECT_EQ(1, result.first->first.data()); + EXPECT_EQ(22, result.first->second.first.data()); + EXPECT_EQ(44, result.first->second.second.data()); + EXPECT_TRUE(result.second); + EXPECT_EQ(1u, m.size()); + EXPECT_EQ(0, key.data()); // moved from + EXPECT_EQ(0, val1.data()); // moved from + EXPECT_EQ(0, val2.data()); // moved from + + // Second call with same key should result in a no-op, returning an iterator + // to the existing element and returning false as the second pair member. + // Key and values that were attempted to be inserted should be left intact. + key = MoveOnlyInt(1); + auto paired_val = std::make_pair(MoveOnlyInt(33), MoveOnlyInt(55)); + // Test construction of mapped_type from pair. + result = m.try_emplace(std::move(key), std::move(paired_val)); + EXPECT_EQ(1, result.first->first.data()); + EXPECT_EQ(22, result.first->second.first.data()); + EXPECT_EQ(44, result.first->second.second.data()); + EXPECT_FALSE(result.second); + EXPECT_EQ(1u, m.size()); + EXPECT_EQ(1, key.data()); // not moved from + EXPECT_EQ(33, paired_val.first.data()); // not moved from + EXPECT_EQ(55, paired_val.second.data()); // not moved from + + // Check that random insertion results in sorted range. + flat_map<MoveOnlyInt, int> map; + for (int i : {3, 1, 5, 6, 8, 7, 0, 9, 4, 2}) { + map.try_emplace(MoveOnlyInt(i), i); + EXPECT_TRUE(absl::c_is_sorted(map)); + } +} + +// try_emplace(const_iterator hint, K&&, Args&&...) +TEST(FlatMap, TryEmplaceMoveOnlyKeyWithHint) { + flat_map<MoveOnlyInt, std::pair<MoveOnlyInt, MoveOnlyInt>> m; + + // Trying to emplace into an empty map should succeed. Insertion should return + // an iterator to the element. The inserted key and value should be moved + // from. + MoveOnlyInt key(1); + MoveOnlyInt val1(22); + MoveOnlyInt val2(44); + // Test piecewise construction of mapped_type. + auto result = + m.try_emplace(m.end(), std::move(key), std::move(val1), std::move(val2)); + EXPECT_EQ(1, result->first.data()); + EXPECT_EQ(22, result->second.first.data()); + EXPECT_EQ(44, result->second.second.data()); + EXPECT_EQ(1u, m.size()); + EXPECT_EQ(0, key.data()); // moved from + EXPECT_EQ(0, val1.data()); // moved from + EXPECT_EQ(0, val2.data()); // moved from + + // Second call with same key should result in a no-op, returning an iterator + // to the existing element. Key and values that were attempted to be inserted + // should be left intact. + key = MoveOnlyInt(1); + val1 = MoveOnlyInt(33); + val2 = MoveOnlyInt(55); + auto paired_val = std::make_pair(MoveOnlyInt(33), MoveOnlyInt(55)); + // Test construction of mapped_type from pair. + result = m.try_emplace(m.end(), std::move(key), std::move(paired_val)); + EXPECT_EQ(1, result->first.data()); + EXPECT_EQ(22, result->second.first.data()); + EXPECT_EQ(44, result->second.second.data()); + EXPECT_EQ(1u, m.size()); + EXPECT_EQ(1, key.data()); // not moved from + EXPECT_EQ(33, paired_val.first.data()); // not moved from + EXPECT_EQ(55, paired_val.second.data()); // not moved from + + // Check that random insertion results in sorted range. + flat_map<MoveOnlyInt, int> map; + for (int i : {3, 1, 5, 6, 8, 7, 0, 9, 4, 2}) { + map.try_emplace(map.end(), MoveOnlyInt(i), i); + EXPECT_TRUE(absl::c_is_sorted(map)); + } +} + +TEST(FlatMap, UsingTransparentCompare) { + using ExplicitInt = MoveOnlyInt; + flat_map<ExplicitInt, int> m; + const auto& m1 = m; + int x = 0; + + // Check if we can use lookup functions without converting to key_type. + // Correctness is checked in flat_tree tests. + m.count(x); + m1.count(x); + m.find(x); + m1.find(x); + m.equal_range(x); + m1.equal_range(x); + m.lower_bound(x); + m1.lower_bound(x); + m.upper_bound(x); + m1.upper_bound(x); + m.erase(x); + + // Check if we broke overload resolution. + m.emplace(ExplicitInt(0), 0); + m.emplace(ExplicitInt(1), 0); + m.erase(m.begin()); + m.erase(m.cbegin()); +} + +TEST(FlatMap, SupportsEraseIf) { + flat_map<MoveOnlyInt, MoveOnlyInt> m; + m.insert(std::make_pair(MoveOnlyInt(1), MoveOnlyInt(1))); + m.insert(std::make_pair(MoveOnlyInt(2), MoveOnlyInt(2))); + m.insert(std::make_pair(MoveOnlyInt(3), MoveOnlyInt(3))); + m.insert(std::make_pair(MoveOnlyInt(4), MoveOnlyInt(4))); + m.insert(std::make_pair(MoveOnlyInt(5), MoveOnlyInt(5))); + + EraseIf(m, [to_be_removed = MoveOnlyInt(2)]( + const std::pair<MoveOnlyInt, MoveOnlyInt>& e) { + return e.first == to_be_removed; + }); + + EXPECT_EQ(m.size(), 4u); + ASSERT_TRUE(m.find(MoveOnlyInt(1)) != m.end()); + ASSERT_FALSE(m.find(MoveOnlyInt(2)) != m.end()); + ASSERT_TRUE(m.find(MoveOnlyInt(3)) != m.end()); + ASSERT_TRUE(m.find(MoveOnlyInt(4)) != m.end()); + ASSERT_TRUE(m.find(MoveOnlyInt(5)) != m.end()); +} + +} // namespace +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/containers/flat_set.h b/third_party/libwebrtc/rtc_base/containers/flat_set.h new file mode 100644 index 0000000000..355690b09d --- /dev/null +++ b/third_party/libwebrtc/rtc_base/containers/flat_set.h @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2021 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 implementation is borrowed from Chromium. + +#ifndef RTC_BASE_CONTAINERS_FLAT_SET_H_ +#define RTC_BASE_CONTAINERS_FLAT_SET_H_ + +#include <functional> +#include <vector> + +#include "rtc_base/containers/flat_tree.h" // IWYU pragma: export +#include "rtc_base/containers/identity.h" + +namespace webrtc { + +// flat_set is a container with a std::set-like interface that stores its +// contents in a sorted container, by default a vector. +// +// Its implementation mostly tracks the corresponding standardization proposal +// https://wg21.link/P1222. +// +// +// PROS +// +// - Good memory locality. +// - Low overhead, especially for smaller sets. +// - Performance is good for more workloads than you might expect (see +// //base/containers/README.md in Chromium repository) +// - Supports C++14 set interface. +// +// CONS +// +// - Inserts and removals are O(n). +// +// IMPORTANT NOTES +// +// - Iterators are invalidated across mutations. +// - If possible, construct a flat_set in one operation by inserting into +// a container and moving that container into the flat_set constructor. +// - For multiple removals use base::EraseIf() which is O(n) rather than +// O(n * removed_items). +// +// QUICK REFERENCE +// +// Most of the core functionality is inherited from flat_tree. Please see +// flat_tree.h for more details for most of these functions. As a quick +// reference, the functions available are: +// +// Constructors (inputs need not be sorted): +// flat_set(const flat_set&); +// flat_set(flat_set&&); +// flat_set(InputIterator first, InputIterator last, +// const Compare& compare = Compare()); +// flat_set(const container_type& items, +// const Compare& compare = Compare()); +// flat_set(container_type&& items, +// const Compare& compare = Compare()); // Re-use storage. +// flat_set(std::initializer_list<value_type> ilist, +// const Compare& comp = Compare()); +// +// Constructors (inputs need to be sorted): +// flat_set(sorted_unique_t, +// InputIterator first, InputIterator last, +// const Compare& compare = Compare()); +// flat_set(sorted_unique_t, +// const container_type& items, +// const Compare& compare = Compare()); +// flat_set(sorted_unique_t, +// container_type&& items, +// const Compare& compare = Compare()); // Re-use storage. +// flat_set(sorted_unique_t, +// std::initializer_list<value_type> ilist, +// const Compare& comp = Compare()); +// +// Assignment functions: +// flat_set& operator=(const flat_set&); +// flat_set& operator=(flat_set&&); +// flat_set& operator=(initializer_list<Key>); +// +// Memory management functions: +// void reserve(size_t); +// size_t capacity() const; +// void shrink_to_fit(); +// +// Size management functions: +// void clear(); +// size_t size() const; +// size_t max_size() const; +// bool empty() const; +// +// Iterator functions: +// iterator begin(); +// const_iterator begin() const; +// const_iterator cbegin() const; +// iterator end(); +// const_iterator end() const; +// const_iterator cend() const; +// reverse_iterator rbegin(); +// const reverse_iterator rbegin() const; +// const_reverse_iterator crbegin() const; +// reverse_iterator rend(); +// const_reverse_iterator rend() const; +// const_reverse_iterator crend() const; +// +// Insert and accessor functions: +// pair<iterator, bool> insert(const key_type&); +// pair<iterator, bool> insert(key_type&&); +// void insert(InputIterator first, InputIterator last); +// iterator insert(const_iterator hint, const key_type&); +// iterator insert(const_iterator hint, key_type&&); +// pair<iterator, bool> emplace(Args&&...); +// iterator emplace_hint(const_iterator, Args&&...); +// +// Underlying type functions: +// container_type extract() &&; +// void replace(container_type&&); +// +// Erase functions: +// iterator erase(iterator); +// iterator erase(const_iterator); +// iterator erase(const_iterator first, const_iterator& last); +// template <typename K> size_t erase(const K& key); +// +// Comparators (see std::set documentation). +// key_compare key_comp() const; +// value_compare value_comp() const; +// +// Search functions: +// template <typename K> size_t count(const K&) const; +// template <typename K> iterator find(const K&); +// template <typename K> const_iterator find(const K&) const; +// template <typename K> bool contains(const K&) const; +// template <typename K> pair<iterator, iterator> equal_range(K&); +// template <typename K> iterator lower_bound(const K&); +// template <typename K> const_iterator lower_bound(const K&) const; +// template <typename K> iterator upper_bound(const K&); +// template <typename K> const_iterator upper_bound(const K&) const; +// +// General functions: +// void swap(flat_set&); +// +// Non-member operators: +// bool operator==(const flat_set&, const flat_set); +// bool operator!=(const flat_set&, const flat_set); +// bool operator<(const flat_set&, const flat_set); +// bool operator>(const flat_set&, const flat_set); +// bool operator>=(const flat_set&, const flat_set); +// bool operator<=(const flat_set&, const flat_set); +// +template <class Key, + class Compare = std::less<>, + class Container = std::vector<Key>> +using flat_set = typename ::webrtc::flat_containers_internal:: + flat_tree<Key, webrtc::identity, Compare, Container>; + +// ---------------------------------------------------------------------------- +// General operations. + +// Erases all elements that match predicate. It has O(size) complexity. +// +// flat_set<int> numbers; +// ... +// EraseIf(numbers, [](int number) { return number % 2 == 1; }); + +// NOLINTNEXTLINE(misc-unused-using-decls) +using ::webrtc::flat_containers_internal::EraseIf; + +} // namespace webrtc + +#endif // RTC_BASE_CONTAINERS_FLAT_SET_H_ diff --git a/third_party/libwebrtc/rtc_base/containers/flat_set_gn/moz.build b/third_party/libwebrtc/rtc_base/containers/flat_set_gn/moz.build new file mode 100644 index 0000000000..5283c7e3d3 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/containers/flat_set_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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("flat_set_gn") diff --git a/third_party/libwebrtc/rtc_base/containers/flat_set_unittest.cc b/third_party/libwebrtc/rtc_base/containers/flat_set_unittest.cc new file mode 100644 index 0000000000..617db92440 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/containers/flat_set_unittest.cc @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2021 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 implementation is borrowed from Chromium. + +#include "rtc_base/containers/flat_set.h" + +#include <algorithm> +#include <string> +#include <utility> +#include <vector> + +#include "rtc_base/containers/move_only_int.h" +#include "test/gmock.h" +#include "test/gtest.h" + +// A flat_set is basically a interface to flat_tree. So several basic +// operations are tested to make sure things are set up properly, but the bulk +// of the tests are in flat_tree_unittests.cc. + +using ::testing::ElementsAre; + +namespace webrtc { +namespace { + +TEST(FlatSet, IncompleteType) { + struct A { + using Set = flat_set<A>; + int data; + Set set_with_incomplete_type; + Set::iterator it; + Set::const_iterator cit; + + // We do not declare operator< because clang complains that it's unused. + }; + + A a; +} + +TEST(FlatSet, RangeConstructor) { + flat_set<int>::value_type input_vals[] = {1, 1, 1, 2, 2, 2, 3, 3, 3}; + + flat_set<int> cont(std::begin(input_vals), std::end(input_vals)); + EXPECT_THAT(cont, ElementsAre(1, 2, 3)); +} + +TEST(FlatSet, MoveConstructor) { + int input_range[] = {1, 2, 3, 4}; + + flat_set<MoveOnlyInt> original(std::begin(input_range), + std::end(input_range)); + flat_set<MoveOnlyInt> moved(std::move(original)); + + EXPECT_EQ(1U, moved.count(MoveOnlyInt(1))); + EXPECT_EQ(1U, moved.count(MoveOnlyInt(2))); + EXPECT_EQ(1U, moved.count(MoveOnlyInt(3))); + EXPECT_EQ(1U, moved.count(MoveOnlyInt(4))); +} + +TEST(FlatSet, InitializerListConstructor) { + flat_set<int> cont({1, 2, 3, 4, 5, 6, 10, 8}); + EXPECT_THAT(cont, ElementsAre(1, 2, 3, 4, 5, 6, 8, 10)); +} + +TEST(FlatSet, InsertFindSize) { + flat_set<int> s; + s.insert(1); + s.insert(1); + s.insert(2); + + EXPECT_EQ(2u, s.size()); + EXPECT_EQ(1, *s.find(1)); + EXPECT_EQ(2, *s.find(2)); + EXPECT_EQ(s.end(), s.find(7)); +} + +TEST(FlatSet, CopySwap) { + flat_set<int> original; + original.insert(1); + original.insert(2); + EXPECT_THAT(original, ElementsAre(1, 2)); + + flat_set<int> copy(original); + EXPECT_THAT(copy, ElementsAre(1, 2)); + + copy.erase(copy.begin()); + copy.insert(10); + EXPECT_THAT(copy, ElementsAre(2, 10)); + + original.swap(copy); + EXPECT_THAT(original, ElementsAre(2, 10)); + EXPECT_THAT(copy, ElementsAre(1, 2)); +} + +TEST(FlatSet, UsingTransparentCompare) { + using ExplicitInt = webrtc::MoveOnlyInt; + flat_set<ExplicitInt> s; + const auto& s1 = s; + int x = 0; + + // Check if we can use lookup functions without converting to key_type. + // Correctness is checked in flat_tree tests. + s.count(x); + s1.count(x); + s.find(x); + s1.find(x); + s.equal_range(x); + s1.equal_range(x); + s.lower_bound(x); + s1.lower_bound(x); + s.upper_bound(x); + s1.upper_bound(x); + s.erase(x); + + // Check if we broke overload resolution. + s.emplace(0); + s.emplace(1); + s.erase(s.begin()); + s.erase(s.cbegin()); +} + +TEST(FlatSet, SupportsEraseIf) { + flat_set<MoveOnlyInt> s; + s.emplace(MoveOnlyInt(1)); + s.emplace(MoveOnlyInt(2)); + s.emplace(MoveOnlyInt(3)); + s.emplace(MoveOnlyInt(4)); + s.emplace(MoveOnlyInt(5)); + + EraseIf(s, [to_be_removed = MoveOnlyInt(2)](const MoveOnlyInt& elem) { + return elem == to_be_removed; + }); + + EXPECT_EQ(s.size(), 4u); + ASSERT_TRUE(s.find(MoveOnlyInt(1)) != s.end()); + ASSERT_FALSE(s.find(MoveOnlyInt(2)) != s.end()); + ASSERT_TRUE(s.find(MoveOnlyInt(3)) != s.end()); + ASSERT_TRUE(s.find(MoveOnlyInt(4)) != s.end()); + ASSERT_TRUE(s.find(MoveOnlyInt(5)) != s.end()); +} +} // namespace +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/containers/flat_tree.cc b/third_party/libwebrtc/rtc_base/containers/flat_tree.cc new file mode 100644 index 0000000000..9e86db191a --- /dev/null +++ b/third_party/libwebrtc/rtc_base/containers/flat_tree.cc @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2021 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 implementation is borrowed from Chromium. + +#include "rtc_base/containers/flat_tree.h" + +namespace webrtc { + +sorted_unique_t sorted_unique; + +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/containers/flat_tree.h b/third_party/libwebrtc/rtc_base/containers/flat_tree.h new file mode 100644 index 0000000000..480784ced4 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/containers/flat_tree.h @@ -0,0 +1,1099 @@ +/* + * Copyright (c) 2021 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 implementation is borrowed from Chromium. + +#ifndef RTC_BASE_CONTAINERS_FLAT_TREE_H_ +#define RTC_BASE_CONTAINERS_FLAT_TREE_H_ + +#include <algorithm> +#include <iterator> +#include <type_traits> +#include <utility> +#include <vector> + +#include "absl/algorithm/container.h" +#include "rtc_base/checks.h" +#include "rtc_base/system/no_unique_address.h" + +namespace webrtc { +// Tag type that allows skipping the sort_and_unique step when constructing a +// flat_tree in case the underlying container is already sorted and has no +// duplicate elements. +struct sorted_unique_t { + constexpr sorted_unique_t() = default; +}; +extern sorted_unique_t sorted_unique; + +namespace flat_containers_internal { + +// Helper functions used in RTC_DCHECKs below to make sure that inputs tagged +// with sorted_unique are indeed sorted and unique. +template <typename Range, typename Comp> +constexpr bool is_sorted_and_unique(const Range& range, Comp comp) { + // Being unique implies that there are no adjacent elements that + // compare equal. So this checks that each element is strictly less + // than the element after it. + return absl::c_adjacent_find(range, std::not_fn(comp)) == std::end(range); +} + +// This is a convenience trait inheriting from std::true_type if Iterator is at +// least a ForwardIterator and thus supports multiple passes over a range. +template <class Iterator> +using is_multipass = + std::is_base_of<std::forward_iterator_tag, + typename std::iterator_traits<Iterator>::iterator_category>; + +// Uses SFINAE to detect whether type has is_transparent member. +template <typename T, typename = void> +struct IsTransparentCompare : std::false_type {}; +template <typename T> +struct IsTransparentCompare<T, std::void_t<typename T::is_transparent>> + : std::true_type {}; + +// Helper inspired by C++20's std::to_array to convert a C-style array to a +// std::array. As opposed to the C++20 version this implementation does not +// provide an overload for rvalues and does not strip cv qualifers from the +// returned std::array::value_type. The returned value_type needs to be +// specified explicitly, allowing the construction of std::arrays with const +// elements. +// +// Reference: https://en.cppreference.com/w/cpp/container/array/to_array +template <typename U, typename T, size_t N, size_t... I> +constexpr std::array<U, N> ToArrayImpl(const T (&data)[N], + std::index_sequence<I...>) { + return {{data[I]...}}; +} + +template <typename U, typename T, size_t N> +constexpr std::array<U, N> ToArray(const T (&data)[N]) { + return ToArrayImpl<U>(data, std::make_index_sequence<N>()); +} + +// std::pair's operator= is not constexpr prior to C++20. Thus we need this +// small helper to invoke operator= on the .first and .second member explicitly. +template <typename T> +constexpr void Assign(T& lhs, T&& rhs) { + lhs = std::move(rhs); +} + +template <typename T, typename U> +constexpr void Assign(std::pair<T, U>& lhs, std::pair<T, U>&& rhs) { + Assign(lhs.first, std::move(rhs.first)); + Assign(lhs.second, std::move(rhs.second)); +} + +// constexpr swap implementation. std::swap is not constexpr prior to C++20. +template <typename T> +constexpr void Swap(T& lhs, T& rhs) { + T tmp = std::move(lhs); + Assign(lhs, std::move(rhs)); + Assign(rhs, std::move(tmp)); +} + +// constexpr prev implementation. std::prev is not constexpr prior to C++17. +template <typename BidirIt> +constexpr BidirIt Prev(BidirIt it) { + return --it; +} + +// constexpr next implementation. std::next is not constexpr prior to C++17. +template <typename InputIt> +constexpr InputIt Next(InputIt it) { + return ++it; +} + +// constexpr sort implementation. std::sort is not constexpr prior to C++20. +// While insertion sort has a quadratic worst case complexity, it was chosen +// because it has linear complexity for nearly sorted data, is stable, and +// simple to implement. +template <typename BidirIt, typename Compare> +constexpr void InsertionSort(BidirIt first, BidirIt last, const Compare& comp) { + if (first == last) + return; + + for (auto it = Next(first); it != last; ++it) { + for (auto curr = it; curr != first && comp(*curr, *Prev(curr)); --curr) + Swap(*curr, *Prev(curr)); + } +} + +// Implementation ------------------------------------------------------------- + +// Implementation for the sorted associative flat_set and flat_map using a +// sorted vector as the backing store. Do not use directly. +// +// The use of "value" in this is like std::map uses, meaning it's the thing +// contained (in the case of map it's a <Kay, Mapped> pair). The Key is how +// things are looked up. In the case of a set, Key == Value. In the case of +// a map, the Key is a component of a Value. +// +// The helper class GetKeyFromValue provides the means to extract a key from a +// value for comparison purposes. It should implement: +// const Key& operator()(const Value&). +template <class Key, class GetKeyFromValue, class KeyCompare, class Container> +class flat_tree { + public: + // -------------------------------------------------------------------------- + // Types. + // + using key_type = Key; + using key_compare = KeyCompare; + using value_type = typename Container::value_type; + + // Wraps the templated key comparison to compare values. + struct value_compare { + constexpr bool operator()(const value_type& left, + const value_type& right) const { + GetKeyFromValue extractor; + return comp(extractor(left), extractor(right)); + } + + RTC_NO_UNIQUE_ADDRESS key_compare comp; + }; + + using pointer = typename Container::pointer; + using const_pointer = typename Container::const_pointer; + using reference = typename Container::reference; + using const_reference = typename Container::const_reference; + using size_type = typename Container::size_type; + using difference_type = typename Container::difference_type; + using iterator = typename Container::iterator; + using const_iterator = typename Container::const_iterator; + using reverse_iterator = typename Container::reverse_iterator; + using const_reverse_iterator = typename Container::const_reverse_iterator; + using container_type = Container; + + // -------------------------------------------------------------------------- + // Lifetime. + // + // Constructors that take range guarantee O(N * log^2(N)) + O(N) complexity + // and take O(N * log(N)) + O(N) if extra memory is available (N is a range + // length). + // + // Assume that move constructors invalidate iterators and references. + // + // The constructors that take ranges, lists, and vectors do not require that + // the input be sorted. + // + // When passing the webrtc::sorted_unique tag as the first argument no sort + // and unique step takes places. This is useful if the underlying container + // already has the required properties. + + flat_tree() = default; + flat_tree(const flat_tree&) = default; + flat_tree(flat_tree&&) = default; + + explicit flat_tree(const key_compare& comp); + + template <class InputIterator> + flat_tree(InputIterator first, + InputIterator last, + const key_compare& comp = key_compare()); + + flat_tree(const container_type& items, + const key_compare& comp = key_compare()); + + explicit flat_tree(container_type&& items, + const key_compare& comp = key_compare()); + + flat_tree(std::initializer_list<value_type> ilist, + const key_compare& comp = key_compare()); + + template <class InputIterator> + flat_tree(sorted_unique_t, + InputIterator first, + InputIterator last, + const key_compare& comp = key_compare()); + + flat_tree(sorted_unique_t, + const container_type& items, + const key_compare& comp = key_compare()); + + constexpr flat_tree(sorted_unique_t, + container_type&& items, + const key_compare& comp = key_compare()); + + flat_tree(sorted_unique_t, + std::initializer_list<value_type> ilist, + const key_compare& comp = key_compare()); + + ~flat_tree() = default; + + // -------------------------------------------------------------------------- + // Assignments. + // + // Assume that move assignment invalidates iterators and references. + + flat_tree& operator=(const flat_tree&) = default; + flat_tree& operator=(flat_tree&&) = default; + // Takes the first if there are duplicates in the initializer list. + flat_tree& operator=(std::initializer_list<value_type> ilist); + + // -------------------------------------------------------------------------- + // Memory management. + // + // Beware that shrink_to_fit() simply forwards the request to the + // container_type and its implementation is free to optimize otherwise and + // leave capacity() to be greater that its size. + // + // reserve() and shrink_to_fit() invalidate iterators and references. + + void reserve(size_type new_capacity); + size_type capacity() const; + void shrink_to_fit(); + + // -------------------------------------------------------------------------- + // Size management. + // + // clear() leaves the capacity() of the flat_tree unchanged. + + void clear(); + + constexpr size_type size() const; + constexpr size_type max_size() const; + constexpr bool empty() const; + + // -------------------------------------------------------------------------- + // Iterators. + // + // Iterators follow the ordering defined by the key comparator used in + // construction of the flat_tree. + + iterator begin(); + constexpr const_iterator begin() const; + const_iterator cbegin() const; + + iterator end(); + constexpr const_iterator end() const; + const_iterator cend() const; + + reverse_iterator rbegin(); + const_reverse_iterator rbegin() const; + const_reverse_iterator crbegin() const; + + reverse_iterator rend(); + const_reverse_iterator rend() const; + const_reverse_iterator crend() const; + + // -------------------------------------------------------------------------- + // Insert operations. + // + // Assume that every operation invalidates iterators and references. + // Insertion of one element can take O(size). Capacity of flat_tree grows in + // an implementation-defined manner. + // + // NOTE: Prefer to build a new flat_tree from a std::vector (or similar) + // instead of calling insert() repeatedly. + + std::pair<iterator, bool> insert(const value_type& val); + std::pair<iterator, bool> insert(value_type&& val); + + iterator insert(const_iterator position_hint, const value_type& x); + iterator insert(const_iterator position_hint, value_type&& x); + + // This method inserts the values from the range [first, last) into the + // current tree. + template <class InputIterator> + void insert(InputIterator first, InputIterator last); + + template <class... Args> + std::pair<iterator, bool> emplace(Args&&... args); + + template <class... Args> + iterator emplace_hint(const_iterator position_hint, Args&&... args); + + // -------------------------------------------------------------------------- + // Underlying type operations. + // + // Assume that either operation invalidates iterators and references. + + // Extracts the container_type and returns it to the caller. Ensures that + // `this` is `empty()` afterwards. + container_type extract() &&; + + // Replaces the container_type with `body`. Expects that `body` is sorted + // and has no repeated elements with regard to value_comp(). + void replace(container_type&& body); + + // -------------------------------------------------------------------------- + // Erase operations. + // + // Assume that every operation invalidates iterators and references. + // + // erase(position), erase(first, last) can take O(size). + // erase(key) may take O(size) + O(log(size)). + // + // Prefer webrtc::EraseIf() or some other variation on erase(remove(), end()) + // idiom when deleting multiple non-consecutive elements. + + iterator erase(iterator position); + // Artificially templatized to break ambiguity if `iterator` and + // `const_iterator` are the same type. + template <typename DummyT = void> + iterator erase(const_iterator position); + iterator erase(const_iterator first, const_iterator last); + template <typename K> + size_type erase(const K& key); + + // -------------------------------------------------------------------------- + // Comparators. + + constexpr key_compare key_comp() const; + constexpr value_compare value_comp() const; + + // -------------------------------------------------------------------------- + // Search operations. + // + // Search operations have O(log(size)) complexity. + + template <typename K> + size_type count(const K& key) const; + + template <typename K> + iterator find(const K& key); + + template <typename K> + const_iterator find(const K& key) const; + + template <typename K> + bool contains(const K& key) const; + + template <typename K> + std::pair<iterator, iterator> equal_range(const K& key); + + template <typename K> + std::pair<const_iterator, const_iterator> equal_range(const K& key) const; + + template <typename K> + iterator lower_bound(const K& key); + + template <typename K> + const_iterator lower_bound(const K& key) const; + + template <typename K> + iterator upper_bound(const K& key); + + template <typename K> + const_iterator upper_bound(const K& key) const; + + // -------------------------------------------------------------------------- + // General operations. + // + // Assume that swap invalidates iterators and references. + // + // Implementation note: currently we use operator==() and operator<() on + // std::vector, because they have the same contract we need, so we use them + // directly for brevity and in case it is more optimal than calling equal() + // and lexicograhpical_compare(). If the underlying container type is changed, + // this code may need to be modified. + + void swap(flat_tree& other) noexcept; + + friend bool operator==(const flat_tree& lhs, const flat_tree& rhs) { + return lhs.body_ == rhs.body_; + } + + friend bool operator!=(const flat_tree& lhs, const flat_tree& rhs) { + return !(lhs == rhs); + } + + friend bool operator<(const flat_tree& lhs, const flat_tree& rhs) { + return lhs.body_ < rhs.body_; + } + + friend bool operator>(const flat_tree& lhs, const flat_tree& rhs) { + return rhs < lhs; + } + + friend bool operator>=(const flat_tree& lhs, const flat_tree& rhs) { + return !(lhs < rhs); + } + + friend bool operator<=(const flat_tree& lhs, const flat_tree& rhs) { + return !(lhs > rhs); + } + + friend void swap(flat_tree& lhs, flat_tree& rhs) noexcept { lhs.swap(rhs); } + + protected: + // Emplaces a new item into the tree that is known not to be in it. This + // is for implementing map operator[]. + template <class... Args> + iterator unsafe_emplace(const_iterator position, Args&&... args); + + // Attempts to emplace a new element with key `key`. Only if `key` is not yet + // present, construct value_type from `args` and insert it. Returns an + // iterator to the element with key `key` and a bool indicating whether an + // insertion happened. + template <class K, class... Args> + std::pair<iterator, bool> emplace_key_args(const K& key, Args&&... args); + + // Similar to `emplace_key_args`, but checks `hint` first as a possible + // insertion position. + template <class K, class... Args> + std::pair<iterator, bool> emplace_hint_key_args(const_iterator hint, + const K& key, + Args&&... args); + + private: + // Helper class for e.g. lower_bound that can compare a value on the left + // to a key on the right. + struct KeyValueCompare { + // The key comparison object must outlive this class. + explicit KeyValueCompare(const key_compare& comp) : comp_(comp) {} + + template <typename T, typename U> + bool operator()(const T& lhs, const U& rhs) const { + return comp_(extract_if_value_type(lhs), extract_if_value_type(rhs)); + } + + private: + const key_type& extract_if_value_type(const value_type& v) const { + GetKeyFromValue extractor; + return extractor(v); + } + + template <typename K> + const K& extract_if_value_type(const K& k) const { + return k; + } + + const key_compare& comp_; + }; + + iterator const_cast_it(const_iterator c_it) { + auto distance = std::distance(cbegin(), c_it); + return std::next(begin(), distance); + } + + // This method is inspired by both std::map::insert(P&&) and + // std::map::insert_or_assign(const K&, V&&). It inserts val if an equivalent + // element is not present yet, otherwise it overwrites. It returns an iterator + // to the modified element and a flag indicating whether insertion or + // assignment happened. + template <class V> + std::pair<iterator, bool> insert_or_assign(V&& val) { + auto position = lower_bound(GetKeyFromValue()(val)); + + if (position == end() || value_comp()(val, *position)) + return {body_.emplace(position, std::forward<V>(val)), true}; + + *position = std::forward<V>(val); + return {position, false}; + } + + // This method is similar to insert_or_assign, with the following differences: + // - Instead of searching [begin(), end()) it only searches [first, last). + // - In case no equivalent element is found, val is appended to the end of the + // underlying body and an iterator to the next bigger element in [first, + // last) is returned. + template <class V> + std::pair<iterator, bool> append_or_assign(iterator first, + iterator last, + V&& val) { + auto position = std::lower_bound(first, last, val, value_comp()); + + if (position == last || value_comp()(val, *position)) { + // emplace_back might invalidate position, which is why distance needs to + // be cached. + const difference_type distance = std::distance(begin(), position); + body_.emplace_back(std::forward<V>(val)); + return {std::next(begin(), distance), true}; + } + + *position = std::forward<V>(val); + return {position, false}; + } + + // This method is similar to insert, with the following differences: + // - Instead of searching [begin(), end()) it only searches [first, last). + // - In case no equivalent element is found, val is appended to the end of the + // underlying body and an iterator to the next bigger element in [first, + // last) is returned. + template <class V> + std::pair<iterator, bool> append_unique(iterator first, + iterator last, + V&& val) { + auto position = std::lower_bound(first, last, val, value_comp()); + + if (position == last || value_comp()(val, *position)) { + // emplace_back might invalidate position, which is why distance needs to + // be cached. + const difference_type distance = std::distance(begin(), position); + body_.emplace_back(std::forward<V>(val)); + return {std::next(begin(), distance), true}; + } + + return {position, false}; + } + + void sort_and_unique(iterator first, iterator last) { + // Preserve stability for the unique code below. + std::stable_sort(first, last, value_comp()); + + // lhs is already <= rhs due to sort, therefore !(lhs < rhs) <=> lhs == rhs. + auto equal_comp = std::not_fn(value_comp()); + erase(std::unique(first, last, equal_comp), last); + } + + void sort_and_unique() { sort_and_unique(begin(), end()); } + + // To support comparators that may not be possible to default-construct, we + // have to store an instance of Compare. Since Compare commonly is stateless, + // we use the RTC_NO_UNIQUE_ADDRESS attribute to save space. + RTC_NO_UNIQUE_ADDRESS key_compare comp_; + // Declare after `key_compare_comp_` to workaround GCC ICE. For details + // see https://crbug.com/1156268 + container_type body_; + + // If the compare is not transparent we want to construct key_type once. + template <typename K> + using KeyTypeOrK = typename std:: + conditional<IsTransparentCompare<key_compare>::value, K, key_type>::type; +}; + +// ---------------------------------------------------------------------------- +// Lifetime. + +template <class Key, class GetKeyFromValue, class KeyCompare, class Container> +flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::flat_tree( + const KeyCompare& comp) + : comp_(comp) {} + +template <class Key, class GetKeyFromValue, class KeyCompare, class Container> +template <class InputIterator> +flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::flat_tree( + InputIterator first, + InputIterator last, + const KeyCompare& comp) + : comp_(comp), body_(first, last) { + sort_and_unique(); +} + +template <class Key, class GetKeyFromValue, class KeyCompare, class Container> +flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::flat_tree( + const container_type& items, + const KeyCompare& comp) + : comp_(comp), body_(items) { + sort_and_unique(); +} + +template <class Key, class GetKeyFromValue, class KeyCompare, class Container> +flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::flat_tree( + container_type&& items, + const KeyCompare& comp) + : comp_(comp), body_(std::move(items)) { + sort_and_unique(); +} + +template <class Key, class GetKeyFromValue, class KeyCompare, class Container> +flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::flat_tree( + std::initializer_list<value_type> ilist, + const KeyCompare& comp) + : flat_tree(std::begin(ilist), std::end(ilist), comp) {} + +template <class Key, class GetKeyFromValue, class KeyCompare, class Container> +template <class InputIterator> +flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::flat_tree( + sorted_unique_t, + InputIterator first, + InputIterator last, + const KeyCompare& comp) + : comp_(comp), body_(first, last) { + RTC_DCHECK(is_sorted_and_unique(*this, value_comp())); +} + +template <class Key, class GetKeyFromValue, class KeyCompare, class Container> +flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::flat_tree( + sorted_unique_t, + const container_type& items, + const KeyCompare& comp) + : comp_(comp), body_(items) { + RTC_DCHECK(is_sorted_and_unique(*this, value_comp())); +} + +template <class Key, class GetKeyFromValue, class KeyCompare, class Container> +constexpr flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::flat_tree( + sorted_unique_t, + container_type&& items, + const KeyCompare& comp) + : comp_(comp), body_(std::move(items)) { + RTC_DCHECK(is_sorted_and_unique(*this, value_comp())); +} + +template <class Key, class GetKeyFromValue, class KeyCompare, class Container> +flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::flat_tree( + sorted_unique_t, + std::initializer_list<value_type> ilist, + const KeyCompare& comp) + : flat_tree(sorted_unique, std::begin(ilist), std::end(ilist), comp) {} + +// ---------------------------------------------------------------------------- +// Assignments. + +template <class Key, class GetKeyFromValue, class KeyCompare, class Container> +auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::operator=( + std::initializer_list<value_type> ilist) -> flat_tree& { + body_ = ilist; + sort_and_unique(); + return *this; +} + +// ---------------------------------------------------------------------------- +// Memory management. + +template <class Key, class GetKeyFromValue, class KeyCompare, class Container> +void flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::reserve( + size_type new_capacity) { + body_.reserve(new_capacity); +} + +template <class Key, class GetKeyFromValue, class KeyCompare, class Container> +auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::capacity() const + -> size_type { + return body_.capacity(); +} + +template <class Key, class GetKeyFromValue, class KeyCompare, class Container> +void flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::shrink_to_fit() { + body_.shrink_to_fit(); +} + +// ---------------------------------------------------------------------------- +// Size management. + +template <class Key, class GetKeyFromValue, class KeyCompare, class Container> +void flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::clear() { + body_.clear(); +} + +template <class Key, class GetKeyFromValue, class KeyCompare, class Container> +constexpr auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::size() + const -> size_type { + return body_.size(); +} + +template <class Key, class GetKeyFromValue, class KeyCompare, class Container> +constexpr auto +flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::max_size() const + -> size_type { + return body_.max_size(); +} + +template <class Key, class GetKeyFromValue, class KeyCompare, class Container> +constexpr bool flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::empty() + const { + return body_.empty(); +} + +// ---------------------------------------------------------------------------- +// Iterators. + +template <class Key, class GetKeyFromValue, class KeyCompare, class Container> +auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::begin() + -> iterator { + return body_.begin(); +} + +template <class Key, class GetKeyFromValue, class KeyCompare, class Container> +constexpr auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::begin() + const -> const_iterator { + return std::begin(body_); +} + +template <class Key, class GetKeyFromValue, class KeyCompare, class Container> +auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::cbegin() const + -> const_iterator { + return body_.cbegin(); +} + +template <class Key, class GetKeyFromValue, class KeyCompare, class Container> +auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::end() -> iterator { + return body_.end(); +} + +template <class Key, class GetKeyFromValue, class KeyCompare, class Container> +constexpr auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::end() + const -> const_iterator { + return std::end(body_); +} + +template <class Key, class GetKeyFromValue, class KeyCompare, class Container> +auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::cend() const + -> const_iterator { + return body_.cend(); +} + +template <class Key, class GetKeyFromValue, class KeyCompare, class Container> +auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::rbegin() + -> reverse_iterator { + return body_.rbegin(); +} + +template <class Key, class GetKeyFromValue, class KeyCompare, class Container> +auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::rbegin() const + -> const_reverse_iterator { + return body_.rbegin(); +} + +template <class Key, class GetKeyFromValue, class KeyCompare, class Container> +auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::crbegin() const + -> const_reverse_iterator { + return body_.crbegin(); +} + +template <class Key, class GetKeyFromValue, class KeyCompare, class Container> +auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::rend() + -> reverse_iterator { + return body_.rend(); +} + +template <class Key, class GetKeyFromValue, class KeyCompare, class Container> +auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::rend() const + -> const_reverse_iterator { + return body_.rend(); +} + +template <class Key, class GetKeyFromValue, class KeyCompare, class Container> +auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::crend() const + -> const_reverse_iterator { + return body_.crend(); +} + +// ---------------------------------------------------------------------------- +// Insert operations. +// +// Currently we use position_hint the same way as eastl or boost: +// https://github.com/electronicarts/EASTL/blob/master/include/EASTL/vector_set.h#L493 + +template <class Key, class GetKeyFromValue, class KeyCompare, class Container> +auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::insert( + const value_type& val) -> std::pair<iterator, bool> { + return emplace_key_args(GetKeyFromValue()(val), val); +} + +template <class Key, class GetKeyFromValue, class KeyCompare, class Container> +auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::insert( + value_type&& val) -> std::pair<iterator, bool> { + return emplace_key_args(GetKeyFromValue()(val), std::move(val)); +} + +template <class Key, class GetKeyFromValue, class KeyCompare, class Container> +auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::insert( + const_iterator position_hint, + const value_type& val) -> iterator { + return emplace_hint_key_args(position_hint, GetKeyFromValue()(val), val) + .first; +} + +template <class Key, class GetKeyFromValue, class KeyCompare, class Container> +auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::insert( + const_iterator position_hint, + value_type&& val) -> iterator { + return emplace_hint_key_args(position_hint, GetKeyFromValue()(val), + std::move(val)) + .first; +} + +template <class Key, class GetKeyFromValue, class KeyCompare, class Container> +template <class InputIterator> +void flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::insert( + InputIterator first, + InputIterator last) { + if (first == last) + return; + + // Dispatch to single element insert if the input range contains a single + // element. + if (is_multipass<InputIterator>() && std::next(first) == last) { + insert(end(), *first); + return; + } + + // Provide a convenience lambda to obtain an iterator pointing past the last + // old element. This needs to be dymanic due to possible re-allocations. + auto middle = [this, size = size()] { return std::next(begin(), size); }; + + // For batch updates initialize the first insertion point. + difference_type pos_first_new = size(); + + // Loop over the input range while appending new values and overwriting + // existing ones, if applicable. Keep track of the first insertion point. + for (; first != last; ++first) { + std::pair<iterator, bool> result = append_unique(begin(), middle(), *first); + if (result.second) { + pos_first_new = + std::min(pos_first_new, std::distance(begin(), result.first)); + } + } + + // The new elements might be unordered and contain duplicates, so post-process + // the just inserted elements and merge them with the rest, inserting them at + // the previously found spot. + sort_and_unique(middle(), end()); + std::inplace_merge(std::next(begin(), pos_first_new), middle(), end(), + value_comp()); +} + +template <class Key, class GetKeyFromValue, class KeyCompare, class Container> +template <class... Args> +auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::emplace( + Args&&... args) -> std::pair<iterator, bool> { + return insert(value_type(std::forward<Args>(args)...)); +} + +template <class Key, class GetKeyFromValue, class KeyCompare, class Container> +template <class... Args> +auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::emplace_hint( + const_iterator position_hint, + Args&&... args) -> iterator { + return insert(position_hint, value_type(std::forward<Args>(args)...)); +} + +// ---------------------------------------------------------------------------- +// Underlying type operations. + +template <class Key, class GetKeyFromValue, class KeyCompare, class Container> +auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>:: + extract() && -> container_type { + return std::exchange(body_, container_type()); +} + +template <class Key, class GetKeyFromValue, class KeyCompare, class Container> +void flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::replace( + container_type&& body) { + // Ensure that `body` is sorted and has no repeated elements according to + // `value_comp()`. + RTC_DCHECK(is_sorted_and_unique(body, value_comp())); + body_ = std::move(body); +} + +// ---------------------------------------------------------------------------- +// Erase operations. + +template <class Key, class GetKeyFromValue, class KeyCompare, class Container> +auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::erase( + iterator position) -> iterator { + RTC_CHECK(position != body_.end()); + return body_.erase(position); +} + +template <class Key, class GetKeyFromValue, class KeyCompare, class Container> +template <typename DummyT> +auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::erase( + const_iterator position) -> iterator { + RTC_CHECK(position != body_.end()); + return body_.erase(position); +} + +template <class Key, class GetKeyFromValue, class KeyCompare, class Container> +template <typename K> +auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::erase(const K& val) + -> size_type { + auto eq_range = equal_range(val); + auto res = std::distance(eq_range.first, eq_range.second); + erase(eq_range.first, eq_range.second); + return res; +} + +template <class Key, class GetKeyFromValue, class KeyCompare, class Container> +auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::erase( + const_iterator first, + const_iterator last) -> iterator { + return body_.erase(first, last); +} + +// ---------------------------------------------------------------------------- +// Comparators. + +template <class Key, class GetKeyFromValue, class KeyCompare, class Container> +constexpr auto +flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::key_comp() const + -> key_compare { + return comp_; +} + +template <class Key, class GetKeyFromValue, class KeyCompare, class Container> +constexpr auto +flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::value_comp() const + -> value_compare { + return value_compare{comp_}; +} + +// ---------------------------------------------------------------------------- +// Search operations. + +template <class Key, class GetKeyFromValue, class KeyCompare, class Container> +template <typename K> +auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::count( + const K& key) const -> size_type { + auto eq_range = equal_range(key); + return std::distance(eq_range.first, eq_range.second); +} + +template <class Key, class GetKeyFromValue, class KeyCompare, class Container> +template <typename K> +auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::find(const K& key) + -> iterator { + return const_cast_it(std::as_const(*this).find(key)); +} + +template <class Key, class GetKeyFromValue, class KeyCompare, class Container> +template <typename K> +auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::find( + const K& key) const -> const_iterator { + auto eq_range = equal_range(key); + return (eq_range.first == eq_range.second) ? end() : eq_range.first; +} + +template <class Key, class GetKeyFromValue, class KeyCompare, class Container> +template <typename K> +bool flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::contains( + const K& key) const { + auto lower = lower_bound(key); + return lower != end() && !comp_(key, GetKeyFromValue()(*lower)); +} + +template <class Key, class GetKeyFromValue, class KeyCompare, class Container> +template <typename K> +auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::equal_range( + const K& key) -> std::pair<iterator, iterator> { + auto res = std::as_const(*this).equal_range(key); + return {const_cast_it(res.first), const_cast_it(res.second)}; +} + +template <class Key, class GetKeyFromValue, class KeyCompare, class Container> +template <typename K> +auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::equal_range( + const K& key) const -> std::pair<const_iterator, const_iterator> { + auto lower = lower_bound(key); + + KeyValueCompare comp(comp_); + if (lower == end() || comp(key, *lower)) + return {lower, lower}; + + return {lower, std::next(lower)}; +} + +template <class Key, class GetKeyFromValue, class KeyCompare, class Container> +template <typename K> +auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::lower_bound( + const K& key) -> iterator { + return const_cast_it(std::as_const(*this).lower_bound(key)); +} + +template <class Key, class GetKeyFromValue, class KeyCompare, class Container> +template <typename K> +auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::lower_bound( + const K& key) const -> const_iterator { + static_assert(std::is_convertible<const KeyTypeOrK<K>&, const K&>::value, + "Requested type cannot be bound to the container's key_type " + "which is required for a non-transparent compare."); + + const KeyTypeOrK<K>& key_ref = key; + + KeyValueCompare comp(comp_); + return absl::c_lower_bound(*this, key_ref, comp); +} + +template <class Key, class GetKeyFromValue, class KeyCompare, class Container> +template <typename K> +auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::upper_bound( + const K& key) -> iterator { + return const_cast_it(std::as_const(*this).upper_bound(key)); +} + +template <class Key, class GetKeyFromValue, class KeyCompare, class Container> +template <typename K> +auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::upper_bound( + const K& key) const -> const_iterator { + static_assert(std::is_convertible<const KeyTypeOrK<K>&, const K&>::value, + "Requested type cannot be bound to the container's key_type " + "which is required for a non-transparent compare."); + + const KeyTypeOrK<K>& key_ref = key; + + KeyValueCompare comp(comp_); + return absl::c_upper_bound(*this, key_ref, comp); +} + +// ---------------------------------------------------------------------------- +// General operations. + +template <class Key, class GetKeyFromValue, class KeyCompare, class Container> +void flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::swap( + flat_tree& other) noexcept { + std::swap(*this, other); +} + +template <class Key, class GetKeyFromValue, class KeyCompare, class Container> +template <class... Args> +auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::unsafe_emplace( + const_iterator position, + Args&&... args) -> iterator { + return body_.emplace(position, std::forward<Args>(args)...); +} + +template <class Key, class GetKeyFromValue, class KeyCompare, class Container> +template <class K, class... Args> +auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::emplace_key_args( + const K& key, + Args&&... args) -> std::pair<iterator, bool> { + auto lower = lower_bound(key); + if (lower == end() || comp_(key, GetKeyFromValue()(*lower))) + return {unsafe_emplace(lower, std::forward<Args>(args)...), true}; + return {lower, false}; +} + +template <class Key, class GetKeyFromValue, class KeyCompare, class Container> +template <class K, class... Args> +auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>:: + emplace_hint_key_args(const_iterator hint, const K& key, Args&&... args) + -> std::pair<iterator, bool> { + KeyValueCompare comp(comp_); + if ((hint == begin() || comp(*std::prev(hint), key))) { + if (hint == end() || comp(key, *hint)) { + // *(hint - 1) < key < *hint => key did not exist and hint is correct. + return {unsafe_emplace(hint, std::forward<Args>(args)...), true}; + } + if (!comp(*hint, key)) { + // key == *hint => no-op, return correct hint. + return {const_cast_it(hint), false}; + } + } + // hint was not helpful, dispatch to hintless version. + return emplace_key_args(key, std::forward<Args>(args)...); +} + +// ---------------------------------------------------------------------------- +// Free functions. + +// Erases all elements that match predicate. It has O(size) complexity. +template <class Key, + class GetKeyFromValue, + class KeyCompare, + class Container, + typename Predicate> +size_t EraseIf( + webrtc::flat_containers_internal:: + flat_tree<Key, GetKeyFromValue, KeyCompare, Container>& container, + Predicate pred) { + auto it = std::remove_if(container.begin(), container.end(), + std::forward<Predicate>(pred)); + size_t removed = std::distance(it, container.end()); + container.erase(it, container.end()); + return removed; +} + +} // namespace flat_containers_internal +} // namespace webrtc + +#endif // RTC_BASE_CONTAINERS_FLAT_TREE_H_ diff --git a/third_party/libwebrtc/rtc_base/containers/flat_tree_unittest.cc b/third_party/libwebrtc/rtc_base/containers/flat_tree_unittest.cc new file mode 100644 index 0000000000..9bb803d16d --- /dev/null +++ b/third_party/libwebrtc/rtc_base/containers/flat_tree_unittest.cc @@ -0,0 +1,1484 @@ +/* + * Copyright (c) 2021 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 implementation is borrowed from Chromium. + +#include "rtc_base/containers/flat_tree.h" + +// Following tests are ported and extended tests from libcpp for std::set. +// They can be found here: +// https://github.com/llvm/llvm-project/tree/main/libcxx/test/std/containers/associative/set +// +// Not ported tests: +// * No tests with PrivateConstructor and std::less<> changed to std::less<T> +// These tests have to do with C++14 std::less<> +// http://en.cppreference.com/w/cpp/utility/functional/less_void +// and add support for templated versions of lookup functions. +// Because we use same implementation, we figured that it's OK just to check +// compilation and this is what we do in flat_set_unittest/flat_map_unittest. +// * No tests for max_size() +// Has to do with allocator support. +// * No tests with DefaultOnly. +// Standard containers allocate each element in the separate node on the heap +// and then manipulate these nodes. Flat containers store their elements in +// contiguous memory and move them around, type is required to be movable. +// * No tests for N3644. +// This proposal suggests that all default constructed iterators compare +// equal. Currently we use std::vector iterators and they don't implement +// this. +// * No tests with min_allocator and no tests counting allocations. +// Flat sets currently don't support allocators. + +#include <array> +#include <deque> +#include <forward_list> +#include <functional> +#include <iterator> +#include <list> +#include <string> +#include <vector> + +#include "rtc_base/containers/identity.h" +#include "rtc_base/containers/move_only_int.h" +#include "test/gmock.h" +#include "test/gtest.h" + +namespace webrtc { +namespace flat_containers_internal { +namespace { + +template <class It> +class InputIterator { + public: + using iterator_category = std::input_iterator_tag; + using value_type = typename std::iterator_traits<It>::value_type; + using difference_type = typename std::iterator_traits<It>::difference_type; + using pointer = It; + using reference = typename std::iterator_traits<It>::reference; + + InputIterator() : it_() {} + explicit InputIterator(It it) : it_(it) {} + + reference operator*() const { return *it_; } + pointer operator->() const { return it_; } + + InputIterator& operator++() { + ++it_; + return *this; + } + InputIterator operator++(int) { + InputIterator tmp(*this); + ++(*this); + return tmp; + } + + friend bool operator==(const InputIterator& lhs, const InputIterator& rhs) { + return lhs.it_ == rhs.it_; + } + friend bool operator!=(const InputIterator& lhs, const InputIterator& rhs) { + return !(lhs == rhs); + } + + private: + It it_; +}; + +template <typename It> +InputIterator<It> MakeInputIterator(It it) { + return InputIterator<It>(it); +} + +class Emplaceable { + public: + Emplaceable() : Emplaceable(0, 0.0) {} + Emplaceable(int i, double d) : int_(i), double_(d) {} + Emplaceable(Emplaceable&& other) : int_(other.int_), double_(other.double_) { + other.int_ = 0; + other.double_ = 0.0; + } + Emplaceable(const Emplaceable&) = delete; + Emplaceable& operator=(const Emplaceable&) = delete; + + Emplaceable& operator=(Emplaceable&& other) { + int_ = other.int_; + other.int_ = 0; + double_ = other.double_; + other.double_ = 0.0; + return *this; + } + + friend bool operator==(const Emplaceable& lhs, const Emplaceable& rhs) { + return std::tie(lhs.int_, lhs.double_) == std::tie(rhs.int_, rhs.double_); + } + + friend bool operator<(const Emplaceable& lhs, const Emplaceable& rhs) { + return std::tie(lhs.int_, lhs.double_) < std::tie(rhs.int_, rhs.double_); + } + + private: + int int_; + double double_; +}; + +struct TemplateConstructor { + template <typename T> + explicit TemplateConstructor(const T&) {} + + friend bool operator<(const TemplateConstructor&, + const TemplateConstructor&) { + return false; + } +}; + +class NonDefaultConstructibleCompare { + public: + explicit NonDefaultConstructibleCompare(int) {} + + template <typename T> + bool operator()(const T& lhs, const T& rhs) const { + return std::less<T>()(lhs, rhs); + } +}; + +template <class PairType> +struct LessByFirst { + bool operator()(const PairType& lhs, const PairType& rhs) const { + return lhs.first < rhs.first; + } +}; + +// Common test trees. +template <typename ContainerT> +using TypedTree = flat_tree<typename ContainerT::value_type, + identity, + std::less<>, + ContainerT>; +using IntTree = TypedTree<std::vector<int>>; +using IntPair = std::pair<int, int>; +using IntPairTree = + flat_tree<IntPair, identity, LessByFirst<IntPair>, std::vector<IntPair>>; +using MoveOnlyTree = + flat_tree<MoveOnlyInt, identity, std::less<>, std::vector<MoveOnlyInt>>; +using EmplaceableTree = + flat_tree<Emplaceable, identity, std::less<>, std::vector<Emplaceable>>; +using ReversedTree = + flat_tree<int, identity, std::greater<int>, std::vector<int>>; + +using TreeWithStrangeCompare = + flat_tree<int, identity, NonDefaultConstructibleCompare, std::vector<int>>; + +using ::testing::ElementsAre; +using ::testing::IsEmpty; + +template <typename T> +class FlatTreeTest : public testing::Test {}; +TYPED_TEST_SUITE_P(FlatTreeTest); + +TEST(FlatTree, IsMultipass) { + static_assert(!is_multipass<std::istream_iterator<int>>(), + "InputIterator is not multipass"); + static_assert(!is_multipass<std::ostream_iterator<int>>(), + "OutputIterator is not multipass"); + + static_assert(is_multipass<std::forward_list<int>::iterator>(), + "ForwardIterator is multipass"); + static_assert(is_multipass<std::list<int>::iterator>(), + "BidirectionalIterator is multipass"); + static_assert(is_multipass<std::vector<int>::iterator>(), + "RandomAccessIterator is multipass"); +} + +// Tests that the compiler generated move operators propagrate noexcept +// specifiers. +TEST(FlatTree, NoExcept) { + struct MoveThrows { + MoveThrows(MoveThrows&&) noexcept(false) {} + MoveThrows& operator=(MoveThrows&&) noexcept(false) { return *this; } + }; + + using MoveThrowsTree = + flat_tree<MoveThrows, identity, std::less<>, std::array<MoveThrows, 1>>; + + static_assert(std::is_nothrow_move_constructible<IntTree>::value, + "Error: IntTree is not nothrow move constructible"); + static_assert(std::is_nothrow_move_assignable<IntTree>::value, + "Error: IntTree is not nothrow move assignable"); + + static_assert(!std::is_nothrow_move_constructible<MoveThrowsTree>::value, + "Error: MoveThrowsTree is nothrow move constructible"); + static_assert(!std::is_nothrow_move_assignable<MoveThrowsTree>::value, + "Error: MoveThrowsTree is nothrow move assignable"); +} + +// ---------------------------------------------------------------------------- +// Class. + +// Check that flat_tree and its iterators can be instantiated with an +// incomplete type. + +TEST(FlatTree, IncompleteType) { + struct A { + using Tree = flat_tree<A, identity, std::less<A>, std::vector<A>>; + int data; + Tree set_with_incomplete_type; + Tree::iterator it; + Tree::const_iterator cit; + + // We do not declare operator< because clang complains that it's unused. + }; + + A a; +} + +TEST(FlatTree, Stability) { + using Pair = std::pair<int, int>; + + using Tree = flat_tree<Pair, identity, LessByFirst<Pair>, std::vector<Pair>>; + + // Constructors are stable. + Tree cont({{0, 0}, {1, 0}, {0, 1}, {2, 0}, {0, 2}, {1, 1}}); + + auto AllOfSecondsAreZero = [&cont] { + return absl::c_all_of(cont, + [](const Pair& elem) { return elem.second == 0; }); + }; + + EXPECT_TRUE(AllOfSecondsAreZero()) << "constructor should be stable"; + + // Should not replace existing. + cont.insert(Pair(0, 2)); + cont.insert(Pair(1, 2)); + cont.insert(Pair(2, 2)); + + EXPECT_TRUE(AllOfSecondsAreZero()) << "insert should be stable"; + + cont.insert(Pair(3, 0)); + cont.insert(Pair(3, 2)); + + EXPECT_TRUE(AllOfSecondsAreZero()) << "insert should be stable"; +} + +// ---------------------------------------------------------------------------- +// Types. + +// key_type +// key_compare +// value_type +// value_compare +// pointer +// const_pointer +// reference +// const_reference +// size_type +// difference_type +// iterator +// const_iterator +// reverse_iterator +// const_reverse_iterator + +TEST(FlatTree, Types) { + // These are guaranteed to be portable. + static_assert((std::is_same<int, IntTree::key_type>::value), ""); + static_assert((std::is_same<int, IntTree::value_type>::value), ""); + static_assert((std::is_same<std::less<>, IntTree::key_compare>::value), ""); + static_assert((std::is_same<int&, IntTree::reference>::value), ""); + static_assert((std::is_same<const int&, IntTree::const_reference>::value), + ""); + static_assert((std::is_same<int*, IntTree::pointer>::value), ""); + static_assert((std::is_same<const int*, IntTree::const_pointer>::value), ""); +} + +// ---------------------------------------------------------------------------- +// Lifetime. + +// flat_tree() +// flat_tree(const Compare& comp) + +TYPED_TEST_P(FlatTreeTest, DefaultConstructor) { + { + TypedTree<TypeParam> cont; + EXPECT_THAT(cont, ElementsAre()); + } + + { + TreeWithStrangeCompare cont(NonDefaultConstructibleCompare(0)); + EXPECT_THAT(cont, ElementsAre()); + } +} + +// flat_tree(const flat_tree& x) + +TYPED_TEST_P(FlatTreeTest, CopyConstructor) { + TypedTree<TypeParam> original({1, 2, 3, 4}); + TypedTree<TypeParam> copied(original); + + EXPECT_THAT(copied, ElementsAre(1, 2, 3, 4)); + + EXPECT_THAT(copied, ElementsAre(1, 2, 3, 4)); + EXPECT_THAT(original, ElementsAre(1, 2, 3, 4)); + EXPECT_EQ(original, copied); +} + +// flat_tree(flat_tree&& x) + +TEST(FlatTree, MoveConstructor) { + int input_range[] = {1, 2, 3, 4}; + + MoveOnlyTree original(std::begin(input_range), std::end(input_range)); + MoveOnlyTree moved(std::move(original)); + + EXPECT_EQ(1U, moved.count(MoveOnlyInt(1))); + EXPECT_EQ(1U, moved.count(MoveOnlyInt(2))); + EXPECT_EQ(1U, moved.count(MoveOnlyInt(3))); + EXPECT_EQ(1U, moved.count(MoveOnlyInt(4))); +} + +// flat_tree(InputIterator first, +// InputIterator last, +// const Compare& comp = Compare()) + +TEST(FlatTree, RangeConstructor) { + { + IntPair input_vals[] = {{1, 1}, {1, 2}, {2, 1}, {2, 2}, {1, 3}, + {2, 3}, {3, 1}, {3, 2}, {3, 3}}; + + IntPairTree first_of(MakeInputIterator(std::begin(input_vals)), + MakeInputIterator(std::end(input_vals))); + EXPECT_THAT(first_of, + ElementsAre(IntPair(1, 1), IntPair(2, 1), IntPair(3, 1))); + } + { + TreeWithStrangeCompare::value_type input_vals[] = {1, 1, 1, 2, 2, + 2, 3, 3, 3}; + + TreeWithStrangeCompare cont(MakeInputIterator(std::begin(input_vals)), + MakeInputIterator(std::end(input_vals)), + NonDefaultConstructibleCompare(0)); + EXPECT_THAT(cont, ElementsAre(1, 2, 3)); + } +} + +// flat_tree(const container_type&) + +TYPED_TEST_P(FlatTreeTest, ContainerCopyConstructor) { + TypeParam items = {1, 2, 3, 4}; + TypedTree<TypeParam> tree(items); + + EXPECT_THAT(tree, ElementsAre(1, 2, 3, 4)); + EXPECT_THAT(items, ElementsAre(1, 2, 3, 4)); +} + +// flat_tree(container_type&&) + +TEST(FlatTree, ContainerMoveConstructor) { + using Pair = std::pair<int, MoveOnlyInt>; + + // Construct an unsorted vector with a duplicate item in it. Sorted by the + // first item, the second allows us to test for stability. Using a move + // only type to ensure the vector is not copied. + std::vector<Pair> storage; + storage.push_back(Pair(2, MoveOnlyInt(0))); + storage.push_back(Pair(1, MoveOnlyInt(0))); + storage.push_back(Pair(2, MoveOnlyInt(1))); + + using Tree = flat_tree<Pair, identity, LessByFirst<Pair>, std::vector<Pair>>; + Tree tree(std::move(storage)); + + // The list should be two items long, with only the first "2" saved. + ASSERT_EQ(2u, tree.size()); + const Pair& zeroth = *tree.begin(); + ASSERT_EQ(1, zeroth.first); + ASSERT_EQ(0, zeroth.second.data()); + + const Pair& first = *(tree.begin() + 1); + ASSERT_EQ(2, first.first); + ASSERT_EQ(0, first.second.data()); +} + +// flat_tree(std::initializer_list<value_type> ilist, +// const Compare& comp = Compare()) + +TYPED_TEST_P(FlatTreeTest, InitializerListConstructor) { + { + TypedTree<TypeParam> cont({1, 2, 3, 4, 5, 6, 10, 8}); + EXPECT_THAT(cont, ElementsAre(1, 2, 3, 4, 5, 6, 8, 10)); + } + { + TypedTree<TypeParam> cont({1, 2, 3, 4, 5, 6, 10, 8}); + EXPECT_THAT(cont, ElementsAre(1, 2, 3, 4, 5, 6, 8, 10)); + } + { + TreeWithStrangeCompare cont({1, 2, 3, 4, 5, 6, 10, 8}, + NonDefaultConstructibleCompare(0)); + EXPECT_THAT(cont, ElementsAre(1, 2, 3, 4, 5, 6, 8, 10)); + } + { + IntPairTree first_of({{1, 1}, {2, 1}, {1, 2}}); + EXPECT_THAT(first_of, ElementsAre(IntPair(1, 1), IntPair(2, 1))); + } +} + +// flat_tree(sorted_unique_t, +// InputIterator first, +// InputIterator last, +// const Compare& comp = Compare()) + +TEST(FlatTree, SortedUniqueRangeConstructor) { + { + IntPair input_vals[] = {{1, 1}, {2, 1}, {3, 1}}; + + IntPairTree first_of(sorted_unique, + MakeInputIterator(std::begin(input_vals)), + MakeInputIterator(std::end(input_vals))); + EXPECT_THAT(first_of, + ElementsAre(IntPair(1, 1), IntPair(2, 1), IntPair(3, 1))); + } + { + TreeWithStrangeCompare::value_type input_vals[] = {1, 2, 3}; + + TreeWithStrangeCompare cont(sorted_unique, + MakeInputIterator(std::begin(input_vals)), + MakeInputIterator(std::end(input_vals)), + NonDefaultConstructibleCompare(0)); + EXPECT_THAT(cont, ElementsAre(1, 2, 3)); + } +} + +// flat_tree(sorted_unique_t, const container_type&) + +TYPED_TEST_P(FlatTreeTest, SortedUniqueContainerCopyConstructor) { + TypeParam items = {1, 2, 3, 4}; + TypedTree<TypeParam> tree(sorted_unique, items); + + EXPECT_THAT(tree, ElementsAre(1, 2, 3, 4)); + EXPECT_THAT(items, ElementsAre(1, 2, 3, 4)); +} + +// flat_tree(sorted_unique_t, std::vector<value_type>&&) + +TEST(FlatTree, SortedUniqueVectorMoveConstructor) { + using Pair = std::pair<int, MoveOnlyInt>; + + std::vector<Pair> storage; + storage.push_back(Pair(1, MoveOnlyInt(0))); + storage.push_back(Pair(2, MoveOnlyInt(0))); + + using Tree = flat_tree<Pair, identity, LessByFirst<Pair>, std::vector<Pair>>; + Tree tree(sorted_unique, std::move(storage)); + + ASSERT_EQ(2u, tree.size()); + const Pair& zeroth = *tree.begin(); + ASSERT_EQ(1, zeroth.first); + ASSERT_EQ(0, zeroth.second.data()); + + const Pair& first = *(tree.begin() + 1); + ASSERT_EQ(2, first.first); + ASSERT_EQ(0, first.second.data()); +} + +// flat_tree(sorted_unique_t, +// std::initializer_list<value_type> ilist, +// const Compare& comp = Compare()) + +TYPED_TEST_P(FlatTreeTest, SortedUniqueInitializerListConstructor) { + { + TypedTree<TypeParam> cont(sorted_unique, {1, 2, 3, 4, 5, 6, 8, 10}); + EXPECT_THAT(cont, ElementsAre(1, 2, 3, 4, 5, 6, 8, 10)); + } + { + TypedTree<TypeParam> cont(sorted_unique, {1, 2, 3, 4, 5, 6, 8, 10}); + EXPECT_THAT(cont, ElementsAre(1, 2, 3, 4, 5, 6, 8, 10)); + } + { + TreeWithStrangeCompare cont(sorted_unique, {1, 2, 3, 4, 5, 6, 8, 10}, + NonDefaultConstructibleCompare(0)); + EXPECT_THAT(cont, ElementsAre(1, 2, 3, 4, 5, 6, 8, 10)); + } + { + IntPairTree first_of(sorted_unique, {{1, 1}, {2, 1}}); + EXPECT_THAT(first_of, ElementsAre(IntPair(1, 1), IntPair(2, 1))); + } +} + +// ---------------------------------------------------------------------------- +// Assignments. + +// flat_tree& operator=(const flat_tree&) + +TYPED_TEST_P(FlatTreeTest, CopyAssignable) { + TypedTree<TypeParam> original({1, 2, 3, 4}); + TypedTree<TypeParam> copied; + copied = original; + + EXPECT_THAT(copied, ElementsAre(1, 2, 3, 4)); + EXPECT_THAT(original, ElementsAre(1, 2, 3, 4)); + EXPECT_EQ(original, copied); +} + +// flat_tree& operator=(flat_tree&&) + +TEST(FlatTree, MoveAssignable) { + int input_range[] = {1, 2, 3, 4}; + + MoveOnlyTree original(std::begin(input_range), std::end(input_range)); + MoveOnlyTree moved; + moved = std::move(original); + + EXPECT_EQ(1U, moved.count(MoveOnlyInt(1))); + EXPECT_EQ(1U, moved.count(MoveOnlyInt(2))); + EXPECT_EQ(1U, moved.count(MoveOnlyInt(3))); + EXPECT_EQ(1U, moved.count(MoveOnlyInt(4))); +} + +// flat_tree& operator=(std::initializer_list<value_type> ilist) + +TYPED_TEST_P(FlatTreeTest, InitializerListAssignable) { + TypedTree<TypeParam> cont({0}); + cont = {1, 2, 3, 4, 5, 6, 10, 8}; + + EXPECT_EQ(0U, cont.count(0)); + EXPECT_THAT(cont, ElementsAre(1, 2, 3, 4, 5, 6, 8, 10)); +} + +// -------------------------------------------------------------------------- +// Memory management. + +// void reserve(size_type new_capacity) + +TEST(FlatTreeTest, Reserve) { + IntTree cont({1, 2, 3}); + + cont.reserve(5); + EXPECT_LE(5U, cont.capacity()); +} + +// size_type capacity() const + +TEST(FlatTreeTest, Capacity) { + IntTree cont({1, 2, 3}); + + EXPECT_LE(cont.size(), cont.capacity()); + cont.reserve(5); + EXPECT_LE(cont.size(), cont.capacity()); +} + +// void shrink_to_fit() + +TEST(FlatTreeTest, ShrinkToFit) { + IntTree cont({1, 2, 3}); + + IntTree::size_type capacity_before = cont.capacity(); + cont.shrink_to_fit(); + EXPECT_GE(capacity_before, cont.capacity()); +} + +// ---------------------------------------------------------------------------- +// Size management. + +// void clear() + +TYPED_TEST_P(FlatTreeTest, Clear) { + TypedTree<TypeParam> cont({1, 2, 3, 4, 5, 6, 7, 8}); + cont.clear(); + EXPECT_THAT(cont, ElementsAre()); +} + +// size_type size() const + +TYPED_TEST_P(FlatTreeTest, Size) { + TypedTree<TypeParam> cont; + + EXPECT_EQ(0U, cont.size()); + cont.insert(2); + EXPECT_EQ(1U, cont.size()); + cont.insert(1); + EXPECT_EQ(2U, cont.size()); + cont.insert(3); + EXPECT_EQ(3U, cont.size()); + cont.erase(cont.begin()); + EXPECT_EQ(2U, cont.size()); + cont.erase(cont.begin()); + EXPECT_EQ(1U, cont.size()); + cont.erase(cont.begin()); + EXPECT_EQ(0U, cont.size()); +} + +// bool empty() const + +TYPED_TEST_P(FlatTreeTest, Empty) { + TypedTree<TypeParam> cont; + + EXPECT_TRUE(cont.empty()); + cont.insert(1); + EXPECT_FALSE(cont.empty()); + cont.clear(); + EXPECT_TRUE(cont.empty()); +} + +// ---------------------------------------------------------------------------- +// Iterators. + +// iterator begin() +// const_iterator begin() const +// iterator end() +// const_iterator end() const +// +// reverse_iterator rbegin() +// const_reverse_iterator rbegin() const +// reverse_iterator rend() +// const_reverse_iterator rend() const +// +// const_iterator cbegin() const +// const_iterator cend() const +// const_reverse_iterator crbegin() const +// const_reverse_iterator crend() const + +TYPED_TEST_P(FlatTreeTest, Iterators) { + TypedTree<TypeParam> cont({1, 2, 3, 4, 5, 6, 7, 8}); + + auto size = + static_cast<typename TypedTree<TypeParam>::difference_type>(cont.size()); + + EXPECT_EQ(size, std::distance(cont.begin(), cont.end())); + EXPECT_EQ(size, std::distance(cont.cbegin(), cont.cend())); + EXPECT_EQ(size, std::distance(cont.rbegin(), cont.rend())); + EXPECT_EQ(size, std::distance(cont.crbegin(), cont.crend())); + + { + auto it = cont.begin(); + auto c_it = cont.cbegin(); + EXPECT_EQ(it, c_it); + for (int j = 1; it != cont.end(); ++it, ++c_it, ++j) { + EXPECT_EQ(j, *it); + EXPECT_EQ(j, *c_it); + } + } + { + auto rit = cont.rbegin(); + auto c_rit = cont.crbegin(); + EXPECT_EQ(rit, c_rit); + for (int j = static_cast<int>(size); rit != cont.rend(); + ++rit, ++c_rit, --j) { + EXPECT_EQ(j, *rit); + EXPECT_EQ(j, *c_rit); + } + } +} + +// ---------------------------------------------------------------------------- +// Insert operations. + +// pair<iterator, bool> insert(const value_type& val) + +TYPED_TEST_P(FlatTreeTest, InsertLValue) { + TypedTree<TypeParam> cont; + + int value = 2; + std::pair<typename TypedTree<TypeParam>::iterator, bool> result = + cont.insert(value); + EXPECT_TRUE(result.second); + EXPECT_EQ(cont.begin(), result.first); + EXPECT_EQ(1U, cont.size()); + EXPECT_EQ(2, *result.first); + + value = 1; + result = cont.insert(value); + EXPECT_TRUE(result.second); + EXPECT_EQ(cont.begin(), result.first); + EXPECT_EQ(2U, cont.size()); + EXPECT_EQ(1, *result.first); + + value = 3; + result = cont.insert(value); + EXPECT_TRUE(result.second); + EXPECT_EQ(std::prev(cont.end()), result.first); + EXPECT_EQ(3U, cont.size()); + EXPECT_EQ(3, *result.first); + + value = 3; + result = cont.insert(value); + EXPECT_FALSE(result.second); + EXPECT_EQ(std::prev(cont.end()), result.first); + EXPECT_EQ(3U, cont.size()); + EXPECT_EQ(3, *result.first); +} + +// pair<iterator, bool> insert(value_type&& val) + +TEST(FlatTree, InsertRValue) { + MoveOnlyTree cont; + + std::pair<MoveOnlyTree::iterator, bool> result = cont.insert(MoveOnlyInt(2)); + EXPECT_TRUE(result.second); + EXPECT_EQ(cont.begin(), result.first); + EXPECT_EQ(1U, cont.size()); + EXPECT_EQ(2, result.first->data()); + + result = cont.insert(MoveOnlyInt(1)); + EXPECT_TRUE(result.second); + EXPECT_EQ(cont.begin(), result.first); + EXPECT_EQ(2U, cont.size()); + EXPECT_EQ(1, result.first->data()); + + result = cont.insert(MoveOnlyInt(3)); + EXPECT_TRUE(result.second); + EXPECT_EQ(std::prev(cont.end()), result.first); + EXPECT_EQ(3U, cont.size()); + EXPECT_EQ(3, result.first->data()); + + result = cont.insert(MoveOnlyInt(3)); + EXPECT_FALSE(result.second); + EXPECT_EQ(std::prev(cont.end()), result.first); + EXPECT_EQ(3U, cont.size()); + EXPECT_EQ(3, result.first->data()); +} + +// iterator insert(const_iterator position_hint, const value_type& val) + +TYPED_TEST_P(FlatTreeTest, InsertPositionLValue) { + TypedTree<TypeParam> cont; + + auto result = cont.insert(cont.cend(), 2); + EXPECT_EQ(cont.begin(), result); + EXPECT_EQ(1U, cont.size()); + EXPECT_EQ(2, *result); + + result = cont.insert(cont.cend(), 1); + EXPECT_EQ(cont.begin(), result); + EXPECT_EQ(2U, cont.size()); + EXPECT_EQ(1, *result); + + result = cont.insert(cont.cend(), 3); + EXPECT_EQ(std::prev(cont.end()), result); + EXPECT_EQ(3U, cont.size()); + EXPECT_EQ(3, *result); + + result = cont.insert(cont.cend(), 3); + EXPECT_EQ(std::prev(cont.end()), result); + EXPECT_EQ(3U, cont.size()); + EXPECT_EQ(3, *result); +} + +// iterator insert(const_iterator position_hint, value_type&& val) + +TEST(FlatTree, InsertPositionRValue) { + MoveOnlyTree cont; + + auto result = cont.insert(cont.cend(), MoveOnlyInt(2)); + EXPECT_EQ(cont.begin(), result); + EXPECT_EQ(1U, cont.size()); + EXPECT_EQ(2, result->data()); + + result = cont.insert(cont.cend(), MoveOnlyInt(1)); + EXPECT_EQ(cont.begin(), result); + EXPECT_EQ(2U, cont.size()); + EXPECT_EQ(1, result->data()); + + result = cont.insert(cont.cend(), MoveOnlyInt(3)); + EXPECT_EQ(std::prev(cont.end()), result); + EXPECT_EQ(3U, cont.size()); + EXPECT_EQ(3, result->data()); + + result = cont.insert(cont.cend(), MoveOnlyInt(3)); + EXPECT_EQ(std::prev(cont.end()), result); + EXPECT_EQ(3U, cont.size()); + EXPECT_EQ(3, result->data()); +} + +// template <class InputIterator> +// void insert(InputIterator first, InputIterator last); + +TEST(FlatTree, InsertIterIter) { + struct GetKeyFromIntIntPair { + const int& operator()(const std::pair<int, int>& p) const { + return p.first; + } + }; + + using IntIntMap = flat_tree<int, GetKeyFromIntIntPair, std::less<int>, + std::vector<IntPair>>; + + { + IntIntMap cont; + IntPair int_pairs[] = {{3, 1}, {1, 1}, {4, 1}, {2, 1}}; + cont.insert(std::begin(int_pairs), std::end(int_pairs)); + EXPECT_THAT(cont, ElementsAre(IntPair(1, 1), IntPair(2, 1), IntPair(3, 1), + IntPair(4, 1))); + } + + { + IntIntMap cont({{1, 1}, {2, 1}, {3, 1}, {4, 1}}); + std::vector<IntPair> int_pairs; + cont.insert(std::begin(int_pairs), std::end(int_pairs)); + EXPECT_THAT(cont, ElementsAre(IntPair(1, 1), IntPair(2, 1), IntPair(3, 1), + IntPair(4, 1))); + } + + { + IntIntMap cont({{1, 1}, {2, 1}, {3, 1}, {4, 1}}); + IntPair int_pairs[] = {{1, 1}}; + cont.insert(std::begin(int_pairs), std::end(int_pairs)); + EXPECT_THAT(cont, ElementsAre(IntPair(1, 1), IntPair(2, 1), IntPair(3, 1), + IntPair(4, 1))); + } + + { + IntIntMap cont({{1, 1}, {2, 1}, {3, 1}, {4, 1}}); + IntPair int_pairs[] = {{5, 1}}; + cont.insert(std::begin(int_pairs), std::end(int_pairs)); + EXPECT_THAT(cont, ElementsAre(IntPair(1, 1), IntPair(2, 1), IntPair(3, 1), + IntPair(4, 1), IntPair(5, 1))); + } + + { + IntIntMap cont({{1, 1}, {2, 1}, {3, 1}, {4, 1}}); + IntPair int_pairs[] = {{3, 2}, {1, 2}, {4, 2}, {2, 2}}; + cont.insert(std::begin(int_pairs), std::end(int_pairs)); + EXPECT_THAT(cont, ElementsAre(IntPair(1, 1), IntPair(2, 1), IntPair(3, 1), + IntPair(4, 1))); + } + + { + IntIntMap cont({{1, 1}, {2, 1}, {3, 1}, {4, 1}}); + IntPair int_pairs[] = {{3, 2}, {1, 2}, {4, 2}, {2, 2}, {7, 2}, {6, 2}, + {8, 2}, {5, 2}, {5, 3}, {6, 3}, {7, 3}, {8, 3}}; + cont.insert(std::begin(int_pairs), std::end(int_pairs)); + EXPECT_THAT(cont, ElementsAre(IntPair(1, 1), IntPair(2, 1), IntPair(3, 1), + IntPair(4, 1), IntPair(5, 2), IntPair(6, 2), + IntPair(7, 2), IntPair(8, 2))); + } +} + +// template <class... Args> +// pair<iterator, bool> emplace(Args&&... args) + +TYPED_TEST_P(FlatTreeTest, Emplace) { + { + EmplaceableTree cont; + + std::pair<EmplaceableTree::iterator, bool> result = cont.emplace(); + EXPECT_TRUE(result.second); + EXPECT_EQ(cont.begin(), result.first); + EXPECT_EQ(1U, cont.size()); + EXPECT_EQ(Emplaceable(), *cont.begin()); + + result = cont.emplace(2, 3.5); + EXPECT_TRUE(result.second); + EXPECT_EQ(std::next(cont.begin()), result.first); + EXPECT_EQ(2U, cont.size()); + EXPECT_EQ(Emplaceable(2, 3.5), *result.first); + + result = cont.emplace(2, 3.5); + EXPECT_FALSE(result.second); + EXPECT_EQ(std::next(cont.begin()), result.first); + EXPECT_EQ(2U, cont.size()); + EXPECT_EQ(Emplaceable(2, 3.5), *result.first); + } + { + TypedTree<TypeParam> cont; + + std::pair<typename TypedTree<TypeParam>::iterator, bool> result = + cont.emplace(2); + EXPECT_TRUE(result.second); + EXPECT_EQ(cont.begin(), result.first); + EXPECT_EQ(1U, cont.size()); + EXPECT_EQ(2, *result.first); + } +} + +// template <class... Args> +// iterator emplace_hint(const_iterator position_hint, Args&&... args) + +TYPED_TEST_P(FlatTreeTest, EmplacePosition) { + { + EmplaceableTree cont; + + auto result = cont.emplace_hint(cont.cend()); + EXPECT_EQ(cont.begin(), result); + EXPECT_EQ(1U, cont.size()); + EXPECT_EQ(Emplaceable(), *cont.begin()); + + result = cont.emplace_hint(cont.cend(), 2, 3.5); + EXPECT_EQ(std::next(cont.begin()), result); + EXPECT_EQ(2U, cont.size()); + EXPECT_EQ(Emplaceable(2, 3.5), *result); + + result = cont.emplace_hint(cont.cbegin(), 2, 3.5); + EXPECT_EQ(std::next(cont.begin()), result); + EXPECT_EQ(2U, cont.size()); + EXPECT_EQ(Emplaceable(2, 3.5), *result); + } + { + TypedTree<TypeParam> cont; + + auto result = cont.emplace_hint(cont.cend(), 2); + EXPECT_EQ(cont.begin(), result); + EXPECT_EQ(1U, cont.size()); + EXPECT_EQ(2, *result); + } +} + +// ---------------------------------------------------------------------------- +// Underlying type operations. + +// underlying_type extract() && +TYPED_TEST_P(FlatTreeTest, Extract) { + TypedTree<TypeParam> cont; + cont.emplace(3); + cont.emplace(1); + cont.emplace(2); + cont.emplace(4); + + TypeParam body = std::move(cont).extract(); + EXPECT_THAT(cont, IsEmpty()); + EXPECT_THAT(body, ElementsAre(1, 2, 3, 4)); +} + +// replace(underlying_type&&) +TYPED_TEST_P(FlatTreeTest, Replace) { + TypeParam body = {1, 2, 3, 4}; + TypedTree<TypeParam> cont; + cont.replace(std::move(body)); + + EXPECT_THAT(cont, ElementsAre(1, 2, 3, 4)); +} + +// ---------------------------------------------------------------------------- +// Erase operations. + +// iterator erase(const_iterator position_hint) + +TYPED_TEST_P(FlatTreeTest, ErasePosition) { + { + TypedTree<TypeParam> cont({1, 2, 3, 4, 5, 6, 7, 8}); + + auto it = cont.erase(std::next(cont.cbegin(), 3)); + EXPECT_EQ(std::next(cont.begin(), 3), it); + EXPECT_THAT(cont, ElementsAre(1, 2, 3, 5, 6, 7, 8)); + + it = cont.erase(std::next(cont.cbegin(), 0)); + EXPECT_EQ(cont.begin(), it); + EXPECT_THAT(cont, ElementsAre(2, 3, 5, 6, 7, 8)); + + it = cont.erase(std::next(cont.cbegin(), 5)); + EXPECT_EQ(cont.end(), it); + EXPECT_THAT(cont, ElementsAre(2, 3, 5, 6, 7)); + + it = cont.erase(std::next(cont.cbegin(), 1)); + EXPECT_EQ(std::next(cont.begin()), it); + EXPECT_THAT(cont, ElementsAre(2, 5, 6, 7)); + + it = cont.erase(std::next(cont.cbegin(), 2)); + EXPECT_EQ(std::next(cont.begin(), 2), it); + EXPECT_THAT(cont, ElementsAre(2, 5, 7)); + + it = cont.erase(std::next(cont.cbegin(), 2)); + EXPECT_EQ(std::next(cont.begin(), 2), it); + EXPECT_THAT(cont, ElementsAre(2, 5)); + + it = cont.erase(std::next(cont.cbegin(), 0)); + EXPECT_EQ(std::next(cont.begin(), 0), it); + EXPECT_THAT(cont, ElementsAre(5)); + + it = cont.erase(cont.cbegin()); + EXPECT_EQ(cont.begin(), it); + EXPECT_EQ(cont.end(), it); + } + // This is LWG #2059. + // There is a potential ambiguity between erase with an iterator and erase + // with a key, if key has a templated constructor. + { + using T = TemplateConstructor; + + flat_tree<T, identity, std::less<>, std::vector<T>> cont; + T v(0); + + auto it = cont.find(v); + if (it != cont.end()) + cont.erase(it); + } +} + +// iterator erase(const_iterator first, const_iterator last) + +TYPED_TEST_P(FlatTreeTest, EraseRange) { + TypedTree<TypeParam> cont({1, 2, 3, 4, 5, 6, 7, 8}); + + auto it = + cont.erase(std::next(cont.cbegin(), 5), std::next(cont.cbegin(), 5)); + EXPECT_EQ(std::next(cont.begin(), 5), it); + EXPECT_THAT(cont, ElementsAre(1, 2, 3, 4, 5, 6, 7, 8)); + + it = cont.erase(std::next(cont.cbegin(), 3), std::next(cont.cbegin(), 4)); + EXPECT_EQ(std::next(cont.begin(), 3), it); + EXPECT_THAT(cont, ElementsAre(1, 2, 3, 5, 6, 7, 8)); + + it = cont.erase(std::next(cont.cbegin(), 2), std::next(cont.cbegin(), 5)); + EXPECT_EQ(std::next(cont.begin(), 2), it); + EXPECT_THAT(cont, ElementsAre(1, 2, 7, 8)); + + it = cont.erase(std::next(cont.cbegin(), 0), std::next(cont.cbegin(), 2)); + EXPECT_EQ(std::next(cont.begin(), 0), it); + EXPECT_THAT(cont, ElementsAre(7, 8)); + + it = cont.erase(cont.cbegin(), cont.cend()); + EXPECT_EQ(cont.begin(), it); + EXPECT_EQ(cont.end(), it); +} + +// size_type erase(const key_type& key) + +TYPED_TEST_P(FlatTreeTest, EraseKey) { + TypedTree<TypeParam> cont({1, 2, 3, 4, 5, 6, 7, 8}); + + EXPECT_EQ(0U, cont.erase(9)); + EXPECT_THAT(cont, ElementsAre(1, 2, 3, 4, 5, 6, 7, 8)); + + EXPECT_EQ(1U, cont.erase(4)); + EXPECT_THAT(cont, ElementsAre(1, 2, 3, 5, 6, 7, 8)); + + EXPECT_EQ(1U, cont.erase(1)); + EXPECT_THAT(cont, ElementsAre(2, 3, 5, 6, 7, 8)); + + EXPECT_EQ(1U, cont.erase(8)); + EXPECT_THAT(cont, ElementsAre(2, 3, 5, 6, 7)); + + EXPECT_EQ(1U, cont.erase(3)); + EXPECT_THAT(cont, ElementsAre(2, 5, 6, 7)); + + EXPECT_EQ(1U, cont.erase(6)); + EXPECT_THAT(cont, ElementsAre(2, 5, 7)); + + EXPECT_EQ(1U, cont.erase(7)); + EXPECT_THAT(cont, ElementsAre(2, 5)); + + EXPECT_EQ(1U, cont.erase(2)); + EXPECT_THAT(cont, ElementsAre(5)); + + EXPECT_EQ(1U, cont.erase(5)); + EXPECT_THAT(cont, ElementsAre()); +} + +TYPED_TEST_P(FlatTreeTest, EraseEndDeath) { + { + TypedTree<TypeParam> tree; + ASSERT_DEATH_IF_SUPPORTED(tree.erase(tree.cend()), ""); + } + + { + TypedTree<TypeParam> tree = {1, 2, 3, 4}; + ASSERT_DEATH_IF_SUPPORTED(tree.erase(tree.find(5)), ""); + } +} + +// ---------------------------------------------------------------------------- +// Comparators. + +// key_compare key_comp() const + +TEST(FlatTree, KeyComp) { + ReversedTree cont({1, 2, 3, 4, 5}); + + EXPECT_TRUE(absl::c_is_sorted(cont, cont.key_comp())); + int new_elements[] = {6, 7, 8, 9, 10}; + std::copy(std::begin(new_elements), std::end(new_elements), + std::inserter(cont, cont.end())); + EXPECT_TRUE(absl::c_is_sorted(cont, cont.key_comp())); +} + +// value_compare value_comp() const + +TEST(FlatTree, ValueComp) { + ReversedTree cont({1, 2, 3, 4, 5}); + + EXPECT_TRUE(absl::c_is_sorted(cont, cont.value_comp())); + int new_elements[] = {6, 7, 8, 9, 10}; + std::copy(std::begin(new_elements), std::end(new_elements), + std::inserter(cont, cont.end())); + EXPECT_TRUE(absl::c_is_sorted(cont, cont.value_comp())); +} + +// ---------------------------------------------------------------------------- +// Search operations. + +// size_type count(const key_type& key) const + +TYPED_TEST_P(FlatTreeTest, Count) { + const TypedTree<TypeParam> cont({5, 6, 7, 8, 9, 10, 11, 12}); + + EXPECT_EQ(1U, cont.count(5)); + EXPECT_EQ(1U, cont.count(6)); + EXPECT_EQ(1U, cont.count(7)); + EXPECT_EQ(1U, cont.count(8)); + EXPECT_EQ(1U, cont.count(9)); + EXPECT_EQ(1U, cont.count(10)); + EXPECT_EQ(1U, cont.count(11)); + EXPECT_EQ(1U, cont.count(12)); + EXPECT_EQ(0U, cont.count(4)); +} + +// iterator find(const key_type& key) +// const_iterator find(const key_type& key) const + +TYPED_TEST_P(FlatTreeTest, Find) { + { + TypedTree<TypeParam> cont({5, 6, 7, 8, 9, 10, 11, 12}); + + EXPECT_EQ(cont.begin(), cont.find(5)); + EXPECT_EQ(std::next(cont.begin()), cont.find(6)); + EXPECT_EQ(std::next(cont.begin(), 2), cont.find(7)); + EXPECT_EQ(std::next(cont.begin(), 3), cont.find(8)); + EXPECT_EQ(std::next(cont.begin(), 4), cont.find(9)); + EXPECT_EQ(std::next(cont.begin(), 5), cont.find(10)); + EXPECT_EQ(std::next(cont.begin(), 6), cont.find(11)); + EXPECT_EQ(std::next(cont.begin(), 7), cont.find(12)); + EXPECT_EQ(std::next(cont.begin(), 8), cont.find(4)); + } + { + const TypedTree<TypeParam> cont({5, 6, 7, 8, 9, 10, 11, 12}); + + EXPECT_EQ(cont.begin(), cont.find(5)); + EXPECT_EQ(std::next(cont.begin()), cont.find(6)); + EXPECT_EQ(std::next(cont.begin(), 2), cont.find(7)); + EXPECT_EQ(std::next(cont.begin(), 3), cont.find(8)); + EXPECT_EQ(std::next(cont.begin(), 4), cont.find(9)); + EXPECT_EQ(std::next(cont.begin(), 5), cont.find(10)); + EXPECT_EQ(std::next(cont.begin(), 6), cont.find(11)); + EXPECT_EQ(std::next(cont.begin(), 7), cont.find(12)); + EXPECT_EQ(std::next(cont.begin(), 8), cont.find(4)); + } +} + +// bool contains(const key_type& key) const + +TYPED_TEST_P(FlatTreeTest, Contains) { + const TypedTree<TypeParam> cont({5, 6, 7, 8, 9, 10, 11, 12}); + + EXPECT_TRUE(cont.contains(5)); + EXPECT_TRUE(cont.contains(6)); + EXPECT_TRUE(cont.contains(7)); + EXPECT_TRUE(cont.contains(8)); + EXPECT_TRUE(cont.contains(9)); + EXPECT_TRUE(cont.contains(10)); + EXPECT_TRUE(cont.contains(11)); + EXPECT_TRUE(cont.contains(12)); + EXPECT_FALSE(cont.contains(4)); +} + +// pair<iterator, iterator> equal_range(const key_type& key) +// pair<const_iterator, const_iterator> equal_range(const key_type& key) const + +TYPED_TEST_P(FlatTreeTest, EqualRange) { + { + TypedTree<TypeParam> cont({5, 7, 9, 11, 13, 15, 17, 19}); + + std::pair<typename TypedTree<TypeParam>::iterator, + typename TypedTree<TypeParam>::iterator> + result = cont.equal_range(5); + EXPECT_EQ(std::next(cont.begin(), 0), result.first); + EXPECT_EQ(std::next(cont.begin(), 1), result.second); + result = cont.equal_range(7); + EXPECT_EQ(std::next(cont.begin(), 1), result.first); + EXPECT_EQ(std::next(cont.begin(), 2), result.second); + result = cont.equal_range(9); + EXPECT_EQ(std::next(cont.begin(), 2), result.first); + EXPECT_EQ(std::next(cont.begin(), 3), result.second); + result = cont.equal_range(11); + EXPECT_EQ(std::next(cont.begin(), 3), result.first); + EXPECT_EQ(std::next(cont.begin(), 4), result.second); + result = cont.equal_range(13); + EXPECT_EQ(std::next(cont.begin(), 4), result.first); + EXPECT_EQ(std::next(cont.begin(), 5), result.second); + result = cont.equal_range(15); + EXPECT_EQ(std::next(cont.begin(), 5), result.first); + EXPECT_EQ(std::next(cont.begin(), 6), result.second); + result = cont.equal_range(17); + EXPECT_EQ(std::next(cont.begin(), 6), result.first); + EXPECT_EQ(std::next(cont.begin(), 7), result.second); + result = cont.equal_range(19); + EXPECT_EQ(std::next(cont.begin(), 7), result.first); + EXPECT_EQ(std::next(cont.begin(), 8), result.second); + result = cont.equal_range(4); + EXPECT_EQ(std::next(cont.begin(), 0), result.first); + EXPECT_EQ(std::next(cont.begin(), 0), result.second); + result = cont.equal_range(6); + EXPECT_EQ(std::next(cont.begin(), 1), result.first); + EXPECT_EQ(std::next(cont.begin(), 1), result.second); + result = cont.equal_range(8); + EXPECT_EQ(std::next(cont.begin(), 2), result.first); + EXPECT_EQ(std::next(cont.begin(), 2), result.second); + result = cont.equal_range(10); + EXPECT_EQ(std::next(cont.begin(), 3), result.first); + EXPECT_EQ(std::next(cont.begin(), 3), result.second); + result = cont.equal_range(12); + EXPECT_EQ(std::next(cont.begin(), 4), result.first); + EXPECT_EQ(std::next(cont.begin(), 4), result.second); + result = cont.equal_range(14); + EXPECT_EQ(std::next(cont.begin(), 5), result.first); + EXPECT_EQ(std::next(cont.begin(), 5), result.second); + result = cont.equal_range(16); + EXPECT_EQ(std::next(cont.begin(), 6), result.first); + EXPECT_EQ(std::next(cont.begin(), 6), result.second); + result = cont.equal_range(18); + EXPECT_EQ(std::next(cont.begin(), 7), result.first); + EXPECT_EQ(std::next(cont.begin(), 7), result.second); + result = cont.equal_range(20); + EXPECT_EQ(std::next(cont.begin(), 8), result.first); + EXPECT_EQ(std::next(cont.begin(), 8), result.second); + } + { + const TypedTree<TypeParam> cont({5, 7, 9, 11, 13, 15, 17, 19}); + + std::pair<typename TypedTree<TypeParam>::const_iterator, + typename TypedTree<TypeParam>::const_iterator> + result = cont.equal_range(5); + EXPECT_EQ(std::next(cont.begin(), 0), result.first); + EXPECT_EQ(std::next(cont.begin(), 1), result.second); + result = cont.equal_range(7); + EXPECT_EQ(std::next(cont.begin(), 1), result.first); + EXPECT_EQ(std::next(cont.begin(), 2), result.second); + result = cont.equal_range(9); + EXPECT_EQ(std::next(cont.begin(), 2), result.first); + EXPECT_EQ(std::next(cont.begin(), 3), result.second); + result = cont.equal_range(11); + EXPECT_EQ(std::next(cont.begin(), 3), result.first); + EXPECT_EQ(std::next(cont.begin(), 4), result.second); + result = cont.equal_range(13); + EXPECT_EQ(std::next(cont.begin(), 4), result.first); + EXPECT_EQ(std::next(cont.begin(), 5), result.second); + result = cont.equal_range(15); + EXPECT_EQ(std::next(cont.begin(), 5), result.first); + EXPECT_EQ(std::next(cont.begin(), 6), result.second); + result = cont.equal_range(17); + EXPECT_EQ(std::next(cont.begin(), 6), result.first); + EXPECT_EQ(std::next(cont.begin(), 7), result.second); + result = cont.equal_range(19); + EXPECT_EQ(std::next(cont.begin(), 7), result.first); + EXPECT_EQ(std::next(cont.begin(), 8), result.second); + result = cont.equal_range(4); + EXPECT_EQ(std::next(cont.begin(), 0), result.first); + EXPECT_EQ(std::next(cont.begin(), 0), result.second); + result = cont.equal_range(6); + EXPECT_EQ(std::next(cont.begin(), 1), result.first); + EXPECT_EQ(std::next(cont.begin(), 1), result.second); + result = cont.equal_range(8); + EXPECT_EQ(std::next(cont.begin(), 2), result.first); + EXPECT_EQ(std::next(cont.begin(), 2), result.second); + result = cont.equal_range(10); + EXPECT_EQ(std::next(cont.begin(), 3), result.first); + EXPECT_EQ(std::next(cont.begin(), 3), result.second); + result = cont.equal_range(12); + EXPECT_EQ(std::next(cont.begin(), 4), result.first); + EXPECT_EQ(std::next(cont.begin(), 4), result.second); + result = cont.equal_range(14); + EXPECT_EQ(std::next(cont.begin(), 5), result.first); + EXPECT_EQ(std::next(cont.begin(), 5), result.second); + result = cont.equal_range(16); + EXPECT_EQ(std::next(cont.begin(), 6), result.first); + EXPECT_EQ(std::next(cont.begin(), 6), result.second); + result = cont.equal_range(18); + EXPECT_EQ(std::next(cont.begin(), 7), result.first); + EXPECT_EQ(std::next(cont.begin(), 7), result.second); + result = cont.equal_range(20); + EXPECT_EQ(std::next(cont.begin(), 8), result.first); + EXPECT_EQ(std::next(cont.begin(), 8), result.second); + } +} + +// iterator lower_bound(const key_type& key); +// const_iterator lower_bound(const key_type& key) const; + +TYPED_TEST_P(FlatTreeTest, LowerBound) { + { + TypedTree<TypeParam> cont({5, 7, 9, 11, 13, 15, 17, 19}); + + EXPECT_EQ(cont.begin(), cont.lower_bound(5)); + EXPECT_EQ(std::next(cont.begin()), cont.lower_bound(7)); + EXPECT_EQ(std::next(cont.begin(), 2), cont.lower_bound(9)); + EXPECT_EQ(std::next(cont.begin(), 3), cont.lower_bound(11)); + EXPECT_EQ(std::next(cont.begin(), 4), cont.lower_bound(13)); + EXPECT_EQ(std::next(cont.begin(), 5), cont.lower_bound(15)); + EXPECT_EQ(std::next(cont.begin(), 6), cont.lower_bound(17)); + EXPECT_EQ(std::next(cont.begin(), 7), cont.lower_bound(19)); + EXPECT_EQ(std::next(cont.begin(), 0), cont.lower_bound(4)); + EXPECT_EQ(std::next(cont.begin(), 1), cont.lower_bound(6)); + EXPECT_EQ(std::next(cont.begin(), 2), cont.lower_bound(8)); + EXPECT_EQ(std::next(cont.begin(), 3), cont.lower_bound(10)); + EXPECT_EQ(std::next(cont.begin(), 4), cont.lower_bound(12)); + EXPECT_EQ(std::next(cont.begin(), 5), cont.lower_bound(14)); + EXPECT_EQ(std::next(cont.begin(), 6), cont.lower_bound(16)); + EXPECT_EQ(std::next(cont.begin(), 7), cont.lower_bound(18)); + EXPECT_EQ(std::next(cont.begin(), 8), cont.lower_bound(20)); + } + { + const TypedTree<TypeParam> cont({5, 7, 9, 11, 13, 15, 17, 19}); + + EXPECT_EQ(cont.begin(), cont.lower_bound(5)); + EXPECT_EQ(std::next(cont.begin()), cont.lower_bound(7)); + EXPECT_EQ(std::next(cont.begin(), 2), cont.lower_bound(9)); + EXPECT_EQ(std::next(cont.begin(), 3), cont.lower_bound(11)); + EXPECT_EQ(std::next(cont.begin(), 4), cont.lower_bound(13)); + EXPECT_EQ(std::next(cont.begin(), 5), cont.lower_bound(15)); + EXPECT_EQ(std::next(cont.begin(), 6), cont.lower_bound(17)); + EXPECT_EQ(std::next(cont.begin(), 7), cont.lower_bound(19)); + EXPECT_EQ(std::next(cont.begin(), 0), cont.lower_bound(4)); + EXPECT_EQ(std::next(cont.begin(), 1), cont.lower_bound(6)); + EXPECT_EQ(std::next(cont.begin(), 2), cont.lower_bound(8)); + EXPECT_EQ(std::next(cont.begin(), 3), cont.lower_bound(10)); + EXPECT_EQ(std::next(cont.begin(), 4), cont.lower_bound(12)); + EXPECT_EQ(std::next(cont.begin(), 5), cont.lower_bound(14)); + EXPECT_EQ(std::next(cont.begin(), 6), cont.lower_bound(16)); + EXPECT_EQ(std::next(cont.begin(), 7), cont.lower_bound(18)); + EXPECT_EQ(std::next(cont.begin(), 8), cont.lower_bound(20)); + } +} + +// iterator upper_bound(const key_type& key) +// const_iterator upper_bound(const key_type& key) const + +TYPED_TEST_P(FlatTreeTest, UpperBound) { + { + TypedTree<TypeParam> cont({5, 7, 9, 11, 13, 15, 17, 19}); + + EXPECT_EQ(std::next(cont.begin(), 1), cont.upper_bound(5)); + EXPECT_EQ(std::next(cont.begin(), 2), cont.upper_bound(7)); + EXPECT_EQ(std::next(cont.begin(), 3), cont.upper_bound(9)); + EXPECT_EQ(std::next(cont.begin(), 4), cont.upper_bound(11)); + EXPECT_EQ(std::next(cont.begin(), 5), cont.upper_bound(13)); + EXPECT_EQ(std::next(cont.begin(), 6), cont.upper_bound(15)); + EXPECT_EQ(std::next(cont.begin(), 7), cont.upper_bound(17)); + EXPECT_EQ(std::next(cont.begin(), 8), cont.upper_bound(19)); + EXPECT_EQ(std::next(cont.begin(), 0), cont.upper_bound(4)); + EXPECT_EQ(std::next(cont.begin(), 1), cont.upper_bound(6)); + EXPECT_EQ(std::next(cont.begin(), 2), cont.upper_bound(8)); + EXPECT_EQ(std::next(cont.begin(), 3), cont.upper_bound(10)); + EXPECT_EQ(std::next(cont.begin(), 4), cont.upper_bound(12)); + EXPECT_EQ(std::next(cont.begin(), 5), cont.upper_bound(14)); + EXPECT_EQ(std::next(cont.begin(), 6), cont.upper_bound(16)); + EXPECT_EQ(std::next(cont.begin(), 7), cont.upper_bound(18)); + EXPECT_EQ(std::next(cont.begin(), 8), cont.upper_bound(20)); + } + { + const TypedTree<TypeParam> cont({5, 7, 9, 11, 13, 15, 17, 19}); + + EXPECT_EQ(std::next(cont.begin(), 1), cont.upper_bound(5)); + EXPECT_EQ(std::next(cont.begin(), 2), cont.upper_bound(7)); + EXPECT_EQ(std::next(cont.begin(), 3), cont.upper_bound(9)); + EXPECT_EQ(std::next(cont.begin(), 4), cont.upper_bound(11)); + EXPECT_EQ(std::next(cont.begin(), 5), cont.upper_bound(13)); + EXPECT_EQ(std::next(cont.begin(), 6), cont.upper_bound(15)); + EXPECT_EQ(std::next(cont.begin(), 7), cont.upper_bound(17)); + EXPECT_EQ(std::next(cont.begin(), 8), cont.upper_bound(19)); + EXPECT_EQ(std::next(cont.begin(), 0), cont.upper_bound(4)); + EXPECT_EQ(std::next(cont.begin(), 1), cont.upper_bound(6)); + EXPECT_EQ(std::next(cont.begin(), 2), cont.upper_bound(8)); + EXPECT_EQ(std::next(cont.begin(), 3), cont.upper_bound(10)); + EXPECT_EQ(std::next(cont.begin(), 4), cont.upper_bound(12)); + EXPECT_EQ(std::next(cont.begin(), 5), cont.upper_bound(14)); + EXPECT_EQ(std::next(cont.begin(), 6), cont.upper_bound(16)); + EXPECT_EQ(std::next(cont.begin(), 7), cont.upper_bound(18)); + EXPECT_EQ(std::next(cont.begin(), 8), cont.upper_bound(20)); + } +} + +// ---------------------------------------------------------------------------- +// General operations. + +// void swap(flat_tree& other) +// void swap(flat_tree& lhs, flat_tree& rhs) + +TYPED_TEST_P(FlatTreeTest, Swap) { + TypedTree<TypeParam> x({1, 2, 3}); + TypedTree<TypeParam> y({4}); + swap(x, y); + EXPECT_THAT(x, ElementsAre(4)); + EXPECT_THAT(y, ElementsAre(1, 2, 3)); + + y.swap(x); + EXPECT_THAT(x, ElementsAre(1, 2, 3)); + EXPECT_THAT(y, ElementsAre(4)); +} + +// bool operator==(const flat_tree& lhs, const flat_tree& rhs) +// bool operator!=(const flat_tree& lhs, const flat_tree& rhs) +// bool operator<(const flat_tree& lhs, const flat_tree& rhs) +// bool operator>(const flat_tree& lhs, const flat_tree& rhs) +// bool operator<=(const flat_tree& lhs, const flat_tree& rhs) +// bool operator>=(const flat_tree& lhs, const flat_tree& rhs) + +TEST(FlatTree, Comparison) { + // Provided comparator does not participate in comparison. + ReversedTree biggest({3}); + ReversedTree smallest({1}); + ReversedTree middle({1, 2}); + + EXPECT_EQ(biggest, biggest); + EXPECT_NE(biggest, smallest); + EXPECT_LT(smallest, middle); + EXPECT_LE(smallest, middle); + EXPECT_LE(middle, middle); + EXPECT_GT(biggest, middle); + EXPECT_GE(biggest, middle); + EXPECT_GE(biggest, biggest); +} + +TYPED_TEST_P(FlatTreeTest, SupportsEraseIf) { + TypedTree<TypeParam> x; + EXPECT_EQ(0u, EraseIf(x, [](int) { return false; })); + EXPECT_THAT(x, ElementsAre()); + + x = {1, 2, 3}; + EXPECT_EQ(1u, EraseIf(x, [](int elem) { return !(elem & 1); })); + EXPECT_THAT(x, ElementsAre(1, 3)); + + x = {1, 2, 3, 4}; + EXPECT_EQ(2u, EraseIf(x, [](int elem) { return elem & 1; })); + EXPECT_THAT(x, ElementsAre(2, 4)); +} + +REGISTER_TYPED_TEST_SUITE_P(FlatTreeTest, + DefaultConstructor, + CopyConstructor, + ContainerCopyConstructor, + InitializerListConstructor, + SortedUniqueContainerCopyConstructor, + SortedUniqueInitializerListConstructor, + CopyAssignable, + InitializerListAssignable, + Clear, + Size, + Empty, + Iterators, + InsertLValue, + InsertPositionLValue, + Emplace, + EmplacePosition, + Extract, + Replace, + ErasePosition, + EraseRange, + EraseKey, + EraseEndDeath, + Count, + Find, + Contains, + EqualRange, + LowerBound, + UpperBound, + Swap, + SupportsEraseIf); + +using IntSequenceContainers = + ::testing::Types<std::deque<int>, std::vector<int>>; +INSTANTIATE_TYPED_TEST_SUITE_P(My, FlatTreeTest, IntSequenceContainers); + +} // namespace +} // namespace flat_containers_internal +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/containers/identity.h b/third_party/libwebrtc/rtc_base/containers/identity.h new file mode 100644 index 0000000000..29592931bd --- /dev/null +++ b/third_party/libwebrtc/rtc_base/containers/identity.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2021 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 implementation is borrowed from Chromium. + +#ifndef RTC_BASE_CONTAINERS_IDENTITY_H_ +#define RTC_BASE_CONTAINERS_IDENTITY_H_ + +#include <utility> + +namespace webrtc { + +// Implementation of C++20's std::identity. +// +// Reference: +// - https://en.cppreference.com/w/cpp/utility/functional/identity +// - https://wg21.link/func.identity +struct identity { + template <typename T> + constexpr T&& operator()(T&& t) const noexcept { + return std::forward<T>(t); + } + + using is_transparent = void; +}; + +} // namespace webrtc + +#endif // RTC_BASE_CONTAINERS_IDENTITY_H_ diff --git a/third_party/libwebrtc/rtc_base/containers/invoke.h b/third_party/libwebrtc/rtc_base/containers/invoke.h new file mode 100644 index 0000000000..5d17a70beb --- /dev/null +++ b/third_party/libwebrtc/rtc_base/containers/invoke.h @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2021 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 implementation is borrowed from Chromium. + +#ifndef RTC_BASE_CONTAINERS_INVOKE_H_ +#define RTC_BASE_CONTAINERS_INVOKE_H_ + +#include <type_traits> +#include <utility> + +namespace webrtc { + +namespace invoke_internal { + +// Helper struct and alias to deduce the class type from a member function +// pointer or member object pointer. +template <typename DecayedF> +struct member_pointer_class {}; + +template <typename ReturnT, typename ClassT> +struct member_pointer_class<ReturnT ClassT::*> { + using type = ClassT; +}; + +template <typename DecayedF> +using member_pointer_class_t = typename member_pointer_class<DecayedF>::type; + +// Utility struct to detect specializations of std::reference_wrapper. +template <typename T> +struct is_reference_wrapper : std::false_type {}; + +template <typename T> +struct is_reference_wrapper<std::reference_wrapper<T>> : std::true_type {}; + +// Small helpers used below in invoke_internal::invoke to make the SFINAE more +// concise. +template <typename F> +const bool& IsMemFunPtr = + std::is_member_function_pointer<std::decay_t<F>>::value; + +template <typename F> +const bool& IsMemObjPtr = std::is_member_object_pointer<std::decay_t<F>>::value; + +template <typename F, + typename T, + typename MemPtrClass = member_pointer_class_t<std::decay_t<F>>> +const bool& IsMemPtrToBaseOf = + std::is_base_of<MemPtrClass, std::decay_t<T>>::value; + +template <typename T> +const bool& IsRefWrapper = is_reference_wrapper<std::decay_t<T>>::value; + +template <bool B> +using EnableIf = std::enable_if_t<B, bool>; + +// Invokes a member function pointer on a reference to an object of a suitable +// type. Covers bullet 1 of the INVOKE definition. +// +// Reference: https://wg21.link/func.require#1.1 +template <typename F, + typename T1, + typename... Args, + EnableIf<IsMemFunPtr<F> && IsMemPtrToBaseOf<F, T1>> = true> +constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1, Args&&... args) { + return (std::forward<T1>(t1).*f)(std::forward<Args>(args)...); +} + +// Invokes a member function pointer on a std::reference_wrapper to an object of +// a suitable type. Covers bullet 2 of the INVOKE definition. +// +// Reference: https://wg21.link/func.require#1.2 +template <typename F, + typename T1, + typename... Args, + EnableIf<IsMemFunPtr<F> && IsRefWrapper<T1>> = true> +constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1, Args&&... args) { + return (t1.get().*f)(std::forward<Args>(args)...); +} + +// Invokes a member function pointer on a pointer-like type to an object of a +// suitable type. Covers bullet 3 of the INVOKE definition. +// +// Reference: https://wg21.link/func.require#1.3 +template <typename F, + typename T1, + typename... Args, + EnableIf<IsMemFunPtr<F> && !IsMemPtrToBaseOf<F, T1> && + !IsRefWrapper<T1>> = true> +constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1, Args&&... args) { + return ((*std::forward<T1>(t1)).*f)(std::forward<Args>(args)...); +} + +// Invokes a member object pointer on a reference to an object of a suitable +// type. Covers bullet 4 of the INVOKE definition. +// +// Reference: https://wg21.link/func.require#1.4 +template <typename F, + typename T1, + EnableIf<IsMemObjPtr<F> && IsMemPtrToBaseOf<F, T1>> = true> +constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1) { + return std::forward<T1>(t1).*f; +} + +// Invokes a member object pointer on a std::reference_wrapper to an object of +// a suitable type. Covers bullet 5 of the INVOKE definition. +// +// Reference: https://wg21.link/func.require#1.5 +template <typename F, + typename T1, + EnableIf<IsMemObjPtr<F> && IsRefWrapper<T1>> = true> +constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1) { + return t1.get().*f; +} + +// Invokes a member object pointer on a pointer-like type to an object of a +// suitable type. Covers bullet 6 of the INVOKE definition. +// +// Reference: https://wg21.link/func.require#1.6 +template <typename F, + typename T1, + EnableIf<IsMemObjPtr<F> && !IsMemPtrToBaseOf<F, T1> && + !IsRefWrapper<T1>> = true> +constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1) { + return (*std::forward<T1>(t1)).*f; +} + +// Invokes a regular function or function object. Covers bullet 7 of the INVOKE +// definition. +// +// Reference: https://wg21.link/func.require#1.7 +template <typename F, typename... Args> +constexpr decltype(auto) InvokeImpl(F&& f, Args&&... args) { + return std::forward<F>(f)(std::forward<Args>(args)...); +} + +} // namespace invoke_internal + +// Implementation of C++17's std::invoke. This is not based on implementation +// referenced in original std::invoke proposal, but rather a manual +// implementation, so that it can be constexpr. +// +// References: +// - https://wg21.link/n4169#implementability +// - https://en.cppreference.com/w/cpp/utility/functional/invoke +// - https://wg21.link/func.invoke +template <typename F, typename... Args> +constexpr decltype(auto) invoke(F&& f, Args&&... args) { + return invoke_internal::InvokeImpl(std::forward<F>(f), + std::forward<Args>(args)...); +} + +} // namespace webrtc + +#endif // RTC_BASE_CONTAINERS_INVOKE_H_ diff --git a/third_party/libwebrtc/rtc_base/containers/move_only_int.h b/third_party/libwebrtc/rtc_base/containers/move_only_int.h new file mode 100644 index 0000000000..8f745aa688 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/containers/move_only_int.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2021 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 implementation is borrowed from Chromium. + +#ifndef RTC_BASE_CONTAINERS_MOVE_ONLY_INT_H_ +#define RTC_BASE_CONTAINERS_MOVE_ONLY_INT_H_ + +namespace webrtc { + +// A move-only class that holds an integer. This is designed for testing +// containers. See also CopyOnlyInt. +class MoveOnlyInt { + public: + explicit MoveOnlyInt(int data = 1) : data_(data) {} + MoveOnlyInt(const MoveOnlyInt& other) = delete; + MoveOnlyInt& operator=(const MoveOnlyInt& other) = delete; + MoveOnlyInt(MoveOnlyInt&& other) : data_(other.data_) { other.data_ = 0; } + ~MoveOnlyInt() { data_ = 0; } + + MoveOnlyInt& operator=(MoveOnlyInt&& other) { + data_ = other.data_; + other.data_ = 0; + return *this; + } + + friend bool operator==(const MoveOnlyInt& lhs, const MoveOnlyInt& rhs) { + return lhs.data_ == rhs.data_; + } + + friend bool operator!=(const MoveOnlyInt& lhs, const MoveOnlyInt& rhs) { + return !operator==(lhs, rhs); + } + + friend bool operator<(const MoveOnlyInt& lhs, int rhs) { + return lhs.data_ < rhs; + } + + friend bool operator<(int lhs, const MoveOnlyInt& rhs) { + return lhs < rhs.data_; + } + + friend bool operator<(const MoveOnlyInt& lhs, const MoveOnlyInt& rhs) { + return lhs.data_ < rhs.data_; + } + + friend bool operator>(const MoveOnlyInt& lhs, const MoveOnlyInt& rhs) { + return rhs < lhs; + } + + friend bool operator<=(const MoveOnlyInt& lhs, const MoveOnlyInt& rhs) { + return !(rhs < lhs); + } + + friend bool operator>=(const MoveOnlyInt& lhs, const MoveOnlyInt& rhs) { + return !(lhs < rhs); + } + + int data() const { return data_; } + + private: + volatile int data_; +}; + +} // namespace webrtc + +#endif // RTC_BASE_CONTAINERS_MOVE_ONLY_INT_H_ diff --git a/third_party/libwebrtc/rtc_base/copy_on_write_buffer.cc b/third_party/libwebrtc/rtc_base/copy_on_write_buffer.cc new file mode 100644 index 0000000000..d8ab53cb24 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/copy_on_write_buffer.cc @@ -0,0 +1,127 @@ +/* + * Copyright 2016 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 "rtc_base/copy_on_write_buffer.h" + +#include <stddef.h> + +#include "absl/strings/string_view.h" + +namespace rtc { + +CopyOnWriteBuffer::CopyOnWriteBuffer() : offset_(0), size_(0) { + RTC_DCHECK(IsConsistent()); +} + +CopyOnWriteBuffer::CopyOnWriteBuffer(const CopyOnWriteBuffer& buf) + : buffer_(buf.buffer_), offset_(buf.offset_), size_(buf.size_) {} + +CopyOnWriteBuffer::CopyOnWriteBuffer(CopyOnWriteBuffer&& buf) noexcept + : buffer_(std::move(buf.buffer_)), offset_(buf.offset_), size_(buf.size_) { + buf.offset_ = 0; + buf.size_ = 0; + RTC_DCHECK(IsConsistent()); +} + +CopyOnWriteBuffer::CopyOnWriteBuffer(absl::string_view s) + : CopyOnWriteBuffer(s.data(), s.length()) {} + +CopyOnWriteBuffer::CopyOnWriteBuffer(size_t size) + : buffer_(size > 0 ? new RefCountedBuffer(size) : nullptr), + offset_(0), + size_(size) { + RTC_DCHECK(IsConsistent()); +} + +CopyOnWriteBuffer::CopyOnWriteBuffer(size_t size, size_t capacity) + : buffer_(size > 0 || capacity > 0 ? new RefCountedBuffer(size, capacity) + : nullptr), + offset_(0), + size_(size) { + RTC_DCHECK(IsConsistent()); +} + +CopyOnWriteBuffer::~CopyOnWriteBuffer() = default; + +bool CopyOnWriteBuffer::operator==(const CopyOnWriteBuffer& buf) const { + // Must either be the same view of the same buffer or have the same contents. + RTC_DCHECK(IsConsistent()); + RTC_DCHECK(buf.IsConsistent()); + return size_ == buf.size_ && + (cdata() == buf.cdata() || memcmp(cdata(), buf.cdata(), size_) == 0); +} + +void CopyOnWriteBuffer::SetSize(size_t size) { + RTC_DCHECK(IsConsistent()); + if (!buffer_) { + if (size > 0) { + buffer_ = new RefCountedBuffer(size); + offset_ = 0; + size_ = size; + } + RTC_DCHECK(IsConsistent()); + return; + } + + if (size <= size_) { + size_ = size; + return; + } + + UnshareAndEnsureCapacity(std::max(capacity(), size)); + buffer_->SetSize(size + offset_); + size_ = size; + RTC_DCHECK(IsConsistent()); +} + +void CopyOnWriteBuffer::EnsureCapacity(size_t new_capacity) { + RTC_DCHECK(IsConsistent()); + if (!buffer_) { + if (new_capacity > 0) { + buffer_ = new RefCountedBuffer(0, new_capacity); + offset_ = 0; + size_ = 0; + } + RTC_DCHECK(IsConsistent()); + return; + } else if (new_capacity <= capacity()) { + return; + } + + UnshareAndEnsureCapacity(new_capacity); + RTC_DCHECK(IsConsistent()); +} + +void CopyOnWriteBuffer::Clear() { + if (!buffer_) + return; + + if (buffer_->HasOneRef()) { + buffer_->Clear(); + } else { + buffer_ = new RefCountedBuffer(0, capacity()); + } + offset_ = 0; + size_ = 0; + RTC_DCHECK(IsConsistent()); +} + +void CopyOnWriteBuffer::UnshareAndEnsureCapacity(size_t new_capacity) { + if (buffer_->HasOneRef() && new_capacity <= capacity()) { + return; + } + + buffer_ = + new RefCountedBuffer(buffer_->data() + offset_, size_, new_capacity); + offset_ = 0; + RTC_DCHECK(IsConsistent()); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/copy_on_write_buffer.h b/third_party/libwebrtc/rtc_base/copy_on_write_buffer.h new file mode 100644 index 0000000000..8332ee6f62 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/copy_on_write_buffer.h @@ -0,0 +1,316 @@ +/* + * Copyright 2016 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 RTC_BASE_COPY_ON_WRITE_BUFFER_H_ +#define RTC_BASE_COPY_ON_WRITE_BUFFER_H_ + +#include <stdint.h> + +#include <algorithm> +#include <cstring> +#include <string> +#include <type_traits> +#include <utility> + +#include "absl/strings/string_view.h" +#include "api/scoped_refptr.h" +#include "rtc_base/buffer.h" +#include "rtc_base/checks.h" +#include "rtc_base/ref_counted_object.h" +#include "rtc_base/system/rtc_export.h" +#include "rtc_base/type_traits.h" + +namespace rtc { + +class RTC_EXPORT CopyOnWriteBuffer { + public: + // An empty buffer. + CopyOnWriteBuffer(); + // Share the data with an existing buffer. + CopyOnWriteBuffer(const CopyOnWriteBuffer& buf); + // Move contents from an existing buffer. + CopyOnWriteBuffer(CopyOnWriteBuffer&& buf) noexcept; + + // Construct a buffer from a string, convenient for unittests. + explicit CopyOnWriteBuffer(absl::string_view s); + + // Construct a buffer with the specified number of uninitialized bytes. + explicit CopyOnWriteBuffer(size_t size); + CopyOnWriteBuffer(size_t size, size_t capacity); + + // Construct a buffer and copy the specified number of bytes into it. The + // source array may be (const) uint8_t*, int8_t*, or char*. + template <typename T, + typename std::enable_if< + internal::BufferCompat<uint8_t, T>::value>::type* = nullptr> + CopyOnWriteBuffer(const T* data, size_t size) + : CopyOnWriteBuffer(data, size, size) {} + template <typename T, + typename std::enable_if< + internal::BufferCompat<uint8_t, T>::value>::type* = nullptr> + CopyOnWriteBuffer(const T* data, size_t size, size_t capacity) + : CopyOnWriteBuffer(size, capacity) { + if (buffer_) { + std::memcpy(buffer_->data(), data, size); + offset_ = 0; + size_ = size; + } + } + + // Construct a buffer from the contents of an array. + template <typename T, + size_t N, + typename std::enable_if< + internal::BufferCompat<uint8_t, T>::value>::type* = nullptr> + CopyOnWriteBuffer(const T (&array)[N]) // NOLINT: runtime/explicit + : CopyOnWriteBuffer(array, N) {} + + // Construct a buffer from a vector like type. + template <typename VecT, + typename ElemT = typename std::remove_pointer_t< + decltype(std::declval<VecT>().data())>, + typename std::enable_if_t< + !std::is_same<VecT, CopyOnWriteBuffer>::value && + HasDataAndSize<VecT, ElemT>::value && + internal::BufferCompat<uint8_t, ElemT>::value>* = nullptr> + explicit CopyOnWriteBuffer(const VecT& v) + : CopyOnWriteBuffer(v.data(), v.size()) {} + + // Construct a buffer from a vector like type and a capacity argument + template <typename VecT, + typename ElemT = typename std::remove_pointer_t< + decltype(std::declval<VecT>().data())>, + typename std::enable_if_t< + !std::is_same<VecT, CopyOnWriteBuffer>::value && + HasDataAndSize<VecT, ElemT>::value && + internal::BufferCompat<uint8_t, ElemT>::value>* = nullptr> + explicit CopyOnWriteBuffer(const VecT& v, size_t capacity) + : CopyOnWriteBuffer(v.data(), v.size(), capacity) {} + + ~CopyOnWriteBuffer(); + + // Get a pointer to the data. Just .data() will give you a (const) uint8_t*, + // but you may also use .data<int8_t>() and .data<char>(). + template <typename T = uint8_t, + typename std::enable_if< + internal::BufferCompat<uint8_t, T>::value>::type* = nullptr> + const T* data() const { + return cdata<T>(); + } + + // Get writable pointer to the data. This will create a copy of the underlying + // data if it is shared with other buffers. + template <typename T = uint8_t, + typename std::enable_if< + internal::BufferCompat<uint8_t, T>::value>::type* = nullptr> + T* MutableData() { + RTC_DCHECK(IsConsistent()); + if (!buffer_) { + return nullptr; + } + UnshareAndEnsureCapacity(capacity()); + return buffer_->data<T>() + offset_; + } + + // Get const pointer to the data. This will not create a copy of the + // underlying data if it is shared with other buffers. + template <typename T = uint8_t, + typename std::enable_if< + internal::BufferCompat<uint8_t, T>::value>::type* = nullptr> + const T* cdata() const { + RTC_DCHECK(IsConsistent()); + if (!buffer_) { + return nullptr; + } + return buffer_->data<T>() + offset_; + } + + size_t size() const { + RTC_DCHECK(IsConsistent()); + return size_; + } + + size_t capacity() const { + RTC_DCHECK(IsConsistent()); + return buffer_ ? buffer_->capacity() - offset_ : 0; + } + + CopyOnWriteBuffer& operator=(const CopyOnWriteBuffer& buf) { + RTC_DCHECK(IsConsistent()); + RTC_DCHECK(buf.IsConsistent()); + if (&buf != this) { + buffer_ = buf.buffer_; + offset_ = buf.offset_; + size_ = buf.size_; + } + return *this; + } + + CopyOnWriteBuffer& operator=(CopyOnWriteBuffer&& buf) { + RTC_DCHECK(IsConsistent()); + RTC_DCHECK(buf.IsConsistent()); + buffer_ = std::move(buf.buffer_); + offset_ = buf.offset_; + size_ = buf.size_; + buf.offset_ = 0; + buf.size_ = 0; + return *this; + } + + bool operator==(const CopyOnWriteBuffer& buf) const; + + bool operator!=(const CopyOnWriteBuffer& buf) const { + return !(*this == buf); + } + + uint8_t operator[](size_t index) const { + RTC_DCHECK_LT(index, size()); + return cdata()[index]; + } + + // Replace the contents of the buffer. Accepts the same types as the + // constructors. + template <typename T, + typename std::enable_if< + internal::BufferCompat<uint8_t, T>::value>::type* = nullptr> + void SetData(const T* data, size_t size) { + RTC_DCHECK(IsConsistent()); + if (!buffer_) { + buffer_ = size > 0 ? new RefCountedBuffer(data, size) : nullptr; + } else if (!buffer_->HasOneRef()) { + buffer_ = new RefCountedBuffer(data, size, capacity()); + } else { + buffer_->SetData(data, size); + } + offset_ = 0; + size_ = size; + + RTC_DCHECK(IsConsistent()); + } + + template <typename T, + size_t N, + typename std::enable_if< + internal::BufferCompat<uint8_t, T>::value>::type* = nullptr> + void SetData(const T (&array)[N]) { + SetData(array, N); + } + + void SetData(const CopyOnWriteBuffer& buf) { + RTC_DCHECK(IsConsistent()); + RTC_DCHECK(buf.IsConsistent()); + if (&buf != this) { + buffer_ = buf.buffer_; + offset_ = buf.offset_; + size_ = buf.size_; + } + } + + // Append data to the buffer. Accepts the same types as the constructors. + template <typename T, + typename std::enable_if< + internal::BufferCompat<uint8_t, T>::value>::type* = nullptr> + void AppendData(const T* data, size_t size) { + RTC_DCHECK(IsConsistent()); + if (!buffer_) { + buffer_ = new RefCountedBuffer(data, size); + offset_ = 0; + size_ = size; + RTC_DCHECK(IsConsistent()); + return; + } + + UnshareAndEnsureCapacity(std::max(capacity(), size_ + size)); + + buffer_->SetSize(offset_ + + size_); // Remove data to the right of the slice. + buffer_->AppendData(data, size); + size_ += size; + + RTC_DCHECK(IsConsistent()); + } + + template <typename T, + size_t N, + typename std::enable_if< + internal::BufferCompat<uint8_t, T>::value>::type* = nullptr> + void AppendData(const T (&array)[N]) { + AppendData(array, N); + } + + template <typename VecT, + typename ElemT = typename std::remove_pointer_t< + decltype(std::declval<VecT>().data())>, + typename std::enable_if_t< + HasDataAndSize<VecT, ElemT>::value && + internal::BufferCompat<uint8_t, ElemT>::value>* = nullptr> + void AppendData(const VecT& v) { + AppendData(v.data(), v.size()); + } + + // Sets the size of the buffer. If the new size is smaller than the old, the + // buffer contents will be kept but truncated; if the new size is greater, + // the existing contents will be kept and the new space will be + // uninitialized. + void SetSize(size_t size); + + // Ensure that the buffer size can be increased to at least capacity without + // further reallocation. (Of course, this operation might need to reallocate + // the buffer.) + void EnsureCapacity(size_t capacity); + + // Resets the buffer to zero size without altering capacity. Works even if the + // buffer has been moved from. + void Clear(); + + // Swaps two buffers. + friend void swap(CopyOnWriteBuffer& a, CopyOnWriteBuffer& b) { + a.buffer_.swap(b.buffer_); + std::swap(a.offset_, b.offset_); + std::swap(a.size_, b.size_); + } + + CopyOnWriteBuffer Slice(size_t offset, size_t length) const { + CopyOnWriteBuffer slice(*this); + RTC_DCHECK_LE(offset, size_); + RTC_DCHECK_LE(length + offset, size_); + slice.offset_ += offset; + slice.size_ = length; + return slice; + } + + private: + using RefCountedBuffer = FinalRefCountedObject<Buffer>; + // Create a copy of the underlying data if it is referenced from other Buffer + // objects or there is not enough capacity. + void UnshareAndEnsureCapacity(size_t new_capacity); + + // Pre- and postcondition of all methods. + bool IsConsistent() const { + if (buffer_) { + return buffer_->capacity() > 0 && offset_ <= buffer_->size() && + offset_ + size_ <= buffer_->size(); + } else { + return size_ == 0 && offset_ == 0; + } + } + + // buffer_ is either null, or points to an rtc::Buffer with capacity > 0. + scoped_refptr<RefCountedBuffer> buffer_; + // This buffer may represent a slice of a original data. + size_t offset_; // Offset of a current slice in the original data in buffer_. + // Should be 0 if the buffer_ is empty. + size_t size_; // Size of a current slice in the original data in buffer_. + // Should be 0 if the buffer_ is empty. +}; + +} // namespace rtc + +#endif // RTC_BASE_COPY_ON_WRITE_BUFFER_H_ diff --git a/third_party/libwebrtc/rtc_base/copy_on_write_buffer_gn/moz.build b/third_party/libwebrtc/rtc_base/copy_on_write_buffer_gn/moz.build new file mode 100644 index 0000000000..f026e25abd --- /dev/null +++ b/third_party/libwebrtc/rtc_base/copy_on_write_buffer_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/rtc_base/copy_on_write_buffer.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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("copy_on_write_buffer_gn") diff --git a/third_party/libwebrtc/rtc_base/copy_on_write_buffer_unittest.cc b/third_party/libwebrtc/rtc_base/copy_on_write_buffer_unittest.cc new file mode 100644 index 0000000000..8a9fc4e2f4 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/copy_on_write_buffer_unittest.cc @@ -0,0 +1,378 @@ +/* + * Copyright 2016 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 "rtc_base/copy_on_write_buffer.h" + +#include <cstdint> + +#include "test/gtest.h" + +namespace rtc { + +namespace { + +// clang-format off +const uint8_t kTestData[] = {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, + 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf}; +// clang-format on + +} // namespace + +void EnsureBuffersShareData(const CopyOnWriteBuffer& buf1, + const CopyOnWriteBuffer& buf2) { + // Data is shared between buffers. + EXPECT_EQ(buf1.size(), buf2.size()); + EXPECT_EQ(buf1.capacity(), buf2.capacity()); + const uint8_t* data1 = buf1.data(); + const uint8_t* data2 = buf2.data(); + EXPECT_EQ(data1, data2); + EXPECT_EQ(buf1, buf2); +} + +void EnsureBuffersDontShareData(const CopyOnWriteBuffer& buf1, + const CopyOnWriteBuffer& buf2) { + // Data is not shared between buffers. + const uint8_t* data1 = buf1.cdata(); + const uint8_t* data2 = buf2.cdata(); + EXPECT_NE(data1, data2); +} + +TEST(CopyOnWriteBufferTest, TestCreateEmptyData) { + CopyOnWriteBuffer buf(static_cast<const uint8_t*>(nullptr), 0); + EXPECT_EQ(buf.size(), 0u); + EXPECT_EQ(buf.capacity(), 0u); + EXPECT_EQ(buf.data(), nullptr); +} + +TEST(CopyOnWriteBufferTest, TestMoveConstruct) { + EXPECT_TRUE(std::is_nothrow_move_constructible_v<CopyOnWriteBuffer>); + + CopyOnWriteBuffer buf1(kTestData, 3, 10); + size_t buf1_size = buf1.size(); + size_t buf1_capacity = buf1.capacity(); + const uint8_t* buf1_data = buf1.cdata(); + + CopyOnWriteBuffer buf2(std::move(buf1)); + EXPECT_EQ(buf1.size(), 0u); + EXPECT_EQ(buf1.capacity(), 0u); + EXPECT_EQ(buf1.data(), nullptr); + EXPECT_EQ(buf2.size(), buf1_size); + EXPECT_EQ(buf2.capacity(), buf1_capacity); + EXPECT_EQ(buf2.data(), buf1_data); +} + +TEST(CopyOnWriteBufferTest, TestMoveAssign) { + CopyOnWriteBuffer buf1(kTestData, 3, 10); + size_t buf1_size = buf1.size(); + size_t buf1_capacity = buf1.capacity(); + const uint8_t* buf1_data = buf1.cdata(); + + CopyOnWriteBuffer buf2; + buf2 = std::move(buf1); + EXPECT_EQ(buf1.size(), 0u); + EXPECT_EQ(buf1.capacity(), 0u); + EXPECT_EQ(buf1.data(), nullptr); + EXPECT_EQ(buf2.size(), buf1_size); + EXPECT_EQ(buf2.capacity(), buf1_capacity); + EXPECT_EQ(buf2.data(), buf1_data); +} + +TEST(CopyOnWriteBufferTest, TestSwap) { + CopyOnWriteBuffer buf1(kTestData, 3, 10); + size_t buf1_size = buf1.size(); + size_t buf1_capacity = buf1.capacity(); + const uint8_t* buf1_data = buf1.cdata(); + + CopyOnWriteBuffer buf2(kTestData, 6, 20); + size_t buf2_size = buf2.size(); + size_t buf2_capacity = buf2.capacity(); + const uint8_t* buf2_data = buf2.cdata(); + + std::swap(buf1, buf2); + EXPECT_EQ(buf1.size(), buf2_size); + EXPECT_EQ(buf1.capacity(), buf2_capacity); + EXPECT_EQ(buf1.data(), buf2_data); + EXPECT_EQ(buf2.size(), buf1_size); + EXPECT_EQ(buf2.capacity(), buf1_capacity); + EXPECT_EQ(buf2.data(), buf1_data); +} + +TEST(CopyOnWriteBufferTest, TestAppendData) { + CopyOnWriteBuffer buf1(kTestData, 3, 10); + CopyOnWriteBuffer buf2(buf1); + + EnsureBuffersShareData(buf1, buf2); + + // AppendData copies the underlying buffer. + buf2.AppendData("foo"); + EXPECT_EQ(buf2.size(), buf1.size() + 4); // "foo" + trailing 0x00 + EXPECT_EQ(buf2.capacity(), buf1.capacity()); + EXPECT_NE(buf2.data(), buf1.data()); + + EXPECT_EQ(buf1, CopyOnWriteBuffer(kTestData, 3)); + const int8_t exp[] = {0x0, 0x1, 0x2, 'f', 'o', 'o', 0x0}; + EXPECT_EQ(buf2, CopyOnWriteBuffer(exp)); +} + +TEST(CopyOnWriteBufferTest, SetEmptyData) { + CopyOnWriteBuffer buf(10); + + buf.SetData<uint8_t>(nullptr, 0); + + EXPECT_EQ(0u, buf.size()); +} + +TEST(CopyOnWriteBufferTest, SetDataNoMoreThanCapacityDoesntCauseReallocation) { + CopyOnWriteBuffer buf1(3, 10); + const uint8_t* const original_allocation = buf1.cdata(); + + buf1.SetData(kTestData, 10); + + EXPECT_EQ(original_allocation, buf1.cdata()); + EXPECT_EQ(buf1, CopyOnWriteBuffer(kTestData, 10)); +} + +TEST(CopyOnWriteBufferTest, SetDataMakeReferenceCopy) { + CopyOnWriteBuffer buf1(kTestData, 3, 10); + CopyOnWriteBuffer buf2; + + buf2.SetData(buf1); + + EnsureBuffersShareData(buf1, buf2); +} + +TEST(CopyOnWriteBufferTest, SetDataOnSharedKeepsOriginal) { + const uint8_t data[] = "foo"; + CopyOnWriteBuffer buf1(kTestData, 3, 10); + const uint8_t* const original_allocation = buf1.cdata(); + CopyOnWriteBuffer buf2(buf1); + + buf2.SetData(data); + + EnsureBuffersDontShareData(buf1, buf2); + EXPECT_EQ(original_allocation, buf1.cdata()); + EXPECT_EQ(buf1, CopyOnWriteBuffer(kTestData, 3)); + EXPECT_EQ(buf2, CopyOnWriteBuffer(data)); +} + +TEST(CopyOnWriteBufferTest, SetDataOnSharedKeepsCapacity) { + CopyOnWriteBuffer buf1(kTestData, 3, 10); + CopyOnWriteBuffer buf2(buf1); + EnsureBuffersShareData(buf1, buf2); + + buf2.SetData(kTestData, 2); + + EnsureBuffersDontShareData(buf1, buf2); + EXPECT_EQ(2u, buf2.size()); + EXPECT_EQ(10u, buf2.capacity()); +} + +TEST(CopyOnWriteBufferTest, TestEnsureCapacity) { + CopyOnWriteBuffer buf1(kTestData, 3, 10); + CopyOnWriteBuffer buf2(buf1); + + // Smaller than existing capacity -> no change and still same contents. + buf2.EnsureCapacity(8); + EnsureBuffersShareData(buf1, buf2); + EXPECT_EQ(buf1.size(), 3u); + EXPECT_EQ(buf1.capacity(), 10u); + EXPECT_EQ(buf2.size(), 3u); + EXPECT_EQ(buf2.capacity(), 10u); + + // Lager than existing capacity -> data is cloned. + buf2.EnsureCapacity(16); + EnsureBuffersDontShareData(buf1, buf2); + EXPECT_EQ(buf1.size(), 3u); + EXPECT_EQ(buf1.capacity(), 10u); + EXPECT_EQ(buf2.size(), 3u); + EXPECT_EQ(buf2.capacity(), 16u); + // The size and contents are still the same. + EXPECT_EQ(buf1, buf2); +} + +TEST(CopyOnWriteBufferTest, SetSizeDoesntChangeOriginal) { + CopyOnWriteBuffer buf1(kTestData, 3, 10); + const uint8_t* const original_allocation = buf1.cdata(); + CopyOnWriteBuffer buf2(buf1); + + buf2.SetSize(16); + + EnsureBuffersDontShareData(buf1, buf2); + EXPECT_EQ(original_allocation, buf1.cdata()); + EXPECT_EQ(3u, buf1.size()); + EXPECT_EQ(10u, buf1.capacity()); +} + +TEST(CopyOnWriteBufferTest, SetSizeCloneContent) { + CopyOnWriteBuffer buf1(kTestData, 3, 10); + CopyOnWriteBuffer buf2(buf1); + + buf2.SetSize(16); + + EXPECT_EQ(buf2.size(), 16u); + EXPECT_EQ(0, memcmp(buf2.data(), kTestData, 3)); +} + +TEST(CopyOnWriteBufferTest, SetSizeMayIncreaseCapacity) { + CopyOnWriteBuffer buf(kTestData, 3, 10); + + buf.SetSize(16); + + EXPECT_EQ(16u, buf.size()); + EXPECT_EQ(16u, buf.capacity()); +} + +TEST(CopyOnWriteBufferTest, SetSizeDoesntDecreaseCapacity) { + CopyOnWriteBuffer buf1(kTestData, 5, 10); + CopyOnWriteBuffer buf2(buf1); + + buf2.SetSize(2); + + EXPECT_EQ(2u, buf2.size()); + EXPECT_EQ(10u, buf2.capacity()); +} + +TEST(CopyOnWriteBufferTest, ClearDoesntChangeOriginal) { + CopyOnWriteBuffer buf1(kTestData, 3, 10); + const uint8_t* const original_allocation = buf1.cdata(); + CopyOnWriteBuffer buf2(buf1); + + buf2.Clear(); + + EnsureBuffersDontShareData(buf1, buf2); + EXPECT_EQ(3u, buf1.size()); + EXPECT_EQ(10u, buf1.capacity()); + EXPECT_EQ(original_allocation, buf1.cdata()); + EXPECT_EQ(0u, buf2.size()); +} + +TEST(CopyOnWriteBufferTest, ClearDoesntChangeCapacity) { + CopyOnWriteBuffer buf1(kTestData, 3, 10); + CopyOnWriteBuffer buf2(buf1); + + buf2.Clear(); + + EXPECT_EQ(0u, buf2.size()); + EXPECT_EQ(10u, buf2.capacity()); +} + +TEST(CopyOnWriteBufferTest, DataAccessorDoesntCloneData) { + CopyOnWriteBuffer buf1(kTestData, 3, 10); + CopyOnWriteBuffer buf2(buf1); + + EXPECT_EQ(buf1.data(), buf2.data()); +} + +TEST(CopyOnWriteBufferTest, MutableDataClonesDataWhenShared) { + CopyOnWriteBuffer buf1(kTestData, 3, 10); + CopyOnWriteBuffer buf2(buf1); + const uint8_t* cdata = buf1.data(); + + uint8_t* data1 = buf1.MutableData(); + uint8_t* data2 = buf2.MutableData(); + // buf1 was cloned above. + EXPECT_NE(data1, cdata); + // Therefore buf2 was no longer sharing data and was not cloned. + EXPECT_EQ(data2, cdata); +} + +TEST(CopyOnWriteBufferTest, SeveralReads) { + CopyOnWriteBuffer buf1(kTestData, 3, 10); + CopyOnWriteBuffer buf2(buf1); + + EnsureBuffersShareData(buf1, buf2); + for (size_t i = 0; i != 3u; ++i) { + EXPECT_EQ(buf1[i], kTestData[i]); + } + EnsureBuffersShareData(buf1, buf2); +} + +TEST(CopyOnWriteBufferTest, SeveralWrites) { + CopyOnWriteBuffer buf1(kTestData, 3, 10); + CopyOnWriteBuffer buf2(buf1); + + EnsureBuffersShareData(buf1, buf2); + for (size_t i = 0; i != 3u; ++i) { + buf1.MutableData()[i] = kTestData[i] + 1; + } + EXPECT_EQ(buf1.size(), 3u); + EXPECT_EQ(buf1.capacity(), 10u); + EXPECT_EQ(buf2.size(), 3u); + EXPECT_EQ(buf2.capacity(), 10u); + EXPECT_EQ(0, memcmp(buf2.cdata(), kTestData, 3)); +} + +TEST(CopyOnWriteBufferTest, CreateSlice) { + CopyOnWriteBuffer buf(kTestData, 10, 10); + CopyOnWriteBuffer slice = buf.Slice(3, 4); + EXPECT_EQ(slice.size(), 4u); + EXPECT_EQ(0, memcmp(buf.cdata() + 3, slice.cdata(), 4)); +} + +TEST(CopyOnWriteBufferTest, NoCopyDataOnSlice) { + CopyOnWriteBuffer buf(kTestData, 10, 10); + CopyOnWriteBuffer slice = buf.Slice(3, 4); + EXPECT_EQ(buf.cdata() + 3, slice.cdata()); +} + +TEST(CopyOnWriteBufferTest, WritingCopiesData) { + CopyOnWriteBuffer buf(kTestData, 10, 10); + CopyOnWriteBuffer slice = buf.Slice(3, 4); + slice.MutableData()[0] = 0xaa; + EXPECT_NE(buf.cdata() + 3, slice.cdata()); + EXPECT_EQ(0, memcmp(buf.cdata(), kTestData, 10)); +} + +TEST(CopyOnWriteBufferTest, WritingToBufferDoesntAffectsSlice) { + CopyOnWriteBuffer buf(kTestData, 10, 10); + CopyOnWriteBuffer slice = buf.Slice(3, 4); + buf.MutableData()[0] = 0xaa; + EXPECT_NE(buf.cdata() + 3, slice.cdata()); + EXPECT_EQ(0, memcmp(slice.cdata(), kTestData + 3, 4)); +} + +TEST(CopyOnWriteBufferTest, SliceOfASlice) { + CopyOnWriteBuffer buf(kTestData, 10, 10); + CopyOnWriteBuffer slice = buf.Slice(3, 7); + CopyOnWriteBuffer slice2 = slice.Slice(2, 3); + EXPECT_EQ(slice2.size(), 3u); + EXPECT_EQ(slice.cdata() + 2, slice2.cdata()); + EXPECT_EQ(buf.cdata() + 5, slice2.cdata()); +} + +TEST(CopyOnWriteBufferTest, SlicesAreIndependent) { + CopyOnWriteBuffer buf(kTestData, 10, 10); + CopyOnWriteBuffer slice = buf.Slice(3, 7); + CopyOnWriteBuffer slice2 = buf.Slice(3, 7); + slice2.MutableData()[0] = 0xaa; + EXPECT_EQ(buf.cdata() + 3, slice.cdata()); +} + +TEST(CopyOnWriteBufferTest, AcceptsVectorLikeTypes) { + std::vector<uint8_t> a = {1, 2}; + std::vector<int8_t> b = {3, 4}; + rtc::ArrayView<uint8_t> c(a); + rtc::ArrayView<const int8_t> d(b); + + CopyOnWriteBuffer a_buf(a); + CopyOnWriteBuffer b_buf(b); + CopyOnWriteBuffer c_buf(c); + CopyOnWriteBuffer d_buf(d); + + CopyOnWriteBuffer all; + all.AppendData(a); + all.AppendData(b); + all.AppendData(c); + all.AppendData(d); + + EXPECT_EQ(all.size(), 8U); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/cpu_time.cc b/third_party/libwebrtc/rtc_base/cpu_time.cc new file mode 100644 index 0000000000..d3fee50c49 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/cpu_time.cc @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2017 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 "rtc_base/cpu_time.h" + +#include "rtc_base/logging.h" +#include "rtc_base/time_utils.h" + +#if defined(WEBRTC_LINUX) +#include <time.h> +#elif defined(WEBRTC_MAC) +#include <mach/mach_init.h> +#include <mach/mach_port.h> +#include <mach/thread_act.h> +#include <mach/thread_info.h> +#include <sys/resource.h> +#include <sys/times.h> +#include <sys/types.h> +#include <unistd.h> +#elif defined(WEBRTC_WIN) +#include <windows.h> +#elif defined(WEBRTC_FUCHSIA) +#include <lib/zx/process.h> +#include <lib/zx/thread.h> +#include <zircon/status.h> +#endif + +#if defined(WEBRTC_WIN) +namespace { +// FILETIME resolution is 100 nanosecs. +const int64_t kNanosecsPerFiletime = 100; +} // namespace +#endif + +namespace rtc { + +int64_t GetProcessCpuTimeNanos() { +#if defined(WEBRTC_FUCHSIA) + zx_info_task_runtime_t runtime_info; + zx_status_t status = + zx::process::self()->get_info(ZX_INFO_TASK_RUNTIME, &runtime_info, + sizeof(runtime_info), nullptr, nullptr); + if (status == ZX_OK) { + return runtime_info.cpu_time; + } else { + RTC_LOG_ERR(LS_ERROR) << "get_info() failed: " + << zx_status_get_string(status); + } +#elif defined(WEBRTC_LINUX) + struct timespec ts; + if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts) == 0) { + return ts.tv_sec * kNumNanosecsPerSec + ts.tv_nsec; + } else { + RTC_LOG_ERR(LS_ERROR) << "clock_gettime() failed."; + } +#elif defined(WEBRTC_MAC) + struct rusage rusage; + if (getrusage(RUSAGE_SELF, &rusage) == 0) { + return rusage.ru_utime.tv_sec * kNumNanosecsPerSec + + rusage.ru_utime.tv_usec * kNumNanosecsPerMicrosec; + } else { + RTC_LOG_ERR(LS_ERROR) << "getrusage() failed."; + } +#elif defined(WEBRTC_WIN) + FILETIME createTime; + FILETIME exitTime; + FILETIME kernelTime; + FILETIME userTime; + if (GetProcessTimes(GetCurrentProcess(), &createTime, &exitTime, &kernelTime, + &userTime) != 0) { + return ((static_cast<uint64_t>(userTime.dwHighDateTime) << 32) + + userTime.dwLowDateTime) * + kNanosecsPerFiletime; + } else { + RTC_LOG_ERR(LS_ERROR) << "GetProcessTimes() failed."; + } +#else + // Not implemented yet. + static_assert( + false, "GetProcessCpuTimeNanos() platform support not yet implemented."); +#endif + return -1; +} + +int64_t GetThreadCpuTimeNanos() { +#if defined(WEBRTC_FUCHSIA) + zx_info_task_runtime_t runtime_info; + zx_status_t status = + zx::thread::self()->get_info(ZX_INFO_TASK_RUNTIME, &runtime_info, + sizeof(runtime_info), nullptr, nullptr); + if (status == ZX_OK) { + return runtime_info.cpu_time; + } else { + RTC_LOG_ERR(LS_ERROR) << "get_info() failed: " + << zx_status_get_string(status); + } +#elif defined(WEBRTC_LINUX) + struct timespec ts; + if (clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts) == 0) { + return ts.tv_sec * kNumNanosecsPerSec + ts.tv_nsec; + } else { + RTC_LOG_ERR(LS_ERROR) << "clock_gettime() failed."; + } +#elif defined(WEBRTC_MAC) + mach_port_t thread_port = mach_thread_self(); + thread_basic_info_data_t info; + mach_msg_type_number_t count = THREAD_BASIC_INFO_COUNT; + kern_return_t kr = + thread_info(thread_port, THREAD_BASIC_INFO, (thread_info_t)&info, &count); + mach_port_deallocate(mach_task_self(), thread_port); + if (kr == KERN_SUCCESS) { + return info.user_time.seconds * kNumNanosecsPerSec + + info.user_time.microseconds * kNumNanosecsPerMicrosec; + } else { + RTC_LOG_ERR(LS_ERROR) << "thread_info() failed."; + } +#elif defined(WEBRTC_WIN) + FILETIME createTime; + FILETIME exitTime; + FILETIME kernelTime; + FILETIME userTime; + if (GetThreadTimes(GetCurrentThread(), &createTime, &exitTime, &kernelTime, + &userTime) != 0) { + return ((static_cast<uint64_t>(userTime.dwHighDateTime) << 32) + + userTime.dwLowDateTime) * + kNanosecsPerFiletime; + } else { + RTC_LOG_ERR(LS_ERROR) << "GetThreadTimes() failed."; + } +#else + // Not implemented yet. + static_assert( + false, "GetThreadCpuTimeNanos() platform support not yet implemented."); +#endif + return -1; +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/cpu_time.h b/third_party/libwebrtc/rtc_base/cpu_time.h new file mode 100644 index 0000000000..f712f623a0 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/cpu_time.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2017 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 RTC_BASE_CPU_TIME_H_ +#define RTC_BASE_CPU_TIME_H_ + +#include <stdint.h> + +namespace rtc { + +// Returns total CPU time of a current process in nanoseconds. +// Time base is unknown, therefore use only to calculate deltas. +int64_t GetProcessCpuTimeNanos(); + +// Returns total CPU time of a current thread in nanoseconds. +// Time base is unknown, therefore use only to calculate deltas. +int64_t GetThreadCpuTimeNanos(); + +} // namespace rtc + +#endif // RTC_BASE_CPU_TIME_H_ diff --git a/third_party/libwebrtc/rtc_base/cpu_time_unittest.cc b/third_party/libwebrtc/rtc_base/cpu_time_unittest.cc new file mode 100644 index 0000000000..94f82f4306 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/cpu_time_unittest.cc @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2017 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 "rtc_base/cpu_time.h" + +#include "rtc_base/platform_thread.h" +#include "rtc_base/time_utils.h" +#include "system_wrappers/include/sleep.h" +#include "test/gtest.h" + +// Only run these tests on non-instrumented builds, because timing on +// instrumented builds is unreliable, causing the test to be flaky. +#if defined(THREAD_SANITIZER) || defined(MEMORY_SANITIZER) || \ + defined(ADDRESS_SANITIZER) +#define MAYBE_TEST(test_name) DISABLED_##test_name +#else +#define MAYBE_TEST(test_name) test_name +#endif + +namespace { +const int kAllowedErrorMillisecs = 30; +const int kProcessingTimeMillisecs = 500; +const int kWorkingThreads = 2; + +// Consumes approximately kProcessingTimeMillisecs of CPU time in single thread. +void WorkingFunction(int64_t* counter) { + *counter = 0; + int64_t stop_cpu_time = + rtc::GetThreadCpuTimeNanos() + + kProcessingTimeMillisecs * rtc::kNumNanosecsPerMillisec; + while (rtc::GetThreadCpuTimeNanos() < stop_cpu_time) { + (*counter)++; + } +} +} // namespace + +namespace rtc { + +// A minimal test which can be run on instrumented builds, so that they're at +// least exercising the code to check for memory leaks/etc. +TEST(CpuTimeTest, BasicTest) { + int64_t process_start_time_nanos = GetProcessCpuTimeNanos(); + int64_t thread_start_time_nanos = GetThreadCpuTimeNanos(); + int64_t process_duration_nanos = + GetProcessCpuTimeNanos() - process_start_time_nanos; + int64_t thread_duration_nanos = + GetThreadCpuTimeNanos() - thread_start_time_nanos; + EXPECT_GE(process_duration_nanos, 0); + EXPECT_GE(thread_duration_nanos, 0); +} + +TEST(CpuTimeTest, MAYBE_TEST(TwoThreads)) { + int64_t process_start_time_nanos = GetProcessCpuTimeNanos(); + int64_t thread_start_time_nanos = GetThreadCpuTimeNanos(); + int64_t counter1; + int64_t counter2; + auto thread1 = PlatformThread::SpawnJoinable( + [&counter1] { WorkingFunction(&counter1); }, "Thread1"); + auto thread2 = PlatformThread::SpawnJoinable( + [&counter2] { WorkingFunction(&counter2); }, "Thread2"); + thread1.Finalize(); + thread2.Finalize(); + + EXPECT_GE(counter1, 0); + EXPECT_GE(counter2, 0); + int64_t process_duration_nanos = + GetProcessCpuTimeNanos() - process_start_time_nanos; + int64_t thread_duration_nanos = + GetThreadCpuTimeNanos() - thread_start_time_nanos; + // This thread did almost nothing. Definetly less work than kProcessingTime. + // Therefore GetThreadCpuTime is not a wall clock. + EXPECT_LE(thread_duration_nanos, + (kProcessingTimeMillisecs - kAllowedErrorMillisecs) * + kNumNanosecsPerMillisec); + // Total process time is at least twice working threads' CPU time. + // Therefore process and thread times are correctly related. + EXPECT_GE(process_duration_nanos, + kWorkingThreads * + (kProcessingTimeMillisecs - kAllowedErrorMillisecs) * + kNumNanosecsPerMillisec); +} + +TEST(CpuTimeTest, MAYBE_TEST(Sleeping)) { + int64_t process_start_time_nanos = GetProcessCpuTimeNanos(); + webrtc::SleepMs(kProcessingTimeMillisecs); + int64_t process_duration_nanos = + GetProcessCpuTimeNanos() - process_start_time_nanos; + // Sleeping should not introduce any additional CPU time. + // Therefore GetProcessCpuTime is not a wall clock. + EXPECT_LE(process_duration_nanos, + (kProcessingTimeMillisecs - kAllowedErrorMillisecs) * + kNumNanosecsPerMillisec); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/crc32.cc b/third_party/libwebrtc/rtc_base/crc32.cc new file mode 100644 index 0000000000..42f86cb268 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/crc32.cc @@ -0,0 +1,50 @@ +/* + * Copyright 2012 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 "rtc_base/crc32.h" + +#include "rtc_base/arraysize.h" + +namespace rtc { + +// This implementation is based on the sample implementation in RFC 1952. + +// CRC32 polynomial, in reversed form. +// See RFC 1952, or http://en.wikipedia.org/wiki/Cyclic_redundancy_check +static const uint32_t kCrc32Polynomial = 0xEDB88320; + +static uint32_t* LoadCrc32Table() { + static uint32_t kCrc32Table[256]; + for (uint32_t i = 0; i < arraysize(kCrc32Table); ++i) { + uint32_t c = i; + for (size_t j = 0; j < 8; ++j) { + if (c & 1) { + c = kCrc32Polynomial ^ (c >> 1); + } else { + c >>= 1; + } + } + kCrc32Table[i] = c; + } + return kCrc32Table; +} + +uint32_t UpdateCrc32(uint32_t start, const void* buf, size_t len) { + static uint32_t* kCrc32Table = LoadCrc32Table(); + + uint32_t c = start ^ 0xFFFFFFFF; + const uint8_t* u = static_cast<const uint8_t*>(buf); + for (size_t i = 0; i < len; ++i) { + c = kCrc32Table[(c ^ u[i]) & 0xFF] ^ (c >> 8); + } + return c ^ 0xFFFFFFFF; +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/crc32.h b/third_party/libwebrtc/rtc_base/crc32.h new file mode 100644 index 0000000000..93376a5a12 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/crc32.h @@ -0,0 +1,37 @@ +/* + * Copyright 2012 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 RTC_BASE_CRC32_H_ +#define RTC_BASE_CRC32_H_ + +#include <stddef.h> +#include <stdint.h> + +#include <string> + +#include "absl/strings/string_view.h" + +namespace rtc { + +// Updates a CRC32 checksum with `len` bytes from `buf`. `initial` holds the +// checksum result from the previous update; for the first call, it should be 0. +uint32_t UpdateCrc32(uint32_t initial, const void* buf, size_t len); + +// Computes a CRC32 checksum using `len` bytes from `buf`. +inline uint32_t ComputeCrc32(const void* buf, size_t len) { + return UpdateCrc32(0, buf, len); +} +inline uint32_t ComputeCrc32(absl::string_view str) { + return ComputeCrc32(str.data(), str.size()); +} + +} // namespace rtc + +#endif // RTC_BASE_CRC32_H_ diff --git a/third_party/libwebrtc/rtc_base/crc32_unittest.cc b/third_party/libwebrtc/rtc_base/crc32_unittest.cc new file mode 100644 index 0000000000..60997b27ae --- /dev/null +++ b/third_party/libwebrtc/rtc_base/crc32_unittest.cc @@ -0,0 +1,37 @@ +/* + * Copyright 2012 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 "rtc_base/crc32.h" + +#include <string> + +#include "test/gtest.h" + +namespace rtc { + +TEST(Crc32Test, TestBasic) { + EXPECT_EQ(0U, ComputeCrc32("")); + EXPECT_EQ(0x352441C2U, ComputeCrc32("abc")); + EXPECT_EQ( + 0x171A3F5FU, + ComputeCrc32("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq")); +} + +TEST(Crc32Test, TestMultipleUpdates) { + std::string input = + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"; + uint32_t c = 0; + for (size_t i = 0; i < input.size(); ++i) { + c = UpdateCrc32(c, &input[i], 1); + } + EXPECT_EQ(0x171A3F5FU, c); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/criticalsection_gn/moz.build b/third_party/libwebrtc/rtc_base/criticalsection_gn/moz.build new file mode 100644 index 0000000000..4aa1aa4353 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/criticalsection_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/rtc_base/deprecated/recursive_critical_section.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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("criticalsection_gn") diff --git a/third_party/libwebrtc/rtc_base/crypt_string.cc b/third_party/libwebrtc/rtc_base/crypt_string.cc new file mode 100644 index 0000000000..cf38a5bbaa --- /dev/null +++ b/third_party/libwebrtc/rtc_base/crypt_string.cc @@ -0,0 +1,46 @@ +/* + * Copyright 2015 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 "rtc_base/crypt_string.h" + +namespace rtc { + +size_t EmptyCryptStringImpl::GetLength() const { + return 0; +} + +void EmptyCryptStringImpl::CopyTo(char* dest, bool nullterminate) const { + if (nullterminate) { + *dest = '\0'; + } +} + +std::string EmptyCryptStringImpl::UrlEncode() const { + return ""; +} + +CryptStringImpl* EmptyCryptStringImpl::Copy() const { + return new EmptyCryptStringImpl(); +} + +void EmptyCryptStringImpl::CopyRawTo(std::vector<unsigned char>* dest) const { + dest->clear(); +} + +CryptString::CryptString() : impl_(new EmptyCryptStringImpl()) {} + +CryptString::CryptString(const CryptString& other) + : impl_(other.impl_->Copy()) {} + +CryptString::CryptString(const CryptStringImpl& impl) : impl_(impl.Copy()) {} + +CryptString::~CryptString() = default; + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/crypt_string.h b/third_party/libwebrtc/rtc_base/crypt_string.h new file mode 100644 index 0000000000..470bd00c42 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/crypt_string.h @@ -0,0 +1,70 @@ +/* + * 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 RTC_BASE_CRYPT_STRING_H_ +#define RTC_BASE_CRYPT_STRING_H_ + +#include <string.h> + +#include <memory> +#include <string> +#include <vector> + +namespace rtc { + +class CryptStringImpl { + public: + virtual ~CryptStringImpl() {} + virtual size_t GetLength() const = 0; + virtual void CopyTo(char* dest, bool nullterminate) const = 0; + virtual std::string UrlEncode() const = 0; + virtual CryptStringImpl* Copy() const = 0; + virtual void CopyRawTo(std::vector<unsigned char>* dest) const = 0; +}; + +class EmptyCryptStringImpl : public CryptStringImpl { + public: + ~EmptyCryptStringImpl() override {} + size_t GetLength() const override; + void CopyTo(char* dest, bool nullterminate) const override; + std::string UrlEncode() const override; + CryptStringImpl* Copy() const override; + void CopyRawTo(std::vector<unsigned char>* dest) const override; +}; + +class CryptString { + public: + CryptString(); + size_t GetLength() const { return impl_->GetLength(); } + void CopyTo(char* dest, bool nullterminate) const { + impl_->CopyTo(dest, nullterminate); + } + CryptString(const CryptString& other); + explicit CryptString(const CryptStringImpl& impl); + ~CryptString(); + CryptString& operator=(const CryptString& other) { + if (this != &other) { + impl_.reset(other.impl_->Copy()); + } + return *this; + } + void Clear() { impl_.reset(new EmptyCryptStringImpl()); } + std::string UrlEncode() const { return impl_->UrlEncode(); } + void CopyRawTo(std::vector<unsigned char>* dest) const { + return impl_->CopyRawTo(dest); + } + + private: + std::unique_ptr<const CryptStringImpl> impl_; +}; + +} // namespace rtc + +#endif // RTC_BASE_CRYPT_STRING_H_ diff --git a/third_party/libwebrtc/rtc_base/data_rate_limiter.cc b/third_party/libwebrtc/rtc_base/data_rate_limiter.cc new file mode 100644 index 0000000000..7288257d76 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/data_rate_limiter.cc @@ -0,0 +1,29 @@ +/* + * Copyright 2012 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 "rtc_base/data_rate_limiter.h" + +namespace rtc { + +bool DataRateLimiter::CanUse(size_t desired, double time) { + return ((time > period_end_ && desired <= max_per_period_) || + (used_in_period_ + desired) <= max_per_period_); +} + +void DataRateLimiter::Use(size_t used, double time) { + if (time > period_end_) { + period_start_ = time; + period_end_ = time + period_length_; + used_in_period_ = 0; + } + used_in_period_ += used; +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/data_rate_limiter.h b/third_party/libwebrtc/rtc_base/data_rate_limiter.h new file mode 100644 index 0000000000..502a2f74b2 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/data_rate_limiter.h @@ -0,0 +1,58 @@ +/* + * Copyright 2012 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 RTC_BASE_DATA_RATE_LIMITER_H_ +#define RTC_BASE_DATA_RATE_LIMITER_H_ + +#include <stddef.h> + +#include "rtc_base/system/rtc_export.h" + +namespace rtc { + +// Limits the rate of use to a certain maximum quantity per period of +// time. Use, for example, for simple bandwidth throttling. +// +// It's implemented like a diet plan: You have so many calories per +// day. If you hit the limit, you can't eat any more until the next +// day. +class RTC_EXPORT DataRateLimiter { + public: + // For example, 100kb per second. + DataRateLimiter(size_t max, double period) + : max_per_period_(max), + period_length_(period), + used_in_period_(0), + period_start_(0.0), + period_end_(period) {} + virtual ~DataRateLimiter() {} + + // Returns true if if the desired quantity is available in the + // current period (< (max - used)). Once the given time passes the + // end of the period, used is set to zero and more use is available. + bool CanUse(size_t desired, double time); + // Increment the quantity used this period. If past the end of a + // period, a new period is started. + void Use(size_t used, double time); + + size_t used_in_period() const { return used_in_period_; } + + size_t max_per_period() const { return max_per_period_; } + + private: + size_t max_per_period_; + double period_length_; + size_t used_in_period_; + double period_start_; + double period_end_; +}; +} // namespace rtc + +#endif // RTC_BASE_DATA_RATE_LIMITER_H_ diff --git a/third_party/libwebrtc/rtc_base/data_rate_limiter_unittest.cc b/third_party/libwebrtc/rtc_base/data_rate_limiter_unittest.cc new file mode 100644 index 0000000000..efd472889c --- /dev/null +++ b/third_party/libwebrtc/rtc_base/data_rate_limiter_unittest.cc @@ -0,0 +1,60 @@ +/* + * Copyright 2012 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 "rtc_base/data_rate_limiter.h" + +#include "test/gtest.h" + +namespace rtc { + +TEST(RateLimiterTest, TestCanUse) { + // Diet: Can eat 2,000 calories per day. + DataRateLimiter limiter = DataRateLimiter(2000, 1.0); + + double monday = 1.0; + double tuesday = 2.0; + double thursday = 4.0; + + EXPECT_TRUE(limiter.CanUse(0, monday)); + EXPECT_TRUE(limiter.CanUse(1000, monday)); + EXPECT_TRUE(limiter.CanUse(1999, monday)); + EXPECT_TRUE(limiter.CanUse(2000, monday)); + EXPECT_FALSE(limiter.CanUse(2001, monday)); + + limiter.Use(1000, monday); + + EXPECT_TRUE(limiter.CanUse(0, monday)); + EXPECT_TRUE(limiter.CanUse(999, monday)); + EXPECT_TRUE(limiter.CanUse(1000, monday)); + EXPECT_FALSE(limiter.CanUse(1001, monday)); + + limiter.Use(1000, monday); + + EXPECT_TRUE(limiter.CanUse(0, monday)); + EXPECT_FALSE(limiter.CanUse(1, monday)); + + EXPECT_TRUE(limiter.CanUse(0, tuesday)); + EXPECT_TRUE(limiter.CanUse(1, tuesday)); + EXPECT_TRUE(limiter.CanUse(1999, tuesday)); + EXPECT_TRUE(limiter.CanUse(2000, tuesday)); + EXPECT_FALSE(limiter.CanUse(2001, tuesday)); + + limiter.Use(1000, tuesday); + + EXPECT_TRUE(limiter.CanUse(1000, tuesday)); + EXPECT_FALSE(limiter.CanUse(1001, tuesday)); + + limiter.Use(1000, thursday); + + EXPECT_TRUE(limiter.CanUse(1000, tuesday)); + EXPECT_FALSE(limiter.CanUse(1001, tuesday)); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/deprecated/recursive_critical_section.cc b/third_party/libwebrtc/rtc_base/deprecated/recursive_critical_section.cc new file mode 100644 index 0000000000..540819888e --- /dev/null +++ b/third_party/libwebrtc/rtc_base/deprecated/recursive_critical_section.cc @@ -0,0 +1,218 @@ +/* + * Copyright 2015 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 "rtc_base/deprecated/recursive_critical_section.h" + +#include <time.h> + +#include "rtc_base/checks.h" +#include "rtc_base/platform_thread_types.h" +#include "rtc_base/synchronization/yield.h" +#include "rtc_base/system/unused.h" + +#if RTC_DCHECK_IS_ON +#define RTC_CS_DEBUG_CODE(x) x +#else // !RTC_DCHECK_IS_ON +#define RTC_CS_DEBUG_CODE(x) +#endif // !RTC_DCHECK_IS_ON + +namespace rtc { + +RecursiveCriticalSection::RecursiveCriticalSection() { +#if defined(WEBRTC_WIN) + InitializeCriticalSection(&crit_); +#elif defined(WEBRTC_POSIX) +#if defined(WEBRTC_MAC) && !RTC_USE_NATIVE_MUTEX_ON_MAC + lock_queue_ = 0; + owning_thread_ = 0; + recursion_ = 0; + semaphore_ = dispatch_semaphore_create(0); +#else + pthread_mutexattr_t mutex_attribute; + pthread_mutexattr_init(&mutex_attribute); + pthread_mutexattr_settype(&mutex_attribute, PTHREAD_MUTEX_RECURSIVE); +#if defined(WEBRTC_MAC) + pthread_mutexattr_setpolicy_np(&mutex_attribute, + _PTHREAD_MUTEX_POLICY_FIRSTFIT); +#endif + pthread_mutex_init(&mutex_, &mutex_attribute); + pthread_mutexattr_destroy(&mutex_attribute); +#endif + RTC_CS_DEBUG_CODE(thread_ = 0); + RTC_CS_DEBUG_CODE(recursion_count_ = 0); + RTC_UNUSED(thread_); + RTC_UNUSED(recursion_count_); +#else +#error Unsupported platform. +#endif +} + +RecursiveCriticalSection::~RecursiveCriticalSection() { +#if defined(WEBRTC_WIN) + DeleteCriticalSection(&crit_); +#elif defined(WEBRTC_POSIX) +#if defined(WEBRTC_MAC) && !RTC_USE_NATIVE_MUTEX_ON_MAC + dispatch_release(semaphore_); +#else + pthread_mutex_destroy(&mutex_); +#endif +#else +#error Unsupported platform. +#endif +} + +void RecursiveCriticalSection::Enter() const RTC_EXCLUSIVE_LOCK_FUNCTION() { +#if defined(WEBRTC_WIN) + EnterCriticalSection(&crit_); +#elif defined(WEBRTC_POSIX) +#if defined(WEBRTC_MAC) && !RTC_USE_NATIVE_MUTEX_ON_MAC + int spin = 3000; + PlatformThreadRef self = CurrentThreadRef(); + bool have_lock = false; + do { + // Instead of calling TryEnter() in this loop, we do two interlocked + // operations, first a read-only one in order to avoid affecting the lock + // cache-line while spinning, in case another thread is using the lock. + if (!IsThreadRefEqual(owning_thread_, self)) { + if (AtomicOps::AcquireLoad(&lock_queue_) == 0) { + if (AtomicOps::CompareAndSwap(&lock_queue_, 0, 1) == 0) { + have_lock = true; + break; + } + } + } else { + AtomicOps::Increment(&lock_queue_); + have_lock = true; + break; + } + + sched_yield(); + } while (--spin); + + if (!have_lock && AtomicOps::Increment(&lock_queue_) > 1) { + // Owning thread cannot be the current thread since TryEnter() would + // have succeeded. + RTC_DCHECK(!IsThreadRefEqual(owning_thread_, self)); + // Wait for the lock to become available. + dispatch_semaphore_wait(semaphore_, DISPATCH_TIME_FOREVER); + RTC_DCHECK(owning_thread_ == 0); + RTC_DCHECK(!recursion_); + } + + owning_thread_ = self; + ++recursion_; + +#else + pthread_mutex_lock(&mutex_); +#endif + +#if RTC_DCHECK_IS_ON + if (!recursion_count_) { + RTC_DCHECK(!thread_); + thread_ = CurrentThreadRef(); + } else { + RTC_DCHECK(CurrentThreadIsOwner()); + } + ++recursion_count_; +#endif +#else +#error Unsupported platform. +#endif +} + +bool RecursiveCriticalSection::TryEnter() const + RTC_EXCLUSIVE_TRYLOCK_FUNCTION(true) { +#if defined(WEBRTC_WIN) + return TryEnterCriticalSection(&crit_) != FALSE; +#elif defined(WEBRTC_POSIX) +#if defined(WEBRTC_MAC) && !RTC_USE_NATIVE_MUTEX_ON_MAC + if (!IsThreadRefEqual(owning_thread_, CurrentThreadRef())) { + if (AtomicOps::CompareAndSwap(&lock_queue_, 0, 1) != 0) + return false; + owning_thread_ = CurrentThreadRef(); + RTC_DCHECK(!recursion_); + } else { + AtomicOps::Increment(&lock_queue_); + } + ++recursion_; +#else + if (pthread_mutex_trylock(&mutex_) != 0) + return false; +#endif +#if RTC_DCHECK_IS_ON + if (!recursion_count_) { + RTC_DCHECK(!thread_); + thread_ = CurrentThreadRef(); + } else { + RTC_DCHECK(CurrentThreadIsOwner()); + } + ++recursion_count_; +#endif + return true; +#else +#error Unsupported platform. +#endif +} + +void RecursiveCriticalSection::Leave() const RTC_UNLOCK_FUNCTION() { + RTC_DCHECK(CurrentThreadIsOwner()); +#if defined(WEBRTC_WIN) + LeaveCriticalSection(&crit_); +#elif defined(WEBRTC_POSIX) +#if RTC_DCHECK_IS_ON + --recursion_count_; + RTC_DCHECK(recursion_count_ >= 0); + if (!recursion_count_) + thread_ = 0; +#endif +#if defined(WEBRTC_MAC) && !RTC_USE_NATIVE_MUTEX_ON_MAC + RTC_DCHECK(IsThreadRefEqual(owning_thread_, CurrentThreadRef())); + RTC_DCHECK_GE(recursion_, 0); + --recursion_; + if (!recursion_) + owning_thread_ = 0; + + if (AtomicOps::Decrement(&lock_queue_) > 0 && !recursion_) + dispatch_semaphore_signal(semaphore_); +#else + pthread_mutex_unlock(&mutex_); +#endif +#else +#error Unsupported platform. +#endif +} + +bool RecursiveCriticalSection::CurrentThreadIsOwner() const { +#if defined(WEBRTC_WIN) + // OwningThread has type HANDLE but actually contains the Thread ID: + // http://stackoverflow.com/questions/12675301/why-is-the-owningthread-member-of-critical-section-of-type-handle-when-it-is-de + // Converting through size_t avoids the VS 2015 warning C4312: conversion from + // 'type1' to 'type2' of greater size + return crit_.OwningThread == + reinterpret_cast<HANDLE>(static_cast<size_t>(GetCurrentThreadId())); +#elif defined(WEBRTC_POSIX) +#if RTC_DCHECK_IS_ON + return IsThreadRefEqual(thread_, CurrentThreadRef()); +#else + return true; +#endif // RTC_DCHECK_IS_ON +#else +#error Unsupported platform. +#endif +} + +CritScope::CritScope(const RecursiveCriticalSection* cs) : cs_(cs) { + cs_->Enter(); +} +CritScope::~CritScope() { + cs_->Leave(); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/deprecated/recursive_critical_section.h b/third_party/libwebrtc/rtc_base/deprecated/recursive_critical_section.h new file mode 100644 index 0000000000..da1e92b9b0 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/deprecated/recursive_critical_section.h @@ -0,0 +1,107 @@ +/* + * 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 RTC_BASE_DEPRECATED_RECURSIVE_CRITICAL_SECTION_H_ +#define RTC_BASE_DEPRECATED_RECURSIVE_CRITICAL_SECTION_H_ + +#include <atomic> + +#include "rtc_base/platform_thread_types.h" +#include "rtc_base/thread_annotations.h" + +#if defined(WEBRTC_WIN) +// clang-format off +// clang formating would change include order. + +// Include winsock2.h before including <windows.h> to maintain consistency with +// win32.h. To include win32.h directly, it must be broken out into its own +// build target. +#include <winsock2.h> +#include <windows.h> +#include <sal.h> // must come after windows headers. +// clang-format on +#endif // defined(WEBRTC_WIN) + +#if defined(WEBRTC_POSIX) +#include <pthread.h> +#endif + +// See notes in the 'Performance' unit test for the effects of this flag. +#define RTC_USE_NATIVE_MUTEX_ON_MAC 1 + +#if defined(WEBRTC_MAC) && !RTC_USE_NATIVE_MUTEX_ON_MAC +#include <dispatch/dispatch.h> +#endif + +namespace rtc { + +// NOTE: This class is deprecated. Please use webrtc::Mutex instead! +// Search using https://www.google.com/?q=recursive+lock+considered+harmful +// to find the reasons. +// +// Locking methods (Enter, TryEnter, Leave)are const to permit protecting +// members inside a const context without requiring mutable +// RecursiveCriticalSections everywhere. RecursiveCriticalSection is +// reentrant lock. +class RTC_LOCKABLE RecursiveCriticalSection { + public: + RecursiveCriticalSection(); + ~RecursiveCriticalSection(); + + void Enter() const RTC_EXCLUSIVE_LOCK_FUNCTION(); + bool TryEnter() const RTC_EXCLUSIVE_TRYLOCK_FUNCTION(true); + void Leave() const RTC_UNLOCK_FUNCTION(); + + private: + // Use only for RTC_DCHECKing. + bool CurrentThreadIsOwner() const; + +#if defined(WEBRTC_WIN) + mutable CRITICAL_SECTION crit_; +#elif defined(WEBRTC_POSIX) +#if defined(WEBRTC_MAC) && !RTC_USE_NATIVE_MUTEX_ON_MAC + // Number of times the lock has been locked + number of threads waiting. + // TODO(tommi): We could use this number and subtract the recursion count + // to find places where we have multiple threads contending on the same lock. + mutable std::atomic<int> lock_queue_; + // `recursion_` represents the recursion count + 1 for the thread that owns + // the lock. Only modified by the thread that owns the lock. + mutable int recursion_; + // Used to signal a single waiting thread when the lock becomes available. + mutable dispatch_semaphore_t semaphore_; + // The thread that currently holds the lock. Required to handle recursion. + mutable PlatformThreadRef owning_thread_; +#else + mutable pthread_mutex_t mutex_; +#endif + mutable PlatformThreadRef thread_; // Only used by RTC_DCHECKs. + mutable int recursion_count_; // Only used by RTC_DCHECKs. +#else // !defined(WEBRTC_WIN) && !defined(WEBRTC_POSIX) +#error Unsupported platform. +#endif +}; + +// CritScope, for serializing execution through a scope. +class RTC_SCOPED_LOCKABLE CritScope { + public: + explicit CritScope(const RecursiveCriticalSection* cs) + RTC_EXCLUSIVE_LOCK_FUNCTION(cs); + ~CritScope() RTC_UNLOCK_FUNCTION(); + + CritScope(const CritScope&) = delete; + CritScope& operator=(const CritScope&) = delete; + + private: + const RecursiveCriticalSection* const cs_; +}; + +} // namespace rtc + +#endif // RTC_BASE_DEPRECATED_RECURSIVE_CRITICAL_SECTION_H_ diff --git a/third_party/libwebrtc/rtc_base/deprecated/recursive_critical_section_unittest.cc b/third_party/libwebrtc/rtc_base/deprecated/recursive_critical_section_unittest.cc new file mode 100644 index 0000000000..38f003d555 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/deprecated/recursive_critical_section_unittest.cc @@ -0,0 +1,288 @@ +/* + * Copyright 2014 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 "rtc_base/deprecated/recursive_critical_section.h" + +#include <stddef.h> +#include <stdint.h> + +#include <memory> +#include <set> +#include <type_traits> +#include <utility> +#include <vector> + +#include "absl/base/attributes.h" +#include "rtc_base/arraysize.h" +#include "rtc_base/checks.h" +#include "rtc_base/event.h" +#include "rtc_base/platform_thread.h" +#include "rtc_base/thread.h" +#include "test/gtest.h" + +namespace rtc { + +namespace { + +constexpr webrtc::TimeDelta kLongTime = webrtc::TimeDelta::Seconds(10); +constexpr int kNumThreads = 16; +constexpr int kOperationsToRun = 1000; + +class UniqueValueVerifier { + public: + void Verify(const std::vector<int>& values) { + for (size_t i = 0; i < values.size(); ++i) { + std::pair<std::set<int>::iterator, bool> result = + all_values_.insert(values[i]); + // Each value should only be taken by one thread, so if this value + // has already been added, something went wrong. + EXPECT_TRUE(result.second) + << " Thread=" << Thread::Current() << " value=" << values[i]; + } + } + + void Finalize() {} + + private: + std::set<int> all_values_; +}; + +class CompareAndSwapVerifier { + public: + CompareAndSwapVerifier() : zero_count_(0) {} + + void Verify(const std::vector<int>& values) { + for (auto v : values) { + if (v == 0) { + EXPECT_EQ(0, zero_count_) << "Thread=" << Thread::Current(); + ++zero_count_; + } else { + EXPECT_EQ(1, v) << " Thread=" << Thread::Current(); + } + } + } + + void Finalize() { EXPECT_EQ(1, zero_count_); } + + private: + int zero_count_; +}; + +class RunnerBase { + public: + explicit RunnerBase(int value) + : threads_active_(0), + start_event_(true, false), + done_event_(true, false), + shared_value_(value) {} + + bool Run() { + // Signal all threads to start. + start_event_.Set(); + + // Wait for all threads to finish. + return done_event_.Wait(kLongTime); + } + + void SetExpectedThreadCount(int count) { threads_active_.store(count); } + + int shared_value() const { return shared_value_; } + + protected: + void BeforeStart() { ASSERT_TRUE(start_event_.Wait(kLongTime)); } + + // Returns true if all threads have finished. + bool AfterEnd() { + if (threads_active_.fetch_sub(1) == 1) { + done_event_.Set(); + return true; + } + return false; + } + + std::atomic<int> threads_active_; + Event start_event_; + Event done_event_; + int shared_value_; +}; + +class RTC_LOCKABLE CriticalSectionLock { + public: + void Lock() RTC_EXCLUSIVE_LOCK_FUNCTION() { cs_.Enter(); } + void Unlock() RTC_UNLOCK_FUNCTION() { cs_.Leave(); } + + private: + RecursiveCriticalSection cs_; +}; + +template <class Lock> +class LockRunner : public RunnerBase { + public: + LockRunner() : RunnerBase(0) {} + + void Loop() { + BeforeStart(); + + lock_.Lock(); + + EXPECT_EQ(0, shared_value_); + int old = shared_value_; + + // Use a loop to increase the chance of race. + for (int i = 0; i < kOperationsToRun; ++i) { + ++shared_value_; + } + EXPECT_EQ(old + kOperationsToRun, shared_value_); + shared_value_ = 0; + + lock_.Unlock(); + + AfterEnd(); + } + + private: + Lock lock_; +}; + +template <typename Runner> +void StartThreads(std::vector<std::unique_ptr<Thread>>* threads, + Runner* handler) { + for (int i = 0; i < kNumThreads; ++i) { + std::unique_ptr<Thread> thread(Thread::Create()); + thread->Start(); + thread->PostTask([handler] { handler->Loop(); }); + threads->push_back(std::move(thread)); + } +} + +} // namespace + +TEST(RecursiveCriticalSectionTest, Basic) { + // Create and start lots of threads. + LockRunner<CriticalSectionLock> runner; + std::vector<std::unique_ptr<Thread>> threads; + StartThreads(&threads, &runner); + runner.SetExpectedThreadCount(kNumThreads); + + // Release the hounds! + EXPECT_TRUE(runner.Run()); + EXPECT_EQ(0, runner.shared_value()); +} + +class PerfTestData { + public: + PerfTestData(int expected_count, Event* event) + : cache_line_barrier_1_(), + cache_line_barrier_2_(), + expected_count_(expected_count), + event_(event) { + cache_line_barrier_1_[0]++; // Avoid 'is not used'. + cache_line_barrier_2_[0]++; // Avoid 'is not used'. + } + ~PerfTestData() {} + + void AddToCounter(int add) { + rtc::CritScope cs(&lock_); + my_counter_ += add; + if (my_counter_ == expected_count_) + event_->Set(); + } + + int64_t total() const { + // Assume that only one thread is running now. + return my_counter_; + } + + private: + uint8_t cache_line_barrier_1_[64]; + RecursiveCriticalSection lock_; + uint8_t cache_line_barrier_2_[64]; + int64_t my_counter_ = 0; + const int expected_count_; + Event* const event_; +}; + +class PerfTestThread { + public: + void Start(PerfTestData* data, int repeats, int id) { + RTC_DCHECK(!data_); + data_ = data; + repeats_ = repeats; + my_id_ = id; + thread_ = PlatformThread::SpawnJoinable( + [this] { + for (int i = 0; i < repeats_; ++i) + data_->AddToCounter(my_id_); + }, + "CsPerf"); + } + + void Stop() { + RTC_DCHECK(data_); + thread_.Finalize(); + repeats_ = 0; + data_ = nullptr; + my_id_ = 0; + } + + private: + PlatformThread thread_; + PerfTestData* data_ = nullptr; + int repeats_ = 0; + int my_id_ = 0; +}; + +// Comparison of output of this test as tested on a MacBook Pro, 13-inch, +// 2017, 3,5 GHz Intel Core i7, 16 GB 2133 MHz LPDDR3, +// running macOS Mojave, 10.14.3. +// +// Native mutex implementation using fair policy (previously macOS default): +// Approximate CPU usage: +// real 4m54.612s +// user 1m20.575s +// sys 3m48.872s +// Unit test output: +// [ OK ] RecursiveCriticalSectionTest.Performance (294375 ms) +// +// Native mutex implementation using first fit policy (current macOS default): +// Approximate CPU usage: +// real 0m11.535s +// user 0m12.738s +// sys 0m31.207s +// Unit test output: +// [ OK ] RecursiveCriticalSectionTest.Performance (11444 ms) +// +// Special partially spin lock based implementation: +// Approximate CPU usage: +// real 0m2.113s +// user 0m3.014s +// sys 0m4.495s +// Unit test output: +// [ OK ] RecursiveCriticalSectionTest.Performance (1885 ms) +// +// The test is disabled by default to avoid unecessarily loading the bots. +TEST(RecursiveCriticalSectionTest, DISABLED_Performance) { + PerfTestThread threads[8]; + Event event; + + static const int kThreadRepeats = 10000000; + static const int kExpectedCount = kThreadRepeats * arraysize(threads); + PerfTestData test_data(kExpectedCount, &event); + + for (auto& t : threads) + t.Start(&test_data, kThreadRepeats, 1); + + event.Wait(Event::kForever); + + for (auto& t : threads) + t.Stop(); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/divide_round_gn/moz.build b/third_party/libwebrtc/rtc_base/divide_round_gn/moz.build new file mode 100644 index 0000000000..79146161c2 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/divide_round_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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("divide_round_gn") diff --git a/third_party/libwebrtc/rtc_base/dscp.h b/third_party/libwebrtc/rtc_base/dscp.h new file mode 100644 index 0000000000..3c39ca66da --- /dev/null +++ b/third_party/libwebrtc/rtc_base/dscp.h @@ -0,0 +1,45 @@ +/* + * Copyright 2013 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 RTC_BASE_DSCP_H_ +#define RTC_BASE_DSCP_H_ + +namespace rtc { +// Differentiated Services Code Point. +// See http://tools.ietf.org/html/rfc2474 for details. +enum DiffServCodePoint { + DSCP_NO_CHANGE = -1, + DSCP_DEFAULT = 0, // Same as DSCP_CS0 + DSCP_CS0 = 0, // The default + DSCP_CS1 = 8, // Bulk/background traffic + DSCP_AF11 = 10, + DSCP_AF12 = 12, + DSCP_AF13 = 14, + DSCP_CS2 = 16, + DSCP_AF21 = 18, + DSCP_AF22 = 20, + DSCP_AF23 = 22, + DSCP_CS3 = 24, + DSCP_AF31 = 26, + DSCP_AF32 = 28, + DSCP_AF33 = 30, + DSCP_CS4 = 32, + DSCP_AF41 = 34, // Video + DSCP_AF42 = 36, // Video + DSCP_AF43 = 38, // Video + DSCP_CS5 = 40, // Video + DSCP_EF = 46, // Voice + DSCP_CS6 = 48, // Voice + DSCP_CS7 = 56, // Control messages +}; + +} // namespace rtc + +#endif // RTC_BASE_DSCP_H_ diff --git a/third_party/libwebrtc/rtc_base/dscp_gn/moz.build b/third_party/libwebrtc/rtc_base/dscp_gn/moz.build new file mode 100644 index 0000000000..7bfe2d0c75 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/dscp_gn/moz.build @@ -0,0 +1,205 @@ +# 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("dscp_gn") diff --git a/third_party/libwebrtc/rtc_base/event.cc b/third_party/libwebrtc/rtc_base/event.cc new file mode 100644 index 0000000000..c2f6f8abab --- /dev/null +++ b/third_party/libwebrtc/rtc_base/event.cc @@ -0,0 +1,210 @@ +/* + * 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 "rtc_base/event.h" + +#if defined(WEBRTC_WIN) +#include <windows.h> +#elif defined(WEBRTC_POSIX) +#include <errno.h> +#include <pthread.h> +#include <sys/time.h> +#include <time.h> +#else +#error "Must define either WEBRTC_WIN or WEBRTC_POSIX." +#endif + +#include "absl/types/optional.h" +#include "rtc_base/checks.h" +#include "rtc_base/synchronization/yield_policy.h" +#include "rtc_base/system/warn_current_thread_is_deadlocked.h" +#include "rtc_base/time_utils.h" + +namespace rtc { + +using ::webrtc::TimeDelta; + +Event::Event() : Event(false, false) {} + +#if defined(WEBRTC_WIN) + +Event::Event(bool manual_reset, bool initially_signaled) { + event_handle_ = ::CreateEvent(nullptr, // Security attributes. + manual_reset, initially_signaled, + nullptr); // Name. + RTC_CHECK(event_handle_); +} + +Event::~Event() { + CloseHandle(event_handle_); +} + +void Event::Set() { + SetEvent(event_handle_); +} + +void Event::Reset() { + ResetEvent(event_handle_); +} + +bool Event::Wait(TimeDelta give_up_after, TimeDelta /*warn_after*/) { + ScopedYieldPolicy::YieldExecution(); + const DWORD ms = + give_up_after.IsPlusInfinity() + ? INFINITE + : give_up_after.RoundUpTo(webrtc::TimeDelta::Millis(1)).ms(); + return (WaitForSingleObject(event_handle_, ms) == WAIT_OBJECT_0); +} + +#elif defined(WEBRTC_POSIX) + +// On MacOS, clock_gettime is available from version 10.12, and on +// iOS, from version 10.0. So we can't use it yet. +#if defined(WEBRTC_MAC) || defined(WEBRTC_IOS) +#define USE_CLOCK_GETTIME 0 +#define USE_PTHREAD_COND_TIMEDWAIT_MONOTONIC_NP 0 +// On Android, pthread_condattr_setclock is available from version 21. By +// default, we target a new enough version for 64-bit platforms but not for +// 32-bit platforms. For older versions, use +// pthread_cond_timedwait_monotonic_np. +#elif defined(WEBRTC_ANDROID) && (__ANDROID_API__ < 21) +#define USE_CLOCK_GETTIME 1 +#define USE_PTHREAD_COND_TIMEDWAIT_MONOTONIC_NP 1 +#else +#define USE_CLOCK_GETTIME 1 +#define USE_PTHREAD_COND_TIMEDWAIT_MONOTONIC_NP 0 +#endif + +Event::Event(bool manual_reset, bool initially_signaled) + : is_manual_reset_(manual_reset), event_status_(initially_signaled) { + RTC_CHECK(pthread_mutex_init(&event_mutex_, nullptr) == 0); + pthread_condattr_t cond_attr; + RTC_CHECK(pthread_condattr_init(&cond_attr) == 0); +#if USE_CLOCK_GETTIME && !USE_PTHREAD_COND_TIMEDWAIT_MONOTONIC_NP + RTC_CHECK(pthread_condattr_setclock(&cond_attr, CLOCK_MONOTONIC) == 0); +#endif + RTC_CHECK(pthread_cond_init(&event_cond_, &cond_attr) == 0); + pthread_condattr_destroy(&cond_attr); +} + +Event::~Event() { + pthread_mutex_destroy(&event_mutex_); + pthread_cond_destroy(&event_cond_); +} + +void Event::Set() { + pthread_mutex_lock(&event_mutex_); + event_status_ = true; + pthread_cond_broadcast(&event_cond_); + pthread_mutex_unlock(&event_mutex_); +} + +void Event::Reset() { + pthread_mutex_lock(&event_mutex_); + event_status_ = false; + pthread_mutex_unlock(&event_mutex_); +} + +namespace { + +timespec GetTimespec(TimeDelta duration_from_now) { + timespec ts; + + // Get the current time. +#if USE_CLOCK_GETTIME + clock_gettime(CLOCK_MONOTONIC, &ts); +#else + timeval tv; + gettimeofday(&tv, nullptr); + ts.tv_sec = tv.tv_sec; + ts.tv_nsec = tv.tv_usec * kNumNanosecsPerMicrosec; +#endif + + // Add the specified number of milliseconds to it. + int64_t microsecs_from_now = duration_from_now.us(); + ts.tv_sec += microsecs_from_now / kNumMicrosecsPerSec; + ts.tv_nsec += + (microsecs_from_now % kNumMicrosecsPerSec) * kNumNanosecsPerMicrosec; + + // Normalize. + if (ts.tv_nsec >= kNumNanosecsPerSec) { + ts.tv_sec++; + ts.tv_nsec -= kNumNanosecsPerSec; + } + + return ts; +} + +} // namespace + +bool Event::Wait(TimeDelta give_up_after, TimeDelta warn_after) { + // Instant when we'll log a warning message (because we've been waiting so + // long it might be a bug), but not yet give up waiting. nullopt if we + // shouldn't log a warning. + const absl::optional<timespec> warn_ts = + warn_after >= give_up_after + ? absl::nullopt + : absl::make_optional(GetTimespec(warn_after)); + + // Instant when we'll stop waiting and return an error. nullopt if we should + // never give up. + const absl::optional<timespec> give_up_ts = + give_up_after.IsPlusInfinity() + ? absl::nullopt + : absl::make_optional(GetTimespec(give_up_after)); + + ScopedYieldPolicy::YieldExecution(); + pthread_mutex_lock(&event_mutex_); + + // Wait for `event_cond_` to trigger and `event_status_` to be set, with the + // given timeout (or without a timeout if none is given). + const auto wait = [&](const absl::optional<timespec> timeout_ts) { + int error = 0; + while (!event_status_ && error == 0) { + if (timeout_ts == absl::nullopt) { + error = pthread_cond_wait(&event_cond_, &event_mutex_); + } else { +#if USE_PTHREAD_COND_TIMEDWAIT_MONOTONIC_NP + error = pthread_cond_timedwait_monotonic_np(&event_cond_, &event_mutex_, + &*timeout_ts); +#else + error = + pthread_cond_timedwait(&event_cond_, &event_mutex_, &*timeout_ts); +#endif + } + } + return error; + }; + + int error; + if (warn_ts == absl::nullopt) { + error = wait(give_up_ts); + } else { + error = wait(warn_ts); + if (error == ETIMEDOUT) { + webrtc::WarnThatTheCurrentThreadIsProbablyDeadlocked(); + error = wait(give_up_ts); + } + } + + // NOTE(liulk): Exactly one thread will auto-reset this event. All + // the other threads will think it's unsignaled. This seems to be + // consistent with auto-reset events in WEBRTC_WIN + if (error == 0 && !is_manual_reset_) + event_status_ = false; + + pthread_mutex_unlock(&event_mutex_); + + return (error == 0); +} + +#endif + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/event.h b/third_party/libwebrtc/rtc_base/event.h new file mode 100644 index 0000000000..12f6a7dca2 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/event.h @@ -0,0 +1,137 @@ +/* + * 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 RTC_BASE_EVENT_H_ +#define RTC_BASE_EVENT_H_ + +#include "api/units/time_delta.h" + +#if defined(WEBRTC_WIN) +#include <windows.h> +#elif defined(WEBRTC_POSIX) +#include <pthread.h> +#else +#error "Must define either WEBRTC_WIN or WEBRTC_POSIX." +#endif + +#include "rtc_base/synchronization/yield_policy.h" + +namespace rtc { + +// RTC_DISALLOW_WAIT() utility +// +// Sets a stack-scoped flag that disallows use of `rtc::Event::Wait` by means +// of raising a DCHECK when a call to `rtc::Event::Wait()` is made.. +// This is useful to guard synchronization-free scopes against regressions. +// +// Example of what this would catch (`ScopeToProtect` calls `Foo`): +// +// void Foo(TaskQueue* tq) { +// Event event; +// tq->PostTask([&event]() { +// event.Set(); +// }); +// event.Wait(Event::kForever); // <- Will trigger a DCHECK. +// } +// +// void ScopeToProtect() { +// TaskQueue* tq = GetSomeTaskQueue(); +// RTC_DISALLOW_WAIT(); // Policy takes effect. +// Foo(tq); +// } +// +#if RTC_DCHECK_IS_ON +#define RTC_DISALLOW_WAIT() ScopedDisallowWait disallow_wait_##__LINE__ +#else +#define RTC_DISALLOW_WAIT() +#endif + +class Event { + public: + // TODO(bugs.webrtc.org/14366): Consider removing this redundant alias. + static constexpr webrtc::TimeDelta kForever = + webrtc::TimeDelta::PlusInfinity(); + + Event(); + Event(bool manual_reset, bool initially_signaled); + Event(const Event&) = delete; + Event& operator=(const Event&) = delete; + ~Event(); + + void Set(); + void Reset(); + + // Waits for the event to become signaled, but logs a warning if it takes more + // than `warn_after`, and gives up completely if it takes more than + // `give_up_after`. (If `warn_after >= give_up_after`, no warning will be + // logged.) Either or both may be `kForever`, which means wait indefinitely. + // + // Care is taken so that the underlying OS wait call isn't requested to sleep + // shorter than `give_up_after`. + // + // Returns true if the event was signaled, false if there was a timeout or + // some other error. + bool Wait(webrtc::TimeDelta give_up_after, webrtc::TimeDelta warn_after); + + // Waits with the given timeout and a reasonable default warning timeout. + bool Wait(webrtc::TimeDelta give_up_after) { + return Wait(give_up_after, give_up_after.IsPlusInfinity() + ? webrtc::TimeDelta::Seconds(3) + : kForever); + } + + private: +#if defined(WEBRTC_WIN) + HANDLE event_handle_; +#elif defined(WEBRTC_POSIX) + pthread_mutex_t event_mutex_; + pthread_cond_t event_cond_; + const bool is_manual_reset_; + bool event_status_; +#endif +}; + +// These classes are provided for compatibility with Chromium. +// The rtc::Event implementation is overriden inside of Chromium for the +// purposes of detecting when threads are blocked that shouldn't be as well as +// to use the more accurate event implementation that's there than is provided +// by default on some platforms (e.g. Windows). +// When building with standalone WebRTC, this class is a noop. +// For further information, please see the +// ScopedAllowBaseSyncPrimitives(ForTesting) classes in Chromium. +class ScopedAllowBaseSyncPrimitives { + public: + ScopedAllowBaseSyncPrimitives() {} + ~ScopedAllowBaseSyncPrimitives() {} +}; + +class ScopedAllowBaseSyncPrimitivesForTesting { + public: + ScopedAllowBaseSyncPrimitivesForTesting() {} + ~ScopedAllowBaseSyncPrimitivesForTesting() {} +}; + +#if RTC_DCHECK_IS_ON +class ScopedDisallowWait { + public: + ScopedDisallowWait() = default; + + private: + class DisallowYieldHandler : public YieldInterface { + public: + void YieldExecution() override { RTC_DCHECK_NOTREACHED(); } + } handler_; + rtc::ScopedYieldPolicy policy{&handler_}; +}; +#endif + +} // namespace rtc + +#endif // RTC_BASE_EVENT_H_ diff --git a/third_party/libwebrtc/rtc_base/event_tracer.cc b/third_party/libwebrtc/rtc_base/event_tracer.cc new file mode 100644 index 0000000000..992a2b5e08 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/event_tracer.cc @@ -0,0 +1,412 @@ +/* + * Copyright (c) 2012 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 "rtc_base/event_tracer.h" + +#include <inttypes.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> + +#include <atomic> +#include <string> +#include <vector> + +#include "absl/strings/string_view.h" +#include "api/sequence_checker.h" +#include "rtc_base/checks.h" +#include "rtc_base/event.h" +#include "rtc_base/logging.h" +#include "rtc_base/platform_thread.h" +#include "rtc_base/platform_thread_types.h" +#include "rtc_base/synchronization/mutex.h" +#include "rtc_base/thread_annotations.h" +#include "rtc_base/time_utils.h" +#include "rtc_base/trace_event.h" + +// This is a guesstimate that should be enough in most cases. +static const size_t kEventLoggerArgsStrBufferInitialSize = 256; +static const size_t kTraceArgBufferLength = 32; + +namespace webrtc { + +namespace { + +GetCategoryEnabledPtr g_get_category_enabled_ptr = nullptr; +AddTraceEventPtr g_add_trace_event_ptr = nullptr; + +} // namespace + +void SetupEventTracer(GetCategoryEnabledPtr get_category_enabled_ptr, + AddTraceEventPtr add_trace_event_ptr) { + g_get_category_enabled_ptr = get_category_enabled_ptr; + g_add_trace_event_ptr = add_trace_event_ptr; +} + +const unsigned char* EventTracer::GetCategoryEnabled(const char* name) { + if (g_get_category_enabled_ptr) + return g_get_category_enabled_ptr(name); + + // A string with null terminator means category is disabled. + return reinterpret_cast<const unsigned char*>("\0"); +} + +// Arguments to this function (phase, etc.) are as defined in +// webrtc/rtc_base/trace_event.h. +void EventTracer::AddTraceEvent(char phase, + const unsigned char* category_enabled, + const char* name, + unsigned long long id, + int num_args, + const char** arg_names, + const unsigned char* arg_types, + const unsigned long long* arg_values, + unsigned char flags) { + if (g_add_trace_event_ptr) { + g_add_trace_event_ptr(phase, category_enabled, name, id, num_args, + arg_names, arg_types, arg_values, flags); + } +} + +} // namespace webrtc + +namespace rtc { +namespace tracing { +namespace { + +// Atomic-int fast path for avoiding logging when disabled. +static std::atomic<int> g_event_logging_active(0); + +// TODO(pbos): Log metadata for all threads, etc. +class EventLogger final { + public: + ~EventLogger() { RTC_DCHECK(thread_checker_.IsCurrent()); } + + void AddTraceEvent(const char* name, + const unsigned char* category_enabled, + char phase, + int num_args, + const char** arg_names, + const unsigned char* arg_types, + const unsigned long long* arg_values, + uint64_t timestamp, + int pid, + rtc::PlatformThreadId thread_id) { + std::vector<TraceArg> args(num_args); + for (int i = 0; i < num_args; ++i) { + TraceArg& arg = args[i]; + arg.name = arg_names[i]; + arg.type = arg_types[i]; + arg.value.as_uint = arg_values[i]; + + // Value is a pointer to a temporary string, so we have to make a copy. + if (arg.type == TRACE_VALUE_TYPE_COPY_STRING) { + // Space for the string and for the terminating null character. + size_t str_length = strlen(arg.value.as_string) + 1; + char* str_copy = new char[str_length]; + memcpy(str_copy, arg.value.as_string, str_length); + arg.value.as_string = str_copy; + } + } + webrtc::MutexLock lock(&mutex_); + trace_events_.push_back( + {name, category_enabled, phase, args, timestamp, 1, thread_id}); + } + + // The TraceEvent format is documented here: + // https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview + void Log() { + RTC_DCHECK(output_file_); + static constexpr webrtc::TimeDelta kLoggingInterval = + webrtc::TimeDelta::Millis(100); + fprintf(output_file_, "{ \"traceEvents\": [\n"); + bool has_logged_event = false; + while (true) { + bool shutting_down = shutdown_event_.Wait(kLoggingInterval); + std::vector<TraceEvent> events; + { + webrtc::MutexLock lock(&mutex_); + trace_events_.swap(events); + } + std::string args_str; + args_str.reserve(kEventLoggerArgsStrBufferInitialSize); + for (TraceEvent& e : events) { + args_str.clear(); + if (!e.args.empty()) { + args_str += ", \"args\": {"; + bool is_first_argument = true; + for (TraceArg& arg : e.args) { + if (!is_first_argument) + args_str += ","; + is_first_argument = false; + args_str += " \""; + args_str += arg.name; + args_str += "\": "; + args_str += TraceArgValueAsString(arg); + + // Delete our copy of the string. + if (arg.type == TRACE_VALUE_TYPE_COPY_STRING) { + delete[] arg.value.as_string; + arg.value.as_string = nullptr; + } + } + args_str += " }"; + } + fprintf(output_file_, + "%s{ \"name\": \"%s\"" + ", \"cat\": \"%s\"" + ", \"ph\": \"%c\"" + ", \"ts\": %" PRIu64 + ", \"pid\": %d" +#if defined(WEBRTC_WIN) + ", \"tid\": %lu" +#else + ", \"tid\": %d" +#endif // defined(WEBRTC_WIN) + "%s" + "}\n", + has_logged_event ? "," : " ", e.name, e.category_enabled, + e.phase, e.timestamp, e.pid, e.tid, args_str.c_str()); + has_logged_event = true; + } + if (shutting_down) + break; + } + fprintf(output_file_, "]}\n"); + if (output_file_owned_) + fclose(output_file_); + output_file_ = nullptr; + } + + void Start(FILE* file, bool owned) { + RTC_DCHECK(thread_checker_.IsCurrent()); + RTC_DCHECK(file); + RTC_DCHECK(!output_file_); + output_file_ = file; + output_file_owned_ = owned; + { + webrtc::MutexLock lock(&mutex_); + // Since the atomic fast-path for adding events to the queue can be + // bypassed while the logging thread is shutting down there may be some + // stale events in the queue, hence the vector needs to be cleared to not + // log events from a previous logging session (which may be days old). + trace_events_.clear(); + } + // Enable event logging (fast-path). This should be disabled since starting + // shouldn't be done twice. + int zero = 0; + RTC_CHECK(g_event_logging_active.compare_exchange_strong(zero, 1)); + + // Finally start, everything should be set up now. + logging_thread_ = + PlatformThread::SpawnJoinable([this] { Log(); }, "EventTracingThread"); + TRACE_EVENT_INSTANT0("webrtc", "EventLogger::Start"); + } + + void Stop() { + RTC_DCHECK(thread_checker_.IsCurrent()); + TRACE_EVENT_INSTANT0("webrtc", "EventLogger::Stop"); + // Try to stop. Abort if we're not currently logging. + int one = 1; + if (g_event_logging_active.compare_exchange_strong(one, 0)) + return; + + // Wake up logging thread to finish writing. + shutdown_event_.Set(); + // Join the logging thread. + logging_thread_.Finalize(); + } + + private: + struct TraceArg { + const char* name; + unsigned char type; + // Copied from webrtc/rtc_base/trace_event.h TraceValueUnion. + union TraceArgValue { + bool as_bool; + unsigned long long as_uint; + long long as_int; + double as_double; + const void* as_pointer; + const char* as_string; + } value; + + // Assert that the size of the union is equal to the size of the as_uint + // field since we are assigning to arbitrary types using it. + static_assert(sizeof(TraceArgValue) == sizeof(unsigned long long), + "Size of TraceArg value union is not equal to the size of " + "the uint field of that union."); + }; + + struct TraceEvent { + const char* name; + const unsigned char* category_enabled; + char phase; + std::vector<TraceArg> args; + uint64_t timestamp; + int pid; + rtc::PlatformThreadId tid; + }; + + static std::string TraceArgValueAsString(TraceArg arg) { + std::string output; + + if (arg.type == TRACE_VALUE_TYPE_STRING || + arg.type == TRACE_VALUE_TYPE_COPY_STRING) { + // Space for every character to be an espaced character + two for + // quatation marks. + output.reserve(strlen(arg.value.as_string) * 2 + 2); + output += '\"'; + const char* c = arg.value.as_string; + do { + if (*c == '"' || *c == '\\') { + output += '\\'; + output += *c; + } else { + output += *c; + } + } while (*++c); + output += '\"'; + } else { + output.resize(kTraceArgBufferLength); + size_t print_length = 0; + switch (arg.type) { + case TRACE_VALUE_TYPE_BOOL: + if (arg.value.as_bool) { + strcpy(&output[0], "true"); + print_length = 4; + } else { + strcpy(&output[0], "false"); + print_length = 5; + } + break; + case TRACE_VALUE_TYPE_UINT: + print_length = snprintf(&output[0], kTraceArgBufferLength, "%llu", + arg.value.as_uint); + break; + case TRACE_VALUE_TYPE_INT: + print_length = snprintf(&output[0], kTraceArgBufferLength, "%lld", + arg.value.as_int); + break; + case TRACE_VALUE_TYPE_DOUBLE: + print_length = snprintf(&output[0], kTraceArgBufferLength, "%f", + arg.value.as_double); + break; + case TRACE_VALUE_TYPE_POINTER: + print_length = snprintf(&output[0], kTraceArgBufferLength, "\"%p\"", + arg.value.as_pointer); + break; + } + size_t output_length = print_length < kTraceArgBufferLength + ? print_length + : kTraceArgBufferLength - 1; + // This will hopefully be very close to nop. On most implementations, it + // just writes null byte and sets the length field of the string. + output.resize(output_length); + } + + return output; + } + + webrtc::Mutex mutex_; + std::vector<TraceEvent> trace_events_ RTC_GUARDED_BY(mutex_); + rtc::PlatformThread logging_thread_; + rtc::Event shutdown_event_; + webrtc::SequenceChecker thread_checker_; + FILE* output_file_ = nullptr; + bool output_file_owned_ = false; +}; + +static std::atomic<EventLogger*> g_event_logger(nullptr); +static const char* const kDisabledTracePrefix = TRACE_DISABLED_BY_DEFAULT(""); +const unsigned char* InternalGetCategoryEnabled(const char* name) { + const char* prefix_ptr = &kDisabledTracePrefix[0]; + const char* name_ptr = name; + // Check whether name contains the default-disabled prefix. + while (*prefix_ptr == *name_ptr && *prefix_ptr != '\0') { + ++prefix_ptr; + ++name_ptr; + } + return reinterpret_cast<const unsigned char*>(*prefix_ptr == '\0' ? "" + : name); +} + +const unsigned char* InternalEnableAllCategories(const char* name) { + return reinterpret_cast<const unsigned char*>(name); +} + +void InternalAddTraceEvent(char phase, + const unsigned char* category_enabled, + const char* name, + unsigned long long id, + int num_args, + const char** arg_names, + const unsigned char* arg_types, + const unsigned long long* arg_values, + unsigned char flags) { + // Fast path for when event tracing is inactive. + if (g_event_logging_active.load() == 0) + return; + + g_event_logger.load()->AddTraceEvent( + name, category_enabled, phase, num_args, arg_names, arg_types, arg_values, + rtc::TimeMicros(), 1, rtc::CurrentThreadId()); +} + +} // namespace + +void SetupInternalTracer(bool enable_all_categories) { + EventLogger* null_logger = nullptr; + RTC_CHECK( + g_event_logger.compare_exchange_strong(null_logger, new EventLogger())); + webrtc::SetupEventTracer(enable_all_categories ? InternalEnableAllCategories + : InternalGetCategoryEnabled, + InternalAddTraceEvent); +} + +void StartInternalCaptureToFile(FILE* file) { + EventLogger* event_logger = g_event_logger.load(); + if (event_logger) { + event_logger->Start(file, false); + } +} + +bool StartInternalCapture(absl::string_view filename) { + EventLogger* event_logger = g_event_logger.load(); + if (!event_logger) + return false; + + FILE* file = fopen(std::string(filename).c_str(), "w"); + if (!file) { + RTC_LOG(LS_ERROR) << "Failed to open trace file '" << filename + << "' for writing."; + return false; + } + event_logger->Start(file, true); + return true; +} + +void StopInternalCapture() { + EventLogger* event_logger = g_event_logger.load(); + if (event_logger) { + event_logger->Stop(); + } +} + +void ShutdownInternalTracer() { + StopInternalCapture(); + EventLogger* old_logger = g_event_logger.load(std::memory_order_acquire); + RTC_DCHECK(old_logger); + RTC_CHECK(g_event_logger.compare_exchange_strong(old_logger, nullptr)); + delete old_logger; + webrtc::SetupEventTracer(nullptr, nullptr); +} + +} // namespace tracing +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/event_tracer.h b/third_party/libwebrtc/rtc_base/event_tracer.h new file mode 100644 index 0000000000..dc2eaed669 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/event_tracer.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2012 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 file defines the interface for event tracing in WebRTC. +// +// Event log handlers are set through SetupEventTracer(). User of this API will +// provide two function pointers to handle event tracing calls. +// +// * GetCategoryEnabledPtr +// Event tracing system calls this function to determine if a particular +// event category is enabled. +// +// * AddTraceEventPtr +// Adds a tracing event. It is the user's responsibility to log the data +// provided. +// +// Parameters for the above two functions are described in trace_event.h. + +#ifndef RTC_BASE_EVENT_TRACER_H_ +#define RTC_BASE_EVENT_TRACER_H_ + +#include <stdio.h> + +#include "absl/strings/string_view.h" +#include "rtc_base/system/rtc_export.h" + +namespace webrtc { + +typedef const unsigned char* (*GetCategoryEnabledPtr)(const char* name); +typedef void (*AddTraceEventPtr)(char phase, + const unsigned char* category_enabled, + const char* name, + unsigned long long id, + int num_args, + const char** arg_names, + const unsigned char* arg_types, + const unsigned long long* arg_values, + unsigned char flags); + +// User of WebRTC can call this method to setup event tracing. +// +// This method must be called before any WebRTC methods. Functions +// provided should be thread-safe. +void SetupEventTracer(GetCategoryEnabledPtr get_category_enabled_ptr, + AddTraceEventPtr add_trace_event_ptr); + +// This class defines interface for the event tracing system to call +// internally. Do not call these methods directly. +class EventTracer { + public: + static const unsigned char* GetCategoryEnabled(const char* name); + + static void AddTraceEvent(char phase, + const unsigned char* category_enabled, + const char* name, + unsigned long long id, + int num_args, + const char** arg_names, + const unsigned char* arg_types, + const unsigned long long* arg_values, + unsigned char flags); +}; + +} // namespace webrtc + +namespace rtc { +namespace tracing { +// Set up internal event tracer. +RTC_EXPORT void SetupInternalTracer(bool enable_all_categories = true); +RTC_EXPORT bool StartInternalCapture(absl::string_view filename); +RTC_EXPORT void StartInternalCaptureToFile(FILE* file); +RTC_EXPORT void StopInternalCapture(); +// Make sure we run this, this will tear down the internal tracing. +RTC_EXPORT void ShutdownInternalTracer(); +} // namespace tracing +} // namespace rtc + +#endif // RTC_BASE_EVENT_TRACER_H_ diff --git a/third_party/libwebrtc/rtc_base/event_tracer_gn/moz.build b/third_party/libwebrtc/rtc_base/event_tracer_gn/moz.build new file mode 100644 index 0000000000..06daf6b03a --- /dev/null +++ b/third_party/libwebrtc/rtc_base/event_tracer_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/rtc_base/event_tracer.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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("event_tracer_gn") diff --git a/third_party/libwebrtc/rtc_base/event_tracer_unittest.cc b/third_party/libwebrtc/rtc_base/event_tracer_unittest.cc new file mode 100644 index 0000000000..d0783c3f2d --- /dev/null +++ b/third_party/libwebrtc/rtc_base/event_tracer_unittest.cc @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2012 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 "rtc_base/event_tracer.h" + +#include "rtc_base/synchronization/mutex.h" +#include "rtc_base/thread_annotations.h" +#include "rtc_base/trace_event.h" +#include "test/gtest.h" + +namespace { + +class TestStatistics { + public: + void Reset() { + webrtc::MutexLock lock(&mutex_); + events_logged_ = 0; + } + + void Increment() { + webrtc::MutexLock lock(&mutex_); + ++events_logged_; + } + + int Count() const { + webrtc::MutexLock lock(&mutex_); + return events_logged_; + } + + static TestStatistics* Get() { + // google.github.io/styleguide/cppguide.html#Static_and_Global_Variables + static auto& test_stats = *new TestStatistics(); + return &test_stats; + } + + private: + mutable webrtc::Mutex mutex_; + int events_logged_ RTC_GUARDED_BY(mutex_) = 0; +}; + +} // namespace + +namespace webrtc { + +TEST(EventTracerTest, EventTracerDisabled) { + { TRACE_EVENT0("test", "EventTracerDisabled"); } + EXPECT_FALSE(TestStatistics::Get()->Count()); + TestStatistics::Get()->Reset(); +} + +#if RTC_TRACE_EVENTS_ENABLED +TEST(EventTracerTest, ScopedTraceEvent) { + SetupEventTracer( + [](const char* /*name*/) { + return reinterpret_cast<const unsigned char*>("test"); + }, + [](char /*phase*/, const unsigned char* /*category_enabled*/, + const char* /*name*/, unsigned long long /*id*/, int /*num_args*/, + const char** /*arg_names*/, const unsigned char* /*arg_types*/, + const unsigned long long* /*arg_values*/, + unsigned char /*flags*/) { TestStatistics::Get()->Increment(); }); + { TRACE_EVENT0("test", "ScopedTraceEvent"); } + EXPECT_EQ(2, TestStatistics::Get()->Count()); + TestStatistics::Get()->Reset(); +} +#endif + +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/event_unittest.cc b/third_party/libwebrtc/rtc_base/event_unittest.cc new file mode 100644 index 0000000000..17f50dc2d1 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/event_unittest.cc @@ -0,0 +1,115 @@ +/* + * 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 "rtc_base/event.h" + +#include "api/units/time_delta.h" +#include "rtc_base/platform_thread.h" +#include "system_wrappers/include/clock.h" +#include "test/gtest.h" + +namespace rtc { + +TEST(EventTest, InitiallySignaled) { + Event event(false, true); + ASSERT_TRUE(event.Wait(webrtc::TimeDelta::Zero())); +} + +TEST(EventTest, ManualReset) { + Event event(true, false); + ASSERT_FALSE(event.Wait(webrtc::TimeDelta::Zero())); + + event.Set(); + ASSERT_TRUE(event.Wait(webrtc::TimeDelta::Zero())); + ASSERT_TRUE(event.Wait(webrtc::TimeDelta::Zero())); + + event.Reset(); + ASSERT_FALSE(event.Wait(webrtc::TimeDelta::Zero())); +} + +TEST(EventTest, AutoReset) { + Event event; + ASSERT_FALSE(event.Wait(webrtc::TimeDelta::Zero())); + + event.Set(); + ASSERT_TRUE(event.Wait(webrtc::TimeDelta::Zero())); + ASSERT_FALSE(event.Wait(webrtc::TimeDelta::Zero())); +} + +class SignalerThread { + public: + void Start(Event* writer, Event* reader) { + writer_ = writer; + reader_ = reader; + thread_ = PlatformThread::SpawnJoinable( + [this] { + while (!stop_event_.Wait(webrtc::TimeDelta::Zero())) { + writer_->Set(); + reader_->Wait(Event::kForever); + } + }, + "EventPerf"); + } + void Stop() { + stop_event_.Set(); + thread_.Finalize(); + } + Event stop_event_; + Event* writer_; + Event* reader_; + PlatformThread thread_; +}; + +TEST(EventTest, UnsignaledWaitDoesNotReturnBeforeTimeout) { + constexpr webrtc::TimeDelta kDuration = webrtc::TimeDelta::Micros(10'499); + Event event; + auto begin = webrtc::Clock::GetRealTimeClock()->CurrentTime(); + EXPECT_FALSE(event.Wait(kDuration)); + EXPECT_GE(webrtc::Clock::GetRealTimeClock()->CurrentTime(), + begin + kDuration); +} + +// These tests are disabled by default and only intended to be run manually. +TEST(EventTest, DISABLED_PerformanceSingleThread) { + static const int kNumIterations = 10000000; + Event event; + for (int i = 0; i < kNumIterations; ++i) { + event.Set(); + event.Wait(webrtc::TimeDelta::Zero()); + } +} + +TEST(EventTest, DISABLED_PerformanceMultiThread) { + static const int kNumIterations = 10000; + Event read; + Event write; + SignalerThread thread; + thread.Start(&read, &write); + + for (int i = 0; i < kNumIterations; ++i) { + write.Set(); + read.Wait(Event::kForever); + } + write.Set(); + + thread.Stop(); +} + +#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID) +// Tests that we crash if we attempt to call rtc::Event::Wait while we're +// not allowed to (as per `RTC_DISALLOW_WAIT()`). +TEST(EventTestDeathTest, DisallowEventWait) { + Event event; + RTC_DISALLOW_WAIT(); + EXPECT_DEATH(event.Wait(Event::kForever), ""); +} +#endif // RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID) + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/experiments/BUILD.gn b/third_party/libwebrtc/rtc_base/experiments/BUILD.gn new file mode 100644 index 0000000000..185d5931f7 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/BUILD.gn @@ -0,0 +1,302 @@ +# 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("alr_experiment") { + sources = [ + "alr_experiment.cc", + "alr_experiment.h", + ] + deps = [ + "..:logging", + "../../api:field_trials_view", + "../../api/transport:field_trial_based_config", + ] + absl_deps = [ + "//third_party/abseil-cpp/absl/strings:strings", + "//third_party/abseil-cpp/absl/types:optional", + ] +} + +rtc_library("field_trial_parser") { + sources = [ + "field_trial_list.cc", + "field_trial_list.h", + "field_trial_parser.cc", + "field_trial_parser.h", + "field_trial_units.cc", + "field_trial_units.h", + "struct_parameters_parser.cc", + "struct_parameters_parser.h", + ] + deps = [ + "../../api/units:data_rate", + "../../api/units:data_size", + "../../api/units:time_delta", + "../../rtc_base:checks", + "../../rtc_base:logging", + "../../rtc_base:safe_conversions", + "../../rtc_base:stringutils", + ] + absl_deps = [ + "//third_party/abseil-cpp/absl/memory", + "//third_party/abseil-cpp/absl/strings:strings", + "//third_party/abseil-cpp/absl/types:optional", + ] +} + +rtc_library("quality_rampup_experiment") { + sources = [ + "quality_rampup_experiment.cc", + "quality_rampup_experiment.h", + ] + deps = [ + ":field_trial_parser", + "..:logging", + "../../api:field_trials_view", + "../../api/transport:field_trial_based_config", + "../../system_wrappers:field_trial", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] +} + +rtc_library("quality_scaler_settings") { + sources = [ + "quality_scaler_settings.cc", + "quality_scaler_settings.h", + ] + deps = [ + ":field_trial_parser", + "..:logging", + "../../api:field_trials_view", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] +} + +rtc_library("bandwidth_quality_scaler_settings") { + sources = [ + "bandwidth_quality_scaler_settings.cc", + "bandwidth_quality_scaler_settings.h", + ] + deps = [ + ":field_trial_parser", + "..:logging", + "../../api:field_trials_view", + "../../api/transport:field_trial_based_config", + "../../system_wrappers:field_trial", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] +} + +rtc_library("quality_scaling_experiment") { + sources = [ + "quality_scaling_experiment.cc", + "quality_scaling_experiment.h", + ] + deps = [ + "..:logging", + "../../api:field_trials_view", + "../../api/transport:field_trial_based_config", + "../../api/video_codecs:video_codecs_api", + ] + absl_deps = [ + "//third_party/abseil-cpp/absl/strings:strings", + "//third_party/abseil-cpp/absl/types:optional", + ] +} + +rtc_library("normalize_simulcast_size_experiment") { + sources = [ + "normalize_simulcast_size_experiment.cc", + "normalize_simulcast_size_experiment.h", + ] + deps = [ + "..:logging", + "../../system_wrappers:field_trial", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] +} + +rtc_library("balanced_degradation_settings") { + sources = [ + "balanced_degradation_settings.cc", + "balanced_degradation_settings.h", + ] + deps = [ + ":field_trial_parser", + "..:logging", + "../../api:field_trials_view", + "../../api/video_codecs:video_codecs_api", + "../../system_wrappers:field_trial", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] +} + +rtc_library("cpu_speed_experiment") { + sources = [ + "cpu_speed_experiment.cc", + "cpu_speed_experiment.h", + ] + deps = [ + ":field_trial_parser", + "..:logging", + "../../system_wrappers:field_trial", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] +} + +rtc_library("encoder_info_settings") { + sources = [ + "encoder_info_settings.cc", + "encoder_info_settings.h", + ] + deps = [ + ":field_trial_parser", + "..:logging", + "../../api/video_codecs:video_codecs_api", + "../../system_wrappers:field_trial", + ] + absl_deps = [ + "//third_party/abseil-cpp/absl/strings", + "//third_party/abseil-cpp/absl/types:optional", + ] +} + +rtc_library("rtt_mult_experiment") { + sources = [ + "rtt_mult_experiment.cc", + "rtt_mult_experiment.h", + ] + deps = [ + "..:logging", + "../../system_wrappers:field_trial", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] +} + +rtc_library("rate_control_settings") { + sources = [ + "rate_control_settings.cc", + "rate_control_settings.h", + ] + deps = [ + ":field_trial_parser", + "..:logging", + "..:safe_conversions", + "../../api:field_trials_view", + "../../api/transport:field_trial_based_config", + "../../api/units:data_size", + "../../api/video_codecs:video_codecs_api", + "../../system_wrappers:field_trial", + "../../video/config:encoder_config", + ] + absl_deps = [ + "//third_party/abseil-cpp/absl/strings", + "//third_party/abseil-cpp/absl/types:optional", + ] +} + +rtc_library("keyframe_interval_settings_experiment") { + sources = [ + "keyframe_interval_settings.cc", + "keyframe_interval_settings.h", + ] + deps = [ + ":field_trial_parser", + "../../api:field_trials_view", + "../../api/transport:field_trial_based_config", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] +} + +rtc_library("stable_target_rate_experiment") { + sources = [ + "stable_target_rate_experiment.cc", + "stable_target_rate_experiment.h", + ] + deps = [ + ":field_trial_parser", + "../../api:field_trials_view", + "../../api/transport:field_trial_based_config", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] +} + +rtc_library("min_video_bitrate_experiment") { + sources = [ + "min_video_bitrate_experiment.cc", + "min_video_bitrate_experiment.h", + ] + deps = [ + ":field_trial_parser", + "../../api/units:data_rate", + "../../api/video:video_frame", + "../../rtc_base:checks", + "../../rtc_base:logging", + "../../system_wrappers:field_trial", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] +} + +if (rtc_include_tests && !build_with_chromium) { + rtc_library("experiments_unittests") { + testonly = true + + sources = [ + "balanced_degradation_settings_unittest.cc", + "bandwidth_quality_scaler_settings_unittest.cc", + "cpu_speed_experiment_unittest.cc", + "encoder_info_settings_unittest.cc", + "field_trial_list_unittest.cc", + "field_trial_parser_unittest.cc", + "field_trial_units_unittest.cc", + "keyframe_interval_settings_unittest.cc", + "min_video_bitrate_experiment_unittest.cc", + "normalize_simulcast_size_experiment_unittest.cc", + "quality_rampup_experiment_unittest.cc", + "quality_scaler_settings_unittest.cc", + "quality_scaling_experiment_unittest.cc", + "rate_control_settings_unittest.cc", + "rtt_mult_experiment_unittest.cc", + "stable_target_rate_experiment_unittest.cc", + "struct_parameters_parser_unittest.cc", + ] + deps = [ + ":balanced_degradation_settings", + ":bandwidth_quality_scaler_settings", + ":cpu_speed_experiment", + ":encoder_info_settings", + ":field_trial_parser", + ":keyframe_interval_settings_experiment", + ":min_video_bitrate_experiment", + ":normalize_simulcast_size_experiment", + ":quality_rampup_experiment", + ":quality_scaler_settings", + ":quality_scaling_experiment", + ":rate_control_settings", + ":rtt_mult_experiment", + ":stable_target_rate_experiment", + "..:gunit_helpers", + "../:rtc_base_tests_utils", + "../../api/units:data_rate", + "../../api/video:video_frame", + "../../api/video_codecs:video_codecs_api", + "../../system_wrappers:field_trial", + "../../test:field_trial", + "../../test:scoped_key_value_config", + "../../test:test_main", + "../../test:test_support", + "../../video/config:encoder_config", + ] + absl_deps = [ + "//third_party/abseil-cpp/absl/strings", + "//third_party/abseil-cpp/absl/types:optional", + ] + } +} diff --git a/third_party/libwebrtc/rtc_base/experiments/DEPS b/third_party/libwebrtc/rtc_base/experiments/DEPS new file mode 100644 index 0000000000..7c8dddef06 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/DEPS @@ -0,0 +1,8 @@ +include_rules = [ + "+system_wrappers", +] +specific_include_rules = { + ".*rate_control_settings.*": [ + "+video/config", + ], +} diff --git a/third_party/libwebrtc/rtc_base/experiments/OWNERS b/third_party/libwebrtc/rtc_base/experiments/OWNERS new file mode 100644 index 0000000000..0a3b89533d --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/OWNERS @@ -0,0 +1,13 @@ +asapersson@webrtc.org +sprang@webrtc.org +srte@webrtc.org + +per-file audio_allocation_settings*=srte@webrtc.org +per-file congestion_controller_experiment*=srte@webrtc.org +per-file cpu_speed_experiment*=asapersson@webrtc.org +per-file field_trial*=srte@webrtc.org +per-file keyframe_interval_settings*=brandtr@webrtc.org +per-file normalize_simulcast_size_experiment*=asapersson@webrtc.org +per-file quality_scaling_experiment*=asapersson@webrtc.org +per-file rtt_mult_experiment*=mhoro@webrtc.org +per-file rate_control_settings*=srte@webrtc.org diff --git a/third_party/libwebrtc/rtc_base/experiments/alr_experiment.cc b/third_party/libwebrtc/rtc_base/experiments/alr_experiment.cc new file mode 100644 index 0000000000..f5d36f6867 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/alr_experiment.cc @@ -0,0 +1,98 @@ +/* + * 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 "rtc_base/experiments/alr_experiment.h" + +#include <inttypes.h> +#include <stdio.h> + +#include <string> + +#include "absl/strings/string_view.h" +#include "api/transport/field_trial_based_config.h" +#include "rtc_base/logging.h" + +namespace webrtc { + +const char AlrExperimentSettings::kScreenshareProbingBweExperimentName[] = + "WebRTC-ProbingScreenshareBwe"; +const char AlrExperimentSettings::kStrictPacingAndProbingExperimentName[] = + "WebRTC-StrictPacingAndProbing"; +const char kDefaultProbingScreenshareBweSettings[] = "1.0,2875,80,40,-60,3"; + +bool AlrExperimentSettings::MaxOneFieldTrialEnabled() { + return AlrExperimentSettings::MaxOneFieldTrialEnabled( + FieldTrialBasedConfig()); +} + +bool AlrExperimentSettings::MaxOneFieldTrialEnabled( + const FieldTrialsView& key_value_config) { + return key_value_config.Lookup(kStrictPacingAndProbingExperimentName) + .empty() || + key_value_config.Lookup(kScreenshareProbingBweExperimentName).empty(); +} + +absl::optional<AlrExperimentSettings> +AlrExperimentSettings::CreateFromFieldTrial(absl::string_view experiment_name) { + return AlrExperimentSettings::CreateFromFieldTrial(FieldTrialBasedConfig(), + experiment_name); +} + +absl::optional<AlrExperimentSettings> +AlrExperimentSettings::CreateFromFieldTrial( + const FieldTrialsView& key_value_config, + absl::string_view experiment_name) { + absl::optional<AlrExperimentSettings> ret; + std::string group_name = key_value_config.Lookup(experiment_name); + + const std::string kIgnoredSuffix = "_Dogfood"; + std::string::size_type suffix_pos = group_name.rfind(kIgnoredSuffix); + if (suffix_pos != std::string::npos && + suffix_pos == group_name.length() - kIgnoredSuffix.length()) { + group_name.resize(group_name.length() - kIgnoredSuffix.length()); + } + + if (group_name.empty()) { + if (experiment_name == kScreenshareProbingBweExperimentName) { + // This experiment is now default-on with fixed settings. + // TODO(sprang): Remove this kill-switch and clean up experiment code. + group_name = kDefaultProbingScreenshareBweSettings; + } else { + return ret; + } + } + + AlrExperimentSettings settings; + if (sscanf(group_name.c_str(), "%f,%" PRId64 ",%d,%d,%d,%d", + &settings.pacing_factor, &settings.max_paced_queue_time, + &settings.alr_bandwidth_usage_percent, + &settings.alr_start_budget_level_percent, + &settings.alr_stop_budget_level_percent, + &settings.group_id) == 6) { + ret.emplace(settings); + RTC_LOG(LS_INFO) << "Using ALR experiment settings: " + "pacing factor: " + << settings.pacing_factor << ", max pacer queue length: " + << settings.max_paced_queue_time + << ", ALR bandwidth usage percent: " + << settings.alr_bandwidth_usage_percent + << ", ALR start budget level percent: " + << settings.alr_start_budget_level_percent + << ", ALR end budget level percent: " + << settings.alr_stop_budget_level_percent + << ", ALR experiment group ID: " << settings.group_id; + } else { + RTC_LOG(LS_INFO) << "Failed to parse ALR experiment: " << experiment_name; + } + + return ret; +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/experiments/alr_experiment.h b/third_party/libwebrtc/rtc_base/experiments/alr_experiment.h new file mode 100644 index 0000000000..048fd90cab --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/alr_experiment.h @@ -0,0 +1,48 @@ +/* + * 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 RTC_BASE_EXPERIMENTS_ALR_EXPERIMENT_H_ +#define RTC_BASE_EXPERIMENTS_ALR_EXPERIMENT_H_ + +#include <stdint.h> + +#include "absl/strings/string_view.h" +#include "absl/types/optional.h" +#include "api/field_trials_view.h" + +namespace webrtc { +struct AlrExperimentSettings { + public: + float pacing_factor; + int64_t max_paced_queue_time; + int alr_bandwidth_usage_percent; + int alr_start_budget_level_percent; + int alr_stop_budget_level_percent; + // Will be sent to the receive side for stats slicing. + // Can be 0..6, because it's sent as a 3 bits value and there's also + // reserved value to indicate absence of experiment. + int group_id; + + static const char kScreenshareProbingBweExperimentName[]; + static const char kStrictPacingAndProbingExperimentName[]; + static absl::optional<AlrExperimentSettings> CreateFromFieldTrial( + absl::string_view experiment_name); + static absl::optional<AlrExperimentSettings> CreateFromFieldTrial( + const FieldTrialsView& key_value_config, + absl::string_view experiment_name); + static bool MaxOneFieldTrialEnabled(); + static bool MaxOneFieldTrialEnabled(const FieldTrialsView& key_value_config); + + private: + AlrExperimentSettings() = default; +}; +} // namespace webrtc + +#endif // RTC_BASE_EXPERIMENTS_ALR_EXPERIMENT_H_ diff --git a/third_party/libwebrtc/rtc_base/experiments/alr_experiment_gn/moz.build b/third_party/libwebrtc/rtc_base/experiments/alr_experiment_gn/moz.build new file mode 100644 index 0000000000..4435f010b6 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/alr_experiment_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/rtc_base/experiments/alr_experiment.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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("alr_experiment_gn") diff --git a/third_party/libwebrtc/rtc_base/experiments/balanced_degradation_settings.cc b/third_party/libwebrtc/rtc_base/experiments/balanced_degradation_settings.cc new file mode 100644 index 0000000000..1a269b4fa6 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/balanced_degradation_settings.cc @@ -0,0 +1,487 @@ +/* + * 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 "rtc_base/experiments/balanced_degradation_settings.h" + +#include <limits> + +#include "rtc_base/experiments/field_trial_list.h" +#include "rtc_base/experiments/field_trial_parser.h" +#include "rtc_base/logging.h" + +namespace webrtc { +namespace { +constexpr char kFieldTrial[] = "WebRTC-Video-BalancedDegradationSettings"; +constexpr int kMinFps = 1; +constexpr int kMaxFps = 100; // 100 means unlimited fps. + +std::vector<BalancedDegradationSettings::Config> DefaultConfigs() { + return {{320 * 240, + 7, + 0, + 0, + BalancedDegradationSettings::kNoFpsDiff, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}}, + {480 * 360, + 10, + 0, + 0, + 1, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}}, + {640 * 480, + 15, + 0, + 0, + 1, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}}}; +} + +bool IsValidConfig( + const BalancedDegradationSettings::CodecTypeSpecific& config) { + if (config.GetQpLow().has_value() != config.GetQpHigh().has_value()) { + RTC_LOG(LS_WARNING) << "Neither or both thresholds should be set."; + return false; + } + if (config.GetQpLow().has_value() && config.GetQpHigh().has_value() && + config.GetQpLow().value() >= config.GetQpHigh().value()) { + RTC_LOG(LS_WARNING) << "Invalid threshold value, low >= high threshold."; + return false; + } + if (config.GetFps().has_value() && (config.GetFps().value() < kMinFps || + config.GetFps().value() > kMaxFps)) { + RTC_LOG(LS_WARNING) << "Unsupported fps setting, value ignored."; + return false; + } + return true; +} + +bool IsValid(const BalancedDegradationSettings::CodecTypeSpecific& config1, + const BalancedDegradationSettings::CodecTypeSpecific& config2) { + bool both_or_none_set = ((config1.qp_low > 0) == (config2.qp_low > 0) && + (config1.qp_high > 0) == (config2.qp_high > 0) && + (config1.fps > 0) == (config2.fps > 0)); + if (!both_or_none_set) { + RTC_LOG(LS_WARNING) << "Invalid value, all/none should be set."; + return false; + } + if (config1.fps > 0 && config1.fps < config2.fps) { + RTC_LOG(LS_WARNING) << "Invalid fps/pixel value provided."; + return false; + } + return true; +} + +bool IsValid(const std::vector<BalancedDegradationSettings::Config>& configs) { + if (configs.size() <= 1) { + if (configs.size() == 1) + RTC_LOG(LS_WARNING) << "Unsupported size, value ignored."; + return false; + } + for (const auto& config : configs) { + if (config.fps < kMinFps || config.fps > kMaxFps) { + RTC_LOG(LS_WARNING) << "Unsupported fps setting, value ignored."; + return false; + } + } + int last_kbps = configs[0].kbps; + for (size_t i = 1; i < configs.size(); ++i) { + if (configs[i].kbps > 0) { + if (configs[i].kbps < last_kbps) { + RTC_LOG(LS_WARNING) << "Invalid bitrate value provided."; + return false; + } + last_kbps = configs[i].kbps; + } + } + for (size_t i = 1; i < configs.size(); ++i) { + if (configs[i].pixels < configs[i - 1].pixels || + configs[i].fps < configs[i - 1].fps) { + RTC_LOG(LS_WARNING) << "Invalid fps/pixel value provided."; + return false; + } + if (!IsValid(configs[i].vp8, configs[i - 1].vp8) || + !IsValid(configs[i].vp9, configs[i - 1].vp9) || + !IsValid(configs[i].h264, configs[i - 1].h264) || + !IsValid(configs[i].av1, configs[i - 1].av1) || + !IsValid(configs[i].generic, configs[i - 1].generic)) { + return false; + } + } + for (const auto& config : configs) { + if (!IsValidConfig(config.vp8) || !IsValidConfig(config.vp9) || + !IsValidConfig(config.h264) || !IsValidConfig(config.av1) || + !IsValidConfig(config.generic)) { + return false; + } + } + return true; +} + +std::vector<BalancedDegradationSettings::Config> GetValidOrDefault( + const std::vector<BalancedDegradationSettings::Config>& configs) { + if (IsValid(configs)) { + return configs; + } + return DefaultConfigs(); +} + +absl::optional<VideoEncoder::QpThresholds> GetThresholds( + VideoCodecType type, + const BalancedDegradationSettings::Config& config) { + absl::optional<int> low; + absl::optional<int> high; + + switch (type) { + case kVideoCodecVP8: + low = config.vp8.GetQpLow(); + high = config.vp8.GetQpHigh(); + break; + case kVideoCodecVP9: + low = config.vp9.GetQpLow(); + high = config.vp9.GetQpHigh(); + break; + case kVideoCodecH265: + // TODO(bugs.webrtc.org/13485): Use H264 QP thresholds for now. + case kVideoCodecH264: + low = config.h264.GetQpLow(); + high = config.h264.GetQpHigh(); + break; + case kVideoCodecAV1: + low = config.av1.GetQpLow(); + high = config.av1.GetQpHigh(); + break; + case kVideoCodecGeneric: + low = config.generic.GetQpLow(); + high = config.generic.GetQpHigh(); + break; + default: + break; + } + + if (low && high) { + RTC_LOG(LS_INFO) << "QP thresholds: low: " << *low << ", high: " << *high; + return absl::optional<VideoEncoder::QpThresholds>( + VideoEncoder::QpThresholds(*low, *high)); + } + return absl::nullopt; +} + +int GetFps(VideoCodecType type, + const absl::optional<BalancedDegradationSettings::Config>& config) { + if (!config.has_value()) { + return std::numeric_limits<int>::max(); + } + + absl::optional<int> fps; + switch (type) { + case kVideoCodecVP8: + fps = config->vp8.GetFps(); + break; + case kVideoCodecH265: + // TODO(bugs.webrtc.org/13485): Use VP9 bitrate limits for now. + case kVideoCodecVP9: + fps = config->vp9.GetFps(); + break; + case kVideoCodecH264: + fps = config->h264.GetFps(); + break; + case kVideoCodecAV1: + fps = config->av1.GetFps(); + break; + case kVideoCodecGeneric: + fps = config->generic.GetFps(); + break; + default: + break; + } + + const int framerate = fps.value_or(config->fps); + + return (framerate == kMaxFps) ? std::numeric_limits<int>::max() : framerate; +} + +absl::optional<int> GetKbps( + VideoCodecType type, + const absl::optional<BalancedDegradationSettings::Config>& config) { + if (!config.has_value()) + return absl::nullopt; + + absl::optional<int> kbps; + switch (type) { + case kVideoCodecVP8: + kbps = config->vp8.GetKbps(); + break; + case kVideoCodecH265: + // TODO(bugs.webrtc.org/13485): Use VP9 bitrate limits for now. + case kVideoCodecVP9: + kbps = config->vp9.GetKbps(); + break; + case kVideoCodecH264: + kbps = config->h264.GetKbps(); + break; + case kVideoCodecAV1: + kbps = config->av1.GetKbps(); + break; + case kVideoCodecGeneric: + kbps = config->generic.GetKbps(); + break; + default: + break; + } + + if (kbps.has_value()) + return kbps; + + return config->kbps > 0 ? absl::optional<int>(config->kbps) : absl::nullopt; +} + +absl::optional<int> GetKbpsRes( + VideoCodecType type, + const absl::optional<BalancedDegradationSettings::Config>& config) { + if (!config.has_value()) + return absl::nullopt; + + absl::optional<int> kbps_res; + switch (type) { + case kVideoCodecVP8: + kbps_res = config->vp8.GetKbpsRes(); + break; + case kVideoCodecH265: + // TODO(bugs.webrtc.org/13485): Use VP9 bitrate limits for now. + case kVideoCodecVP9: + kbps_res = config->vp9.GetKbpsRes(); + break; + case kVideoCodecH264: + kbps_res = config->h264.GetKbpsRes(); + break; + case kVideoCodecAV1: + kbps_res = config->av1.GetKbpsRes(); + break; + case kVideoCodecGeneric: + kbps_res = config->generic.GetKbpsRes(); + break; + default: + break; + } + + if (kbps_res.has_value()) + return kbps_res; + + return config->kbps_res > 0 ? absl::optional<int>(config->kbps_res) + : absl::nullopt; +} +} // namespace + +absl::optional<int> BalancedDegradationSettings::CodecTypeSpecific::GetQpLow() + const { + return (qp_low > 0) ? absl::optional<int>(qp_low) : absl::nullopt; +} + +absl::optional<int> BalancedDegradationSettings::CodecTypeSpecific::GetQpHigh() + const { + return (qp_high > 0) ? absl::optional<int>(qp_high) : absl::nullopt; +} + +absl::optional<int> BalancedDegradationSettings::CodecTypeSpecific::GetFps() + const { + return (fps > 0) ? absl::optional<int>(fps) : absl::nullopt; +} + +absl::optional<int> BalancedDegradationSettings::CodecTypeSpecific::GetKbps() + const { + return (kbps > 0) ? absl::optional<int>(kbps) : absl::nullopt; +} + +absl::optional<int> BalancedDegradationSettings::CodecTypeSpecific::GetKbpsRes() + const { + return (kbps_res > 0) ? absl::optional<int>(kbps_res) : absl::nullopt; +} + +BalancedDegradationSettings::Config::Config() = default; + +BalancedDegradationSettings::Config::Config(int pixels, + int fps, + int kbps, + int kbps_res, + int fps_diff, + CodecTypeSpecific vp8, + CodecTypeSpecific vp9, + CodecTypeSpecific h264, + CodecTypeSpecific av1, + CodecTypeSpecific generic) + : pixels(pixels), + fps(fps), + kbps(kbps), + kbps_res(kbps_res), + fps_diff(fps_diff), + vp8(vp8), + vp9(vp9), + h264(h264), + av1(av1), + generic(generic) {} + +BalancedDegradationSettings::BalancedDegradationSettings( + const FieldTrialsView& field_trials) { + FieldTrialStructList<Config> configs( + {FieldTrialStructMember("pixels", [](Config* c) { return &c->pixels; }), + FieldTrialStructMember("fps", [](Config* c) { return &c->fps; }), + FieldTrialStructMember("kbps", [](Config* c) { return &c->kbps; }), + FieldTrialStructMember("kbps_res", + [](Config* c) { return &c->kbps_res; }), + FieldTrialStructMember("fps_diff", + [](Config* c) { return &c->fps_diff; }), + FieldTrialStructMember("vp8_qp_low", + [](Config* c) { return &c->vp8.qp_low; }), + FieldTrialStructMember("vp8_qp_high", + [](Config* c) { return &c->vp8.qp_high; }), + FieldTrialStructMember("vp8_fps", [](Config* c) { return &c->vp8.fps; }), + FieldTrialStructMember("vp8_kbps", + [](Config* c) { return &c->vp8.kbps; }), + FieldTrialStructMember("vp8_kbps_res", + [](Config* c) { return &c->vp8.kbps_res; }), + FieldTrialStructMember("vp9_qp_low", + [](Config* c) { return &c->vp9.qp_low; }), + FieldTrialStructMember("vp9_qp_high", + [](Config* c) { return &c->vp9.qp_high; }), + FieldTrialStructMember("vp9_fps", [](Config* c) { return &c->vp9.fps; }), + FieldTrialStructMember("vp9_kbps", + [](Config* c) { return &c->vp9.kbps; }), + FieldTrialStructMember("vp9_kbps_res", + [](Config* c) { return &c->vp9.kbps_res; }), + FieldTrialStructMember("h264_qp_low", + [](Config* c) { return &c->h264.qp_low; }), + FieldTrialStructMember("h264_qp_high", + [](Config* c) { return &c->h264.qp_high; }), + FieldTrialStructMember("h264_fps", + [](Config* c) { return &c->h264.fps; }), + FieldTrialStructMember("h264_kbps", + [](Config* c) { return &c->h264.kbps; }), + FieldTrialStructMember("h264_kbps_res", + [](Config* c) { return &c->h264.kbps_res; }), + FieldTrialStructMember("av1_qp_low", + [](Config* c) { return &c->av1.qp_low; }), + FieldTrialStructMember("av1_qp_high", + [](Config* c) { return &c->av1.qp_high; }), + FieldTrialStructMember("av1_fps", [](Config* c) { return &c->av1.fps; }), + FieldTrialStructMember("av1_kbps", + [](Config* c) { return &c->av1.kbps; }), + FieldTrialStructMember("av1_kbps_res", + [](Config* c) { return &c->av1.kbps_res; }), + FieldTrialStructMember("generic_qp_low", + [](Config* c) { return &c->generic.qp_low; }), + FieldTrialStructMember("generic_qp_high", + [](Config* c) { return &c->generic.qp_high; }), + FieldTrialStructMember("generic_fps", + [](Config* c) { return &c->generic.fps; }), + FieldTrialStructMember("generic_kbps", + [](Config* c) { return &c->generic.kbps; }), + FieldTrialStructMember("generic_kbps_res", + [](Config* c) { return &c->generic.kbps_res; })}, + {}); + + ParseFieldTrial({&configs}, field_trials.Lookup(kFieldTrial)); + + configs_ = GetValidOrDefault(configs.Get()); + RTC_DCHECK_GT(configs_.size(), 1); +} + +BalancedDegradationSettings::~BalancedDegradationSettings() {} + +std::vector<BalancedDegradationSettings::Config> +BalancedDegradationSettings::GetConfigs() const { + return configs_; +} + +int BalancedDegradationSettings::MinFps(VideoCodecType type, int pixels) const { + return GetFps(type, GetMinFpsConfig(pixels)); +} + +absl::optional<BalancedDegradationSettings::Config> +BalancedDegradationSettings::GetMinFpsConfig(int pixels) const { + for (const auto& config : configs_) { + if (pixels <= config.pixels) + return config; + } + return absl::nullopt; +} + +int BalancedDegradationSettings::MaxFps(VideoCodecType type, int pixels) const { + return GetFps(type, GetMaxFpsConfig(pixels)); +} + +absl::optional<BalancedDegradationSettings::Config> +BalancedDegradationSettings::GetMaxFpsConfig(int pixels) const { + for (size_t i = 0; i < configs_.size() - 1; ++i) { + if (pixels <= configs_[i].pixels) + return configs_[i + 1]; + } + return absl::nullopt; +} + +bool BalancedDegradationSettings::CanAdaptUp(VideoCodecType type, + int pixels, + uint32_t bitrate_bps) const { + absl::optional<int> min_kbps = GetKbps(type, GetMaxFpsConfig(pixels)); + if (!min_kbps.has_value() || bitrate_bps == 0) { + return true; // No limit configured or bitrate provided. + } + return bitrate_bps >= static_cast<uint32_t>(min_kbps.value() * 1000); +} + +bool BalancedDegradationSettings::CanAdaptUpResolution( + VideoCodecType type, + int pixels, + uint32_t bitrate_bps) const { + absl::optional<int> min_kbps = GetKbpsRes(type, GetMaxFpsConfig(pixels)); + if (!min_kbps.has_value() || bitrate_bps == 0) { + return true; // No limit configured or bitrate provided. + } + return bitrate_bps >= static_cast<uint32_t>(min_kbps.value() * 1000); +} + +absl::optional<int> BalancedDegradationSettings::MinFpsDiff(int pixels) const { + for (const auto& config : configs_) { + if (pixels <= config.pixels) { + return (config.fps_diff > kNoFpsDiff) + ? absl::optional<int>(config.fps_diff) + : absl::nullopt; + } + } + return absl::nullopt; +} + +absl::optional<VideoEncoder::QpThresholds> +BalancedDegradationSettings::GetQpThresholds(VideoCodecType type, + int pixels) const { + return GetThresholds(type, GetConfig(pixels)); +} + +BalancedDegradationSettings::Config BalancedDegradationSettings::GetConfig( + int pixels) const { + for (const auto& config : configs_) { + if (pixels <= config.pixels) + return config; + } + return configs_.back(); // Use last above highest pixels. +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/experiments/balanced_degradation_settings.h b/third_party/libwebrtc/rtc_base/experiments/balanced_degradation_settings.h new file mode 100644 index 0000000000..2bca73dfb9 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/balanced_degradation_settings.h @@ -0,0 +1,143 @@ +/* + * 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 RTC_BASE_EXPERIMENTS_BALANCED_DEGRADATION_SETTINGS_H_ +#define RTC_BASE_EXPERIMENTS_BALANCED_DEGRADATION_SETTINGS_H_ + +#include <vector> + +#include "absl/types/optional.h" +#include "api/field_trials_view.h" +#include "api/video_codecs/video_encoder.h" + +namespace webrtc { + +class BalancedDegradationSettings { + public: + static constexpr int kNoFpsDiff = -100; + + BalancedDegradationSettings(const FieldTrialsView& field_trials); + ~BalancedDegradationSettings(); + + struct CodecTypeSpecific { + CodecTypeSpecific() {} + CodecTypeSpecific(int qp_low, int qp_high, int fps, int kbps, int kbps_res) + : qp_low(qp_low), + qp_high(qp_high), + fps(fps), + kbps(kbps), + kbps_res(kbps_res) {} + + bool operator==(const CodecTypeSpecific& o) const { + return qp_low == o.qp_low && qp_high == o.qp_high && fps == o.fps && + kbps == o.kbps && kbps_res == o.kbps_res; + } + + absl::optional<int> GetQpLow() const; + absl::optional<int> GetQpHigh() const; + absl::optional<int> GetFps() const; + absl::optional<int> GetKbps() const; + absl::optional<int> GetKbpsRes() const; + + // Optional settings. + int qp_low = 0; + int qp_high = 0; + int fps = 0; // If unset, defaults to `fps` in Config. + int kbps = 0; // If unset, defaults to `kbps` in Config. + int kbps_res = 0; // If unset, defaults to `kbps_res` in Config. + }; + + struct Config { + Config(); + Config(int pixels, + int fps, + int kbps, + int kbps_res, + int fps_diff, + CodecTypeSpecific vp8, + CodecTypeSpecific vp9, + CodecTypeSpecific h264, + CodecTypeSpecific av1, + CodecTypeSpecific generic); + + bool operator==(const Config& o) const { + return pixels == o.pixels && fps == o.fps && kbps == o.kbps && + kbps_res == o.kbps_res && fps_diff == o.fps_diff && vp8 == o.vp8 && + vp9 == o.vp9 && h264 == o.h264 && av1 == o.av1 && + generic == o.generic; + } + + // Example: + // WebRTC-Video-BalancedDegradationSettings/pixels:100|200|300,fps:5|15|25/ + // pixels <= 100 -> min framerate: 5 fps + // pixels <= 200 -> min framerate: 15 fps + // pixels <= 300 -> min framerate: 25 fps + // + // WebRTC-Video-BalancedDegradationSettings/pixels:100|200|300, + // fps:5|15|25, // Min framerate. + // kbps:0|60|70, // Min bitrate needed to adapt up. + // kbps_res:0|65|75/ // Min bitrate needed to adapt up in resolution. + // + // pixels: fps: kbps: kbps_res: + // 300 30 - - + // 300 25 70 kbps 75 kbps + // 200 25 70 kbps - + // 200 15 60 kbps 65 kbps + // 100 15 60 kbps - + // 100 5 + // optional optional + + int pixels = 0; // Video frame size. + // If the frame size is less than or equal to `pixels`: + int fps = 0; // Min framerate to be used. + int kbps = 0; // Min bitrate needed to adapt up (resolution/fps). + int kbps_res = 0; // Min bitrate needed to adapt up in resolution. + int fps_diff = kNoFpsDiff; // Min fps reduction needed (input fps - `fps`) + // w/o triggering a new subsequent downgrade + // check. + CodecTypeSpecific vp8; + CodecTypeSpecific vp9; + CodecTypeSpecific h264; + CodecTypeSpecific av1; + CodecTypeSpecific generic; + }; + + // Returns configurations from field trial on success (default on failure). + std::vector<Config> GetConfigs() const; + + // Gets the min/max framerate from `configs_` based on `pixels`. + int MinFps(VideoCodecType type, int pixels) const; + int MaxFps(VideoCodecType type, int pixels) const; + + // Checks if quality can be increased based on `pixels` and `bitrate_bps`. + bool CanAdaptUp(VideoCodecType type, int pixels, uint32_t bitrate_bps) const; + bool CanAdaptUpResolution(VideoCodecType type, + int pixels, + uint32_t bitrate_bps) const; + + // Gets the min framerate diff from `configs_` based on `pixels`. + absl::optional<int> MinFpsDiff(int pixels) const; + + // Gets QpThresholds for the codec `type` based on `pixels`. + absl::optional<VideoEncoder::QpThresholds> GetQpThresholds( + VideoCodecType type, + int pixels) const; + + private: + absl::optional<Config> GetMinFpsConfig(int pixels) const; + absl::optional<Config> GetMaxFpsConfig(int pixels) const; + Config GetConfig(int pixels) const; + + std::vector<Config> configs_; +}; + +} // namespace webrtc + +#endif // RTC_BASE_EXPERIMENTS_BALANCED_DEGRADATION_SETTINGS_H_ diff --git a/third_party/libwebrtc/rtc_base/experiments/balanced_degradation_settings_gn/moz.build b/third_party/libwebrtc/rtc_base/experiments/balanced_degradation_settings_gn/moz.build new file mode 100644 index 0000000000..cbbb32ab70 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/balanced_degradation_settings_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/rtc_base/experiments/balanced_degradation_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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("balanced_degradation_settings_gn") diff --git a/third_party/libwebrtc/rtc_base/experiments/balanced_degradation_settings_unittest.cc b/third_party/libwebrtc/rtc_base/experiments/balanced_degradation_settings_unittest.cc new file mode 100644 index 0000000000..996c06f8f2 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/balanced_degradation_settings_unittest.cc @@ -0,0 +1,619 @@ +/* + * 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 "rtc_base/experiments/balanced_degradation_settings.h" + +#include <limits> + +#include "rtc_base/gunit.h" +#include "test/gmock.h" +#include "test/scoped_key_value_config.h" + +namespace webrtc { +namespace { + +void VerifyIsDefault( + const std::vector<BalancedDegradationSettings::Config>& config) { + EXPECT_THAT(config, + ::testing::ElementsAre( + BalancedDegradationSettings::Config{ + 320 * 240, + 7, + 0, + 0, + BalancedDegradationSettings::kNoFpsDiff, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}}, + BalancedDegradationSettings::Config{480 * 360, + 10, + 0, + 0, + 1, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}}, + BalancedDegradationSettings::Config{640 * 480, + 15, + 0, + 0, + 1, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}})); +} +} // namespace + +TEST(BalancedDegradationSettings, GetsDefaultConfigIfNoList) { + webrtc::test::ScopedKeyValueConfig field_trials(""); + BalancedDegradationSettings settings(field_trials); + VerifyIsDefault(settings.GetConfigs()); + EXPECT_TRUE(settings.CanAdaptUp(kVideoCodecVP8, 1, /*bitrate_bps*/ 1)); + EXPECT_TRUE( + settings.CanAdaptUpResolution(kVideoCodecVP8, 1, /*bitrate_bps*/ 1)); + EXPECT_FALSE(settings.MinFpsDiff(1)); + EXPECT_FALSE(settings.GetQpThresholds(kVideoCodecVP8, 1)); + EXPECT_FALSE(settings.GetQpThresholds(kVideoCodecVP9, 1)); + EXPECT_FALSE(settings.GetQpThresholds(kVideoCodecH264, 1)); + EXPECT_FALSE(settings.GetQpThresholds(kVideoCodecAV1, 1)); + EXPECT_FALSE(settings.GetQpThresholds(kVideoCodecGeneric, 1)); + EXPECT_FALSE(settings.GetQpThresholds(kVideoCodecMultiplex, 1)); +} + +TEST(BalancedDegradationSettings, GetsConfig) { + webrtc::test::ScopedKeyValueConfig field_trials( + "WebRTC-Video-BalancedDegradationSettings/" + "pixels:11|22|33,fps:5|15|25,other:4|5|6/"); + BalancedDegradationSettings settings(field_trials); + EXPECT_THAT(settings.GetConfigs(), + ::testing::ElementsAre( + BalancedDegradationSettings::Config{ + 11, + 5, + 0, + 0, + BalancedDegradationSettings::kNoFpsDiff, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}}, + BalancedDegradationSettings::Config{ + 22, + 15, + 0, + 0, + BalancedDegradationSettings::kNoFpsDiff, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}}, + BalancedDegradationSettings::Config{ + 33, + 25, + 0, + 0, + BalancedDegradationSettings::kNoFpsDiff, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}})); +} + +TEST(BalancedDegradationSettings, GetsDefaultConfigForZeroFpsValue) { + webrtc::test::ScopedKeyValueConfig field_trials( + "WebRTC-Video-BalancedDegradationSettings/" + "pixels:1000|2000|3000,fps:0|15|25/"); + BalancedDegradationSettings settings(field_trials); + VerifyIsDefault(settings.GetConfigs()); +} + +TEST(BalancedDegradationSettings, GetsDefaultConfigIfPixelsDecreases) { + webrtc::test::ScopedKeyValueConfig field_trials( + "WebRTC-Video-BalancedDegradationSettings/" + "pixels:1000|999|3000,fps:5|15|25/"); + BalancedDegradationSettings settings(field_trials); + VerifyIsDefault(settings.GetConfigs()); +} + +TEST(BalancedDegradationSettings, GetsDefaultConfigIfFramerateDecreases) { + webrtc::test::ScopedKeyValueConfig field_trials( + "WebRTC-Video-BalancedDegradationSettings/" + "pixels:1000|2000|3000,fps:5|4|25/"); + BalancedDegradationSettings settings(field_trials); + VerifyIsDefault(settings.GetConfigs()); +} + +TEST(BalancedDegradationSettings, GetsConfigWithSpecificFps) { + webrtc::test::ScopedKeyValueConfig field_trials( + "WebRTC-Video-BalancedDegradationSettings/" + "pixels:1000|2000|3000,fps:5|15|25,vp8_fps:7|8|9,vp9_fps:9|10|11," + "h264_fps:11|12|13,av1_fps:1|2|3,generic_fps:13|14|15/"); + BalancedDegradationSettings settings(field_trials); + EXPECT_THAT(settings.GetConfigs(), + ::testing::ElementsAre( + BalancedDegradationSettings::Config{ + 1000, + 5, + 0, + 0, + BalancedDegradationSettings::kNoFpsDiff, + {0, 0, 7, 0, 0}, + {0, 0, 9, 0, 0}, + {0, 0, 11, 0, 0}, + {0, 0, 1, 0, 0}, + {0, 0, 13, 0, 0}}, + BalancedDegradationSettings::Config{ + 2000, + 15, + 0, + 0, + BalancedDegradationSettings::kNoFpsDiff, + {0, 0, 8, 0, 0}, + {0, 0, 10, 0, 0}, + {0, 0, 12, 0, 0}, + {0, 0, 2, 0, 0}, + {0, 0, 14, 0, 0}}, + BalancedDegradationSettings::Config{ + 3000, + 25, + 0, + 0, + BalancedDegradationSettings::kNoFpsDiff, + {0, 0, 9, 0, 0}, + {0, 0, 11, 0, 0}, + {0, 0, 13, 0, 0}, + {0, 0, 3, 0, 0}, + {0, 0, 15, 0, 0}})); +} + +TEST(BalancedDegradationSettings, GetsDefaultConfigForZeroVp8FpsValue) { + webrtc::test::ScopedKeyValueConfig field_trials( + "WebRTC-Video-BalancedDegradationSettings/" + "pixels:1000|2000|3000,fps:7|15|25,vp8_fps:0|15|25/"); + BalancedDegradationSettings settings(field_trials); + VerifyIsDefault(settings.GetConfigs()); +} + +TEST(BalancedDegradationSettings, GetsDefaultConfigForInvalidFpsValue) { + webrtc::test::ScopedKeyValueConfig field_trials( + "WebRTC-Video-BalancedDegradationSettings/" + "pixels:1000|2000|3000,fps:7|15|25,vp8_fps:10|15|2000/"); + BalancedDegradationSettings settings(field_trials); + VerifyIsDefault(settings.GetConfigs()); +} + +TEST(BalancedDegradationSettings, GetsDefaultConfigIfVp8FramerateDecreases) { + webrtc::test::ScopedKeyValueConfig field_trials( + "WebRTC-Video-BalancedDegradationSettings/" + "pixels:1000|2000|3000,fps:4|5|25,vp8_fps:5|4|25/"); + BalancedDegradationSettings settings(field_trials); + VerifyIsDefault(settings.GetConfigs()); +} + +TEST(BalancedDegradationSettings, GetsMinFps) { + webrtc::test::ScopedKeyValueConfig field_trials( + "WebRTC-Video-BalancedDegradationSettings/" + "pixels:1000|2000|3000,fps:5|15|25/"); + BalancedDegradationSettings settings(field_trials); + EXPECT_EQ(5, settings.MinFps(kVideoCodecVP8, 1)); + EXPECT_EQ(5, settings.MinFps(kVideoCodecVP8, 1000)); + EXPECT_EQ(15, settings.MinFps(kVideoCodecVP8, 1001)); + EXPECT_EQ(15, settings.MinFps(kVideoCodecVP8, 2000)); + EXPECT_EQ(25, settings.MinFps(kVideoCodecVP8, 2001)); + EXPECT_EQ(25, settings.MinFps(kVideoCodecVP8, 3000)); + EXPECT_EQ(std::numeric_limits<int>::max(), + settings.MinFps(kVideoCodecVP8, 3001)); +} + +TEST(BalancedDegradationSettings, GetsVp8MinFps) { + webrtc::test::ScopedKeyValueConfig field_trials( + "WebRTC-Video-BalancedDegradationSettings/" + "pixels:1000|2000|3000,fps:5|15|25,vp8_fps:7|10|12/"); + BalancedDegradationSettings settings(field_trials); + EXPECT_EQ(7, settings.MinFps(kVideoCodecVP8, 1)); + EXPECT_EQ(7, settings.MinFps(kVideoCodecVP8, 1000)); + EXPECT_EQ(10, settings.MinFps(kVideoCodecVP8, 1001)); + EXPECT_EQ(10, settings.MinFps(kVideoCodecVP8, 2000)); + EXPECT_EQ(12, settings.MinFps(kVideoCodecVP8, 2001)); + EXPECT_EQ(12, settings.MinFps(kVideoCodecVP8, 3000)); + EXPECT_EQ(std::numeric_limits<int>::max(), + settings.MinFps(kVideoCodecVP8, 3001)); +} + +TEST(BalancedDegradationSettings, GetsMaxFps) { + webrtc::test::ScopedKeyValueConfig field_trials( + "WebRTC-Video-BalancedDegradationSettings/" + "pixels:1000|2000|3000,fps:5|15|25/"); + BalancedDegradationSettings settings(field_trials); + EXPECT_EQ(15, settings.MaxFps(kVideoCodecVP8, 1)); + EXPECT_EQ(15, settings.MaxFps(kVideoCodecVP8, 1000)); + EXPECT_EQ(25, settings.MaxFps(kVideoCodecVP8, 1001)); + EXPECT_EQ(25, settings.MaxFps(kVideoCodecVP8, 2000)); + EXPECT_EQ(std::numeric_limits<int>::max(), + settings.MaxFps(kVideoCodecVP8, 2001)); +} + +TEST(BalancedDegradationSettings, GetsVp8MaxFps) { + webrtc::test::ScopedKeyValueConfig field_trials( + "WebRTC-Video-BalancedDegradationSettings/" + "pixels:1000|2000|3000,fps:5|15|25,vp8_fps:7|10|12/"); + BalancedDegradationSettings settings(field_trials); + EXPECT_EQ(10, settings.MaxFps(kVideoCodecVP8, 1)); + EXPECT_EQ(10, settings.MaxFps(kVideoCodecVP8, 1000)); + EXPECT_EQ(12, settings.MaxFps(kVideoCodecVP8, 1001)); + EXPECT_EQ(12, settings.MaxFps(kVideoCodecVP8, 2000)); + EXPECT_EQ(std::numeric_limits<int>::max(), + settings.MaxFps(kVideoCodecVP8, 2001)); +} + +TEST(BalancedDegradationSettings, GetsVp9Fps) { + webrtc::test::ScopedKeyValueConfig field_trials( + "WebRTC-Video-BalancedDegradationSettings/" + "pixels:1000|2000|3000,fps:5|15|25,vp9_fps:7|10|12/"); + BalancedDegradationSettings settings(field_trials); + EXPECT_EQ(7, settings.MinFps(kVideoCodecVP9, 1000)); + EXPECT_EQ(10, settings.MaxFps(kVideoCodecVP9, 1000)); +} + +TEST(BalancedDegradationSettings, GetsH264Fps) { + webrtc::test::ScopedKeyValueConfig field_trials( + "WebRTC-Video-BalancedDegradationSettings/" + "pixels:1000|2000|3000,fps:5|15|25,h264_fps:8|11|13/"); + BalancedDegradationSettings settings(field_trials); + EXPECT_EQ(11, settings.MinFps(kVideoCodecH264, 2000)); + EXPECT_EQ(13, settings.MaxFps(kVideoCodecH264, 2000)); +} + +TEST(BalancedDegradationSettings, GetsGenericFps) { + webrtc::test::ScopedKeyValueConfig field_trials( + "WebRTC-Video-BalancedDegradationSettings/" + "pixels:1000|2000|3000,fps:5|15|25,generic_fps:9|12|14/"); + BalancedDegradationSettings settings(field_trials); + EXPECT_EQ(14, settings.MinFps(kVideoCodecGeneric, 3000)); + EXPECT_EQ(std::numeric_limits<int>::max(), + settings.MaxFps(kVideoCodecGeneric, 3000)); +} + +TEST(BalancedDegradationSettings, GetsUnlimitedForMaxValidFps) { + webrtc::test::ScopedKeyValueConfig field_trials( + "WebRTC-Video-BalancedDegradationSettings/" + "pixels:1000|2000|3000,fps:5|15|100,vp8_fps:30|100|100/"); + const int kUnlimitedFps = std::numeric_limits<int>::max(); + BalancedDegradationSettings settings(field_trials); + EXPECT_EQ(15, settings.MinFps(kVideoCodecH264, 2000)); + EXPECT_EQ(kUnlimitedFps, settings.MinFps(kVideoCodecH264, 2001)); + EXPECT_EQ(30, settings.MinFps(kVideoCodecVP8, 1000)); + EXPECT_EQ(kUnlimitedFps, settings.MinFps(kVideoCodecVP8, 1001)); +} + +TEST(BalancedDegradationSettings, GetsConfigWithBitrate) { + webrtc::test::ScopedKeyValueConfig field_trials( + "WebRTC-Video-BalancedDegradationSettings/" + "pixels:11|22|33,fps:5|15|25,kbps:44|88|99,kbps_res:55|111|222," + "vp8_kbps:11|12|13,vp8_kbps_res:14|15|16," + "vp9_kbps:21|22|23,vp9_kbps_res:24|25|26," + "h264_kbps:31|32|33,h264_kbps_res:34|35|36," + "av1_kbps:41|42|43,av1_kbps_res:44|45|46," + "generic_kbps:51|52|53,generic_kbps_res:54|55|56/"); + BalancedDegradationSettings settings(field_trials); + EXPECT_THAT(settings.GetConfigs(), + ::testing::ElementsAre( + BalancedDegradationSettings::Config{ + 11, + 5, + 44, + 55, + BalancedDegradationSettings::kNoFpsDiff, + {0, 0, 0, 11, 14}, + {0, 0, 0, 21, 24}, + {0, 0, 0, 31, 34}, + {0, 0, 0, 41, 44}, + {0, 0, 0, 51, 54}}, + BalancedDegradationSettings::Config{ + 22, + 15, + 88, + 111, + BalancedDegradationSettings::kNoFpsDiff, + {0, 0, 0, 12, 15}, + {0, 0, 0, 22, 25}, + {0, 0, 0, 32, 35}, + {0, 0, 0, 42, 45}, + {0, 0, 0, 52, 55}}, + BalancedDegradationSettings::Config{ + 33, + 25, + 99, + 222, + BalancedDegradationSettings::kNoFpsDiff, + {0, 0, 0, 13, 16}, + {0, 0, 0, 23, 26}, + {0, 0, 0, 33, 36}, + {0, 0, 0, 43, 46}, + {0, 0, 0, 53, 56}})); +} + +TEST(BalancedDegradationSettings, GetsDefaultConfigIfBitrateDecreases) { + webrtc::test::ScopedKeyValueConfig field_trials( + "WebRTC-Video-BalancedDegradationSettings/" + "pixels:11|22|33,fps:5|15|25,kbps:44|43|99/"); + BalancedDegradationSettings settings(field_trials); + VerifyIsDefault(settings.GetConfigs()); +} + +TEST(BalancedDegradationSettings, + GetsDefaultConfigIfBitrateDecreasesWithUnsetValue) { + webrtc::test::ScopedKeyValueConfig field_trials( + "WebRTC-Video-BalancedDegradationSettings/" + "pixels:11|22|33,fps:5|15|25,kbps:44|0|43/"); + BalancedDegradationSettings settings(field_trials); + VerifyIsDefault(settings.GetConfigs()); +} + +TEST(BalancedDegradationSettings, CanAdaptUp) { + VideoCodecType vp8 = kVideoCodecVP8; + webrtc::test::ScopedKeyValueConfig field_trials( + "WebRTC-Video-BalancedDegradationSettings/" + "pixels:1000|2000|3000|4000,fps:5|15|25|30,kbps:0|80|0|90," + "vp9_kbps:40|50|60|70/"); + BalancedDegradationSettings s(field_trials); + EXPECT_TRUE(s.CanAdaptUp(vp8, 1000, 0)); // No bitrate provided. + EXPECT_FALSE(s.CanAdaptUp(vp8, 1000, 79000)); + EXPECT_TRUE(s.CanAdaptUp(vp8, 1000, 80000)); + EXPECT_TRUE(s.CanAdaptUp(vp8, 1001, 1)); // No limit configured. + EXPECT_FALSE(s.CanAdaptUp(vp8, 3000, 89000)); + EXPECT_TRUE(s.CanAdaptUp(vp8, 3000, 90000)); + EXPECT_TRUE(s.CanAdaptUp(vp8, 3001, 1)); // No limit. +} + +TEST(BalancedDegradationSettings, CanAdaptUpWithCodecType) { + webrtc::test::ScopedKeyValueConfig field_trials( + "WebRTC-Video-BalancedDegradationSettings/" + "pixels:1000|2000|3000|4000,fps:5|15|25|30,vp8_kbps:0|30|40|50," + "vp9_kbps:0|60|70|80,h264_kbps:0|55|65|75,av1_kbps:0|77|88|99," + "generic_kbps:0|25|35|45/"); + BalancedDegradationSettings s(field_trials); + EXPECT_FALSE(s.CanAdaptUp(kVideoCodecVP8, 1000, 29000)); + EXPECT_TRUE(s.CanAdaptUp(kVideoCodecVP8, 1000, 30000)); + EXPECT_FALSE(s.CanAdaptUp(kVideoCodecVP9, 1000, 59000)); + EXPECT_TRUE(s.CanAdaptUp(kVideoCodecVP9, 1000, 60000)); + EXPECT_FALSE(s.CanAdaptUp(kVideoCodecH264, 1000, 54000)); + EXPECT_TRUE(s.CanAdaptUp(kVideoCodecH264, 1000, 55000)); + EXPECT_FALSE(s.CanAdaptUp(kVideoCodecAV1, 1000, 76000)); + EXPECT_TRUE(s.CanAdaptUp(kVideoCodecAV1, 1000, 77000)); + EXPECT_FALSE(s.CanAdaptUp(kVideoCodecGeneric, 1000, 24000)); + EXPECT_TRUE(s.CanAdaptUp(kVideoCodecGeneric, 1000, 25000)); + EXPECT_TRUE(s.CanAdaptUp(kVideoCodecMultiplex, 1000, 1)); // Not configured. +} + +TEST(BalancedDegradationSettings, CanAdaptUpResolution) { + VideoCodecType vp8 = kVideoCodecVP8; + webrtc::test::ScopedKeyValueConfig field_trials( + "WebRTC-Video-BalancedDegradationSettings/" + "pixels:1000|2000|3000|4000,fps:5|15|25|30,kbps_res:0|80|0|90," + "vp9_kbps_res:40|50|60|70/"); + BalancedDegradationSettings s(field_trials); + EXPECT_TRUE(s.CanAdaptUpResolution(vp8, 1000, 0)); // No bitrate provided. + EXPECT_FALSE(s.CanAdaptUpResolution(vp8, 1000, 79000)); + EXPECT_TRUE(s.CanAdaptUpResolution(vp8, 1000, 80000)); + EXPECT_TRUE(s.CanAdaptUpResolution(vp8, 1001, 1)); // No limit configured. + EXPECT_FALSE(s.CanAdaptUpResolution(vp8, 3000, 89000)); + EXPECT_TRUE(s.CanAdaptUpResolution(vp8, 3000, 90000)); + EXPECT_TRUE(s.CanAdaptUpResolution(vp8, 3001, 1)); // No limit. +} + +TEST(BalancedDegradationSettings, CanAdaptUpResolutionWithCodecType) { + webrtc::test::ScopedKeyValueConfig field_trials( + "WebRTC-Video-BalancedDegradationSettings/" + "pixels:1000|2000|3000|4000,fps:5|15|25|30,vp8_kbps_res:0|30|40|50," + "vp9_kbps_res:0|60|70|80,h264_kbps_res:0|55|65|75," + "av1_kbps_res:0|77|88|99,generic_kbps_res:0|25|35|45/"); + BalancedDegradationSettings s(field_trials); + EXPECT_FALSE(s.CanAdaptUpResolution(kVideoCodecVP8, 1000, 29000)); + EXPECT_TRUE(s.CanAdaptUpResolution(kVideoCodecVP8, 1000, 30000)); + EXPECT_FALSE(s.CanAdaptUpResolution(kVideoCodecVP9, 1000, 59000)); + EXPECT_TRUE(s.CanAdaptUpResolution(kVideoCodecVP9, 1000, 60000)); + EXPECT_FALSE(s.CanAdaptUpResolution(kVideoCodecH264, 1000, 54000)); + EXPECT_TRUE(s.CanAdaptUpResolution(kVideoCodecH264, 1000, 55000)); + EXPECT_FALSE(s.CanAdaptUpResolution(kVideoCodecAV1, 1000, 76000)); + EXPECT_TRUE(s.CanAdaptUpResolution(kVideoCodecAV1, 1000, 77000)); + EXPECT_FALSE(s.CanAdaptUpResolution(kVideoCodecGeneric, 1000, 24000)); + EXPECT_TRUE(s.CanAdaptUpResolution(kVideoCodecGeneric, 1000, 25000)); + EXPECT_TRUE(s.CanAdaptUpResolution(kVideoCodecMultiplex, 1000, + 1)); // Not configured. +} + +TEST(BalancedDegradationSettings, GetsFpsDiff) { + webrtc::test::ScopedKeyValueConfig field_trials( + "WebRTC-Video-BalancedDegradationSettings/" + "pixels:1000|2000|3000,fps:5|15|25,fps_diff:0|-2|3/"); + BalancedDegradationSettings settings(field_trials); + EXPECT_EQ(0, settings.MinFpsDiff(1)); + EXPECT_EQ(0, settings.MinFpsDiff(1000)); + EXPECT_EQ(-2, settings.MinFpsDiff(1001)); + EXPECT_EQ(-2, settings.MinFpsDiff(2000)); + EXPECT_EQ(3, settings.MinFpsDiff(2001)); + EXPECT_EQ(3, settings.MinFpsDiff(3000)); + EXPECT_FALSE(settings.MinFpsDiff(3001)); +} + +TEST(BalancedDegradationSettings, GetsNoFpsDiffIfValueBelowMinSetting) { + webrtc::test::ScopedKeyValueConfig field_trials( + "WebRTC-Video-BalancedDegradationSettings/" + "pixels:1000|2000|3000,fps:5|15|25,fps_diff:-100|-99|-101/"); + // Min valid fps_diff setting: -99. + BalancedDegradationSettings settings(field_trials); + EXPECT_FALSE(settings.MinFpsDiff(1000)); + EXPECT_EQ(-99, settings.MinFpsDiff(2000)); + EXPECT_FALSE(settings.MinFpsDiff(3000)); +} + +TEST(BalancedDegradationSettings, QpThresholdsNotSetByDefault) { + webrtc::test::ScopedKeyValueConfig field_trials( + "WebRTC-Video-BalancedDegradationSettings/" + "pixels:1000|2000|3000,fps:5|15|25/"); + BalancedDegradationSettings settings(field_trials); + EXPECT_FALSE(settings.GetQpThresholds(kVideoCodecVP8, 1)); + EXPECT_FALSE(settings.GetQpThresholds(kVideoCodecVP9, 1)); + EXPECT_FALSE(settings.GetQpThresholds(kVideoCodecH264, 1)); + EXPECT_FALSE(settings.GetQpThresholds(kVideoCodecAV1, 1)); + EXPECT_FALSE(settings.GetQpThresholds(kVideoCodecGeneric, 1)); +} + +TEST(BalancedDegradationSettings, GetsConfigWithQpThresholds) { + webrtc::test::ScopedKeyValueConfig field_trials( + "WebRTC-Video-BalancedDegradationSettings/" + "pixels:1000|2000|3000,fps:5|15|25,vp8_qp_low:89|90|88," + "vp8_qp_high:90|91|92,vp9_qp_low:27|28|29,vp9_qp_high:120|130|140," + "h264_qp_low:12|13|14,h264_qp_high:20|30|40,av1_qp_low:2|3|4," + "av1_qp_high:11|33|44,generic_qp_low:7|6|5,generic_qp_high:22|23|24/"); + BalancedDegradationSettings settings(field_trials); + EXPECT_THAT(settings.GetConfigs(), + ::testing::ElementsAre( + BalancedDegradationSettings::Config{ + 1000, + 5, + 0, + 0, + BalancedDegradationSettings::kNoFpsDiff, + {89, 90, 0, 0, 0}, + {27, 120, 0, 0, 0}, + {12, 20, 0, 0, 0}, + {2, 11, 0, 0, 0}, + {7, 22, 0, 0, 0}}, + BalancedDegradationSettings::Config{ + 2000, + 15, + 0, + 0, + BalancedDegradationSettings::kNoFpsDiff, + {90, 91, 0, 0, 0}, + {28, 130, 0, 0, 0}, + {13, 30, 0, 0, 0}, + {3, 33, 0, 0, 0}, + {6, 23, 0, 0, 0}}, + BalancedDegradationSettings::Config{ + 3000, + 25, + 0, + 0, + BalancedDegradationSettings::kNoFpsDiff, + {88, 92, 0, 0, 0}, + {29, 140, 0, 0, 0}, + {14, 40, 0, 0, 0}, + {4, 44, 0, 0, 0}, + {5, 24, 0, 0, 0}})); +} + +TEST(BalancedDegradationSettings, GetsDefaultConfigIfOnlyHasLowThreshold) { + webrtc::test::ScopedKeyValueConfig field_trials( + "WebRTC-Video-BalancedDegradationSettings/" + "pixels:1000|2000|3000,fps:5|15|25,vp8_qp_low:89|90|88/"); + BalancedDegradationSettings settings(field_trials); + VerifyIsDefault(settings.GetConfigs()); +} + +TEST(BalancedDegradationSettings, GetsDefaultConfigIfOnlyHasHighThreshold) { + webrtc::test::ScopedKeyValueConfig field_trials( + "WebRTC-Video-BalancedDegradationSettings/" + "pixels:1000|2000|3000,fps:5|15|25,vp8_qp_high:90|91|92/"); + BalancedDegradationSettings settings(field_trials); + VerifyIsDefault(settings.GetConfigs()); +} + +TEST(BalancedDegradationSettings, GetsDefaultConfigIfLowEqualsHigh) { + webrtc::test::ScopedKeyValueConfig field_trials( + "WebRTC-Video-BalancedDegradationSettings/" + "pixels:1000|2000|3000,fps:5|15|25," + "vp8_qp_low:89|90|88,vp8_qp_high:90|91|88/"); + BalancedDegradationSettings settings(field_trials); + VerifyIsDefault(settings.GetConfigs()); +} + +TEST(BalancedDegradationSettings, GetsDefaultConfigIfLowGreaterThanHigh) { + webrtc::test::ScopedKeyValueConfig field_trials( + "WebRTC-Video-BalancedDegradationSettings/" + "pixels:1000|2000|3000,fps:5|15|25," + "vp8_qp_low:89|90|88,vp8_qp_high:90|91|87/"); + BalancedDegradationSettings settings(field_trials); + VerifyIsDefault(settings.GetConfigs()); +} + +TEST(BalancedDegradationSettings, GetsDefaultConfigForZeroQpValue) { + webrtc::test::ScopedKeyValueConfig field_trials( + "WebRTC-Video-BalancedDegradationSettings/" + "pixels:1000|2000|3000,fps:5|15|25," + "vp8_qp_low:89|0|88,vp8_qp_high:90|91|92/"); + BalancedDegradationSettings settings(field_trials); + VerifyIsDefault(settings.GetConfigs()); +} + +TEST(BalancedDegradationSettings, GetsVp8QpThresholds) { + webrtc::test::ScopedKeyValueConfig field_trials( + "WebRTC-Video-BalancedDegradationSettings/" + "pixels:1000|2000|3000,fps:5|15|25," + "vp8_qp_low:89|90|88,vp8_qp_high:90|91|92/"); + BalancedDegradationSettings settings(field_trials); + EXPECT_EQ(89, settings.GetQpThresholds(kVideoCodecVP8, 1)->low); + EXPECT_EQ(90, settings.GetQpThresholds(kVideoCodecVP8, 1)->high); + EXPECT_EQ(90, settings.GetQpThresholds(kVideoCodecVP8, 1000)->high); + EXPECT_EQ(91, settings.GetQpThresholds(kVideoCodecVP8, 1001)->high); + EXPECT_EQ(91, settings.GetQpThresholds(kVideoCodecVP8, 2000)->high); + EXPECT_EQ(92, settings.GetQpThresholds(kVideoCodecVP8, 2001)->high); + EXPECT_EQ(92, settings.GetQpThresholds(kVideoCodecVP8, 3000)->high); + EXPECT_EQ(92, settings.GetQpThresholds(kVideoCodecVP8, 3001)->high); +} + +TEST(BalancedDegradationSettings, GetsVp9QpThresholds) { + webrtc::test::ScopedKeyValueConfig field_trials( + "WebRTC-Video-BalancedDegradationSettings/" + "pixels:1000|2000|3000,fps:5|15|25," + "vp9_qp_low:55|56|57,vp9_qp_high:155|156|157/"); + BalancedDegradationSettings settings(field_trials); + const auto thresholds = settings.GetQpThresholds(kVideoCodecVP9, 1000); + EXPECT_TRUE(thresholds); + EXPECT_EQ(55, thresholds->low); + EXPECT_EQ(155, thresholds->high); +} + +TEST(BalancedDegradationSettings, GetsH264QpThresholds) { + webrtc::test::ScopedKeyValueConfig field_trials( + "WebRTC-Video-BalancedDegradationSettings/" + "pixels:1000|2000|3000,fps:5|15|25," + "h264_qp_low:21|22|23,h264_qp_high:41|43|42/"); + BalancedDegradationSettings settings(field_trials); + const auto thresholds = settings.GetQpThresholds(kVideoCodecH264, 2000); + EXPECT_TRUE(thresholds); + EXPECT_EQ(22, thresholds->low); + EXPECT_EQ(43, thresholds->high); +} + +TEST(BalancedDegradationSettings, GetsGenericQpThresholds) { + webrtc::test::ScopedKeyValueConfig field_trials( + "WebRTC-Video-BalancedDegradationSettings/" + "pixels:1000|2000|3000,fps:5|15|25," + "generic_qp_low:2|3|4,generic_qp_high:22|23|24/"); + BalancedDegradationSettings settings(field_trials); + const auto thresholds = settings.GetQpThresholds(kVideoCodecGeneric, 3000); + EXPECT_TRUE(thresholds); + EXPECT_EQ(4, thresholds->low); + EXPECT_EQ(24, thresholds->high); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/experiments/bandwidth_quality_scaler_settings.cc b/third_party/libwebrtc/rtc_base/experiments/bandwidth_quality_scaler_settings.cc new file mode 100644 index 0000000000..0a9df493ed --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/bandwidth_quality_scaler_settings.cc @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2021 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 "rtc_base/experiments/bandwidth_quality_scaler_settings.h" + +#include "api/transport/field_trial_based_config.h" +#include "rtc_base/logging.h" + +namespace webrtc { + +BandwidthQualityScalerSettings::BandwidthQualityScalerSettings( + const FieldTrialsView* const key_value_config) + : bitrate_state_update_interval_s_("bitrate_state_update_interval_s_") { + ParseFieldTrial( + {&bitrate_state_update_interval_s_}, + key_value_config->Lookup("WebRTC-Video-BandwidthQualityScalerSettings")); +} + +BandwidthQualityScalerSettings +BandwidthQualityScalerSettings::ParseFromFieldTrials() { + FieldTrialBasedConfig field_trial_config; + return BandwidthQualityScalerSettings(&field_trial_config); +} + +absl::optional<uint32_t> +BandwidthQualityScalerSettings::BitrateStateUpdateInterval() const { + if (bitrate_state_update_interval_s_ && + bitrate_state_update_interval_s_.Value() <= 0) { + RTC_LOG(LS_WARNING) + << "Unsupported bitrate_state_update_interval_s_ value, ignored."; + return absl::nullopt; + } + return bitrate_state_update_interval_s_.GetOptional(); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/experiments/bandwidth_quality_scaler_settings.h b/third_party/libwebrtc/rtc_base/experiments/bandwidth_quality_scaler_settings.h new file mode 100644 index 0000000000..21e115df01 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/bandwidth_quality_scaler_settings.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2021 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 RTC_BASE_EXPERIMENTS_BANDWIDTH_QUALITY_SCALER_SETTINGS_H_ +#define RTC_BASE_EXPERIMENTS_BANDWIDTH_QUALITY_SCALER_SETTINGS_H_ + +#include "absl/types/optional.h" +#include "api/field_trials_view.h" +#include "rtc_base/experiments/field_trial_parser.h" + +namespace webrtc { + +class BandwidthQualityScalerSettings final { + public: + static BandwidthQualityScalerSettings ParseFromFieldTrials(); + + absl::optional<uint32_t> BitrateStateUpdateInterval() const; + + private: + explicit BandwidthQualityScalerSettings( + const FieldTrialsView* const key_value_config); + + FieldTrialOptional<uint32_t> bitrate_state_update_interval_s_; +}; + +} // namespace webrtc + +#endif // RTC_BASE_EXPERIMENTS_BANDWIDTH_QUALITY_SCALER_SETTINGS_H_ diff --git a/third_party/libwebrtc/rtc_base/experiments/bandwidth_quality_scaler_settings_gn/moz.build b/third_party/libwebrtc/rtc_base/experiments/bandwidth_quality_scaler_settings_gn/moz.build new file mode 100644 index 0000000000..95a92d20e1 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/bandwidth_quality_scaler_settings_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/rtc_base/experiments/bandwidth_quality_scaler_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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("bandwidth_quality_scaler_settings_gn") diff --git a/third_party/libwebrtc/rtc_base/experiments/bandwidth_quality_scaler_settings_unittest.cc b/third_party/libwebrtc/rtc_base/experiments/bandwidth_quality_scaler_settings_unittest.cc new file mode 100644 index 0000000000..fab22cede0 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/bandwidth_quality_scaler_settings_unittest.cc @@ -0,0 +1,49 @@ +/* + * Copyright 2021 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 "rtc_base/experiments/bandwidth_quality_scaler_settings.h" + +#include "test/field_trial.h" +#include "test/gtest.h" + +namespace webrtc { +namespace { + +TEST(BandwidthQualityScalerSettingsTest, ValuesNotSetByDefault) { + const auto settings = BandwidthQualityScalerSettings::ParseFromFieldTrials(); + EXPECT_FALSE(settings.BitrateStateUpdateInterval()); +} + +TEST(BandwidthQualityScalerSettingsTest, ParseBitrateStateUpdateInterval) { + test::ScopedFieldTrials field_trials( + "WebRTC-Video-BandwidthQualityScalerSettings/" + "bitrate_state_update_interval_s_:100/"); + EXPECT_EQ(100u, BandwidthQualityScalerSettings::ParseFromFieldTrials() + .BitrateStateUpdateInterval()); +} + +TEST(BandwidthQualityScalerSettingsTest, ParseAll) { + test::ScopedFieldTrials field_trials( + "WebRTC-Video-BandwidthQualityScalerSettings/" + "bitrate_state_update_interval_s_:100/"); + EXPECT_EQ(100u, BandwidthQualityScalerSettings::ParseFromFieldTrials() + .BitrateStateUpdateInterval()); +} + +TEST(BandwidthQualityScalerSettingsTest, DoesNotParseIncorrectValue) { + test::ScopedFieldTrials field_trials( + "WebRTC-Video-BandwidthQualityScalerSettings/" + "bitrate_state_update_interval_s_:??/"); + const auto settings = BandwidthQualityScalerSettings::ParseFromFieldTrials(); + EXPECT_FALSE(settings.BitrateStateUpdateInterval()); +} + +} // namespace +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/experiments/cpu_speed_experiment.cc b/third_party/libwebrtc/rtc_base/experiments/cpu_speed_experiment.cc new file mode 100644 index 0000000000..7e61255260 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/cpu_speed_experiment.cc @@ -0,0 +1,89 @@ +/* + * 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. + */ + +#include "rtc_base/experiments/cpu_speed_experiment.h" + +#include <stdio.h> + +#include "rtc_base/experiments/field_trial_list.h" +#include "rtc_base/logging.h" +#include "system_wrappers/include/field_trial.h" + +namespace webrtc { +namespace { +constexpr char kFieldTrial[] = "WebRTC-VP8-CpuSpeed-Arm"; +constexpr int kMinSetting = -16; +constexpr int kMaxSetting = -1; + +std::vector<CpuSpeedExperiment::Config> GetValidOrEmpty( + const std::vector<CpuSpeedExperiment::Config>& configs) { + if (configs.empty()) { + return {}; + } + + for (const auto& config : configs) { + if (config.cpu_speed < kMinSetting || config.cpu_speed > kMaxSetting) { + RTC_LOG(LS_WARNING) << "Unsupported cpu speed setting, value ignored."; + return {}; + } + } + + for (size_t i = 1; i < configs.size(); ++i) { + if (configs[i].pixels < configs[i - 1].pixels || + configs[i].cpu_speed > configs[i - 1].cpu_speed) { + RTC_LOG(LS_WARNING) << "Invalid parameter value provided."; + return {}; + } + } + + return configs; +} + +bool HasLeCores(const std::vector<CpuSpeedExperiment::Config>& configs) { + for (const auto& config : configs) { + if (config.cpu_speed_le_cores == 0) + return false; + } + return true; +} +} // namespace + +CpuSpeedExperiment::CpuSpeedExperiment() : cores_("cores") { + FieldTrialStructList<Config> configs( + {FieldTrialStructMember("pixels", [](Config* c) { return &c->pixels; }), + FieldTrialStructMember("cpu_speed", + [](Config* c) { return &c->cpu_speed; }), + FieldTrialStructMember( + "cpu_speed_le_cores", + [](Config* c) { return &c->cpu_speed_le_cores; })}, + {}); + ParseFieldTrial({&configs, &cores_}, field_trial::FindFullName(kFieldTrial)); + + configs_ = GetValidOrEmpty(configs.Get()); +} + +CpuSpeedExperiment::~CpuSpeedExperiment() {} + +absl::optional<int> CpuSpeedExperiment::GetValue(int pixels, + int num_cores) const { + if (configs_.empty()) + return absl::nullopt; + + bool use_le = HasLeCores(configs_) && cores_ && num_cores <= cores_.Value(); + + for (const auto& config : configs_) { + if (pixels <= config.pixels) + return use_le ? absl::optional<int>(config.cpu_speed_le_cores) + : absl::optional<int>(config.cpu_speed); + } + return absl::optional<int>(kMinSetting); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/experiments/cpu_speed_experiment.h b/third_party/libwebrtc/rtc_base/experiments/cpu_speed_experiment.h new file mode 100644 index 0000000000..24ec0c0ec6 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/cpu_speed_experiment.h @@ -0,0 +1,64 @@ +/* + * 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 RTC_BASE_EXPERIMENTS_CPU_SPEED_EXPERIMENT_H_ +#define RTC_BASE_EXPERIMENTS_CPU_SPEED_EXPERIMENT_H_ + +#include <vector> + +#include "absl/types/optional.h" +#include "rtc_base/experiments/field_trial_parser.h" + +namespace webrtc { + +class CpuSpeedExperiment { + public: + CpuSpeedExperiment(); + ~CpuSpeedExperiment(); + + // Example: + // WebRTC-VP8-CpuSpeed-Arm/pixels:100|200|300,cpu_speed:-1|-2|-3/ + // pixels <= 100 -> cpu speed: -1 + // pixels <= 200 -> cpu speed: -2 + // pixels <= 300 -> cpu speed: -3 + + // WebRTC-VP8-CpuSpeed-Arm/pixels:100|200|300,cpu_speed:-1|-2|-3/, + // cpu_speed_le_cores:-4|-5|-6,cores:3/ + // If `num_cores` > 3 + // pixels <= 100 -> cpu speed: -1 + // pixels <= 200 -> cpu speed: -2 + // pixels <= 300 -> cpu speed: -3 + // else + // pixels <= 100 -> cpu speed: -4 + // pixels <= 200 -> cpu speed: -5 + // pixels <= 300 -> cpu speed: -6 + + struct Config { + int pixels = 0; // The video frame size. + int cpu_speed = 0; // The `cpu_speed` to be used if the frame size is less + // than or equal to `pixels`. + // Optional. + int cpu_speed_le_cores = 0; // Same as `cpu_speed` above but only used if + // `num_cores` <= `cores_`. + }; + + // Gets the cpu speed based on `pixels` and `num_cores`. + absl::optional<int> GetValue(int pixels, int num_cores) const; + + private: + std::vector<Config> configs_; + + // Threshold for when to use `cpu_speed_le_cores`. + FieldTrialOptional<int> cores_; +}; + +} // namespace webrtc + +#endif // RTC_BASE_EXPERIMENTS_CPU_SPEED_EXPERIMENT_H_ diff --git a/third_party/libwebrtc/rtc_base/experiments/cpu_speed_experiment_gn/moz.build b/third_party/libwebrtc/rtc_base/experiments/cpu_speed_experiment_gn/moz.build new file mode 100644 index 0000000000..5151c986c4 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/cpu_speed_experiment_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/rtc_base/experiments/cpu_speed_experiment.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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("cpu_speed_experiment_gn") diff --git a/third_party/libwebrtc/rtc_base/experiments/cpu_speed_experiment_unittest.cc b/third_party/libwebrtc/rtc_base/experiments/cpu_speed_experiment_unittest.cc new file mode 100644 index 0000000000..2105da3818 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/cpu_speed_experiment_unittest.cc @@ -0,0 +1,106 @@ +/* + * 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. + */ + +#include "rtc_base/experiments/cpu_speed_experiment.h" + +#include "rtc_base/gunit.h" +#include "test/field_trial.h" +#include "test/gmock.h" + +namespace webrtc { + +TEST(CpuSpeedExperimentTest, NoValueIfNotEnabled) { + CpuSpeedExperiment cpu_speed_config; + EXPECT_FALSE(cpu_speed_config.GetValue(1, /*num_cores=*/1)); +} + +TEST(CpuSpeedExperimentTest, GetValue) { + webrtc::test::ScopedFieldTrials field_trials( + "WebRTC-VP8-CpuSpeed-Arm/pixels:1000,cpu_speed:-12,cores:4/"); + + CpuSpeedExperiment cpu_speed_config; + EXPECT_EQ(-12, cpu_speed_config.GetValue(1, /*num_cores=*/1)); + EXPECT_EQ(-12, cpu_speed_config.GetValue(1000, /*num_cores=*/1)); + EXPECT_EQ(-16, cpu_speed_config.GetValue(1001, /*num_cores=*/1)); +} + +TEST(CpuSpeedExperimentTest, GetValueWithList) { + webrtc::test::ScopedFieldTrials field_trials( + "WebRTC-VP8-CpuSpeed-Arm/pixels:1000|2000|3000,cpu_speed:-1|-10|-16/"); + + CpuSpeedExperiment cpu_speed_config; + EXPECT_EQ(-1, cpu_speed_config.GetValue(1, /*num_cores=*/1)); + EXPECT_EQ(-1, cpu_speed_config.GetValue(1000, /*num_cores=*/1)); + EXPECT_EQ(-10, cpu_speed_config.GetValue(1001, /*num_cores=*/1)); + EXPECT_EQ(-10, cpu_speed_config.GetValue(2000, /*num_cores=*/1)); + EXPECT_EQ(-16, cpu_speed_config.GetValue(2001, /*num_cores=*/1)); + EXPECT_EQ(-16, cpu_speed_config.GetValue(3000, /*num_cores=*/1)); + EXPECT_EQ(-16, cpu_speed_config.GetValue(3001, /*num_cores=*/1)); +} + +TEST(CpuSpeedExperimentTest, GetValueWithCores) { + webrtc::test::ScopedFieldTrials field_trials( + "WebRTC-VP8-CpuSpeed-Arm/" + "pixels:1000|2000|3000,cpu_speed:-1|-10|-16," + "cpu_speed_le_cores:-5|-11|-16,cores:2/"); + + CpuSpeedExperiment cpu_speed_config; + EXPECT_EQ(-5, cpu_speed_config.GetValue(1000, /*num_cores=*/1)); + EXPECT_EQ(-11, cpu_speed_config.GetValue(2000, /*num_cores=*/2)); + EXPECT_EQ(-1, cpu_speed_config.GetValue(1000, /*num_cores=*/3)); + EXPECT_EQ(-10, cpu_speed_config.GetValue(2000, /*num_cores=*/4)); +} + +TEST(CpuSpeedExperimentTest, GetValueWithCoresUnconfigured) { + webrtc::test::ScopedFieldTrials field_trials( + "WebRTC-VP8-CpuSpeed-Arm/" + "pixels:1000|2000|3000,cpu_speed:-1|-10|-16," + "cpu_speed_le_cores:-5|-11|-16/"); + + CpuSpeedExperiment cpu_speed_config; + EXPECT_EQ(-1, cpu_speed_config.GetValue(1000, /*num_cores=*/1)); + EXPECT_EQ(-10, cpu_speed_config.GetValue(2000, /*num_cores=*/2)); +} + +TEST(CpuSpeedExperimentTest, GetValueFailsForTooSmallValue) { + // Supported range: [-16, -1]. + webrtc::test::ScopedFieldTrials field_trials( + "WebRTC-VP8-CpuSpeed-Arm/pixels:1000|2000|3000,cpu_speed:-1|-10|-17/"); + + CpuSpeedExperiment cpu_speed_config; + EXPECT_FALSE(cpu_speed_config.GetValue(1, /*num_cores=*/1)); +} + +TEST(CpuSpeedExperimentTest, GetValueFailsForTooLargeValue) { + // Supported range: [-16, -1]. + webrtc::test::ScopedFieldTrials field_trials( + "WebRTC-VP8-CpuSpeed-Arm/pixels:1000|2000|3000,cpu_speed:0|-10|-16/"); + + CpuSpeedExperiment cpu_speed_config; + EXPECT_FALSE(cpu_speed_config.GetValue(1, /*num_cores=*/1)); +} + +TEST(CpuSpeedExperimentTest, GetValueFailsIfPixelsDecreases) { + webrtc::test::ScopedFieldTrials field_trials( + "WebRTC-VP8-CpuSpeed-Arm/pixels:1000|999|3000,cpu_speed:-5|-10|-16/"); + + CpuSpeedExperiment cpu_speed_config; + EXPECT_FALSE(cpu_speed_config.GetValue(1, /*num_cores=*/1)); +} + +TEST(CpuSpeedExperimentTest, GetValueFailsIfCpuSpeedIncreases) { + webrtc::test::ScopedFieldTrials field_trials( + "WebRTC-VP8-CpuSpeed-Arm/pixels:1000|2000|3000,cpu_speed:-5|-4|-16/"); + + CpuSpeedExperiment cpu_speed_config; + EXPECT_FALSE(cpu_speed_config.GetValue(1, /*num_cores=*/1)); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/experiments/encoder_info_settings.cc b/third_party/libwebrtc/rtc_base/experiments/encoder_info_settings.cc new file mode 100644 index 0000000000..136201d261 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/encoder_info_settings.cc @@ -0,0 +1,236 @@ +/* + * Copyright 2021 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 "rtc_base/experiments/encoder_info_settings.h" + +#include <stdio.h> + +#include "absl/strings/string_view.h" +#include "rtc_base/experiments/field_trial_list.h" +#include "rtc_base/logging.h" +#include "system_wrappers/include/field_trial.h" + +namespace webrtc { +namespace { + +std::vector<VideoEncoder::ResolutionBitrateLimits> ToResolutionBitrateLimits( + const std::vector<EncoderInfoSettings::BitrateLimit>& limits) { + std::vector<VideoEncoder::ResolutionBitrateLimits> result; + for (const auto& limit : limits) { + result.push_back(VideoEncoder::ResolutionBitrateLimits( + limit.frame_size_pixels, limit.min_start_bitrate_bps, + limit.min_bitrate_bps, limit.max_bitrate_bps)); + } + return result; +} +constexpr float kDefaultMinBitratebps = 30000; +} // namespace + +// Default bitrate limits for simulcast with one active stream: +// {frame_size_pixels, min_start_bitrate_bps, min_bitrate_bps, max_bitrate_bps}. +std::vector<VideoEncoder::ResolutionBitrateLimits> +EncoderInfoSettings::GetDefaultSinglecastBitrateLimits( + VideoCodecType codec_type) { + if (codec_type == kVideoCodecAV1) { + // AV1 singlecast max bitrate limits are higher than AV1 SVC max limits. + // This is because in singlecast we normally have just one receiver, BWE is + // known end-to-end and the encode target bitrate guarantees delivery of + // video. + // The min bitrate limits are not used in singlecast (used in SVC/simulcast + // to de-/activate spatial layers) and are set to zero. Send resolution in + // singlecast is assumed to be regulated by QP-based quality scaler. + return {{320 * 180, 0, 0, 256000}, + {480 * 270, 176000, 0, 384000}, + {640 * 360, 256000, 0, 512000}, + {960 * 540, 384000, 0, 1024000}, + {1280 * 720, 576000, 0, 1536000}}; + } + + if (codec_type == kVideoCodecVP9) { + // VP9 singlecast bitrate limits are derived ~directly from VP9 SVC bitrate + // limits. The current max limits are unnecessarily too strict for + // singlecast, where BWE is known end-to-end, especially for low + // resolutions. + return {{320 * 180, 0, 30000, 150000}, + {480 * 270, 120000, 30000, 300000}, + {640 * 360, 190000, 30000, 420000}, + {960 * 540, 350000, 30000, 1000000}, + {1280 * 720, 480000, 30000, 1500000}}; + } + + // VP8 and other codecs. + return {{320 * 180, 0, 30000, 300000}, + {480 * 270, 200000, 30000, 500000}, + {640 * 360, 300000, 30000, 800000}, + {960 * 540, 500000, 30000, 1500000}, + {1280 * 720, 900000, 30000, 2500000}}; +} + +absl::optional<VideoEncoder::ResolutionBitrateLimits> +EncoderInfoSettings::GetDefaultSinglecastBitrateLimitsForResolution( + VideoCodecType codec_type, + int frame_size_pixels) { + VideoEncoder::EncoderInfo info; + info.resolution_bitrate_limits = + GetDefaultSinglecastBitrateLimits(codec_type); + return info.GetEncoderBitrateLimitsForResolution(frame_size_pixels); +} + +// Return the suitable bitrate limits for specified resolution when qp is +// untrusted, they are experimental values. +// TODO(bugs.webrtc.org/12942): Maybe we need to add other codecs(VP8/VP9) +// experimental values. +std::vector<VideoEncoder::ResolutionBitrateLimits> +EncoderInfoSettings::GetDefaultSinglecastBitrateLimitsWhenQpIsUntrusted() { + // Specific limits for H264/AVC + return {{0 * 0, 0, 0, 0}, + {320 * 180, 0, 30000, 300000}, + {480 * 270, 300000, 30000, 500000}, + {640 * 360, 500000, 30000, 800000}, + {960 * 540, 800000, 30000, 1500000}, + {1280 * 720, 1500000, 30000, 2500000}, + {1920 * 1080, 2500000, 30000, 4000000}}; +} + +// Through linear interpolation, return the bitrate limit corresponding to the +// specified |frame_size_pixels|. +absl::optional<VideoEncoder::ResolutionBitrateLimits> +EncoderInfoSettings::GetSinglecastBitrateLimitForResolutionWhenQpIsUntrusted( + absl::optional<int> frame_size_pixels, + const std::vector<VideoEncoder::ResolutionBitrateLimits>& + resolution_bitrate_limits) { + if (!frame_size_pixels.has_value() || frame_size_pixels.value() <= 0) { + return absl::nullopt; + } + + std::vector<VideoEncoder::ResolutionBitrateLimits> bitrate_limits = + resolution_bitrate_limits; + + // Sort the list of bitrate limits by resolution. + sort(bitrate_limits.begin(), bitrate_limits.end(), + [](const VideoEncoder::ResolutionBitrateLimits& lhs, + const VideoEncoder::ResolutionBitrateLimits& rhs) { + return lhs.frame_size_pixels < rhs.frame_size_pixels; + }); + + if (bitrate_limits.empty()) { + return absl::nullopt; + } + + int interpolation_index = -1; + for (size_t i = 0; i < bitrate_limits.size(); ++i) { + if (bitrate_limits[i].frame_size_pixels >= frame_size_pixels.value()) { + interpolation_index = i; + break; + } + } + + // -1 means that the maximum resolution is exceeded, we will select the + // largest data as the return result. + if (interpolation_index == -1) { + return *bitrate_limits.rbegin(); + } + + // If we have a matching resolution, return directly without interpolation. + if (bitrate_limits[interpolation_index].frame_size_pixels == + frame_size_pixels.value()) { + return bitrate_limits[interpolation_index]; + } + + // No matching resolution, do a linear interpolate. + int lower_pixel_count = + bitrate_limits[interpolation_index - 1].frame_size_pixels; + int upper_pixel_count = bitrate_limits[interpolation_index].frame_size_pixels; + float alpha = (frame_size_pixels.value() - lower_pixel_count) * 1.0 / + (upper_pixel_count - lower_pixel_count); + int min_start_bitrate_bps = static_cast<int>( + bitrate_limits[interpolation_index].min_start_bitrate_bps * alpha + + bitrate_limits[interpolation_index - 1].min_start_bitrate_bps * + (1.0 - alpha)); + int max_bitrate_bps = static_cast<int>( + bitrate_limits[interpolation_index].max_bitrate_bps * alpha + + bitrate_limits[interpolation_index - 1].max_bitrate_bps * (1.0 - alpha)); + + if (max_bitrate_bps >= min_start_bitrate_bps) { + return VideoEncoder::ResolutionBitrateLimits( + frame_size_pixels.value(), min_start_bitrate_bps, kDefaultMinBitratebps, + max_bitrate_bps); + } else { + RTC_LOG(LS_WARNING) + << "BitRate interpolation calculating result is abnormal. " + << " lower_pixel_count = " << lower_pixel_count + << " upper_pixel_count = " << upper_pixel_count + << " frame_size_pixels = " << frame_size_pixels.value() + << " min_start_bitrate_bps = " << min_start_bitrate_bps + << " min_bitrate_bps = " << kDefaultMinBitratebps + << " max_bitrate_bps = " << max_bitrate_bps; + return absl::nullopt; + } +} + +EncoderInfoSettings::EncoderInfoSettings(absl::string_view name) + : requested_resolution_alignment_("requested_resolution_alignment"), + apply_alignment_to_all_simulcast_layers_( + "apply_alignment_to_all_simulcast_layers") { + FieldTrialStructList<BitrateLimit> bitrate_limits( + {FieldTrialStructMember( + "frame_size_pixels", + [](BitrateLimit* b) { return &b->frame_size_pixels; }), + FieldTrialStructMember( + "min_start_bitrate_bps", + [](BitrateLimit* b) { return &b->min_start_bitrate_bps; }), + FieldTrialStructMember( + "min_bitrate_bps", + [](BitrateLimit* b) { return &b->min_bitrate_bps; }), + FieldTrialStructMember( + "max_bitrate_bps", + [](BitrateLimit* b) { return &b->max_bitrate_bps; })}, + {}); + + std::string name_str(name); + if (field_trial::FindFullName(name_str).empty()) { + // Encoder name not found, use common string applying to all encoders. + name_str = "WebRTC-GetEncoderInfoOverride"; + } + + ParseFieldTrial({&bitrate_limits, &requested_resolution_alignment_, + &apply_alignment_to_all_simulcast_layers_}, + field_trial::FindFullName(name_str)); + + resolution_bitrate_limits_ = ToResolutionBitrateLimits(bitrate_limits.Get()); +} + +absl::optional<uint32_t> EncoderInfoSettings::requested_resolution_alignment() + const { + if (requested_resolution_alignment_ && + requested_resolution_alignment_.Value() < 1) { + RTC_LOG(LS_WARNING) << "Unsupported alignment value, ignored."; + return absl::nullopt; + } + return requested_resolution_alignment_.GetOptional(); +} + +EncoderInfoSettings::~EncoderInfoSettings() {} + +SimulcastEncoderAdapterEncoderInfoSettings:: + SimulcastEncoderAdapterEncoderInfoSettings() + : EncoderInfoSettings( + "WebRTC-SimulcastEncoderAdapter-GetEncoderInfoOverride") {} + +LibvpxVp8EncoderInfoSettings::LibvpxVp8EncoderInfoSettings() + : EncoderInfoSettings("WebRTC-VP8-GetEncoderInfoOverride") {} + +LibvpxVp9EncoderInfoSettings::LibvpxVp9EncoderInfoSettings() + : EncoderInfoSettings("WebRTC-VP9-GetEncoderInfoOverride") {} + +LibaomAv1EncoderInfoSettings::LibaomAv1EncoderInfoSettings() + : EncoderInfoSettings("WebRTC-Av1-GetEncoderInfoOverride") {} + +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/experiments/encoder_info_settings.h b/third_party/libwebrtc/rtc_base/experiments/encoder_info_settings.h new file mode 100644 index 0000000000..416bf6be7a --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/encoder_info_settings.h @@ -0,0 +1,100 @@ +/* + * Copyright 2021 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 RTC_BASE_EXPERIMENTS_ENCODER_INFO_SETTINGS_H_ +#define RTC_BASE_EXPERIMENTS_ENCODER_INFO_SETTINGS_H_ + +#include <string> +#include <vector> + +#include "absl/strings/string_view.h" +#include "absl/types/optional.h" +#include "api/video_codecs/video_encoder.h" +#include "rtc_base/experiments/field_trial_parser.h" + +namespace webrtc { + +class EncoderInfoSettings { + public: + virtual ~EncoderInfoSettings(); + + // Bitrate limits per resolution. + struct BitrateLimit { + int frame_size_pixels = 0; // The video frame size. + int min_start_bitrate_bps = 0; // The minimum bitrate to start encoding. + int min_bitrate_bps = 0; // The minimum bitrate. + int max_bitrate_bps = 0; // The maximum bitrate. + }; + + absl::optional<uint32_t> requested_resolution_alignment() const; + bool apply_alignment_to_all_simulcast_layers() const { + return apply_alignment_to_all_simulcast_layers_.Get(); + } + std::vector<VideoEncoder::ResolutionBitrateLimits> resolution_bitrate_limits() + const { + return resolution_bitrate_limits_; + } + + static std::vector<VideoEncoder::ResolutionBitrateLimits> + GetDefaultSinglecastBitrateLimits(VideoCodecType codec_type); + + static absl::optional<VideoEncoder::ResolutionBitrateLimits> + GetDefaultSinglecastBitrateLimitsForResolution(VideoCodecType codec_type, + int frame_size_pixels); + + static std::vector<VideoEncoder::ResolutionBitrateLimits> + GetDefaultSinglecastBitrateLimitsWhenQpIsUntrusted(); + + static absl::optional<VideoEncoder::ResolutionBitrateLimits> + GetSinglecastBitrateLimitForResolutionWhenQpIsUntrusted( + absl::optional<int> frame_size_pixels, + const std::vector<VideoEncoder::ResolutionBitrateLimits>& + resolution_bitrate_limits); + + protected: + explicit EncoderInfoSettings(absl::string_view name); + + private: + FieldTrialOptional<uint32_t> requested_resolution_alignment_; + FieldTrialFlag apply_alignment_to_all_simulcast_layers_; + std::vector<VideoEncoder::ResolutionBitrateLimits> resolution_bitrate_limits_; +}; + +// EncoderInfo settings for SimulcastEncoderAdapter. +class SimulcastEncoderAdapterEncoderInfoSettings : public EncoderInfoSettings { + public: + SimulcastEncoderAdapterEncoderInfoSettings(); + ~SimulcastEncoderAdapterEncoderInfoSettings() override {} +}; + +// EncoderInfo settings for LibvpxVp8Encoder. +class LibvpxVp8EncoderInfoSettings : public EncoderInfoSettings { + public: + LibvpxVp8EncoderInfoSettings(); + ~LibvpxVp8EncoderInfoSettings() override {} +}; + +// EncoderInfo settings for LibvpxVp9Encoder. +class LibvpxVp9EncoderInfoSettings : public EncoderInfoSettings { + public: + LibvpxVp9EncoderInfoSettings(); + ~LibvpxVp9EncoderInfoSettings() override {} +}; + +// EncoderInfo settings for LibaomAv1Encoder. +class LibaomAv1EncoderInfoSettings : public EncoderInfoSettings { + public: + LibaomAv1EncoderInfoSettings(); + ~LibaomAv1EncoderInfoSettings() override {} +}; + +} // namespace webrtc + +#endif // RTC_BASE_EXPERIMENTS_ENCODER_INFO_SETTINGS_H_ diff --git a/third_party/libwebrtc/rtc_base/experiments/encoder_info_settings_gn/moz.build b/third_party/libwebrtc/rtc_base/experiments/encoder_info_settings_gn/moz.build new file mode 100644 index 0000000000..b7a699fe03 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/encoder_info_settings_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/rtc_base/experiments/encoder_info_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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("encoder_info_settings_gn") diff --git a/third_party/libwebrtc/rtc_base/experiments/encoder_info_settings_unittest.cc b/third_party/libwebrtc/rtc_base/experiments/encoder_info_settings_unittest.cc new file mode 100644 index 0000000000..929c777821 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/encoder_info_settings_unittest.cc @@ -0,0 +1,102 @@ +/* + * Copyright 2021 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 "rtc_base/experiments/encoder_info_settings.h" + +#include "rtc_base/gunit.h" +#include "test/field_trial.h" +#include "test/gmock.h" + +namespace webrtc { + +TEST(SimulcastEncoderAdapterSettingsTest, NoValuesWithoutFieldTrial) { + SimulcastEncoderAdapterEncoderInfoSettings settings; + EXPECT_EQ(absl::nullopt, settings.requested_resolution_alignment()); + EXPECT_FALSE(settings.apply_alignment_to_all_simulcast_layers()); + EXPECT_TRUE(settings.resolution_bitrate_limits().empty()); +} + +TEST(SimulcastEncoderAdapterSettingsTest, NoValueForInvalidAlignment) { + webrtc::test::ScopedFieldTrials field_trials( + "WebRTC-SimulcastEncoderAdapter-GetEncoderInfoOverride/" + "requested_resolution_alignment:0/"); + + SimulcastEncoderAdapterEncoderInfoSettings settings; + EXPECT_EQ(absl::nullopt, settings.requested_resolution_alignment()); +} + +TEST(SimulcastEncoderAdapterSettingsTest, GetResolutionAlignment) { + webrtc::test::ScopedFieldTrials field_trials( + "WebRTC-SimulcastEncoderAdapter-GetEncoderInfoOverride/" + "requested_resolution_alignment:2/"); + + SimulcastEncoderAdapterEncoderInfoSettings settings; + EXPECT_EQ(2u, settings.requested_resolution_alignment()); + EXPECT_FALSE(settings.apply_alignment_to_all_simulcast_layers()); + EXPECT_TRUE(settings.resolution_bitrate_limits().empty()); +} + +TEST(SimulcastEncoderAdapterSettingsTest, GetApplyAlignment) { + webrtc::test::ScopedFieldTrials field_trials( + "WebRTC-SimulcastEncoderAdapter-GetEncoderInfoOverride/" + "requested_resolution_alignment:3," + "apply_alignment_to_all_simulcast_layers/"); + + SimulcastEncoderAdapterEncoderInfoSettings settings; + EXPECT_EQ(3u, settings.requested_resolution_alignment()); + EXPECT_TRUE(settings.apply_alignment_to_all_simulcast_layers()); + EXPECT_TRUE(settings.resolution_bitrate_limits().empty()); +} + +TEST(SimulcastEncoderAdapterSettingsTest, GetResolutionBitrateLimits) { + webrtc::test::ScopedFieldTrials field_trials( + "WebRTC-SimulcastEncoderAdapter-GetEncoderInfoOverride/" + "frame_size_pixels:123," + "min_start_bitrate_bps:11000," + "min_bitrate_bps:44000," + "max_bitrate_bps:77000/"); + + SimulcastEncoderAdapterEncoderInfoSettings settings; + EXPECT_EQ(absl::nullopt, settings.requested_resolution_alignment()); + EXPECT_FALSE(settings.apply_alignment_to_all_simulcast_layers()); + EXPECT_THAT(settings.resolution_bitrate_limits(), + ::testing::ElementsAre(VideoEncoder::ResolutionBitrateLimits{ + 123, 11000, 44000, 77000})); +} + +TEST(SimulcastEncoderAdapterSettingsTest, GetResolutionBitrateLimitsWithList) { + webrtc::test::ScopedFieldTrials field_trials( + "WebRTC-SimulcastEncoderAdapter-GetEncoderInfoOverride/" + "frame_size_pixels:123|456|789," + "min_start_bitrate_bps:11000|22000|33000," + "min_bitrate_bps:44000|55000|66000," + "max_bitrate_bps:77000|88000|99000/"); + + SimulcastEncoderAdapterEncoderInfoSettings settings; + EXPECT_THAT( + settings.resolution_bitrate_limits(), + ::testing::ElementsAre( + VideoEncoder::ResolutionBitrateLimits{123, 11000, 44000, 77000}, + VideoEncoder::ResolutionBitrateLimits{456, 22000, 55000, 88000}, + VideoEncoder::ResolutionBitrateLimits{789, 33000, 66000, 99000})); +} + +TEST(EncoderSettingsTest, CommonSettingsUsedIfEncoderNameUnspecified) { + webrtc::test::ScopedFieldTrials field_trials( + "WebRTC-VP8-GetEncoderInfoOverride/requested_resolution_alignment:2/" + "WebRTC-GetEncoderInfoOverride/requested_resolution_alignment:3/"); + + LibvpxVp8EncoderInfoSettings vp8_settings; + EXPECT_EQ(2u, vp8_settings.requested_resolution_alignment()); + LibvpxVp9EncoderInfoSettings vp9_settings; + EXPECT_EQ(3u, vp9_settings.requested_resolution_alignment()); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/experiments/field_trial_list.cc b/third_party/libwebrtc/rtc_base/experiments/field_trial_list.cc new file mode 100644 index 0000000000..72cd79f2d2 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/field_trial_list.cc @@ -0,0 +1,59 @@ +/* + * 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 "rtc_base/experiments/field_trial_list.h" + +#include "absl/strings/string_view.h" + +namespace webrtc { + +FieldTrialListBase::FieldTrialListBase(absl::string_view key) + : FieldTrialParameterInterface(key), + failed_(false), + parse_got_called_(false) {} + +bool FieldTrialListBase::Failed() const { + return failed_; +} +bool FieldTrialListBase::Used() const { + return parse_got_called_; +} + +int FieldTrialListWrapper::Length() { + return GetList()->Size(); +} +bool FieldTrialListWrapper::Failed() { + return GetList()->Failed(); +} +bool FieldTrialListWrapper::Used() { + return GetList()->Used(); +} + +bool FieldTrialStructListBase::Parse(absl::optional<std::string> str_value) { + RTC_DCHECK_NOTREACHED(); + return true; +} + +int FieldTrialStructListBase::ValidateAndGetLength() { + int length = -1; + for (std::unique_ptr<FieldTrialListWrapper>& list : sub_lists_) { + if (list->Failed()) + return -1; + else if (!list->Used()) + continue; + else if (length == -1) + length = list->Length(); + else if (length != list->Length()) + return -1; + } + + return length; +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/experiments/field_trial_list.h b/third_party/libwebrtc/rtc_base/experiments/field_trial_list.h new file mode 100644 index 0000000000..63403cc51d --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/field_trial_list.h @@ -0,0 +1,226 @@ +/* + * 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 RTC_BASE_EXPERIMENTS_FIELD_TRIAL_LIST_H_ +#define RTC_BASE_EXPERIMENTS_FIELD_TRIAL_LIST_H_ + +#include <initializer_list> +#include <memory> +#include <string> +#include <vector> + +#include "absl/strings/string_view.h" +#include "rtc_base/experiments/field_trial_parser.h" +#include "rtc_base/string_encode.h" + +// List support for field trial strings. FieldTrialList and FieldTrialStructList +// are used similarly to the other FieldTrialParameters, but take a variable +// number of parameters. A FieldTrialList<T> parses a |-delimeted string into a +// list of T, using ParseTypedParameter to parse the individual tokens. +// Example string: "my_list:1|2|3,empty_list,other_list:aardvark". + +// A FieldTrialStructList combines multiple lists into a list-of-structs. It +// ensures that all its sublists parse correctly and have the same length, then +// uses user-supplied accessor functions to write those elements into structs of +// a user-supplied type. + +// See the unit test for usage and behavior. + +namespace webrtc { + +class FieldTrialListBase : public FieldTrialParameterInterface { + protected: + friend class FieldTrialListWrapper; + explicit FieldTrialListBase(absl::string_view key); + + bool Failed() const; + bool Used() const; + + virtual int Size() = 0; + + bool failed_; + bool parse_got_called_; +}; + +// This class represents a vector of type T. The elements are separated by a | +// and parsed using ParseTypedParameter. +template <typename T> +class FieldTrialList : public FieldTrialListBase { + public: + explicit FieldTrialList(absl::string_view key) : FieldTrialList(key, {}) {} + FieldTrialList(absl::string_view key, std::initializer_list<T> default_values) + : FieldTrialListBase(key), values_(default_values) {} + + std::vector<T> Get() const { return values_; } + operator std::vector<T>() const { return Get(); } + typename std::vector<T>::const_reference operator[](size_t index) const { + return values_[index]; + } + const std::vector<T>* operator->() const { return &values_; } + + protected: + bool Parse(absl::optional<std::string> str_value) override { + parse_got_called_ = true; + + if (!str_value) { + values_.clear(); + return true; + } + + std::vector<T> new_values_; + + for (const absl::string_view token : rtc::split(str_value.value(), '|')) { + absl::optional<T> value = ParseTypedParameter<T>(token); + if (value) { + new_values_.push_back(*value); + } else { + failed_ = true; + return false; + } + } + + values_.swap(new_values_); + return true; + } + + int Size() override { return values_.size(); } + + private: + std::vector<T> values_; +}; + +class FieldTrialListWrapper { + public: + virtual ~FieldTrialListWrapper() = default; + + // Takes the element at the given index in the wrapped list and writes it to + // the given struct. + virtual void WriteElement(void* struct_to_write, int index) = 0; + + virtual FieldTrialListBase* GetList() = 0; + + int Length(); + + // Returns true iff the wrapped list has failed to parse at least one token. + bool Failed(); + + bool Used(); + + protected: + FieldTrialListWrapper() = default; +}; + +namespace field_trial_list_impl { +// The LambdaTypeTraits struct provides type information about lambdas in the +// template expressions below. +template <typename T> +struct LambdaTypeTraits : public LambdaTypeTraits<decltype(&T::operator())> {}; + +template <typename ClassType, typename RetType, typename SourceType> +struct LambdaTypeTraits<RetType* (ClassType::*)(SourceType*) const> { + using ret = RetType; + using src = SourceType; +}; + +template <typename T> +struct TypedFieldTrialListWrapper : FieldTrialListWrapper { + public: + TypedFieldTrialListWrapper(absl::string_view key, + std::function<void(void*, T)> sink) + : list_(key), sink_(sink) {} + + void WriteElement(void* struct_to_write, int index) override { + sink_(struct_to_write, list_[index]); + } + + FieldTrialListBase* GetList() override { return &list_; } + + private: + FieldTrialList<T> list_; + std::function<void(void*, T)> sink_; +}; + +} // namespace field_trial_list_impl + +template <typename F, + typename Traits = typename field_trial_list_impl::LambdaTypeTraits<F>> +FieldTrialListWrapper* FieldTrialStructMember(absl::string_view key, + F accessor) { + return new field_trial_list_impl::TypedFieldTrialListWrapper< + typename Traits::ret>(key, [accessor](void* s, typename Traits::ret t) { + *accessor(static_cast<typename Traits::src*>(s)) = t; + }); +} + +// This base class is here to reduce the amount of code we have to generate for +// each type of FieldTrialStructList. +class FieldTrialStructListBase : public FieldTrialParameterInterface { + protected: + FieldTrialStructListBase( + std::initializer_list<FieldTrialListWrapper*> sub_lists) + : FieldTrialParameterInterface(""), sub_lists_() { + // Take ownership of the list wrappers generated by FieldTrialStructMember + // on the call site. + for (FieldTrialListWrapper* const* it = sub_lists.begin(); + it != sub_lists.end(); it++) { + sub_parameters_.push_back((*it)->GetList()); + sub_lists_.push_back(std::unique_ptr<FieldTrialListWrapper>(*it)); + } + } + + // Check that all of our sublists that were in the field trial string had the + // same number of elements. If they do, we return that length. If they had + // different lengths, any sublist had parse failures or no sublists had + // user-supplied values, we return -1. + int ValidateAndGetLength(); + + bool Parse(absl::optional<std::string> str_value) override; + + std::vector<std::unique_ptr<FieldTrialListWrapper>> sub_lists_; +}; + +template <typename S> +class FieldTrialStructList : public FieldTrialStructListBase { + public: + FieldTrialStructList(std::initializer_list<FieldTrialListWrapper*> l, + std::initializer_list<S> default_list) + : FieldTrialStructListBase(l), values_(default_list) {} + + std::vector<S> Get() const { return values_; } + operator std::vector<S>() const { return Get(); } + const S& operator[](size_t index) const { return values_[index]; } + const std::vector<S>* operator->() const { return &values_; } + + protected: + void ParseDone() override { + int length = ValidateAndGetLength(); + + if (length == -1) + return; + + std::vector<S> new_values(length, S()); + + for (std::unique_ptr<FieldTrialListWrapper>& li : sub_lists_) { + if (li->Used()) { + for (int i = 0; i < length; i++) { + li->WriteElement(&new_values[i], i); + } + } + } + + values_.swap(new_values); + } + + private: + std::vector<S> values_; +}; + +} // namespace webrtc + +#endif // RTC_BASE_EXPERIMENTS_FIELD_TRIAL_LIST_H_ diff --git a/third_party/libwebrtc/rtc_base/experiments/field_trial_list_unittest.cc b/third_party/libwebrtc/rtc_base/experiments/field_trial_list_unittest.cc new file mode 100644 index 0000000000..221a3c6929 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/field_trial_list_unittest.cc @@ -0,0 +1,141 @@ +/* + * 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 "rtc_base/experiments/field_trial_list.h" + +#include "absl/strings/string_view.h" +#include "rtc_base/gunit.h" +#include "test/gmock.h" + +using testing::ElementsAre; +using testing::IsEmpty; + +namespace webrtc { + +struct Garment { + int price = 0; + std::string color = ""; + bool has_glitter = false; + + // Only needed for testing. + Garment() = default; + Garment(int p, absl::string_view c, bool g) + : price(p), color(c), has_glitter(g) {} + + bool operator==(const Garment& other) const { + return price == other.price && color == other.color && + has_glitter == other.has_glitter; + } +}; + +TEST(FieldTrialListTest, ParsesListParameter) { + FieldTrialList<int> my_list("l", {5}); + EXPECT_THAT(my_list.Get(), ElementsAre(5)); + // If one element is invalid the list is unchanged. + ParseFieldTrial({&my_list}, "l:1|2|hat"); + EXPECT_THAT(my_list.Get(), ElementsAre(5)); + ParseFieldTrial({&my_list}, "l"); + EXPECT_THAT(my_list.Get(), IsEmpty()); + ParseFieldTrial({&my_list}, "l:1|2|3"); + EXPECT_THAT(my_list.Get(), ElementsAre(1, 2, 3)); + ParseFieldTrial({&my_list}, "l:-1"); + EXPECT_THAT(my_list.Get(), ElementsAre(-1)); + + FieldTrialList<std::string> another_list("l", {"hat"}); + EXPECT_THAT(another_list.Get(), ElementsAre("hat")); + ParseFieldTrial({&another_list}, "l"); + EXPECT_THAT(another_list.Get(), IsEmpty()); + ParseFieldTrial({&another_list}, "l:"); + EXPECT_THAT(another_list.Get(), ElementsAre("")); + ParseFieldTrial({&another_list}, "l:scarf|hat|mittens"); + EXPECT_THAT(another_list.Get(), ElementsAre("scarf", "hat", "mittens")); + ParseFieldTrial({&another_list}, "l:scarf"); + EXPECT_THAT(another_list.Get(), ElementsAre("scarf")); +} + +// Normal usage. +TEST(FieldTrialListTest, ParsesStructList) { + FieldTrialStructList<Garment> my_list( + {FieldTrialStructMember("color", [](Garment* g) { return &g->color; }), + FieldTrialStructMember("price", [](Garment* g) { return &g->price; }), + FieldTrialStructMember("has_glitter", + [](Garment* g) { return &g->has_glitter; })}, + {{1, "blue", false}, {2, "red", true}}); + + ParseFieldTrial({&my_list}, + "color:mauve|red|gold," + "price:10|20|30," + "has_glitter:1|0|1," + "other_param:asdf"); + + ASSERT_THAT(my_list.Get(), + ElementsAre(Garment{10, "mauve", true}, Garment{20, "red", false}, + Garment{30, "gold", true})); +} + +// One FieldTrialList has the wrong length, so we use the user-provided default +// list. +TEST(FieldTrialListTest, StructListKeepsDefaultWithMismatchingLength) { + FieldTrialStructList<Garment> my_list( + {FieldTrialStructMember("wrong_length", + [](Garment* g) { return &g->color; }), + FieldTrialStructMember("price", [](Garment* g) { return &g->price; })}, + {{1, "blue", true}, {2, "red", false}}); + + ParseFieldTrial({&my_list}, + "wrong_length:mauve|magenta|chartreuse|indigo," + "garment:hat|hat|crown," + "price:10|20|30"); + + ASSERT_THAT(my_list.Get(), + ElementsAre(Garment{1, "blue", true}, Garment{2, "red", false})); +} + +// One list is missing. We set the values we're given, and the others remain +// as whatever the Garment default constructor set them to. +TEST(FieldTrialListTest, StructListUsesDefaultForMissingList) { + FieldTrialStructList<Garment> my_list( + {FieldTrialStructMember("color", [](Garment* g) { return &g->color; }), + FieldTrialStructMember("price", [](Garment* g) { return &g->price; })}, + {{1, "blue", true}, {2, "red", false}}); + + ParseFieldTrial({&my_list}, "price:10|20|30"); + + ASSERT_THAT(my_list.Get(), + ElementsAre(Garment{10, "", false}, Garment{20, "", false}, + Garment{30, "", false})); +} + +// The user haven't provided values for any lists, so we use the default list. +TEST(FieldTrialListTest, StructListUsesDefaultListWithoutValues) { + FieldTrialStructList<Garment> my_list( + {FieldTrialStructMember("color", [](Garment* g) { return &g->color; }), + FieldTrialStructMember("price", [](Garment* g) { return &g->price; })}, + {{1, "blue", true}, {2, "red", false}}); + + ParseFieldTrial({&my_list}, ""); + + ASSERT_THAT(my_list.Get(), + ElementsAre(Garment{1, "blue", true}, Garment{2, "red", false})); +} + +// Some lists are provided and all are empty, so we return a empty list. +TEST(FieldTrialListTest, StructListHandlesEmptyLists) { + FieldTrialStructList<Garment> my_list( + {FieldTrialStructMember("color", [](Garment* g) { return &g->color; }), + FieldTrialStructMember("price", [](Garment* g) { return &g->price; })}, + {{1, "blue", true}, {2, "red", false}}); + + ParseFieldTrial({&my_list}, "color,price"); + + ASSERT_EQ(my_list.Get().size(), 0u); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/experiments/field_trial_parser.cc b/third_party/libwebrtc/rtc_base/experiments/field_trial_parser.cc new file mode 100644 index 0000000000..78d5489f5e --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/field_trial_parser.cc @@ -0,0 +1,260 @@ +/* + * 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 "rtc_base/experiments/field_trial_parser.h" + +#include <inttypes.h> + +#include <algorithm> +#include <map> +#include <type_traits> +#include <utility> + +#include "absl/strings/string_view.h" +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" +#include "rtc_base/numerics/safe_conversions.h" + +namespace webrtc { + +FieldTrialParameterInterface::FieldTrialParameterInterface( + absl::string_view key) + : key_(key) {} +FieldTrialParameterInterface::~FieldTrialParameterInterface() { + RTC_DCHECK(used_) << "Field trial parameter with key: '" << key_ + << "' never used."; +} + +void ParseFieldTrial( + std::initializer_list<FieldTrialParameterInterface*> fields, + absl::string_view trial_string) { + std::map<absl::string_view, FieldTrialParameterInterface*> field_map; + FieldTrialParameterInterface* keyless_field = nullptr; + for (FieldTrialParameterInterface* field : fields) { + field->MarkAsUsed(); + if (!field->sub_parameters_.empty()) { + for (FieldTrialParameterInterface* sub_field : field->sub_parameters_) { + RTC_DCHECK(!sub_field->key_.empty()); + sub_field->MarkAsUsed(); + field_map[sub_field->key_] = sub_field; + } + continue; + } + + if (field->key_.empty()) { + RTC_DCHECK(!keyless_field); + keyless_field = field; + } else { + field_map[field->key_] = field; + } + } + bool logged_unknown_key = false; + + absl::string_view tail = trial_string; + while (!tail.empty()) { + size_t key_end = tail.find_first_of(",:"); + absl::string_view key = tail.substr(0, key_end); + absl::optional<std::string> opt_value; + if (key_end == absl::string_view::npos) { + tail = ""; + } else if (tail[key_end] == ':') { + tail = tail.substr(key_end + 1); + size_t value_end = tail.find(','); + opt_value.emplace(tail.substr(0, value_end)); + if (value_end == absl::string_view::npos) { + tail = ""; + } else { + tail = tail.substr(value_end + 1); + } + } else { + RTC_DCHECK_EQ(tail[key_end], ','); + tail = tail.substr(key_end + 1); + } + + auto field = field_map.find(key); + if (field != field_map.end()) { + if (!field->second->Parse(std::move(opt_value))) { + RTC_LOG(LS_WARNING) << "Failed to read field with key: '" << key + << "' in trial: \"" << trial_string << "\""; + } + } else if (!opt_value && keyless_field && !key.empty()) { + if (!keyless_field->Parse(std::string(key))) { + RTC_LOG(LS_WARNING) << "Failed to read empty key field with value '" + << key << "' in trial: \"" << trial_string << "\""; + } + } else if (key.empty() || key[0] != '_') { + // "_" is be used to prefix keys that are part of the string for + // debugging purposes but not neccessarily used. + // e.g. WebRTC-Experiment/param: value, _DebuggingString + if (!logged_unknown_key) { + RTC_LOG(LS_INFO) << "No field with key: '" << key + << "' (found in trial: \"" << trial_string << "\")"; + std::string valid_keys; + for (const auto& f : field_map) { + valid_keys.append(f.first.data(), f.first.size()); + valid_keys += ", "; + } + RTC_LOG(LS_INFO) << "Valid keys are: " << valid_keys; + logged_unknown_key = true; + } + } + } + + for (FieldTrialParameterInterface* field : fields) { + field->ParseDone(); + } +} + +template <> +absl::optional<bool> ParseTypedParameter<bool>(absl::string_view str) { + if (str == "true" || str == "1") { + return true; + } else if (str == "false" || str == "0") { + return false; + } + return absl::nullopt; +} + +template <> +absl::optional<double> ParseTypedParameter<double>(absl::string_view str) { + double value; + char unit[2]{0, 0}; + if (sscanf(std::string(str).c_str(), "%lf%1s", &value, unit) >= 1) { + if (unit[0] == '%') + return value / 100; + return value; + } else { + return absl::nullopt; + } +} + +template <> +absl::optional<int> ParseTypedParameter<int>(absl::string_view str) { + int64_t value; + if (sscanf(std::string(str).c_str(), "%" SCNd64, &value) == 1) { + if (rtc::IsValueInRangeForNumericType<int, int64_t>(value)) { + return static_cast<int>(value); + } + } + return absl::nullopt; +} + +template <> +absl::optional<unsigned> ParseTypedParameter<unsigned>(absl::string_view str) { + int64_t value; + if (sscanf(std::string(str).c_str(), "%" SCNd64, &value) == 1) { + if (rtc::IsValueInRangeForNumericType<unsigned, int64_t>(value)) { + return static_cast<unsigned>(value); + } + } + return absl::nullopt; +} + +template <> +absl::optional<std::string> ParseTypedParameter<std::string>( + absl::string_view str) { + return std::string(str); +} + +template <> +absl::optional<absl::optional<bool>> ParseTypedParameter<absl::optional<bool>>( + absl::string_view str) { + return ParseOptionalParameter<bool>(str); +} +template <> +absl::optional<absl::optional<int>> ParseTypedParameter<absl::optional<int>>( + absl::string_view str) { + return ParseOptionalParameter<int>(str); +} +template <> +absl::optional<absl::optional<unsigned>> +ParseTypedParameter<absl::optional<unsigned>>(absl::string_view str) { + return ParseOptionalParameter<unsigned>(str); +} +template <> +absl::optional<absl::optional<double>> +ParseTypedParameter<absl::optional<double>>(absl::string_view str) { + return ParseOptionalParameter<double>(str); +} + +FieldTrialFlag::FieldTrialFlag(absl::string_view key) + : FieldTrialFlag(key, false) {} + +FieldTrialFlag::FieldTrialFlag(absl::string_view key, bool default_value) + : FieldTrialParameterInterface(key), value_(default_value) {} + +bool FieldTrialFlag::Get() const { + return value_; +} + +webrtc::FieldTrialFlag::operator bool() const { + return value_; +} + +bool FieldTrialFlag::Parse(absl::optional<std::string> str_value) { + // Only set the flag if there is no argument provided. + if (str_value) { + absl::optional<bool> opt_value = ParseTypedParameter<bool>(*str_value); + if (!opt_value) + return false; + value_ = *opt_value; + } else { + value_ = true; + } + return true; +} + +AbstractFieldTrialEnum::AbstractFieldTrialEnum( + absl::string_view key, + int default_value, + std::map<std::string, int> mapping) + : FieldTrialParameterInterface(key), + value_(default_value), + enum_mapping_(mapping) { + for (auto& key_val : enum_mapping_) + valid_values_.insert(key_val.second); +} +AbstractFieldTrialEnum::AbstractFieldTrialEnum(const AbstractFieldTrialEnum&) = + default; +AbstractFieldTrialEnum::~AbstractFieldTrialEnum() = default; + +bool AbstractFieldTrialEnum::Parse(absl::optional<std::string> str_value) { + if (str_value) { + auto it = enum_mapping_.find(*str_value); + if (it != enum_mapping_.end()) { + value_ = it->second; + return true; + } + absl::optional<int> value = ParseTypedParameter<int>(*str_value); + if (value.has_value() && + (valid_values_.find(*value) != valid_values_.end())) { + value_ = *value; + return true; + } + } + return false; +} + +template class FieldTrialParameter<bool>; +template class FieldTrialParameter<double>; +template class FieldTrialParameter<int>; +template class FieldTrialParameter<unsigned>; +template class FieldTrialParameter<std::string>; + +template class FieldTrialConstrained<double>; +template class FieldTrialConstrained<int>; +template class FieldTrialConstrained<unsigned>; + +template class FieldTrialOptional<double>; +template class FieldTrialOptional<int>; +template class FieldTrialOptional<unsigned>; +template class FieldTrialOptional<bool>; +template class FieldTrialOptional<std::string>; + +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/experiments/field_trial_parser.h b/third_party/libwebrtc/rtc_base/experiments/field_trial_parser.h new file mode 100644 index 0000000000..822895e70b --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/field_trial_parser.h @@ -0,0 +1,291 @@ +/* + * 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 RTC_BASE_EXPERIMENTS_FIELD_TRIAL_PARSER_H_ +#define RTC_BASE_EXPERIMENTS_FIELD_TRIAL_PARSER_H_ + +#include <stdint.h> + +#include <initializer_list> +#include <map> +#include <set> +#include <string> +#include <vector> + +#include "absl/strings/string_view.h" +#include "absl/types/optional.h" + +// Field trial parser functionality. Provides funcitonality to parse field trial +// argument strings in key:value format. Each parameter is described using +// key:value, parameters are separated with a ,. Values can't include the comma +// character, since there's no quote facility. For most types, white space is +// ignored. Parameters are declared with a given type for which an +// implementation of ParseTypedParameter should be provided. The +// ParseTypedParameter implementation is given whatever is between the : and the +// ,. If the key is provided without : a FieldTrialOptional will use nullopt. + +// Example string: "my_optional,my_int:3,my_string:hello" + +// For further description of usage and behavior, see the examples in the unit +// tests. + +namespace webrtc { +class FieldTrialParameterInterface { + public: + virtual ~FieldTrialParameterInterface(); + std::string key() const { return key_; } + + protected: + // Protected to allow implementations to provide assignment and copy. + FieldTrialParameterInterface(const FieldTrialParameterInterface&) = default; + FieldTrialParameterInterface& operator=(const FieldTrialParameterInterface&) = + default; + explicit FieldTrialParameterInterface(absl::string_view key); + friend void ParseFieldTrial( + std::initializer_list<FieldTrialParameterInterface*> fields, + absl::string_view trial_string); + void MarkAsUsed() { used_ = true; } + virtual bool Parse(absl::optional<std::string> str_value) = 0; + + virtual void ParseDone() {} + + std::vector<FieldTrialParameterInterface*> sub_parameters_; + + private: + std::string key_; + bool used_ = false; +}; + +// ParseFieldTrial function parses the given string and fills the given fields +// with extracted values if available. +void ParseFieldTrial( + std::initializer_list<FieldTrialParameterInterface*> fields, + absl::string_view trial_string); + +// Specialize this in code file for custom types. Should return absl::nullopt if +// the given string cannot be properly parsed. +template <typename T> +absl::optional<T> ParseTypedParameter(absl::string_view); + +// This class uses the ParseTypedParameter function to implement a parameter +// implementation with an enforced default value. +template <typename T> +class FieldTrialParameter : public FieldTrialParameterInterface { + public: + FieldTrialParameter(absl::string_view key, T default_value) + : FieldTrialParameterInterface(key), value_(default_value) {} + T Get() const { return value_; } + operator T() const { return Get(); } + const T* operator->() const { return &value_; } + + void SetForTest(T value) { value_ = value; } + + protected: + bool Parse(absl::optional<std::string> str_value) override { + if (str_value) { + absl::optional<T> value = ParseTypedParameter<T>(*str_value); + if (value.has_value()) { + value_ = value.value(); + return true; + } + } + return false; + } + + private: + T value_; +}; + +// This class uses the ParseTypedParameter function to implement a parameter +// implementation with an enforced default value and a range constraint. Values +// outside the configured range will be ignored. +template <typename T> +class FieldTrialConstrained : public FieldTrialParameterInterface { + public: + FieldTrialConstrained(absl::string_view key, + T default_value, + absl::optional<T> lower_limit, + absl::optional<T> upper_limit) + : FieldTrialParameterInterface(key), + value_(default_value), + lower_limit_(lower_limit), + upper_limit_(upper_limit) {} + T Get() const { return value_; } + operator T() const { return Get(); } + const T* operator->() const { return &value_; } + + protected: + bool Parse(absl::optional<std::string> str_value) override { + if (str_value) { + absl::optional<T> value = ParseTypedParameter<T>(*str_value); + if (value && (!lower_limit_ || *value >= *lower_limit_) && + (!upper_limit_ || *value <= *upper_limit_)) { + value_ = *value; + return true; + } + } + return false; + } + + private: + T value_; + absl::optional<T> lower_limit_; + absl::optional<T> upper_limit_; +}; + +class AbstractFieldTrialEnum : public FieldTrialParameterInterface { + public: + AbstractFieldTrialEnum(absl::string_view key, + int default_value, + std::map<std::string, int> mapping); + ~AbstractFieldTrialEnum() override; + AbstractFieldTrialEnum(const AbstractFieldTrialEnum&); + + protected: + bool Parse(absl::optional<std::string> str_value) override; + + protected: + int value_; + std::map<std::string, int> enum_mapping_; + std::set<int> valid_values_; +}; + +// The FieldTrialEnum class can be used to quickly define a parser for a +// specific enum. It handles values provided as integers and as strings if a +// mapping is provided. +template <typename T> +class FieldTrialEnum : public AbstractFieldTrialEnum { + public: + FieldTrialEnum(absl::string_view key, + T default_value, + std::map<std::string, T> mapping) + : AbstractFieldTrialEnum(key, + static_cast<int>(default_value), + ToIntMap(mapping)) {} + T Get() const { return static_cast<T>(value_); } + operator T() const { return Get(); } + + private: + static std::map<std::string, int> ToIntMap(std::map<std::string, T> mapping) { + std::map<std::string, int> res; + for (const auto& it : mapping) + res[it.first] = static_cast<int>(it.second); + return res; + } +}; + +// This class uses the ParseTypedParameter function to implement an optional +// parameter implementation that can default to absl::nullopt. +template <typename T> +class FieldTrialOptional : public FieldTrialParameterInterface { + public: + explicit FieldTrialOptional(absl::string_view key) + : FieldTrialParameterInterface(key) {} + FieldTrialOptional(absl::string_view key, absl::optional<T> default_value) + : FieldTrialParameterInterface(key), value_(default_value) {} + absl::optional<T> GetOptional() const { return value_; } + const T& Value() const { return value_.value(); } + const T& operator*() const { return value_.value(); } + const T* operator->() const { return &value_.value(); } + explicit operator bool() const { return value_.has_value(); } + + protected: + bool Parse(absl::optional<std::string> str_value) override { + if (str_value) { + absl::optional<T> value = ParseTypedParameter<T>(*str_value); + if (!value.has_value()) + return false; + value_ = value.value(); + } else { + value_ = absl::nullopt; + } + return true; + } + + private: + absl::optional<T> value_; +}; + +// Equivalent to a FieldTrialParameter<bool> in the case that both key and value +// are present. If key is missing, evaluates to false. If key is present, but no +// explicit value is provided, the flag evaluates to true. +class FieldTrialFlag : public FieldTrialParameterInterface { + public: + explicit FieldTrialFlag(absl::string_view key); + FieldTrialFlag(absl::string_view key, bool default_value); + bool Get() const; + explicit operator bool() const; + + protected: + bool Parse(absl::optional<std::string> str_value) override; + + private: + bool value_; +}; + +template <typename T> +absl::optional<absl::optional<T>> ParseOptionalParameter( + absl::string_view str) { + if (str.empty()) + return absl::optional<T>(); + auto parsed = ParseTypedParameter<T>(str); + if (parsed.has_value()) + return parsed; + return absl::nullopt; +} + +template <> +absl::optional<bool> ParseTypedParameter<bool>(absl::string_view str); +template <> +absl::optional<double> ParseTypedParameter<double>(absl::string_view str); +template <> +absl::optional<int> ParseTypedParameter<int>(absl::string_view str); +template <> +absl::optional<unsigned> ParseTypedParameter<unsigned>(absl::string_view str); +template <> +absl::optional<std::string> ParseTypedParameter<std::string>( + absl::string_view str); + +template <> +absl::optional<absl::optional<bool>> ParseTypedParameter<absl::optional<bool>>( + absl::string_view str); +template <> +absl::optional<absl::optional<int>> ParseTypedParameter<absl::optional<int>>( + absl::string_view str); +template <> +absl::optional<absl::optional<unsigned>> +ParseTypedParameter<absl::optional<unsigned>>(absl::string_view str); +template <> +absl::optional<absl::optional<double>> +ParseTypedParameter<absl::optional<double>>(absl::string_view str); + +// Accepts true, false, else parsed with sscanf %i, true if != 0. +extern template class FieldTrialParameter<bool>; +// Interpreted using sscanf %lf. +extern template class FieldTrialParameter<double>; +// Interpreted using sscanf %i. +extern template class FieldTrialParameter<int>; +// Interpreted using sscanf %u. +extern template class FieldTrialParameter<unsigned>; +// Using the given value as is. +extern template class FieldTrialParameter<std::string>; + +extern template class FieldTrialConstrained<double>; +extern template class FieldTrialConstrained<int>; +extern template class FieldTrialConstrained<unsigned>; + +extern template class FieldTrialOptional<double>; +extern template class FieldTrialOptional<int>; +extern template class FieldTrialOptional<unsigned>; +extern template class FieldTrialOptional<bool>; +extern template class FieldTrialOptional<std::string>; + +} // namespace webrtc + +#endif // RTC_BASE_EXPERIMENTS_FIELD_TRIAL_PARSER_H_ diff --git a/third_party/libwebrtc/rtc_base/experiments/field_trial_parser_gn/moz.build b/third_party/libwebrtc/rtc_base/experiments/field_trial_parser_gn/moz.build new file mode 100644 index 0000000000..ea63aafc99 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/field_trial_parser_gn/moz.build @@ -0,0 +1,235 @@ +# 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/rtc_base/experiments/field_trial_list.cc", + "/third_party/libwebrtc/rtc_base/experiments/field_trial_parser.cc", + "/third_party/libwebrtc/rtc_base/experiments/field_trial_units.cc", + "/third_party/libwebrtc/rtc_base/experiments/struct_parameters_parser.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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("field_trial_parser_gn") diff --git a/third_party/libwebrtc/rtc_base/experiments/field_trial_parser_unittest.cc b/third_party/libwebrtc/rtc_base/experiments/field_trial_parser_unittest.cc new file mode 100644 index 0000000000..73d115357f --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/field_trial_parser_unittest.cc @@ -0,0 +1,187 @@ +/* + * 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. + */ +#include "rtc_base/experiments/field_trial_parser.h" + +#include "absl/strings/string_view.h" +#include "rtc_base/experiments/field_trial_list.h" +#include "rtc_base/gunit.h" +#include "system_wrappers/include/field_trial.h" +#include "test/field_trial.h" +#include "test/gmock.h" + +namespace webrtc { +namespace { + +constexpr char kDummyExperiment[] = "WebRTC-DummyExperiment"; + +struct DummyExperiment { + FieldTrialFlag enabled = FieldTrialFlag("Enabled"); + FieldTrialParameter<double> factor = FieldTrialParameter<double>("f", 0.5); + FieldTrialParameter<int> retries = FieldTrialParameter<int>("r", 5); + FieldTrialParameter<unsigned> size = FieldTrialParameter<unsigned>("s", 3); + FieldTrialParameter<bool> ping = FieldTrialParameter<bool>("p", 0); + FieldTrialParameter<std::string> hash = + FieldTrialParameter<std::string>("h", "a80"); + + DummyExperiment() + : DummyExperiment([] { + field_trial::FieldTrialsAllowedInScopeForTesting k{ + {kDummyExperiment}}; + return field_trial::FindFullName(kDummyExperiment); + }()) {} + + explicit DummyExperiment(absl::string_view field_trial) { + ParseFieldTrial({&enabled, &factor, &retries, &size, &ping, &hash}, + field_trial); + } +}; + +enum class CustomEnum { + kDefault = 0, + kRed = 1, + kBlue = 2, +}; + +} // namespace + +TEST(FieldTrialParserTest, ParsesValidParameters) { + DummyExperiment exp("Enabled,f:-1.7,r:2,s:10,p:1,h:x7c"); + EXPECT_TRUE(exp.enabled.Get()); + EXPECT_EQ(exp.factor.Get(), -1.7); + EXPECT_EQ(exp.retries.Get(), 2); + EXPECT_EQ(exp.size.Get(), 10u); + EXPECT_EQ(exp.ping.Get(), true); + EXPECT_EQ(exp.hash.Get(), "x7c"); +} +TEST(FieldTrialParserTest, InitializesFromFieldTrial) { + test::ScopedFieldTrials field_trials( + "WebRTC-OtherExperiment/Disabled/" + "WebRTC-DummyExperiment/Enabled,f:-1.7,r:2,s:10,p:1,h:x7c/" + "WebRTC-AnotherExperiment/Enabled,f:-3.1,otherstuff:beef/"); + DummyExperiment exp; + EXPECT_TRUE(exp.enabled.Get()); + EXPECT_EQ(exp.factor.Get(), -1.7); + EXPECT_EQ(exp.retries.Get(), 2); + EXPECT_EQ(exp.size.Get(), 10u); + EXPECT_EQ(exp.ping.Get(), true); + EXPECT_EQ(exp.hash.Get(), "x7c"); +} +TEST(FieldTrialParserTest, UsesDefaults) { + DummyExperiment exp(""); + EXPECT_FALSE(exp.enabled.Get()); + EXPECT_EQ(exp.factor.Get(), 0.5); + EXPECT_EQ(exp.retries.Get(), 5); + EXPECT_EQ(exp.size.Get(), 3u); + EXPECT_EQ(exp.ping.Get(), false); + EXPECT_EQ(exp.hash.Get(), "a80"); +} +TEST(FieldTrialParserTest, CanHandleMixedInput) { + DummyExperiment exp("p:true,h:,Enabled"); + EXPECT_TRUE(exp.enabled.Get()); + EXPECT_EQ(exp.factor.Get(), 0.5); + EXPECT_EQ(exp.retries.Get(), 5); + EXPECT_EQ(exp.size.Get(), 3u); + EXPECT_EQ(exp.ping.Get(), true); + EXPECT_EQ(exp.hash.Get(), ""); +} +TEST(FieldTrialParserTest, ParsesDoubleParameter) { + FieldTrialParameter<double> double_param("f", 0.0); + ParseFieldTrial({&double_param}, "f:45%"); + EXPECT_EQ(double_param.Get(), 0.45); + ParseFieldTrial({&double_param}, "f:34 %"); + EXPECT_EQ(double_param.Get(), 0.34); + ParseFieldTrial({&double_param}, "f:0.67"); + EXPECT_EQ(double_param.Get(), 0.67); +} +TEST(FieldTrialParserTest, IgnoresNewKey) { + DummyExperiment exp("Disabled,r:-11,foo"); + EXPECT_FALSE(exp.enabled.Get()); + EXPECT_EQ(exp.factor.Get(), 0.5); + EXPECT_EQ(exp.retries.Get(), -11); +} +TEST(FieldTrialParserTest, IgnoresInvalid) { + DummyExperiment exp("Enabled,f,p:,r:%,,s:-1,:foo,h"); + EXPECT_TRUE(exp.enabled.Get()); + EXPECT_EQ(exp.factor.Get(), 0.5); + EXPECT_EQ(exp.retries.Get(), 5); + EXPECT_EQ(exp.size.Get(), 3u); + EXPECT_EQ(exp.ping.Get(), false); + EXPECT_EQ(exp.hash.Get(), "a80"); +} +TEST(FieldTrialParserTest, IgnoresOutOfRange) { + FieldTrialConstrained<double> low("low", 10, absl::nullopt, 100); + FieldTrialConstrained<double> high("high", 10, 5, absl::nullopt); + ParseFieldTrial({&low, &high}, "low:1000,high:0"); + EXPECT_EQ(low.Get(), 10); + EXPECT_EQ(high.Get(), 10); + ParseFieldTrial({&low, &high}, "low:inf,high:nan"); + EXPECT_EQ(low.Get(), 10); + EXPECT_EQ(high.Get(), 10); + ParseFieldTrial({&low, &high}, "low:20,high:20"); + EXPECT_EQ(low.Get(), 20); + EXPECT_EQ(high.Get(), 20); + + FieldTrialConstrained<unsigned> size("size", 5, 1, 10); + ParseFieldTrial({&size}, "size:0"); + EXPECT_EQ(size.Get(), 5u); +} +TEST(FieldTrialParserTest, ReadsValuesFromFieldWithoutKey) { + FieldTrialFlag enabled("Enabled"); + FieldTrialParameter<int> req("", 10); + ParseFieldTrial({&enabled, &req}, "Enabled,20"); + EXPECT_EQ(req.Get(), 20); + ParseFieldTrial({&req}, "30"); + EXPECT_EQ(req.Get(), 30); +} +TEST(FieldTrialParserTest, ParsesOptionalParameters) { + FieldTrialOptional<int> max_count("c", absl::nullopt); + ParseFieldTrial({&max_count}, ""); + EXPECT_FALSE(max_count.GetOptional().has_value()); + ParseFieldTrial({&max_count}, "c:10"); + EXPECT_EQ(max_count.GetOptional().value(), 10); + ParseFieldTrial({&max_count}, "c"); + EXPECT_FALSE(max_count.GetOptional().has_value()); + ParseFieldTrial({&max_count}, "c:20"); + EXPECT_EQ(max_count.GetOptional().value(), 20); + ParseFieldTrial({&max_count}, "c:"); + EXPECT_EQ(max_count.GetOptional().value(), 20); + + FieldTrialOptional<unsigned> max_size("c", absl::nullopt); + ParseFieldTrial({&max_size}, ""); + EXPECT_FALSE(max_size.GetOptional().has_value()); + ParseFieldTrial({&max_size}, "c:10"); + EXPECT_EQ(max_size.GetOptional().value(), 10u); + ParseFieldTrial({&max_size}, "c"); + EXPECT_FALSE(max_size.GetOptional().has_value()); + ParseFieldTrial({&max_size}, "c:20"); + EXPECT_EQ(max_size.GetOptional().value(), 20u); + + FieldTrialOptional<std::string> optional_string("s", std::string("ab")); + ParseFieldTrial({&optional_string}, "s:"); + EXPECT_EQ(optional_string.GetOptional().value(), ""); + ParseFieldTrial({&optional_string}, "s"); + EXPECT_FALSE(optional_string.GetOptional().has_value()); +} +TEST(FieldTrialParserTest, ParsesCustomEnumParameter) { + FieldTrialEnum<CustomEnum> my_enum("e", CustomEnum::kDefault, + {{"default", CustomEnum::kDefault}, + {"red", CustomEnum::kRed}, + {"blue", CustomEnum::kBlue}}); + ParseFieldTrial({&my_enum}, ""); + EXPECT_EQ(my_enum.Get(), CustomEnum::kDefault); + ParseFieldTrial({&my_enum}, "e:red"); + EXPECT_EQ(my_enum.Get(), CustomEnum::kRed); + ParseFieldTrial({&my_enum}, "e:2"); + EXPECT_EQ(my_enum.Get(), CustomEnum::kBlue); + ParseFieldTrial({&my_enum}, "e:5"); + EXPECT_EQ(my_enum.Get(), CustomEnum::kBlue); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/experiments/field_trial_units.cc b/third_party/libwebrtc/rtc_base/experiments/field_trial_units.cc new file mode 100644 index 0000000000..92af46a9e3 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/field_trial_units.cc @@ -0,0 +1,116 @@ +/* + * 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. + */ +#include "rtc_base/experiments/field_trial_units.h" + +#include <stdio.h> + +#include <limits> +#include <string> + +#include "absl/strings/string_view.h" +#include "absl/types/optional.h" + +// Large enough to fit "seconds", the longest supported unit name. +#define RTC_TRIAL_UNIT_LENGTH_STR "7" +#define RTC_TRIAL_UNIT_SIZE 8 + +namespace webrtc { +namespace { + +struct ValueWithUnit { + double value; + std::string unit; +}; + +absl::optional<ValueWithUnit> ParseValueWithUnit(absl::string_view str) { + if (str == "inf") { + return ValueWithUnit{std::numeric_limits<double>::infinity(), ""}; + } else if (str == "-inf") { + return ValueWithUnit{-std::numeric_limits<double>::infinity(), ""}; + } else { + double double_val; + char unit_char[RTC_TRIAL_UNIT_SIZE]; + unit_char[0] = 0; + if (sscanf(std::string(str).c_str(), "%lf%" RTC_TRIAL_UNIT_LENGTH_STR "s", + &double_val, unit_char) >= 1) { + return ValueWithUnit{double_val, unit_char}; + } + } + return absl::nullopt; +} +} // namespace + +template <> +absl::optional<DataRate> ParseTypedParameter<DataRate>(absl::string_view str) { + absl::optional<ValueWithUnit> result = ParseValueWithUnit(str); + if (result) { + if (result->unit.empty() || result->unit == "kbps") { + return DataRate::KilobitsPerSec(result->value); + } else if (result->unit == "bps") { + return DataRate::BitsPerSec(result->value); + } + } + return absl::nullopt; +} + +template <> +absl::optional<DataSize> ParseTypedParameter<DataSize>(absl::string_view str) { + absl::optional<ValueWithUnit> result = ParseValueWithUnit(str); + if (result) { + if (result->unit.empty() || result->unit == "bytes") + return DataSize::Bytes(result->value); + } + return absl::nullopt; +} + +template <> +absl::optional<TimeDelta> ParseTypedParameter<TimeDelta>( + absl::string_view str) { + absl::optional<ValueWithUnit> result = ParseValueWithUnit(str); + if (result) { + if (result->unit == "s" || result->unit == "seconds") { + return TimeDelta::Seconds(result->value); + } else if (result->unit == "us") { + return TimeDelta::Micros(result->value); + } else if (result->unit.empty() || result->unit == "ms") { + return TimeDelta::Millis(result->value); + } + } + return absl::nullopt; +} + +template <> +absl::optional<absl::optional<DataRate>> +ParseTypedParameter<absl::optional<DataRate>>(absl::string_view str) { + return ParseOptionalParameter<DataRate>(str); +} +template <> +absl::optional<absl::optional<DataSize>> +ParseTypedParameter<absl::optional<DataSize>>(absl::string_view str) { + return ParseOptionalParameter<DataSize>(str); +} +template <> +absl::optional<absl::optional<TimeDelta>> +ParseTypedParameter<absl::optional<TimeDelta>>(absl::string_view str) { + return ParseOptionalParameter<TimeDelta>(str); +} + +template class FieldTrialParameter<DataRate>; +template class FieldTrialParameter<DataSize>; +template class FieldTrialParameter<TimeDelta>; + +template class FieldTrialConstrained<DataRate>; +template class FieldTrialConstrained<DataSize>; +template class FieldTrialConstrained<TimeDelta>; + +template class FieldTrialOptional<DataRate>; +template class FieldTrialOptional<DataSize>; +template class FieldTrialOptional<TimeDelta>; +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/experiments/field_trial_units.h b/third_party/libwebrtc/rtc_base/experiments/field_trial_units.h new file mode 100644 index 0000000000..408367c031 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/field_trial_units.h @@ -0,0 +1,41 @@ +/* + * 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 RTC_BASE_EXPERIMENTS_FIELD_TRIAL_UNITS_H_ +#define RTC_BASE_EXPERIMENTS_FIELD_TRIAL_UNITS_H_ + +#include "absl/strings/string_view.h" +#include "api/units/data_rate.h" +#include "api/units/data_size.h" +#include "api/units/time_delta.h" +#include "rtc_base/experiments/field_trial_parser.h" + +namespace webrtc { + +template <> +absl::optional<DataRate> ParseTypedParameter<DataRate>(absl::string_view str); +template <> +absl::optional<DataSize> ParseTypedParameter<DataSize>(absl::string_view str); +template <> +absl::optional<TimeDelta> ParseTypedParameter<TimeDelta>(absl::string_view str); + +extern template class FieldTrialParameter<DataRate>; +extern template class FieldTrialParameter<DataSize>; +extern template class FieldTrialParameter<TimeDelta>; + +extern template class FieldTrialConstrained<DataRate>; +extern template class FieldTrialConstrained<DataSize>; +extern template class FieldTrialConstrained<TimeDelta>; + +extern template class FieldTrialOptional<DataRate>; +extern template class FieldTrialOptional<DataSize>; +extern template class FieldTrialOptional<TimeDelta>; +} // namespace webrtc + +#endif // RTC_BASE_EXPERIMENTS_FIELD_TRIAL_UNITS_H_ diff --git a/third_party/libwebrtc/rtc_base/experiments/field_trial_units_unittest.cc b/third_party/libwebrtc/rtc_base/experiments/field_trial_units_unittest.cc new file mode 100644 index 0000000000..8996663d8e --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/field_trial_units_unittest.cc @@ -0,0 +1,87 @@ +/* + * 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. + */ +#include "rtc_base/experiments/field_trial_units.h" + +#include <string> + +#include "absl/strings/string_view.h" +#include "absl/types/optional.h" +#include "rtc_base/experiments/field_trial_parser.h" +#include "test/gtest.h" + +namespace webrtc { +namespace { +struct DummyExperiment { + FieldTrialParameter<DataRate> target_rate = + FieldTrialParameter<DataRate>("t", DataRate::KilobitsPerSec(100)); + FieldTrialParameter<TimeDelta> period = + FieldTrialParameter<TimeDelta>("p", TimeDelta::Millis(100)); + FieldTrialOptional<DataSize> max_buffer = + FieldTrialOptional<DataSize>("b", absl::nullopt); + + explicit DummyExperiment(absl::string_view field_trial) { + ParseFieldTrial({&target_rate, &max_buffer, &period}, field_trial); + } +}; +} // namespace + +TEST(FieldTrialParserUnitsTest, FallsBackToDefaults) { + DummyExperiment exp(""); + EXPECT_EQ(exp.target_rate.Get(), DataRate::KilobitsPerSec(100)); + EXPECT_FALSE(exp.max_buffer.GetOptional().has_value()); + EXPECT_EQ(exp.period.Get(), TimeDelta::Millis(100)); +} +TEST(FieldTrialParserUnitsTest, ParsesUnitParameters) { + DummyExperiment exp("t:300kbps,b:5bytes,p:300ms"); + EXPECT_EQ(exp.target_rate.Get(), DataRate::KilobitsPerSec(300)); + EXPECT_EQ(*exp.max_buffer.GetOptional(), DataSize::Bytes(5)); + EXPECT_EQ(exp.period.Get(), TimeDelta::Millis(300)); +} +TEST(FieldTrialParserUnitsTest, ParsesDefaultUnitParameters) { + DummyExperiment exp("t:300,b:5,p:300"); + EXPECT_EQ(exp.target_rate.Get(), DataRate::KilobitsPerSec(300)); + EXPECT_EQ(*exp.max_buffer.GetOptional(), DataSize::Bytes(5)); + EXPECT_EQ(exp.period.Get(), TimeDelta::Millis(300)); +} +TEST(FieldTrialParserUnitsTest, ParsesInfinityParameter) { + DummyExperiment exp("t:inf,p:inf"); + EXPECT_EQ(exp.target_rate.Get(), DataRate::Infinity()); + EXPECT_EQ(exp.period.Get(), TimeDelta::PlusInfinity()); +} +TEST(FieldTrialParserUnitsTest, ParsesOtherUnitParameters) { + DummyExperiment exp("t:300bps,p:0.3 seconds,b:8 bytes"); + EXPECT_EQ(exp.target_rate.Get(), DataRate::BitsPerSec(300)); + EXPECT_EQ(*exp.max_buffer.GetOptional(), DataSize::Bytes(8)); + EXPECT_EQ(exp.period.Get(), TimeDelta::Millis(300)); +} +TEST(FieldTrialParserUnitsTest, IgnoresOutOfRange) { + FieldTrialConstrained<DataRate> rate("r", DataRate::KilobitsPerSec(30), + DataRate::KilobitsPerSec(10), + DataRate::KilobitsPerSec(100)); + FieldTrialConstrained<TimeDelta> delta("d", TimeDelta::Millis(30), + TimeDelta::Millis(10), + TimeDelta::Millis(100)); + FieldTrialConstrained<DataSize> size( + "s", DataSize::Bytes(30), DataSize::Bytes(10), DataSize::Bytes(100)); + ParseFieldTrial({&rate, &delta, &size}, "r:0,d:0,s:0"); + EXPECT_EQ(rate->kbps(), 30); + EXPECT_EQ(delta->ms(), 30); + EXPECT_EQ(size->bytes(), 30); + ParseFieldTrial({&rate, &delta, &size}, "r:300,d:300,s:300"); + EXPECT_EQ(rate->kbps(), 30); + EXPECT_EQ(delta->ms(), 30); + EXPECT_EQ(size->bytes(), 30); + ParseFieldTrial({&rate, &delta, &size}, "r:50,d:50,s:50"); + EXPECT_EQ(rate->kbps(), 50); + EXPECT_EQ(delta->ms(), 50); + EXPECT_EQ(size->bytes(), 50); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/experiments/keyframe_interval_settings.cc b/third_party/libwebrtc/rtc_base/experiments/keyframe_interval_settings.cc new file mode 100644 index 0000000000..413e2a91d5 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/keyframe_interval_settings.cc @@ -0,0 +1,39 @@ +/* + * 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. + */ + +#include "rtc_base/experiments/keyframe_interval_settings.h" + +#include "api/transport/field_trial_based_config.h" + +namespace webrtc { + +namespace { + +constexpr char kFieldTrialName[] = "WebRTC-KeyframeInterval"; + +} // namespace + +KeyframeIntervalSettings::KeyframeIntervalSettings( + const FieldTrialsView* const key_value_config) + : min_keyframe_send_interval_ms_("min_keyframe_send_interval_ms") { + ParseFieldTrial({&min_keyframe_send_interval_ms_}, + key_value_config->Lookup(kFieldTrialName)); +} + +KeyframeIntervalSettings KeyframeIntervalSettings::ParseFromFieldTrials() { + FieldTrialBasedConfig field_trial_config; + return KeyframeIntervalSettings(&field_trial_config); +} + +absl::optional<int> KeyframeIntervalSettings::MinKeyframeSendIntervalMs() + const { + return min_keyframe_send_interval_ms_.GetOptional(); +} +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/experiments/keyframe_interval_settings.h b/third_party/libwebrtc/rtc_base/experiments/keyframe_interval_settings.h new file mode 100644 index 0000000000..aff7854516 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/keyframe_interval_settings.h @@ -0,0 +1,39 @@ +/* + * 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 RTC_BASE_EXPERIMENTS_KEYFRAME_INTERVAL_SETTINGS_H_ +#define RTC_BASE_EXPERIMENTS_KEYFRAME_INTERVAL_SETTINGS_H_ + +#include "absl/types/optional.h" +#include "api/field_trials_view.h" +#include "rtc_base/experiments/field_trial_parser.h" + +namespace webrtc { + +// TODO(bugs.webrtc.org/10427): Remove and replace with proper configuration +// parameter, or move to using FIR if intent is to avoid triggering multiple +// times to PLIs corresponding to the same request when RTT is large. +class KeyframeIntervalSettings final { + public: + static KeyframeIntervalSettings ParseFromFieldTrials(); + + // Sender side. + // The encoded keyframe send rate is <= 1/MinKeyframeSendIntervalMs(). + absl::optional<int> MinKeyframeSendIntervalMs() const; + + private: + explicit KeyframeIntervalSettings(const FieldTrialsView* key_value_config); + + FieldTrialOptional<int> min_keyframe_send_interval_ms_; +}; + +} // namespace webrtc + +#endif // RTC_BASE_EXPERIMENTS_KEYFRAME_INTERVAL_SETTINGS_H_ diff --git a/third_party/libwebrtc/rtc_base/experiments/keyframe_interval_settings_experiment_gn/moz.build b/third_party/libwebrtc/rtc_base/experiments/keyframe_interval_settings_experiment_gn/moz.build new file mode 100644 index 0000000000..3857bc9451 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/keyframe_interval_settings_experiment_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/rtc_base/experiments/keyframe_interval_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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("keyframe_interval_settings_experiment_gn") diff --git a/third_party/libwebrtc/rtc_base/experiments/keyframe_interval_settings_unittest.cc b/third_party/libwebrtc/rtc_base/experiments/keyframe_interval_settings_unittest.cc new file mode 100644 index 0000000000..25cebbcd70 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/keyframe_interval_settings_unittest.cc @@ -0,0 +1,43 @@ +/* + * 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 "rtc_base/experiments/keyframe_interval_settings.h" + +#include "test/field_trial.h" +#include "test/gtest.h" + +namespace webrtc { +namespace { + +TEST(KeyframeIntervalSettingsTest, ParsesMinKeyframeSendIntervalMs) { + EXPECT_FALSE(KeyframeIntervalSettings::ParseFromFieldTrials() + .MinKeyframeSendIntervalMs()); + + test::ScopedFieldTrials field_trials( + "WebRTC-KeyframeInterval/min_keyframe_send_interval_ms:100/"); + EXPECT_EQ(KeyframeIntervalSettings::ParseFromFieldTrials() + .MinKeyframeSendIntervalMs(), + 100); +} + +TEST(KeyframeIntervalSettingsTest, DoesNotParseIncorrectValues) { + EXPECT_FALSE(KeyframeIntervalSettings::ParseFromFieldTrials() + .MinKeyframeSendIntervalMs()); + + test::ScopedFieldTrials field_trials( + "WebRTC-KeyframeInterval/min_keyframe_send_interval_ms:a/"); + EXPECT_FALSE(KeyframeIntervalSettings::ParseFromFieldTrials() + .MinKeyframeSendIntervalMs()); + EXPECT_FALSE(KeyframeIntervalSettings::ParseFromFieldTrials() + .MinKeyframeSendIntervalMs()); +} + +} // namespace +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/experiments/min_video_bitrate_experiment.cc b/third_party/libwebrtc/rtc_base/experiments/min_video_bitrate_experiment.cc new file mode 100644 index 0000000000..f9e7613a15 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/min_video_bitrate_experiment.cc @@ -0,0 +1,116 @@ +/* + * 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 "rtc_base/experiments/min_video_bitrate_experiment.h" + +#include <string> + +#include "rtc_base/checks.h" +#include "rtc_base/experiments/field_trial_parser.h" +#include "rtc_base/logging.h" +#include "system_wrappers/include/field_trial.h" + +namespace webrtc { + +const int kDefaultMinVideoBitrateBps = 30000; + +namespace { +const char kForcedFallbackFieldTrial[] = + "WebRTC-VP8-Forced-Fallback-Encoder-v2"; +const char kMinVideoBitrateExperiment[] = "WebRTC-Video-MinVideoBitrate"; + +absl::optional<int> GetFallbackMinBpsFromFieldTrial(VideoCodecType type) { + if (type != kVideoCodecVP8) { + return absl::nullopt; + } + + if (!webrtc::field_trial::IsEnabled(kForcedFallbackFieldTrial)) { + return absl::nullopt; + } + + const std::string group = + webrtc::field_trial::FindFullName(kForcedFallbackFieldTrial); + if (group.empty()) { + return absl::nullopt; + } + + int min_pixels; // Ignored. + int max_pixels; // Ignored. + int min_bps; + if (sscanf(group.c_str(), "Enabled-%d,%d,%d", &min_pixels, &max_pixels, + &min_bps) != 3) { + return absl::nullopt; + } + + if (min_bps <= 0) { + return absl::nullopt; + } + + return min_bps; +} +} // namespace + +absl::optional<DataRate> GetExperimentalMinVideoBitrate(VideoCodecType type) { + const absl::optional<int> fallback_min_bitrate_bps = + GetFallbackMinBpsFromFieldTrial(type); + if (fallback_min_bitrate_bps) { + return DataRate::BitsPerSec(*fallback_min_bitrate_bps); + } + + if (webrtc::field_trial::IsEnabled(kMinVideoBitrateExperiment)) { + webrtc::FieldTrialFlag enabled("Enabled"); + + // Backwards-compatibility with an old experiment - a generic minimum which, + // if set, applies to all codecs. + webrtc::FieldTrialOptional<webrtc::DataRate> min_video_bitrate("br"); + + // New experiment - per-codec minimum bitrate. + webrtc::FieldTrialOptional<webrtc::DataRate> min_bitrate_vp8("vp8_br"); + webrtc::FieldTrialOptional<webrtc::DataRate> min_bitrate_vp9("vp9_br"); + webrtc::FieldTrialOptional<webrtc::DataRate> min_bitrate_av1("av1_br"); + webrtc::FieldTrialOptional<webrtc::DataRate> min_bitrate_h264("h264_br"); + + webrtc::ParseFieldTrial( + {&enabled, &min_video_bitrate, &min_bitrate_vp8, &min_bitrate_vp9, + &min_bitrate_av1, &min_bitrate_h264}, + webrtc::field_trial::FindFullName(kMinVideoBitrateExperiment)); + + if (min_video_bitrate) { + if (min_bitrate_vp8 || min_bitrate_vp9 || min_bitrate_av1 || + min_bitrate_h264) { + // "br" is mutually-exclusive with the other configuration possibilites. + RTC_LOG(LS_WARNING) << "Self-contradictory experiment config."; + } + return *min_video_bitrate; + } + + switch (type) { + case kVideoCodecVP8: + return min_bitrate_vp8.GetOptional(); + case kVideoCodecH265: + // TODO(bugs.webrtc.org/13485): Use VP9 bitrate limits for now. + case kVideoCodecVP9: + return min_bitrate_vp9.GetOptional(); + case kVideoCodecAV1: + return min_bitrate_av1.GetOptional(); + case kVideoCodecH264: + return min_bitrate_h264.GetOptional(); + case kVideoCodecGeneric: + case kVideoCodecMultiplex: + return absl::nullopt; + } + + RTC_DCHECK_NOTREACHED(); + } + + return absl::nullopt; +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/experiments/min_video_bitrate_experiment.h b/third_party/libwebrtc/rtc_base/experiments/min_video_bitrate_experiment.h new file mode 100644 index 0000000000..9ea8783894 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/min_video_bitrate_experiment.h @@ -0,0 +1,28 @@ +/* + * 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 RTC_BASE_EXPERIMENTS_MIN_VIDEO_BITRATE_EXPERIMENT_H_ +#define RTC_BASE_EXPERIMENTS_MIN_VIDEO_BITRATE_EXPERIMENT_H_ + +#include "absl/types/optional.h" +#include "api/units/data_rate.h" +#include "api/video/video_codec_type.h" + +namespace webrtc { + +extern const int kDefaultMinVideoBitrateBps; + +// Return the experiment-driven minimum video bitrate. +// If no experiment is effective, returns nullopt. +absl::optional<DataRate> GetExperimentalMinVideoBitrate(VideoCodecType type); + +} // namespace webrtc + +#endif // RTC_BASE_EXPERIMENTS_MIN_VIDEO_BITRATE_EXPERIMENT_H_ diff --git a/third_party/libwebrtc/rtc_base/experiments/min_video_bitrate_experiment_gn/moz.build b/third_party/libwebrtc/rtc_base/experiments/min_video_bitrate_experiment_gn/moz.build new file mode 100644 index 0000000000..5f811a6c6d --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/min_video_bitrate_experiment_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/rtc_base/experiments/min_video_bitrate_experiment.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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("min_video_bitrate_experiment_gn") diff --git a/third_party/libwebrtc/rtc_base/experiments/min_video_bitrate_experiment_unittest.cc b/third_party/libwebrtc/rtc_base/experiments/min_video_bitrate_experiment_unittest.cc new file mode 100644 index 0000000000..9792bad61c --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/min_video_bitrate_experiment_unittest.cc @@ -0,0 +1,161 @@ +/* + * 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 "rtc_base/experiments/min_video_bitrate_experiment.h" + +#include "absl/types/optional.h" +#include "api/units/data_rate.h" +#include "api/video/video_codec_type.h" +#include "test/field_trial.h" +#include "test/gtest.h" + +namespace webrtc { +namespace { + +TEST(GetExperimentalMinVideoBitrateTest, + NulloptForAllCodecsIfFieldTrialUndefined) { + test::ScopedFieldTrials field_trials(""); + + EXPECT_EQ(GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecGeneric), + absl::nullopt); + EXPECT_EQ(GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecVP8), + absl::nullopt); + EXPECT_EQ(GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecVP9), + absl::nullopt); + EXPECT_EQ(GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecH264), + absl::nullopt); + EXPECT_EQ( + GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecMultiplex), + absl::nullopt); +} + +TEST(GetExperimentalMinVideoBitrateTest, + NulloptForAllCodecsIfFieldTrialDisabled) { + test::ScopedFieldTrials field_trials( + "WebRTC-Video-MinVideoBitrate/Disabled,br:123kbps/"); + + EXPECT_EQ(GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecGeneric), + absl::nullopt); + EXPECT_EQ(GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecVP8), + absl::nullopt); + EXPECT_EQ(GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecVP9), + absl::nullopt); + EXPECT_EQ(GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecH264), + absl::nullopt); + EXPECT_EQ( + GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecMultiplex), + absl::nullopt); +} + +TEST(GetExperimentalMinVideoBitrateTest, BrForAllCodecsIfDefined) { + test::ScopedFieldTrials field_trials( + "WebRTC-Video-MinVideoBitrate/Enabled,br:123kbps/"); + + EXPECT_EQ(GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecGeneric), + absl::make_optional(DataRate::KilobitsPerSec(123))); + EXPECT_EQ(GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecVP8), + absl::make_optional(DataRate::KilobitsPerSec(123))); + EXPECT_EQ(GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecVP9), + absl::make_optional(DataRate::KilobitsPerSec(123))); + EXPECT_EQ(GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecH264), + absl::make_optional(DataRate::KilobitsPerSec(123))); + EXPECT_EQ( + GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecMultiplex), + absl::make_optional(DataRate::KilobitsPerSec(123))); +} + +TEST(GetExperimentalMinVideoBitrateTest, BrTrumpsSpecificCodecConfigs) { + test::ScopedFieldTrials field_trials( + "WebRTC-Video-MinVideoBitrate/" + "Enabled,br:123kbps,vp8_br:100kbps,vp9_br:200kbps,h264_br:300kbps/"); + + EXPECT_EQ(GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecGeneric), + absl::make_optional(DataRate::KilobitsPerSec(123))); + EXPECT_EQ(GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecVP8), + absl::make_optional(DataRate::KilobitsPerSec(123))); + EXPECT_EQ(GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecVP9), + absl::make_optional(DataRate::KilobitsPerSec(123))); + EXPECT_EQ(GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecH264), + absl::make_optional(DataRate::KilobitsPerSec(123))); + EXPECT_EQ( + GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecMultiplex), + absl::make_optional(DataRate::KilobitsPerSec(123))); +} + +TEST(GetExperimentalMinVideoBitrateTest, + SpecificCodecConfigsIgnoredIfExpDisabled) { + test::ScopedFieldTrials field_trials( + "WebRTC-Video-MinVideoBitrate/" + "Disabled,vp8_br:100kbps,vp9_br:200kbps,h264_br:300kbps/"); + + EXPECT_EQ(GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecGeneric), + absl::nullopt); + EXPECT_EQ(GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecVP8), + absl::nullopt); + EXPECT_EQ(GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecVP9), + absl::nullopt); + EXPECT_EQ(GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecH264), + absl::nullopt); + EXPECT_EQ( + GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecMultiplex), + absl::nullopt); +} + +TEST(GetExperimentalMinVideoBitrateTest, SpecificCodecConfigsUsedIfExpEnabled) { + test::ScopedFieldTrials field_trials( + "WebRTC-Video-MinVideoBitrate/" + "Enabled,vp8_br:100kbps,vp9_br:200kbps,h264_br:300kbps/"); + + EXPECT_EQ(GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecGeneric), + absl::nullopt); + EXPECT_EQ(GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecVP8), + absl::make_optional(DataRate::KilobitsPerSec(100))); + EXPECT_EQ(GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecVP9), + absl::make_optional(DataRate::KilobitsPerSec(200))); + EXPECT_EQ(GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecH264), + absl::make_optional(DataRate::KilobitsPerSec(300))); + EXPECT_EQ( + GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecMultiplex), + absl::nullopt); +} + +TEST(GetExperimentalMinVideoBitrateTest, + Vp8BitrateValueTakenFromFallbackIfAvailable) { + test::ScopedFieldTrials field_trials( + "WebRTC-Video-MinVideoBitrate/" + "Enabled,vp8_br:100kbps,vp9_br:200kbps,h264_br:300kbps/" + "WebRTC-VP8-Forced-Fallback-Encoder-v2/" + "Enabled-444444,555555,666666/"); + + EXPECT_EQ(GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecVP8), + absl::make_optional(DataRate::BitsPerSec(666666))); +} + +TEST(GetExperimentalMinVideoBitrateTest, + NonVp8BitrateValuesTakenFromMinVideoBitrate) { + test::ScopedFieldTrials field_trials( + "WebRTC-Video-MinVideoBitrate/" + "Enabled,vp8_br:100kbps,vp9_br:200kbps,h264_br:300kbps/" + "WebRTC-VP8-Forced-Fallback-Encoder-v2/" + "Enabled-444444,555555,666666/"); + + EXPECT_EQ(GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecGeneric), + absl::nullopt); + EXPECT_EQ(GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecVP9), + absl::make_optional(DataRate::KilobitsPerSec(200))); + EXPECT_EQ(GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecH264), + absl::make_optional(DataRate::KilobitsPerSec(300))); + EXPECT_EQ( + GetExperimentalMinVideoBitrate(VideoCodecType::kVideoCodecMultiplex), + absl::nullopt); +} + +} // namespace +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/experiments/normalize_simulcast_size_experiment.cc b/third_party/libwebrtc/rtc_base/experiments/normalize_simulcast_size_experiment.cc new file mode 100644 index 0000000000..ce817a0797 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/normalize_simulcast_size_experiment.cc @@ -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. + */ + +#include "rtc_base/experiments/normalize_simulcast_size_experiment.h" + +#include <stdio.h> + +#include <string> + +#include "rtc_base/logging.h" +#include "system_wrappers/include/field_trial.h" + +namespace webrtc { +namespace { +constexpr char kFieldTrial[] = "WebRTC-NormalizeSimulcastResolution"; +constexpr int kMinSetting = 0; +constexpr int kMaxSetting = 5; +} // namespace + +absl::optional<int> NormalizeSimulcastSizeExperiment::GetBase2Exponent() { + if (!webrtc::field_trial::IsEnabled(kFieldTrial)) + return absl::nullopt; + + const std::string group = webrtc::field_trial::FindFullName(kFieldTrial); + if (group.empty()) + return absl::nullopt; + + int exponent; + if (sscanf(group.c_str(), "Enabled-%d", &exponent) != 1) { + RTC_LOG(LS_WARNING) << "No parameter provided."; + return absl::nullopt; + } + + if (exponent < kMinSetting || exponent > kMaxSetting) { + RTC_LOG(LS_WARNING) << "Unsupported exp value provided, value ignored."; + return absl::nullopt; + } + + return absl::optional<int>(exponent); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/experiments/normalize_simulcast_size_experiment.h b/third_party/libwebrtc/rtc_base/experiments/normalize_simulcast_size_experiment.h new file mode 100644 index 0000000000..6b358202b2 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/normalize_simulcast_size_experiment.h @@ -0,0 +1,25 @@ +/* + * 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 RTC_BASE_EXPERIMENTS_NORMALIZE_SIMULCAST_SIZE_EXPERIMENT_H_ +#define RTC_BASE_EXPERIMENTS_NORMALIZE_SIMULCAST_SIZE_EXPERIMENT_H_ + +#include "absl/types/optional.h" + +namespace webrtc { +class NormalizeSimulcastSizeExperiment { + public: + // Returns the base two exponent from field trial. + static absl::optional<int> GetBase2Exponent(); +}; + +} // namespace webrtc + +#endif // RTC_BASE_EXPERIMENTS_NORMALIZE_SIMULCAST_SIZE_EXPERIMENT_H_ diff --git a/third_party/libwebrtc/rtc_base/experiments/normalize_simulcast_size_experiment_gn/moz.build b/third_party/libwebrtc/rtc_base/experiments/normalize_simulcast_size_experiment_gn/moz.build new file mode 100644 index 0000000000..68ad8a0f14 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/normalize_simulcast_size_experiment_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/rtc_base/experiments/normalize_simulcast_size_experiment.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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("normalize_simulcast_size_experiment_gn") diff --git a/third_party/libwebrtc/rtc_base/experiments/normalize_simulcast_size_experiment_unittest.cc b/third_party/libwebrtc/rtc_base/experiments/normalize_simulcast_size_experiment_unittest.cc new file mode 100644 index 0000000000..34e07427cf --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/normalize_simulcast_size_experiment_unittest.cc @@ -0,0 +1,59 @@ +/* + * 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. + */ + +#include "rtc_base/experiments/normalize_simulcast_size_experiment.h" + +#include "test/field_trial.h" +#include "test/gtest.h" + +namespace webrtc { + +TEST(NormalizeSimulcastSizeExperimentTest, GetExponent) { + webrtc::test::ScopedFieldTrials field_trials( + "WebRTC-NormalizeSimulcastResolution/Enabled-2/"); + EXPECT_EQ(2, NormalizeSimulcastSizeExperiment::GetBase2Exponent()); +} + +TEST(NormalizeSimulcastSizeExperimentTest, GetExponentWithTwoParameters) { + webrtc::test::ScopedFieldTrials field_trials( + "WebRTC-NormalizeSimulcastResolution/Enabled-3-4/"); + EXPECT_EQ(3, NormalizeSimulcastSizeExperiment::GetBase2Exponent()); +} + +TEST(NormalizeSimulcastSizeExperimentTest, GetExponentFailsIfNotEnabled) { + webrtc::test::ScopedFieldTrials field_trials( + "WebRTC-NormalizeSimulcastResolution/Disabled/"); + EXPECT_FALSE(NormalizeSimulcastSizeExperiment::GetBase2Exponent()); +} + +TEST(NormalizeSimulcastSizeExperimentTest, + GetExponentFailsForInvalidFieldTrial) { + webrtc::test::ScopedFieldTrials field_trials( + "WebRTC-NormalizeSimulcastResolution/Enabled-invalid/"); + EXPECT_FALSE(NormalizeSimulcastSizeExperiment::GetBase2Exponent()); +} + +TEST(NormalizeSimulcastSizeExperimentTest, + GetExponentFailsForNegativeOutOfBoundValue) { + // Supported range: [0, 5]. + webrtc::test::ScopedFieldTrials field_trials( + "WebRTC-NormalizeSimulcastResolution/Enabled--1/"); + EXPECT_FALSE(NormalizeSimulcastSizeExperiment::GetBase2Exponent()); +} + +TEST(NormalizeSimulcastSizeExperimentTest, + GetExponentFailsForPositiveOutOfBoundValue) { + // Supported range: [0, 5]. + webrtc::test::ScopedFieldTrials field_trials( + "WebRTC-NormalizeSimulcastResolution/Enabled-6/"); + EXPECT_FALSE(NormalizeSimulcastSizeExperiment::GetBase2Exponent()); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/experiments/quality_rampup_experiment.cc b/third_party/libwebrtc/rtc_base/experiments/quality_rampup_experiment.cc new file mode 100644 index 0000000000..509ba91dc3 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/quality_rampup_experiment.cc @@ -0,0 +1,82 @@ +/* + * 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. + */ + +#include "rtc_base/experiments/quality_rampup_experiment.h" + +#include <algorithm> + +#include "api/transport/field_trial_based_config.h" +#include "rtc_base/logging.h" + +namespace webrtc { + +QualityRampupExperiment::QualityRampupExperiment( + const FieldTrialsView* const key_value_config) + : min_pixels_("min_pixels"), + min_duration_ms_("min_duration_ms"), + max_bitrate_factor_("max_bitrate_factor") { + ParseFieldTrial( + {&min_pixels_, &min_duration_ms_, &max_bitrate_factor_}, + key_value_config->Lookup("WebRTC-Video-QualityRampupSettings")); +} + +QualityRampupExperiment QualityRampupExperiment::ParseSettings() { + FieldTrialBasedConfig field_trial_config; + return QualityRampupExperiment(&field_trial_config); +} + +absl::optional<int> QualityRampupExperiment::MinPixels() const { + return min_pixels_.GetOptional(); +} + +absl::optional<int> QualityRampupExperiment::MinDurationMs() const { + return min_duration_ms_.GetOptional(); +} + +absl::optional<double> QualityRampupExperiment::MaxBitrateFactor() const { + return max_bitrate_factor_.GetOptional(); +} + +void QualityRampupExperiment::SetMaxBitrate(int pixels, + uint32_t max_bitrate_kbps) { + if (!min_pixels_ || pixels < min_pixels_.Value() || max_bitrate_kbps == 0) { + return; + } + max_bitrate_kbps_ = std::max(max_bitrate_kbps_.value_or(0), max_bitrate_kbps); +} + +bool QualityRampupExperiment::BwHigh(int64_t now_ms, + uint32_t available_bw_kbps) { + if (!min_pixels_ || !min_duration_ms_ || !max_bitrate_kbps_) { + return false; + } + + if (available_bw_kbps < + max_bitrate_kbps_.value() * MaxBitrateFactor().value_or(1)) { + start_ms_.reset(); + return false; + } + + if (!start_ms_) + start_ms_ = now_ms; + + return (now_ms - *start_ms_) >= min_duration_ms_.Value(); +} + +void QualityRampupExperiment::Reset() { + start_ms_.reset(); + max_bitrate_kbps_.reset(); +} + +bool QualityRampupExperiment::Enabled() const { + return min_pixels_ && min_duration_ms_; +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/experiments/quality_rampup_experiment.h b/third_party/libwebrtc/rtc_base/experiments/quality_rampup_experiment.h new file mode 100644 index 0000000000..e8048a3c1c --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/quality_rampup_experiment.h @@ -0,0 +1,53 @@ +/* + * 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 RTC_BASE_EXPERIMENTS_QUALITY_RAMPUP_EXPERIMENT_H_ +#define RTC_BASE_EXPERIMENTS_QUALITY_RAMPUP_EXPERIMENT_H_ + +#include "absl/types/optional.h" +#include "api/field_trials_view.h" +#include "rtc_base/experiments/field_trial_parser.h" + +namespace webrtc { + +class QualityRampupExperiment final { + public: + static QualityRampupExperiment ParseSettings(); + + absl::optional<int> MinPixels() const; + absl::optional<int> MinDurationMs() const; + absl::optional<double> MaxBitrateFactor() const; + + // Sets the max bitrate and the frame size. + // The call has no effect if the frame size is less than `min_pixels_`. + void SetMaxBitrate(int pixels, uint32_t max_bitrate_kbps); + + // Returns true if the available bandwidth is a certain percentage + // (max_bitrate_factor_) above `max_bitrate_kbps_` for `min_duration_ms_`. + bool BwHigh(int64_t now_ms, uint32_t available_bw_kbps); + + void Reset(); + bool Enabled() const; + + private: + explicit QualityRampupExperiment( + const FieldTrialsView* const key_value_config); + + FieldTrialOptional<int> min_pixels_; + FieldTrialOptional<int> min_duration_ms_; + FieldTrialOptional<double> max_bitrate_factor_; + + absl::optional<int64_t> start_ms_; + absl::optional<uint32_t> max_bitrate_kbps_; +}; + +} // namespace webrtc + +#endif // RTC_BASE_EXPERIMENTS_QUALITY_RAMPUP_EXPERIMENT_H_ diff --git a/third_party/libwebrtc/rtc_base/experiments/quality_rampup_experiment_gn/moz.build b/third_party/libwebrtc/rtc_base/experiments/quality_rampup_experiment_gn/moz.build new file mode 100644 index 0000000000..c4b1f5bc22 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/quality_rampup_experiment_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/rtc_base/experiments/quality_rampup_experiment.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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("quality_rampup_experiment_gn") diff --git a/third_party/libwebrtc/rtc_base/experiments/quality_rampup_experiment_unittest.cc b/third_party/libwebrtc/rtc_base/experiments/quality_rampup_experiment_unittest.cc new file mode 100644 index 0000000000..b0ede34791 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/quality_rampup_experiment_unittest.cc @@ -0,0 +1,139 @@ +/* + * 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 "rtc_base/experiments/quality_rampup_experiment.h" + +#include "test/field_trial.h" +#include "test/gtest.h" + +namespace webrtc { +namespace { + +class QualityRampupExperimentTest : public ::testing::Test { + protected: + int64_t NowMs() const { return current_ms_; } + int64_t AdvanceMs(int64_t delta_ms) { + current_ms_ += delta_ms; + return current_ms_; + } + int64_t current_ms_ = 2345; +}; + +TEST_F(QualityRampupExperimentTest, ValuesNotSetByDefault) { + const auto settings = QualityRampupExperiment::ParseSettings(); + EXPECT_FALSE(settings.MinPixels()); + EXPECT_FALSE(settings.MinDurationMs()); + EXPECT_FALSE(settings.MaxBitrateFactor()); +} + +TEST_F(QualityRampupExperimentTest, ParseMinPixels) { + test::ScopedFieldTrials field_trials( + "WebRTC-Video-QualityRampupSettings/min_pixels:10000/"); + EXPECT_EQ(10000, QualityRampupExperiment::ParseSettings().MinPixels()); +} + +TEST_F(QualityRampupExperimentTest, ParseMinDuration) { + test::ScopedFieldTrials field_trials( + "WebRTC-Video-QualityRampupSettings/min_duration_ms:987/"); + EXPECT_EQ(987, QualityRampupExperiment::ParseSettings().MinDurationMs()); +} + +TEST_F(QualityRampupExperimentTest, ParseMaxBitrateFactor) { + test::ScopedFieldTrials field_trials( + "WebRTC-Video-QualityRampupSettings/max_bitrate_factor:1.23/"); + EXPECT_EQ(1.23, QualityRampupExperiment::ParseSettings().MaxBitrateFactor()); +} + +TEST_F(QualityRampupExperimentTest, ReportsBwHighWhenDurationPassed) { + test::ScopedFieldTrials field_trials( + "WebRTC-Video-QualityRampupSettings/" + "min_pixels:10000,min_duration_ms:2000/"); + auto exp = QualityRampupExperiment::ParseSettings(); + EXPECT_EQ(10000, exp.MinPixels()); + EXPECT_EQ(2000, exp.MinDurationMs()); + + const uint32_t kMaxKbps = 800; + exp.SetMaxBitrate(/*pixels*/ 10000, kMaxKbps); + + const uint32_t kAvailableKbps = kMaxKbps; + EXPECT_FALSE(exp.BwHigh(NowMs(), kAvailableKbps)); + EXPECT_FALSE(exp.BwHigh(AdvanceMs(2000 - 1), kAvailableKbps)); + EXPECT_TRUE(exp.BwHigh(AdvanceMs(1), kAvailableKbps)); +} + +TEST_F(QualityRampupExperimentTest, UsesMaxSetBitrate) { + test::ScopedFieldTrials field_trials( + "WebRTC-Video-QualityRampupSettings/" + "min_pixels:10000,min_duration_ms:2000/"); + auto exp = QualityRampupExperiment::ParseSettings(); + + const uint32_t kMaxKbps = 800; + exp.SetMaxBitrate(/*pixels*/ 10000, kMaxKbps); + exp.SetMaxBitrate(/*pixels*/ 10000, kMaxKbps - 1); + + EXPECT_FALSE(exp.BwHigh(NowMs(), kMaxKbps - 1)); + EXPECT_FALSE(exp.BwHigh(AdvanceMs(2000), kMaxKbps - 1)); + EXPECT_FALSE(exp.BwHigh(AdvanceMs(1), kMaxKbps)); + EXPECT_TRUE(exp.BwHigh(AdvanceMs(2000), kMaxKbps)); +} + +TEST_F(QualityRampupExperimentTest, DoesNotReportBwHighIfBelowMinPixels) { + test::ScopedFieldTrials field_trials( + "WebRTC-Video-QualityRampupSettings/" + "min_pixels:10000,min_duration_ms:2000/"); + auto exp = QualityRampupExperiment::ParseSettings(); + + const uint32_t kMaxKbps = 800; + exp.SetMaxBitrate(/*pixels*/ 9999, kMaxKbps); + + const uint32_t kAvailableKbps = kMaxKbps; + EXPECT_FALSE(exp.BwHigh(NowMs(), kAvailableKbps)); + EXPECT_FALSE(exp.BwHigh(AdvanceMs(2000), kAvailableKbps)); +} + +TEST_F(QualityRampupExperimentTest, ReportsBwHighWithMaxBitrateFactor) { + test::ScopedFieldTrials field_trials( + "WebRTC-Video-QualityRampupSettings/" + "min_pixels:10000,min_duration_ms:2000,max_bitrate_factor:1.5/"); + auto exp = QualityRampupExperiment::ParseSettings(); + EXPECT_EQ(10000, exp.MinPixels()); + EXPECT_EQ(2000, exp.MinDurationMs()); + EXPECT_EQ(1.5, exp.MaxBitrateFactor()); + + const uint32_t kMaxKbps = 800; + exp.SetMaxBitrate(/*pixels*/ 10000, kMaxKbps); + + const uint32_t kAvailableKbps = kMaxKbps * 1.5; + EXPECT_FALSE(exp.BwHigh(NowMs(), kAvailableKbps - 1)); + EXPECT_FALSE(exp.BwHigh(AdvanceMs(2000), kAvailableKbps - 1)); + EXPECT_FALSE(exp.BwHigh(AdvanceMs(1), kAvailableKbps)); + EXPECT_TRUE(exp.BwHigh(AdvanceMs(2000), kAvailableKbps)); +} + +TEST_F(QualityRampupExperimentTest, ReportsBwHigh) { + test::ScopedFieldTrials field_trials( + "WebRTC-Video-QualityRampupSettings/" + "min_pixels:10000,min_duration_ms:2000/"); + auto exp = QualityRampupExperiment::ParseSettings(); + + const uint32_t kMaxKbps = 800; + exp.SetMaxBitrate(/*pixels*/ 10000, kMaxKbps); + + const uint32_t kAvailableKbps = kMaxKbps; + EXPECT_FALSE(exp.BwHigh(NowMs(), kAvailableKbps)); + EXPECT_FALSE(exp.BwHigh(AdvanceMs(2000 - 1), kAvailableKbps)); + EXPECT_FALSE(exp.BwHigh(AdvanceMs(1), kAvailableKbps - 1)); // Below, reset. + EXPECT_FALSE(exp.BwHigh(AdvanceMs(1), kAvailableKbps)); + EXPECT_FALSE(exp.BwHigh(AdvanceMs(2000 - 1), kAvailableKbps)); + EXPECT_TRUE(exp.BwHigh(AdvanceMs(1), kAvailableKbps)); +} + +} // namespace +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/experiments/quality_scaler_settings.cc b/third_party/libwebrtc/rtc_base/experiments/quality_scaler_settings.cc new file mode 100644 index 0000000000..24da211d89 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/quality_scaler_settings.cc @@ -0,0 +1,96 @@ +/* + * 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. + */ + +#include "rtc_base/experiments/quality_scaler_settings.h" + +#include "api/field_trials_view.h" +#include "rtc_base/logging.h" + +namespace webrtc { +namespace { +const int kMinFrames = 10; +const double kMinScaleFactor = 0.01; +} // namespace + +QualityScalerSettings::QualityScalerSettings( + const FieldTrialsView& field_trials) + : sampling_period_ms_("sampling_period_ms"), + average_qp_window_("average_qp_window"), + min_frames_("min_frames"), + initial_scale_factor_("initial_scale_factor"), + scale_factor_("scale_factor"), + initial_bitrate_interval_ms_("initial_bitrate_interval_ms"), + initial_bitrate_factor_("initial_bitrate_factor") { + ParseFieldTrial({&sampling_period_ms_, &average_qp_window_, &min_frames_, + &initial_scale_factor_, &scale_factor_, + &initial_bitrate_interval_ms_, &initial_bitrate_factor_}, + field_trials.Lookup("WebRTC-Video-QualityScalerSettings")); +} + +absl::optional<int> QualityScalerSettings::SamplingPeriodMs() const { + if (sampling_period_ms_ && sampling_period_ms_.Value() <= 0) { + RTC_LOG(LS_WARNING) << "Unsupported sampling_period_ms value, ignored."; + return absl::nullopt; + } + return sampling_period_ms_.GetOptional(); +} + +absl::optional<int> QualityScalerSettings::AverageQpWindow() const { + if (average_qp_window_ && average_qp_window_.Value() <= 0) { + RTC_LOG(LS_WARNING) << "Unsupported average_qp_window value, ignored."; + return absl::nullopt; + } + return average_qp_window_.GetOptional(); +} + +absl::optional<int> QualityScalerSettings::MinFrames() const { + if (min_frames_ && min_frames_.Value() < kMinFrames) { + RTC_LOG(LS_WARNING) << "Unsupported min_frames value, ignored."; + return absl::nullopt; + } + return min_frames_.GetOptional(); +} + +absl::optional<double> QualityScalerSettings::InitialScaleFactor() const { + if (initial_scale_factor_ && + initial_scale_factor_.Value() < kMinScaleFactor) { + RTC_LOG(LS_WARNING) << "Unsupported initial_scale_factor value, ignored."; + return absl::nullopt; + } + return initial_scale_factor_.GetOptional(); +} + +absl::optional<double> QualityScalerSettings::ScaleFactor() const { + if (scale_factor_ && scale_factor_.Value() < kMinScaleFactor) { + RTC_LOG(LS_WARNING) << "Unsupported scale_factor value, ignored."; + return absl::nullopt; + } + return scale_factor_.GetOptional(); +} + +absl::optional<int> QualityScalerSettings::InitialBitrateIntervalMs() const { + if (initial_bitrate_interval_ms_ && + initial_bitrate_interval_ms_.Value() < 0) { + RTC_LOG(LS_WARNING) << "Unsupported bitrate_interval value, ignored."; + return absl::nullopt; + } + return initial_bitrate_interval_ms_.GetOptional(); +} + +absl::optional<double> QualityScalerSettings::InitialBitrateFactor() const { + if (initial_bitrate_factor_ && + initial_bitrate_factor_.Value() < kMinScaleFactor) { + RTC_LOG(LS_WARNING) << "Unsupported initial_bitrate_factor value, ignored."; + return absl::nullopt; + } + return initial_bitrate_factor_.GetOptional(); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/experiments/quality_scaler_settings.h b/third_party/libwebrtc/rtc_base/experiments/quality_scaler_settings.h new file mode 100644 index 0000000000..1085816697 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/quality_scaler_settings.h @@ -0,0 +1,44 @@ +/* + * 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 RTC_BASE_EXPERIMENTS_QUALITY_SCALER_SETTINGS_H_ +#define RTC_BASE_EXPERIMENTS_QUALITY_SCALER_SETTINGS_H_ + +#include "absl/types/optional.h" +#include "api/field_trials_view.h" +#include "rtc_base/experiments/field_trial_parser.h" + +namespace webrtc { + +class QualityScalerSettings final { + public: + explicit QualityScalerSettings(const FieldTrialsView& field_trials); + + absl::optional<int> SamplingPeriodMs() const; + absl::optional<int> AverageQpWindow() const; + absl::optional<int> MinFrames() const; + absl::optional<double> InitialScaleFactor() const; + absl::optional<double> ScaleFactor() const; + absl::optional<int> InitialBitrateIntervalMs() const; + absl::optional<double> InitialBitrateFactor() const; + + private: + FieldTrialOptional<int> sampling_period_ms_; + FieldTrialOptional<int> average_qp_window_; + FieldTrialOptional<int> min_frames_; + FieldTrialOptional<double> initial_scale_factor_; + FieldTrialOptional<double> scale_factor_; + FieldTrialOptional<int> initial_bitrate_interval_ms_; + FieldTrialOptional<double> initial_bitrate_factor_; +}; + +} // namespace webrtc + +#endif // RTC_BASE_EXPERIMENTS_QUALITY_SCALER_SETTINGS_H_ diff --git a/third_party/libwebrtc/rtc_base/experiments/quality_scaler_settings_gn/moz.build b/third_party/libwebrtc/rtc_base/experiments/quality_scaler_settings_gn/moz.build new file mode 100644 index 0000000000..298ca9297c --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/quality_scaler_settings_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/rtc_base/experiments/quality_scaler_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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("quality_scaler_settings_gn") diff --git a/third_party/libwebrtc/rtc_base/experiments/quality_scaler_settings_unittest.cc b/third_party/libwebrtc/rtc_base/experiments/quality_scaler_settings_unittest.cc new file mode 100644 index 0000000000..578fe97b03 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/quality_scaler_settings_unittest.cc @@ -0,0 +1,100 @@ +/* + * 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 "rtc_base/experiments/quality_scaler_settings.h" + +#include "test/gtest.h" +#include "test/scoped_key_value_config.h" + +namespace webrtc { +namespace { + +TEST(QualityScalerSettingsTest, ValuesNotSetByDefault) { + webrtc::test::ScopedKeyValueConfig field_trials(""); + const auto settings = QualityScalerSettings(field_trials); + EXPECT_FALSE(settings.MinFrames()); + EXPECT_FALSE(settings.InitialScaleFactor()); + EXPECT_FALSE(settings.ScaleFactor()); + EXPECT_FALSE(settings.InitialBitrateIntervalMs()); + EXPECT_FALSE(settings.InitialBitrateFactor()); +} + +TEST(QualityScalerSettingsTest, ParseMinFrames) { + test::ScopedKeyValueConfig field_trials( + "WebRTC-Video-QualityScalerSettings/min_frames:100/"); + EXPECT_EQ(100, QualityScalerSettings(field_trials).MinFrames()); +} + +TEST(QualityScalerSettingsTest, ParseInitialScaleFactor) { + test::ScopedKeyValueConfig field_trials( + "WebRTC-Video-QualityScalerSettings/initial_scale_factor:1.5/"); + EXPECT_EQ(1.5, QualityScalerSettings(field_trials).InitialScaleFactor()); +} + +TEST(QualityScalerSettingsTest, ParseScaleFactor) { + test::ScopedKeyValueConfig field_trials( + "WebRTC-Video-QualityScalerSettings/scale_factor:1.1/"); + EXPECT_EQ(1.1, QualityScalerSettings(field_trials).ScaleFactor()); +} + +TEST(QualityScalerSettingsTest, ParseInitialBitrateInterval) { + test::ScopedKeyValueConfig field_trials( + "WebRTC-Video-QualityScalerSettings/initial_bitrate_interval_ms:1000/"); + EXPECT_EQ(1000, + QualityScalerSettings(field_trials).InitialBitrateIntervalMs()); +} + +TEST(QualityScalerSettingsTest, ParseInitialBitrateFactor) { + test::ScopedKeyValueConfig field_trials( + "WebRTC-Video-QualityScalerSettings/initial_bitrate_factor:0.75/"); + EXPECT_EQ(0.75, QualityScalerSettings(field_trials).InitialBitrateFactor()); +} + +TEST(QualityScalerSettingsTest, ParseAll) { + test::ScopedKeyValueConfig field_trials( + "WebRTC-Video-QualityScalerSettings/" + "min_frames:100,initial_scale_factor:1.5,scale_factor:0.9," + "initial_bitrate_interval_ms:5500,initial_bitrate_factor:0.7/"); + const auto settings = QualityScalerSettings(field_trials); + EXPECT_EQ(100, settings.MinFrames()); + EXPECT_EQ(1.5, settings.InitialScaleFactor()); + EXPECT_EQ(0.9, settings.ScaleFactor()); + EXPECT_EQ(5500, settings.InitialBitrateIntervalMs()); + EXPECT_EQ(0.7, settings.InitialBitrateFactor()); +} + +TEST(QualityScalerSettingsTest, DoesNotParseIncorrectValue) { + test::ScopedKeyValueConfig field_trials( + "WebRTC-Video-QualityScalerSettings/" + "min_frames:a,initial_scale_factor:b,scale_factor:c," + "initial_bitrate_interval_ms:d,initial_bitrate_factor:e/"); + const auto settings = QualityScalerSettings(field_trials); + EXPECT_FALSE(settings.MinFrames()); + EXPECT_FALSE(settings.InitialScaleFactor()); + EXPECT_FALSE(settings.ScaleFactor()); + EXPECT_FALSE(settings.InitialBitrateIntervalMs()); + EXPECT_FALSE(settings.InitialBitrateFactor()); +} + +TEST(QualityScalerSettingsTest, DoesNotReturnTooSmallValue) { + test::ScopedKeyValueConfig field_trials( + "WebRTC-Video-QualityScalerSettings/" + "min_frames:0,initial_scale_factor:0.0,scale_factor:0.0," + "initial_bitrate_interval_ms:-1,initial_bitrate_factor:0.0/"); + const auto settings = QualityScalerSettings(field_trials); + EXPECT_FALSE(settings.MinFrames()); + EXPECT_FALSE(settings.InitialScaleFactor()); + EXPECT_FALSE(settings.ScaleFactor()); + EXPECT_FALSE(settings.InitialBitrateIntervalMs()); + EXPECT_FALSE(settings.InitialBitrateFactor()); +} + +} // namespace +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/experiments/quality_scaling_experiment.cc b/third_party/libwebrtc/rtc_base/experiments/quality_scaling_experiment.cc new file mode 100644 index 0000000000..ee3d7c0320 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/quality_scaling_experiment.cc @@ -0,0 +1,117 @@ +/* + * 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. + */ +#include "rtc_base/experiments/quality_scaling_experiment.h" + +#include <stdio.h> + +#include <string> + +#include "absl/strings/match.h" +#include "api/field_trials_view.h" +#include "api/transport/field_trial_based_config.h" +#include "rtc_base/logging.h" + +namespace webrtc { +namespace { +constexpr char kFieldTrial[] = "WebRTC-Video-QualityScaling"; +constexpr int kMinQp = 1; +constexpr int kMaxVp8Qp = 127; +constexpr int kMaxVp9Qp = 255; +constexpr int kMaxH264Qp = 51; +constexpr int kMaxGenericQp = 255; + +#if !defined(WEBRTC_IOS) +constexpr char kDefaultQualityScalingSetttings[] = + "Enabled-29,95,149,205,24,37,26,36,0.9995,0.9999,1"; +#endif + +absl::optional<VideoEncoder::QpThresholds> GetThresholds(int low, + int high, + int max) { + if (low < kMinQp || high > max || high < low) + return absl::nullopt; + + RTC_LOG(LS_INFO) << "QP thresholds: low: " << low << ", high: " << high; + return absl::optional<VideoEncoder::QpThresholds>( + VideoEncoder::QpThresholds(low, high)); +} +} // namespace + +bool QualityScalingExperiment::Enabled(const FieldTrialsView& field_trials) { +#if defined(WEBRTC_IOS) + return absl::StartsWith(field_trials.Lookup(kFieldTrial), "Enabled"); +#else + return !absl::StartsWith(field_trials.Lookup(kFieldTrial), "Disabled"); +#endif +} + +absl::optional<QualityScalingExperiment::Settings> +QualityScalingExperiment::ParseSettings(const FieldTrialsView& field_trials) { + std::string group = field_trials.Lookup(kFieldTrial); + // TODO(http://crbug.com/webrtc/12401): Completely remove the experiment code + // after few releases. +#if !defined(WEBRTC_IOS) + if (group.empty()) + group = kDefaultQualityScalingSetttings; +#endif + Settings s; + if (sscanf(group.c_str(), "Enabled-%d,%d,%d,%d,%d,%d,%d,%d,%f,%f,%d", + &s.vp8_low, &s.vp8_high, &s.vp9_low, &s.vp9_high, &s.h264_low, + &s.h264_high, &s.generic_low, &s.generic_high, &s.alpha_high, + &s.alpha_low, &s.drop) != 11) { + RTC_LOG(LS_WARNING) << "Invalid number of parameters provided."; + return absl::nullopt; + } + return s; +} + +absl::optional<VideoEncoder::QpThresholds> +QualityScalingExperiment::GetQpThresholds(VideoCodecType codec_type, + const FieldTrialsView& field_trials) { + const auto settings = ParseSettings(field_trials); + if (!settings) + return absl::nullopt; + + switch (codec_type) { + case kVideoCodecVP8: + return GetThresholds(settings->vp8_low, settings->vp8_high, kMaxVp8Qp); + case kVideoCodecVP9: + return GetThresholds(settings->vp9_low, settings->vp9_high, kMaxVp9Qp); + case kVideoCodecH265: + // TODO(bugs.webrtc.org/13485): Use H264 QP thresholds for now. + case kVideoCodecH264: + return GetThresholds(settings->h264_low, settings->h264_high, kMaxH264Qp); + case kVideoCodecGeneric: + return GetThresholds(settings->generic_low, settings->generic_high, + kMaxGenericQp); + default: + return absl::nullopt; + } +} + +QualityScalingExperiment::Config QualityScalingExperiment::GetConfig( + const FieldTrialsView& field_trials) { + const auto settings = ParseSettings(field_trials); + if (!settings) + return Config(); + + Config config; + config.use_all_drop_reasons = settings->drop > 0; + + if (settings->alpha_high < 0 || settings->alpha_low < settings->alpha_high) { + RTC_LOG(LS_WARNING) << "Invalid alpha value provided, using default."; + return config; + } + config.alpha_high = settings->alpha_high; + config.alpha_low = settings->alpha_low; + return config; +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/experiments/quality_scaling_experiment.h b/third_party/libwebrtc/rtc_base/experiments/quality_scaling_experiment.h new file mode 100644 index 0000000000..bd24c06e55 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/quality_scaling_experiment.h @@ -0,0 +1,61 @@ +/* + * 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 RTC_BASE_EXPERIMENTS_QUALITY_SCALING_EXPERIMENT_H_ +#define RTC_BASE_EXPERIMENTS_QUALITY_SCALING_EXPERIMENT_H_ + +#include "absl/types/optional.h" +#include "api/field_trials_view.h" +#include "api/video_codecs/video_encoder.h" + +namespace webrtc { +class QualityScalingExperiment { + public: + struct Settings { + int vp8_low; // VP8: low QP threshold. + int vp8_high; // VP8: high QP threshold. + int vp9_low; // VP9: low QP threshold. + int vp9_high; // VP9: high QP threshold. + int h264_low; // H264: low QP threshold. + int h264_high; // H264: high QP threshold. + int generic_low; // Generic: low QP threshold. + int generic_high; // Generic: high QP threshold. + float alpha_high; // `alpha_` for ExpFilter used when checking high QP. + float alpha_low; // `alpha_` for ExpFilter used when checking low QP. + int drop; // >0 sets `use_all_drop_reasons` to true. + }; + + // Used by QualityScaler. + struct Config { + float alpha_high = 0.9995f; + float alpha_low = 0.9999f; + // If set, all type of dropped frames are used. + // Otherwise only dropped frames by MediaOptimization are used. + bool use_all_drop_reasons = false; + }; + + // Returns true if the experiment is enabled. + static bool Enabled(const FieldTrialsView& field_trials); + + // Returns settings from field trial. + static absl::optional<Settings> ParseSettings( + const FieldTrialsView& field_trials); + + // Returns QpThresholds for the `codec_type`. + static absl::optional<VideoEncoder::QpThresholds> GetQpThresholds( + VideoCodecType codec_type, + const FieldTrialsView& field_trials); + + // Returns parsed values. If the parsing fails, default values are returned. + static Config GetConfig(const FieldTrialsView& field_trials); +}; + +} // namespace webrtc + +#endif // RTC_BASE_EXPERIMENTS_QUALITY_SCALING_EXPERIMENT_H_ diff --git a/third_party/libwebrtc/rtc_base/experiments/quality_scaling_experiment_gn/moz.build b/third_party/libwebrtc/rtc_base/experiments/quality_scaling_experiment_gn/moz.build new file mode 100644 index 0000000000..d606a38148 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/quality_scaling_experiment_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/rtc_base/experiments/quality_scaling_experiment.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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("quality_scaling_experiment_gn") diff --git a/third_party/libwebrtc/rtc_base/experiments/quality_scaling_experiment_unittest.cc b/third_party/libwebrtc/rtc_base/experiments/quality_scaling_experiment_unittest.cc new file mode 100644 index 0000000000..0c1450557a --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/quality_scaling_experiment_unittest.cc @@ -0,0 +1,186 @@ +/* + * 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. + */ + +#include "rtc_base/experiments/quality_scaling_experiment.h" + +#include "test/gtest.h" +#include "test/scoped_key_value_config.h" + +namespace webrtc { +namespace { +void ExpectEqualSettings(QualityScalingExperiment::Settings a, + QualityScalingExperiment::Settings b) { + EXPECT_EQ(a.vp8_low, b.vp8_low); + EXPECT_EQ(a.vp8_high, b.vp8_high); + EXPECT_EQ(a.vp9_low, b.vp9_low); + EXPECT_EQ(a.vp9_high, b.vp9_high); + EXPECT_EQ(a.h264_low, b.h264_low); + EXPECT_EQ(a.h264_high, b.h264_high); + EXPECT_EQ(a.generic_low, b.generic_low); + EXPECT_EQ(a.generic_high, b.generic_high); + EXPECT_EQ(a.alpha_high, b.alpha_high); + EXPECT_EQ(a.alpha_low, b.alpha_low); + EXPECT_EQ(a.drop, b.drop); +} + +void ExpectEqualConfig(QualityScalingExperiment::Config a, + QualityScalingExperiment::Config b) { + EXPECT_EQ(a.alpha_high, b.alpha_high); + EXPECT_EQ(a.alpha_low, b.alpha_low); + EXPECT_EQ(a.use_all_drop_reasons, b.use_all_drop_reasons); +} +} // namespace + +#if !defined(WEBRTC_IOS) +// TODO(bugs.webrtc.org/12401): investigate why QualityScaler kicks in on iOS. +TEST(QualityScalingExperimentTest, DefaultEnabledWithoutFieldTrial) { + webrtc::test::ScopedKeyValueConfig field_trials(""); + EXPECT_TRUE(QualityScalingExperiment::Enabled(field_trials)); +} +#else +TEST(QualityScalingExperimentTest, DefaultDisabledWithoutFieldTrialIOS) { + webrtc::test::ScopedKeyValueConfig field_trials(""); + EXPECT_FALSE(QualityScalingExperiment::Enabled(field_trials)); +} +#endif + +TEST(QualityScalingExperimentTest, EnabledWithFieldTrial) { + webrtc::test::ScopedKeyValueConfig field_trials( + "WebRTC-Video-QualityScaling/Enabled/"); + EXPECT_TRUE(QualityScalingExperiment::Enabled(field_trials)); +} + +TEST(QualityScalingExperimentTest, ParseSettings) { + const QualityScalingExperiment::Settings kExpected = {1, 2, 3, 4, 5, 6, + 7, 8, 0.9f, 0.99f, 1}; + webrtc::test::ScopedKeyValueConfig field_trials( + "WebRTC-Video-QualityScaling/Enabled-1,2,3,4,5,6,7,8,0.9,0.99,1/"); + const auto settings = QualityScalingExperiment::ParseSettings(field_trials); + EXPECT_TRUE(settings); + ExpectEqualSettings(kExpected, *settings); +} + +#if !defined(WEBRTC_IOS) +// TODO(bugs.webrtc.org/12401): investigate why QualityScaler kicks in on iOS. +TEST(QualityScalingExperimentTest, ParseSettingsUsesDefaultsWithoutFieldTrial) { + webrtc::test::ScopedKeyValueConfig field_trials(""); + // Uses some default hard coded values. + EXPECT_TRUE(QualityScalingExperiment::ParseSettings(field_trials)); +} +#else +TEST(QualityScalingExperimentTest, ParseSettingsFailsWithoutFieldTrial) { + webrtc::test::ScopedKeyValueConfig field_trials(""); + EXPECT_FALSE(QualityScalingExperiment::ParseSettings(field_trials)); +} +#endif + +TEST(QualityScalingExperimentTest, ParseSettingsFailsWithInvalidFieldTrial) { + webrtc::test::ScopedKeyValueConfig field_trials( + "WebRTC-Video-QualityScaling/Enabled-invalid/"); + EXPECT_FALSE(QualityScalingExperiment::ParseSettings(field_trials)); +} + +TEST(QualityScalingExperimentTest, GetConfig) { + webrtc::test::ScopedKeyValueConfig field_trials( + "WebRTC-Video-QualityScaling/Enabled-1,2,3,4,5,6,7,8,0.9,0.99,0/"); + const auto config = QualityScalingExperiment::GetConfig(field_trials); + EXPECT_EQ(0.9f, config.alpha_high); + EXPECT_EQ(0.99f, config.alpha_low); + EXPECT_FALSE(config.use_all_drop_reasons); +} + +TEST(QualityScalingExperimentTest, GetsDefaultConfigForInvalidFieldTrial) { + webrtc::test::ScopedKeyValueConfig field_trials( + "WebRTC-Video-QualityScaling/Enabled-invalid/"); + const auto config = QualityScalingExperiment::GetConfig(field_trials); + ExpectEqualConfig(config, QualityScalingExperiment::Config()); +} + +TEST(QualityScalingExperimentTest, GetsDefaultAlphaForInvalidValue) { + QualityScalingExperiment::Config expected_config; + expected_config.use_all_drop_reasons = true; + webrtc::test::ScopedKeyValueConfig field_trials( + "WebRTC-Video-QualityScaling/Enabled-1,2,3,4,5,6,7,8,0.99,0.9,1/"); + const auto config = QualityScalingExperiment::GetConfig(field_trials); + ExpectEqualConfig(config, expected_config); +} + +TEST(QualityScalingExperimentTest, GetVp8Thresholds) { + webrtc::test::ScopedKeyValueConfig field_trials( + "WebRTC-Video-QualityScaling/Enabled-1,2,3,4,5,6,0,0,0.9,0.99,1/"); + const auto thresholds = + QualityScalingExperiment::GetQpThresholds(kVideoCodecVP8, field_trials); + EXPECT_TRUE(thresholds); + EXPECT_EQ(1, thresholds->low); + EXPECT_EQ(2, thresholds->high); +} + +TEST(QualityScalingExperimentTest, GetThresholdsFailsForInvalidVp8Value) { + webrtc::test::ScopedKeyValueConfig field_trials( + "WebRTC-Video-QualityScaling/Enabled-0,0,3,4,5,6,7,8,0.9,0.99,1/"); + const auto thresholds = + QualityScalingExperiment::GetQpThresholds(kVideoCodecVP8, field_trials); + EXPECT_FALSE(thresholds); +} + +TEST(QualityScalingExperimentTest, GetVp9Thresholds) { + webrtc::test::ScopedKeyValueConfig field_trials( + "WebRTC-Video-QualityScaling/Enabled-1,2,3,4,5,6,0,0,0.9,0.99,1/"); + const auto thresholds = + QualityScalingExperiment::GetQpThresholds(kVideoCodecVP9, field_trials); + EXPECT_TRUE(thresholds); + EXPECT_EQ(3, thresholds->low); + EXPECT_EQ(4, thresholds->high); +} + +TEST(QualityScalingExperimentTest, GetThresholdsFailsForInvalidVp9Value) { + webrtc::test::ScopedKeyValueConfig field_trials( + "WebRTC-Video-QualityScaling/Enabled-1,2,0,0,5,6,7,8,0.9,0.99,1/"); + const auto thresholds = + QualityScalingExperiment::GetQpThresholds(kVideoCodecVP9, field_trials); + EXPECT_FALSE(thresholds); +} + +TEST(QualityScalingExperimentTest, GetH264Thresholds) { + webrtc::test::ScopedKeyValueConfig field_trials( + "WebRTC-Video-QualityScaling/Enabled-1,2,3,4,5,6,0,0,0.9,0.99,1/"); + const auto thresholds = + QualityScalingExperiment::GetQpThresholds(kVideoCodecH264, field_trials); + EXPECT_TRUE(thresholds); + EXPECT_EQ(5, thresholds->low); + EXPECT_EQ(6, thresholds->high); +} + +TEST(QualityScalingExperimentTest, GetThresholdsFailsForInvalidH264Value) { + webrtc::test::ScopedKeyValueConfig field_trials( + "WebRTC-Video-QualityScaling/Enabled-1,2,3,4,0,0,7,8,0.9,0.99,1/"); + const auto thresholds = + QualityScalingExperiment::GetQpThresholds(kVideoCodecH264, field_trials); + EXPECT_FALSE(thresholds); +} + +TEST(QualityScalingExperimentTest, GetGenericThresholds) { + webrtc::test::ScopedKeyValueConfig field_trials( + "WebRTC-Video-QualityScaling/Enabled-1,2,3,4,0,0,7,8,0.9,0.99,1/"); + const auto thresholds = QualityScalingExperiment::GetQpThresholds( + kVideoCodecGeneric, field_trials); + EXPECT_TRUE(thresholds); + EXPECT_EQ(7, thresholds->low); + EXPECT_EQ(8, thresholds->high); +} + +TEST(QualityScalingExperimentTest, GetThresholdsFailsForInvalidGenericValue) { + webrtc::test::ScopedKeyValueConfig field_trials( + "WebRTC-Video-QualityScaling/Enabled-1,2,3,4,5,6,0,0,0.9,0.99,1/"); + const auto thresholds = QualityScalingExperiment::GetQpThresholds( + kVideoCodecGeneric, field_trials); + EXPECT_FALSE(thresholds); +} +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/experiments/rate_control_settings.cc b/third_party/libwebrtc/rtc_base/experiments/rate_control_settings.cc new file mode 100644 index 0000000000..84e7b1bcc1 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/rate_control_settings.cc @@ -0,0 +1,183 @@ +/* + * 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. + */ + +#include "rtc_base/experiments/rate_control_settings.h" + +#include <inttypes.h> +#include <stdio.h> + +#include <string> + +#include "absl/strings/match.h" +#include "api/transport/field_trial_based_config.h" +#include "rtc_base/logging.h" +#include "rtc_base/numerics/safe_conversions.h" + +namespace webrtc { + +namespace { + +const int kDefaultAcceptedQueueMs = 350; + +const int kDefaultMinPushbackTargetBitrateBps = 30000; + +const char kCongestionWindowDefaultFieldTrialString[] = + "QueueSize:350,MinBitrate:30000,DropFrame:true"; + +const char kUseBaseHeavyVp8Tl3RateAllocationFieldTrialName[] = + "WebRTC-UseBaseHeavyVP8TL3RateAllocation"; + +bool IsEnabled(const FieldTrialsView* const key_value_config, + absl::string_view key) { + return absl::StartsWith(key_value_config->Lookup(key), "Enabled"); +} + +} // namespace + +constexpr char CongestionWindowConfig::kKey[]; + +std::unique_ptr<StructParametersParser> CongestionWindowConfig::Parser() { + return StructParametersParser::Create("QueueSize", &queue_size_ms, // + "MinBitrate", &min_bitrate_bps, + "InitWin", &initial_data_window, + "DropFrame", &drop_frame_only); +} + +// static +CongestionWindowConfig CongestionWindowConfig::Parse(absl::string_view config) { + CongestionWindowConfig res; + res.Parser()->Parse(config); + return res; +} + +constexpr char VideoRateControlConfig::kKey[]; + +std::unique_ptr<StructParametersParser> VideoRateControlConfig::Parser() { + // The empty comments ensures that each pair is on a separate line. + return StructParametersParser::Create( + "pacing_factor", &pacing_factor, // + "alr_probing", &alr_probing, // + "vp8_qp_max", &vp8_qp_max, // + "vp8_min_pixels", &vp8_min_pixels, // + "trust_vp8", &trust_vp8, // + "trust_vp9", &trust_vp9, // + "bitrate_adjuster", &bitrate_adjuster, // + "adjuster_use_headroom", &adjuster_use_headroom, // + "vp8_s0_boost", &vp8_s0_boost, // + "vp8_base_heavy_tl3_alloc", &vp8_base_heavy_tl3_alloc); +} + +RateControlSettings::RateControlSettings( + const FieldTrialsView* const key_value_config) { + std::string congestion_window_config = + key_value_config->Lookup(CongestionWindowConfig::kKey).empty() + ? kCongestionWindowDefaultFieldTrialString + : key_value_config->Lookup(CongestionWindowConfig::kKey); + congestion_window_config_ = + CongestionWindowConfig::Parse(congestion_window_config); + video_config_.vp8_base_heavy_tl3_alloc = IsEnabled( + key_value_config, kUseBaseHeavyVp8Tl3RateAllocationFieldTrialName); + video_config_.Parser()->Parse( + key_value_config->Lookup(VideoRateControlConfig::kKey)); +} + +RateControlSettings::~RateControlSettings() = default; +RateControlSettings::RateControlSettings(RateControlSettings&&) = default; + +RateControlSettings RateControlSettings::ParseFromFieldTrials() { + FieldTrialBasedConfig field_trial_config; + return RateControlSettings(&field_trial_config); +} + +RateControlSettings RateControlSettings::ParseFromKeyValueConfig( + const FieldTrialsView* const key_value_config) { + FieldTrialBasedConfig field_trial_config; + return RateControlSettings(key_value_config ? key_value_config + : &field_trial_config); +} + +bool RateControlSettings::UseCongestionWindow() const { + return static_cast<bool>(congestion_window_config_.queue_size_ms); +} + +int64_t RateControlSettings::GetCongestionWindowAdditionalTimeMs() const { + return congestion_window_config_.queue_size_ms.value_or( + kDefaultAcceptedQueueMs); +} + +bool RateControlSettings::UseCongestionWindowPushback() const { + return congestion_window_config_.queue_size_ms && + congestion_window_config_.min_bitrate_bps; +} + +bool RateControlSettings::UseCongestionWindowDropFrameOnly() const { + return congestion_window_config_.drop_frame_only; +} + +uint32_t RateControlSettings::CongestionWindowMinPushbackTargetBitrateBps() + const { + return congestion_window_config_.min_bitrate_bps.value_or( + kDefaultMinPushbackTargetBitrateBps); +} + +absl::optional<DataSize> +RateControlSettings::CongestionWindowInitialDataWindow() const { + return congestion_window_config_.initial_data_window; +} + +absl::optional<double> RateControlSettings::GetPacingFactor() const { + return video_config_.pacing_factor; +} + +bool RateControlSettings::UseAlrProbing() const { + return video_config_.alr_probing; +} + +absl::optional<int> RateControlSettings::LibvpxVp8QpMax() const { + if (video_config_.vp8_qp_max && + (*video_config_.vp8_qp_max < 0 || *video_config_.vp8_qp_max > 63)) { + RTC_LOG(LS_WARNING) << "Unsupported vp8_qp_max_ value, ignored."; + return absl::nullopt; + } + return video_config_.vp8_qp_max; +} + +absl::optional<int> RateControlSettings::LibvpxVp8MinPixels() const { + if (video_config_.vp8_min_pixels && *video_config_.vp8_min_pixels < 1) { + return absl::nullopt; + } + return video_config_.vp8_min_pixels; +} + +bool RateControlSettings::LibvpxVp8TrustedRateController() const { + return video_config_.trust_vp8; +} + +bool RateControlSettings::Vp8BoostBaseLayerQuality() const { + return video_config_.vp8_s0_boost; +} + +bool RateControlSettings::LibvpxVp9TrustedRateController() const { + return video_config_.trust_vp9; +} + +bool RateControlSettings::Vp8BaseHeavyTl3RateAllocation() const { + return video_config_.vp8_base_heavy_tl3_alloc; +} + +bool RateControlSettings::UseEncoderBitrateAdjuster() const { + return video_config_.bitrate_adjuster; +} + +bool RateControlSettings::BitrateAdjusterCanUseNetworkHeadroom() const { + return video_config_.adjuster_use_headroom; +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/experiments/rate_control_settings.h b/third_party/libwebrtc/rtc_base/experiments/rate_control_settings.h new file mode 100644 index 0000000000..05e942d39f --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/rate_control_settings.h @@ -0,0 +1,93 @@ +/* + * 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 RTC_BASE_EXPERIMENTS_RATE_CONTROL_SETTINGS_H_ +#define RTC_BASE_EXPERIMENTS_RATE_CONTROL_SETTINGS_H_ + +#include "absl/types/optional.h" +#include "api/field_trials_view.h" +#include "api/units/data_size.h" +#include "api/video_codecs/video_codec.h" +#include "rtc_base/experiments/struct_parameters_parser.h" +#include "video/config/video_encoder_config.h" + +namespace webrtc { + +struct CongestionWindowConfig { + static constexpr char kKey[] = "WebRTC-CongestionWindow"; + absl::optional<int> queue_size_ms; + absl::optional<int> min_bitrate_bps; + absl::optional<DataSize> initial_data_window; + bool drop_frame_only = false; + std::unique_ptr<StructParametersParser> Parser(); + static CongestionWindowConfig Parse(absl::string_view config); +}; + +struct VideoRateControlConfig { + static constexpr char kKey[] = "WebRTC-VideoRateControl"; + absl::optional<double> pacing_factor; + bool alr_probing = false; + absl::optional<int> vp8_qp_max; + absl::optional<int> vp8_min_pixels; + bool trust_vp8 = true; + bool trust_vp9 = true; + bool bitrate_adjuster = true; + bool adjuster_use_headroom = true; + bool vp8_s0_boost = false; + bool vp8_base_heavy_tl3_alloc = false; + + std::unique_ptr<StructParametersParser> Parser(); +}; + +class RateControlSettings final { + public: + ~RateControlSettings(); + RateControlSettings(RateControlSettings&&); + + static RateControlSettings ParseFromFieldTrials(); + static RateControlSettings ParseFromKeyValueConfig( + const FieldTrialsView* const key_value_config); + + // When CongestionWindowPushback is enabled, the pacer is oblivious to + // the congestion window. The relation between outstanding data and + // the congestion window affects encoder allocations directly. + bool UseCongestionWindow() const; + int64_t GetCongestionWindowAdditionalTimeMs() const; + bool UseCongestionWindowPushback() const; + bool UseCongestionWindowDropFrameOnly() const; + uint32_t CongestionWindowMinPushbackTargetBitrateBps() const; + absl::optional<DataSize> CongestionWindowInitialDataWindow() const; + + absl::optional<double> GetPacingFactor() const; + bool UseAlrProbing() const; + + absl::optional<int> LibvpxVp8QpMax() const; + absl::optional<int> LibvpxVp8MinPixels() const; + bool LibvpxVp8TrustedRateController() const; + bool Vp8BoostBaseLayerQuality() const; + bool Vp8DynamicRateSettings() const; + bool LibvpxVp9TrustedRateController() const; + bool Vp9DynamicRateSettings() const; + + bool Vp8BaseHeavyTl3RateAllocation() const; + + bool UseEncoderBitrateAdjuster() const; + bool BitrateAdjusterCanUseNetworkHeadroom() const; + + private: + explicit RateControlSettings(const FieldTrialsView* const key_value_config); + + CongestionWindowConfig congestion_window_config_; + VideoRateControlConfig video_config_; +}; + +} // namespace webrtc + +#endif // RTC_BASE_EXPERIMENTS_RATE_CONTROL_SETTINGS_H_ diff --git a/third_party/libwebrtc/rtc_base/experiments/rate_control_settings_gn/moz.build b/third_party/libwebrtc/rtc_base/experiments/rate_control_settings_gn/moz.build new file mode 100644 index 0000000000..be85251358 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/rate_control_settings_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/rtc_base/experiments/rate_control_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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("rate_control_settings_gn") diff --git a/third_party/libwebrtc/rtc_base/experiments/rate_control_settings_unittest.cc b/third_party/libwebrtc/rtc_base/experiments/rate_control_settings_unittest.cc new file mode 100644 index 0000000000..91ebf531bd --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/rate_control_settings_unittest.cc @@ -0,0 +1,191 @@ +/* + * 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 "rtc_base/experiments/rate_control_settings.h" + +#include "api/video_codecs/video_codec.h" +#include "test/field_trial.h" +#include "test/gtest.h" +#include "video/config/video_encoder_config.h" + +namespace webrtc { + +namespace { + +TEST(RateControlSettingsTest, CongestionWindow) { + EXPECT_TRUE( + RateControlSettings::ParseFromFieldTrials().UseCongestionWindow()); + + test::ScopedFieldTrials field_trials( + "WebRTC-CongestionWindow/QueueSize:100/"); + const RateControlSettings settings_after = + RateControlSettings::ParseFromFieldTrials(); + EXPECT_TRUE(settings_after.UseCongestionWindow()); + EXPECT_EQ(settings_after.GetCongestionWindowAdditionalTimeMs(), 100); +} + +TEST(RateControlSettingsTest, CongestionWindowPushback) { + EXPECT_TRUE(RateControlSettings::ParseFromFieldTrials() + .UseCongestionWindowPushback()); + + test::ScopedFieldTrials field_trials( + "WebRTC-CongestionWindow/QueueSize:100,MinBitrate:100000/"); + const RateControlSettings settings_after = + RateControlSettings::ParseFromFieldTrials(); + EXPECT_TRUE(settings_after.UseCongestionWindowPushback()); + EXPECT_EQ(settings_after.CongestionWindowMinPushbackTargetBitrateBps(), + 100000u); +} + +TEST(RateControlSettingsTest, CongestionWindowPushbackDropframe) { + EXPECT_TRUE(RateControlSettings::ParseFromFieldTrials() + .UseCongestionWindowPushback()); + + test::ScopedFieldTrials field_trials( + "WebRTC-CongestionWindow/" + "QueueSize:100,MinBitrate:100000,DropFrame:true/"); + const RateControlSettings settings_after = + RateControlSettings::ParseFromFieldTrials(); + EXPECT_TRUE(settings_after.UseCongestionWindowPushback()); + EXPECT_EQ(settings_after.CongestionWindowMinPushbackTargetBitrateBps(), + 100000u); + EXPECT_TRUE(settings_after.UseCongestionWindowDropFrameOnly()); +} + +TEST(RateControlSettingsTest, CongestionWindowPushbackDefaultConfig) { + const RateControlSettings settings = + RateControlSettings::ParseFromFieldTrials(); + EXPECT_TRUE(settings.UseCongestionWindowPushback()); + EXPECT_EQ(settings.CongestionWindowMinPushbackTargetBitrateBps(), 30000u); + EXPECT_TRUE(settings.UseCongestionWindowDropFrameOnly()); +} + +TEST(RateControlSettingsTest, PacingFactor) { + EXPECT_FALSE(RateControlSettings::ParseFromFieldTrials().GetPacingFactor()); + + test::ScopedFieldTrials field_trials( + "WebRTC-VideoRateControl/pacing_factor:1.2/"); + const RateControlSettings settings_after = + RateControlSettings::ParseFromFieldTrials(); + // Need to explicitly dereference the absl::optional + // for the EXPECT_DOUBLE_EQ to compile. + ASSERT_TRUE(settings_after.GetPacingFactor()); + EXPECT_DOUBLE_EQ(*settings_after.GetPacingFactor(), 1.2); +} + +TEST(RateControlSettingsTest, AlrProbing) { + EXPECT_FALSE(RateControlSettings::ParseFromFieldTrials().UseAlrProbing()); + + test::ScopedFieldTrials field_trials( + "WebRTC-VideoRateControl/alr_probing:1/"); + EXPECT_TRUE(RateControlSettings::ParseFromFieldTrials().UseAlrProbing()); +} + +TEST(RateControlSettingsTest, LibvpxVp8QpMax) { + EXPECT_FALSE(RateControlSettings::ParseFromFieldTrials().LibvpxVp8QpMax()); + + test::ScopedFieldTrials field_trials( + "WebRTC-VideoRateControl/vp8_qp_max:50/"); + EXPECT_EQ(RateControlSettings::ParseFromFieldTrials().LibvpxVp8QpMax(), 50); +} + +TEST(RateControlSettingsTest, DoesNotGetTooLargeLibvpxVp8QpMaxValue) { + test::ScopedFieldTrials field_trials( + "WebRTC-VideoRateControl/vp8_qp_max:70/"); + EXPECT_FALSE(RateControlSettings::ParseFromFieldTrials().LibvpxVp8QpMax()); +} + +TEST(RateControlSettingsTest, LibvpxVp8MinPixels) { + EXPECT_FALSE( + RateControlSettings::ParseFromFieldTrials().LibvpxVp8MinPixels()); + + test::ScopedFieldTrials field_trials( + "WebRTC-VideoRateControl/vp8_min_pixels:50000/"); + EXPECT_EQ(RateControlSettings::ParseFromFieldTrials().LibvpxVp8MinPixels(), + 50000); +} + +TEST(RateControlSettingsTest, DoesNotGetTooSmallLibvpxVp8MinPixelValue) { + test::ScopedFieldTrials field_trials( + "WebRTC-VideoRateControl/vp8_min_pixels:0/"); + EXPECT_FALSE( + RateControlSettings::ParseFromFieldTrials().LibvpxVp8MinPixels()); +} + +TEST(RateControlSettingsTest, LibvpxTrustedRateController) { + const RateControlSettings settings_before = + RateControlSettings::ParseFromFieldTrials(); + EXPECT_TRUE(settings_before.LibvpxVp8TrustedRateController()); + EXPECT_TRUE(settings_before.LibvpxVp9TrustedRateController()); + + test::ScopedFieldTrials field_trials( + "WebRTC-VideoRateControl/trust_vp8:0,trust_vp9:0/"); + const RateControlSettings settings_after = + RateControlSettings::ParseFromFieldTrials(); + EXPECT_FALSE(settings_after.LibvpxVp8TrustedRateController()); + EXPECT_FALSE(settings_after.LibvpxVp9TrustedRateController()); +} + +TEST(RateControlSettingsTest, Vp8BaseHeavyTl3RateAllocationLegacyKey) { + const RateControlSettings settings_before = + RateControlSettings::ParseFromFieldTrials(); + EXPECT_FALSE(settings_before.Vp8BaseHeavyTl3RateAllocation()); + + test::ScopedFieldTrials field_trials( + "WebRTC-UseBaseHeavyVP8TL3RateAllocation/Enabled/"); + const RateControlSettings settings_after = + RateControlSettings::ParseFromFieldTrials(); + EXPECT_TRUE(settings_after.Vp8BaseHeavyTl3RateAllocation()); +} + +TEST(RateControlSettingsTest, + Vp8BaseHeavyTl3RateAllocationVideoRateControlKey) { + const RateControlSettings settings_before = + RateControlSettings::ParseFromFieldTrials(); + EXPECT_FALSE(settings_before.Vp8BaseHeavyTl3RateAllocation()); + + test::ScopedFieldTrials field_trials( + "WebRTC-VideoRateControl/vp8_base_heavy_tl3_alloc:1/"); + const RateControlSettings settings_after = + RateControlSettings::ParseFromFieldTrials(); + EXPECT_TRUE(settings_after.Vp8BaseHeavyTl3RateAllocation()); +} + +TEST(RateControlSettingsTest, + Vp8BaseHeavyTl3RateAllocationVideoRateControlKeyOverridesLegacyKey) { + const RateControlSettings settings_before = + RateControlSettings::ParseFromFieldTrials(); + EXPECT_FALSE(settings_before.Vp8BaseHeavyTl3RateAllocation()); + + test::ScopedFieldTrials field_trials( + "WebRTC-UseBaseHeavyVP8TL3RateAllocation/Enabled/WebRTC-VideoRateControl/" + "vp8_base_heavy_tl3_alloc:0/"); + const RateControlSettings settings_after = + RateControlSettings::ParseFromFieldTrials(); + EXPECT_FALSE(settings_after.Vp8BaseHeavyTl3RateAllocation()); +} + +TEST(RateControlSettingsTest, UseEncoderBitrateAdjuster) { + // Should be on by default. + EXPECT_TRUE( + RateControlSettings::ParseFromFieldTrials().UseEncoderBitrateAdjuster()); + + { + // Can be turned off via field trial. + test::ScopedFieldTrials field_trials( + "WebRTC-VideoRateControl/bitrate_adjuster:false/"); + EXPECT_FALSE(RateControlSettings::ParseFromFieldTrials() + .UseEncoderBitrateAdjuster()); + } +} + +} // namespace + +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/experiments/rtt_mult_experiment.cc b/third_party/libwebrtc/rtc_base/experiments/rtt_mult_experiment.cc new file mode 100644 index 0000000000..e15b928937 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/rtt_mult_experiment.cc @@ -0,0 +1,39 @@ +/* + * 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. + */ +#include "rtc_base/experiments/rtt_mult_experiment.h" + +#include <stdio.h> + +#include <algorithm> +#include <string> + +#include "rtc_base/logging.h" +#include "system_wrappers/include/field_trial.h" + +namespace webrtc { + +namespace { +const char kRttMultExperiment[] = "WebRTC-RttMult"; +} // namespace + +bool RttMultExperiment::RttMultEnabled() { + return !field_trial::IsDisabled(kRttMultExperiment); +} + +absl::optional<RttMultExperiment::Settings> +RttMultExperiment::GetRttMultValue() { + if (!RttMultExperiment::RttMultEnabled()) { + return absl::nullopt; + } + return RttMultExperiment::Settings{.rtt_mult_setting = 0.9, + .rtt_mult_add_cap_ms = 200.0}; +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/experiments/rtt_mult_experiment.h b/third_party/libwebrtc/rtc_base/experiments/rtt_mult_experiment.h new file mode 100644 index 0000000000..a868e63e8d --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/rtt_mult_experiment.h @@ -0,0 +1,35 @@ +/* + * 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 RTC_BASE_EXPERIMENTS_RTT_MULT_EXPERIMENT_H_ +#define RTC_BASE_EXPERIMENTS_RTT_MULT_EXPERIMENT_H_ + +#include "absl/types/optional.h" + +namespace webrtc { + +class RttMultExperiment { + public: + struct Settings { + float rtt_mult_setting; // Jitter buffer size is increased by this factor + // times the estimated RTT. + float rtt_mult_add_cap_ms; // Jitter buffer size increase is capped by this + // value. + }; + + // Returns true if the experiment is enabled. + static bool RttMultEnabled(); + + // Returns rtt_mult value and rtt_mult addition cap value from field trial. + static absl::optional<RttMultExperiment::Settings> GetRttMultValue(); +}; + +} // namespace webrtc + +#endif // RTC_BASE_EXPERIMENTS_RTT_MULT_EXPERIMENT_H_ diff --git a/third_party/libwebrtc/rtc_base/experiments/rtt_mult_experiment_gn/moz.build b/third_party/libwebrtc/rtc_base/experiments/rtt_mult_experiment_gn/moz.build new file mode 100644 index 0000000000..7229d639e8 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/rtt_mult_experiment_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/rtc_base/experiments/rtt_mult_experiment.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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("rtt_mult_experiment_gn") diff --git a/third_party/libwebrtc/rtc_base/experiments/rtt_mult_experiment_unittest.cc b/third_party/libwebrtc/rtc_base/experiments/rtt_mult_experiment_unittest.cc new file mode 100644 index 0000000000..a6798a1411 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/rtt_mult_experiment_unittest.cc @@ -0,0 +1,31 @@ +/* + * 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. + */ + +#include "rtc_base/experiments/rtt_mult_experiment.h" + +#include "test/field_trial.h" +#include "test/gtest.h" + +namespace webrtc { + +TEST(RttMultExperimentTest, RttMultEnabledByDefault) { + EXPECT_TRUE(RttMultExperiment::RttMultEnabled()); + ASSERT_TRUE(RttMultExperiment::GetRttMultValue()); + EXPECT_EQ(0.9f, RttMultExperiment::GetRttMultValue()->rtt_mult_setting); + EXPECT_EQ(200.0f, RttMultExperiment::GetRttMultValue()->rtt_mult_add_cap_ms); +} + +TEST(RttMultExperimentTest, RttMultDisabledByFieldTrial) { + webrtc::test::ScopedFieldTrials field_trials("WebRTC-RttMult/Disabled/"); + EXPECT_FALSE(RttMultExperiment::RttMultEnabled()); + EXPECT_FALSE(RttMultExperiment::GetRttMultValue()); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/experiments/stable_target_rate_experiment.cc b/third_party/libwebrtc/rtc_base/experiments/stable_target_rate_experiment.cc new file mode 100644 index 0000000000..fa04fa35b4 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/stable_target_rate_experiment.cc @@ -0,0 +1,63 @@ +/* + * 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 "rtc_base/experiments/stable_target_rate_experiment.h" + +#include "api/transport/field_trial_based_config.h" + +namespace webrtc { +namespace { +constexpr char kFieldTrialName[] = "WebRTC-StableTargetRate"; +} // namespace + +StableTargetRateExperiment::StableTargetRateExperiment( + const FieldTrialsView* const key_value_config, + double default_video_hysteresis, + double default_screenshare_hysteresis) + : enabled_("enabled", false), + video_hysteresis_factor_("video_hysteresis_factor", + default_video_hysteresis), + screenshare_hysteresis_factor_("screenshare_hysteresis_factor", + default_screenshare_hysteresis) { + ParseFieldTrial( + {&enabled_, &video_hysteresis_factor_, &screenshare_hysteresis_factor_}, + key_value_config->Lookup(kFieldTrialName)); +} + +StableTargetRateExperiment::StableTargetRateExperiment( + const StableTargetRateExperiment&) = default; +StableTargetRateExperiment::StableTargetRateExperiment( + StableTargetRateExperiment&&) = default; + +StableTargetRateExperiment StableTargetRateExperiment::ParseFromFieldTrials() { + FieldTrialBasedConfig config; + return ParseFromKeyValueConfig(&config); +} + +StableTargetRateExperiment StableTargetRateExperiment::ParseFromKeyValueConfig( + const FieldTrialsView* const key_value_config) { + return StableTargetRateExperiment(key_value_config, + /*default_video_hysteresis=*/1.2, + /*default_screenshare_hysteresis=*/1.35); +} + +bool StableTargetRateExperiment::IsEnabled() const { + return enabled_.Get(); +} + +double StableTargetRateExperiment::GetVideoHysteresisFactor() const { + return video_hysteresis_factor_.Get(); +} + +double StableTargetRateExperiment::GetScreenshareHysteresisFactor() const { + return screenshare_hysteresis_factor_.Get(); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/experiments/stable_target_rate_experiment.h b/third_party/libwebrtc/rtc_base/experiments/stable_target_rate_experiment.h new file mode 100644 index 0000000000..be0f9da129 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/stable_target_rate_experiment.h @@ -0,0 +1,44 @@ +/* + * 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 RTC_BASE_EXPERIMENTS_STABLE_TARGET_RATE_EXPERIMENT_H_ +#define RTC_BASE_EXPERIMENTS_STABLE_TARGET_RATE_EXPERIMENT_H_ + +#include "api/field_trials_view.h" +#include "rtc_base/experiments/field_trial_parser.h" + +namespace webrtc { + +class StableTargetRateExperiment { + public: + StableTargetRateExperiment(const StableTargetRateExperiment&); + StableTargetRateExperiment(StableTargetRateExperiment&&); + static StableTargetRateExperiment ParseFromFieldTrials(); + static StableTargetRateExperiment ParseFromKeyValueConfig( + const FieldTrialsView* const key_value_config); + + bool IsEnabled() const; + double GetVideoHysteresisFactor() const; + double GetScreenshareHysteresisFactor() const; + + private: + explicit StableTargetRateExperiment( + const FieldTrialsView* const key_value_config, + double default_video_hysteresis, + double default_screenshare_hysteresis); + + FieldTrialParameter<bool> enabled_; + FieldTrialParameter<double> video_hysteresis_factor_; + FieldTrialParameter<double> screenshare_hysteresis_factor_; +}; + +} // namespace webrtc + +#endif // RTC_BASE_EXPERIMENTS_STABLE_TARGET_RATE_EXPERIMENT_H_ diff --git a/third_party/libwebrtc/rtc_base/experiments/stable_target_rate_experiment_gn/moz.build b/third_party/libwebrtc/rtc_base/experiments/stable_target_rate_experiment_gn/moz.build new file mode 100644 index 0000000000..d031f8ace4 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/stable_target_rate_experiment_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/rtc_base/experiments/stable_target_rate_experiment.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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("stable_target_rate_experiment_gn") diff --git a/third_party/libwebrtc/rtc_base/experiments/stable_target_rate_experiment_unittest.cc b/third_party/libwebrtc/rtc_base/experiments/stable_target_rate_experiment_unittest.cc new file mode 100644 index 0000000000..854398e910 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/stable_target_rate_experiment_unittest.cc @@ -0,0 +1,67 @@ +/* + * 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 "rtc_base/experiments/stable_target_rate_experiment.h" + +#include "test/field_trial.h" +#include "test/gtest.h" + +namespace webrtc { + +TEST(StableBweExperimentTest, Default) { + StableTargetRateExperiment config = + StableTargetRateExperiment::ParseFromFieldTrials(); + EXPECT_FALSE(config.IsEnabled()); + EXPECT_EQ(config.GetVideoHysteresisFactor(), 1.2); + EXPECT_EQ(config.GetScreenshareHysteresisFactor(), 1.35); +} + +TEST(StableBweExperimentTest, EnabledNoHysteresis) { + webrtc::test::ScopedFieldTrials field_trials( + "WebRTC-StableTargetRate/enabled:true/"); + + StableTargetRateExperiment config = + StableTargetRateExperiment::ParseFromFieldTrials(); + EXPECT_TRUE(config.IsEnabled()); + EXPECT_EQ(config.GetVideoHysteresisFactor(), 1.2); + EXPECT_EQ(config.GetScreenshareHysteresisFactor(), 1.35); +} + +TEST(StableBweExperimentTest, EnabledWithHysteresis) { + webrtc::test::ScopedFieldTrials field_trials( + "WebRTC-StableTargetRate/" + "enabled:true," + "video_hysteresis_factor:1.1," + "screenshare_hysteresis_factor:1.2/"); + + StableTargetRateExperiment config = + StableTargetRateExperiment::ParseFromFieldTrials(); + EXPECT_TRUE(config.IsEnabled()); + EXPECT_EQ(config.GetVideoHysteresisFactor(), 1.1); + EXPECT_EQ(config.GetScreenshareHysteresisFactor(), 1.2); +} + +TEST(StableBweExperimentTest, HysteresisOverrideVideoRateHystersis) { + webrtc::test::ScopedFieldTrials field_trials( + "WebRTC-StableTargetRate/" + "enabled:true," + "video_hysteresis_factor:1.1," + "screenshare_hysteresis_factor:1.2/" + "WebRTC-VideoRateControl/video_hysteresis:1.3," + "screenshare_hysteresis:1.4/"); + + StableTargetRateExperiment config = + StableTargetRateExperiment::ParseFromFieldTrials(); + EXPECT_TRUE(config.IsEnabled()); + EXPECT_EQ(config.GetVideoHysteresisFactor(), 1.1); + EXPECT_EQ(config.GetScreenshareHysteresisFactor(), 1.2); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/experiments/struct_parameters_parser.cc b/third_party/libwebrtc/rtc_base/experiments/struct_parameters_parser.cc new file mode 100644 index 0000000000..011df3eaba --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/struct_parameters_parser.cc @@ -0,0 +1,135 @@ +/* + * 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. + */ +#include "rtc_base/experiments/struct_parameters_parser.h" + +#include <algorithm> + +#include "absl/strings/string_view.h" +#include "rtc_base/logging.h" + +namespace webrtc { +namespace { +size_t FindOrEnd(absl::string_view str, size_t start, char delimiter) { + size_t pos = str.find(delimiter, start); + pos = (pos == absl::string_view::npos) ? str.length() : pos; + return pos; +} +} // namespace + +namespace struct_parser_impl { +namespace { +inline void StringEncode(std::string* target, bool val) { + *target += rtc::ToString(val); +} +inline void StringEncode(std::string* target, double val) { + *target += rtc::ToString(val); +} +inline void StringEncode(std::string* target, int val) { + *target += rtc::ToString(val); +} +inline void StringEncode(std::string* target, unsigned val) { + *target += rtc::ToString(val); +} +inline void StringEncode(std::string* target, DataRate val) { + *target += webrtc::ToString(val); +} +inline void StringEncode(std::string* target, DataSize val) { + *target += webrtc::ToString(val); +} +inline void StringEncode(std::string* target, TimeDelta val) { + *target += webrtc::ToString(val); +} + +template <typename T> +inline void StringEncode(std::string* sb, absl::optional<T> val) { + if (val) + StringEncode(sb, *val); +} +} // namespace +template <typename T> +bool TypedParser<T>::Parse(absl::string_view src, void* target) { + auto parsed = ParseTypedParameter<T>(std::string(src)); + if (parsed.has_value()) + *reinterpret_cast<T*>(target) = *parsed; + return parsed.has_value(); +} +template <typename T> +void TypedParser<T>::Encode(const void* src, std::string* target) { + StringEncode(target, *reinterpret_cast<const T*>(src)); +} + +template class TypedParser<bool>; +template class TypedParser<double>; +template class TypedParser<int>; +template class TypedParser<unsigned>; +template class TypedParser<absl::optional<double>>; +template class TypedParser<absl::optional<int>>; +template class TypedParser<absl::optional<unsigned>>; + +template class TypedParser<DataRate>; +template class TypedParser<DataSize>; +template class TypedParser<TimeDelta>; +template class TypedParser<absl::optional<DataRate>>; +template class TypedParser<absl::optional<DataSize>>; +template class TypedParser<absl::optional<TimeDelta>>; +} // namespace struct_parser_impl + +StructParametersParser::StructParametersParser( + std::vector<struct_parser_impl::MemberParameter> members) + : members_(std::move(members)) {} + +void StructParametersParser::Parse(absl::string_view src) { + size_t i = 0; + while (i < src.length()) { + size_t val_end = FindOrEnd(src, i, ','); + size_t colon_pos = FindOrEnd(src, i, ':'); + size_t key_end = std::min(val_end, colon_pos); + size_t val_begin = key_end + 1u; + absl::string_view key(src.substr(i, key_end - i)); + absl::string_view opt_value; + if (val_end >= val_begin) + opt_value = src.substr(val_begin, val_end - val_begin); + i = val_end + 1u; + bool found = false; + for (auto& member : members_) { + if (key == member.key) { + found = true; + if (!member.parser.parse(opt_value, member.member_ptr)) { + RTC_LOG(LS_WARNING) << "Failed to read field with key: '" << key + << "' in trial: \"" << src << "\""; + } + break; + } + } + // "_" is be used to prefix keys that are part of the string for + // debugging purposes but not neccessarily used. + // e.g. WebRTC-Experiment/param: value, _DebuggingString + if (!found && (key.empty() || key[0] != '_')) { + RTC_LOG(LS_INFO) << "No field with key: '" << key + << "' (found in trial: \"" << src << "\")"; + } + } +} + +std::string StructParametersParser::Encode() const { + std::string res; + bool first = true; + for (const auto& member : members_) { + if (!first) + res += ","; + res += member.key; + res += ":"; + member.parser.encode(member.member_ptr, &res); + first = false; + } + return res; +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/experiments/struct_parameters_parser.h b/third_party/libwebrtc/rtc_base/experiments/struct_parameters_parser.h new file mode 100644 index 0000000000..f5f8340209 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/struct_parameters_parser.h @@ -0,0 +1,110 @@ +/* + * 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 RTC_BASE_EXPERIMENTS_STRUCT_PARAMETERS_PARSER_H_ +#define RTC_BASE_EXPERIMENTS_STRUCT_PARAMETERS_PARSER_H_ + +#include <functional> +#include <map> +#include <memory> +#include <string> +#include <utility> +#include <vector> + +#include "absl/memory/memory.h" +#include "absl/strings/string_view.h" +#include "absl/types/optional.h" +#include "rtc_base/experiments/field_trial_parser.h" +#include "rtc_base/experiments/field_trial_units.h" +#include "rtc_base/string_encode.h" + +namespace webrtc { +namespace struct_parser_impl { +struct TypedMemberParser { + public: + bool (*parse)(absl::string_view src, void* target); + void (*encode)(const void* src, std::string* target); +}; + +struct MemberParameter { + const char* key; + void* member_ptr; + TypedMemberParser parser; +}; + +template <typename T> +class TypedParser { + public: + static bool Parse(absl::string_view src, void* target); + static void Encode(const void* src, std::string* target); +}; + +// Instantiated in cc file to avoid duplication during compile. Add additional +// parsers as needed. Generally, try to use these suggested types even if the +// context where the value is used might require a different type. For instance, +// a size_t representing a packet size should use an int parameter as there's no +// need to support packet sizes larger than INT32_MAX. +extern template class TypedParser<bool>; +extern template class TypedParser<double>; +extern template class TypedParser<int>; +extern template class TypedParser<unsigned>; +extern template class TypedParser<absl::optional<double>>; +extern template class TypedParser<absl::optional<int>>; +extern template class TypedParser<absl::optional<unsigned>>; + +extern template class TypedParser<DataRate>; +extern template class TypedParser<DataSize>; +extern template class TypedParser<TimeDelta>; +extern template class TypedParser<absl::optional<DataRate>>; +extern template class TypedParser<absl::optional<DataSize>>; +extern template class TypedParser<absl::optional<TimeDelta>>; + +template <typename T> +void AddMembers(MemberParameter* out, const char* key, T* member) { + *out = MemberParameter{ + key, member, + TypedMemberParser{&TypedParser<T>::Parse, &TypedParser<T>::Encode}}; +} + +template <typename T, typename... Args> +void AddMembers(MemberParameter* out, + const char* key, + T* member, + Args... args) { + AddMembers(out, key, member); + AddMembers(++out, args...); +} +} // namespace struct_parser_impl + +class StructParametersParser { + public: + template <typename T, typename... Args> + static std::unique_ptr<StructParametersParser> Create(const char* first_key, + T* first_member, + Args... args) { + std::vector<struct_parser_impl::MemberParameter> members( + sizeof...(args) / 2 + 1); + struct_parser_impl::AddMembers(&members.front(), std::move(first_key), + first_member, args...); + return absl::WrapUnique(new StructParametersParser(std::move(members))); + } + + void Parse(absl::string_view src); + std::string Encode() const; + + private: + explicit StructParametersParser( + std::vector<struct_parser_impl::MemberParameter> members); + + std::vector<struct_parser_impl::MemberParameter> members_; +}; + +} // namespace webrtc + +#endif // RTC_BASE_EXPERIMENTS_STRUCT_PARAMETERS_PARSER_H_ diff --git a/third_party/libwebrtc/rtc_base/experiments/struct_parameters_parser_unittest.cc b/third_party/libwebrtc/rtc_base/experiments/struct_parameters_parser_unittest.cc new file mode 100644 index 0000000000..0824bd3b27 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/experiments/struct_parameters_parser_unittest.cc @@ -0,0 +1,68 @@ +/* + * 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. + */ +#include "rtc_base/experiments/struct_parameters_parser.h" + +#include "rtc_base/gunit.h" + +namespace webrtc { +namespace { +struct DummyConfig { + bool enabled = false; + double factor = 0.5; + int retries = 5; + unsigned size = 3; + bool ping = 0; + absl::optional<TimeDelta> duration; + absl::optional<TimeDelta> latency = TimeDelta::Millis(100); + std::unique_ptr<StructParametersParser> Parser(); +}; + +std::unique_ptr<StructParametersParser> DummyConfig::Parser() { + // The empty comments ensures that each pair is on a separate line. + return StructParametersParser::Create("e", &enabled, // + "f", &factor, // + "r", &retries, // + "s", &size, // + "p", &ping, // + "d", &duration, // + "l", &latency); +} +} // namespace + +TEST(StructParametersParserTest, ParsesValidParameters) { + DummyConfig exp; + exp.Parser()->Parse("e:1,f:-1.7,r:2,s:7,p:1,d:8,l:,"); + EXPECT_TRUE(exp.enabled); + EXPECT_EQ(exp.factor, -1.7); + EXPECT_EQ(exp.retries, 2); + EXPECT_EQ(exp.size, 7u); + EXPECT_EQ(exp.ping, true); + EXPECT_EQ(exp.duration.value().ms(), 8); + EXPECT_FALSE(exp.latency); +} + +TEST(StructParametersParserTest, UsesDefaults) { + DummyConfig exp; + exp.Parser()->Parse(""); + EXPECT_FALSE(exp.enabled); + EXPECT_EQ(exp.factor, 0.5); + EXPECT_EQ(exp.retries, 5); + EXPECT_EQ(exp.size, 3u); + EXPECT_EQ(exp.ping, false); +} + +TEST(StructParametersParserTest, EncodeAll) { + DummyConfig exp; + auto encoded = exp.Parser()->Encode(); + // All parameters are encoded. + EXPECT_EQ(encoded, "e:false,f:0.5,r:5,s:3,p:false,d:,l:100 ms"); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/fake_clock.cc b/third_party/libwebrtc/rtc_base/fake_clock.cc new file mode 100644 index 0000000000..652a5afa3a --- /dev/null +++ b/third_party/libwebrtc/rtc_base/fake_clock.cc @@ -0,0 +1,62 @@ +/* + * Copyright 2016 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 "rtc_base/fake_clock.h" + +#include "rtc_base/checks.h" +#include "rtc_base/thread.h" + +namespace rtc { + +int64_t FakeClock::TimeNanos() const { + webrtc::MutexLock lock(&lock_); + return time_ns_; +} + +void FakeClock::SetTime(webrtc::Timestamp new_time) { + webrtc::MutexLock lock(&lock_); + RTC_DCHECK(new_time.us() * 1000 >= time_ns_); + time_ns_ = new_time.us() * 1000; +} + +void FakeClock::AdvanceTime(webrtc::TimeDelta delta) { + webrtc::MutexLock lock(&lock_); + time_ns_ += delta.ns(); +} + +void ThreadProcessingFakeClock::SetTime(webrtc::Timestamp time) { + clock_.SetTime(time); + // If message queues are waiting in a socket select() with a timeout provided + // by the OS, they should wake up and dispatch all messages that are ready. + ThreadManager::ProcessAllMessageQueuesForTesting(); +} + +void ThreadProcessingFakeClock::AdvanceTime(webrtc::TimeDelta delta) { + clock_.AdvanceTime(delta); + ThreadManager::ProcessAllMessageQueuesForTesting(); +} + +ScopedBaseFakeClock::ScopedBaseFakeClock() { + prev_clock_ = SetClockForTesting(this); +} + +ScopedBaseFakeClock::~ScopedBaseFakeClock() { + SetClockForTesting(prev_clock_); +} + +ScopedFakeClock::ScopedFakeClock() { + prev_clock_ = SetClockForTesting(this); +} + +ScopedFakeClock::~ScopedFakeClock() { + SetClockForTesting(prev_clock_); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/fake_clock.h b/third_party/libwebrtc/rtc_base/fake_clock.h new file mode 100644 index 0000000000..edb507becb --- /dev/null +++ b/third_party/libwebrtc/rtc_base/fake_clock.h @@ -0,0 +1,83 @@ +/* + * Copyright 2016 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 RTC_BASE_FAKE_CLOCK_H_ +#define RTC_BASE_FAKE_CLOCK_H_ + +#include <stdint.h> + +#include "api/units/time_delta.h" +#include "api/units/timestamp.h" +#include "rtc_base/synchronization/mutex.h" +#include "rtc_base/thread_annotations.h" +#include "rtc_base/time_utils.h" + +namespace rtc { + +// Fake clock for use with unit tests, which does not tick on its own. +// Starts at time 0. +// +// TODO(deadbeef): Unify with webrtc::SimulatedClock. +class FakeClock : public ClockInterface { + public: + FakeClock() = default; + FakeClock(const FakeClock&) = delete; + FakeClock& operator=(const FakeClock&) = delete; + ~FakeClock() override = default; + + // ClockInterface implementation. + int64_t TimeNanos() const override; + + // Methods that can be used by the test to control the time. + + // Should only be used to set a time in the future. + void SetTime(webrtc::Timestamp new_time); + + void AdvanceTime(webrtc::TimeDelta delta); + + private: + mutable webrtc::Mutex lock_; + int64_t time_ns_ RTC_GUARDED_BY(lock_) = 0; +}; + +class ThreadProcessingFakeClock : public ClockInterface { + public: + int64_t TimeNanos() const override { return clock_.TimeNanos(); } + void SetTime(webrtc::Timestamp time); + void AdvanceTime(webrtc::TimeDelta delta); + + private: + FakeClock clock_; +}; + +// Helper class that sets itself as the global clock in its constructor and +// unsets it in its destructor. +class ScopedBaseFakeClock : public FakeClock { + public: + ScopedBaseFakeClock(); + ~ScopedBaseFakeClock() override; + + private: + ClockInterface* prev_clock_; +}; + +// TODO(srte): Rename this to reflect that it also does thread processing. +class ScopedFakeClock : public ThreadProcessingFakeClock { + public: + ScopedFakeClock(); + ~ScopedFakeClock() override; + + private: + ClockInterface* prev_clock_; +}; + +} // namespace rtc + +#endif // RTC_BASE_FAKE_CLOCK_H_ diff --git a/third_party/libwebrtc/rtc_base/fake_clock_unittest.cc b/third_party/libwebrtc/rtc_base/fake_clock_unittest.cc new file mode 100644 index 0000000000..fc1d5100e6 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/fake_clock_unittest.cc @@ -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. + */ + +#include "rtc_base/fake_clock.h" + +#include "test/gtest.h" + +namespace rtc { +TEST(ScopedFakeClockTest, OverridesGlobalClock) { + const int64_t kFixedTimeUs = 100000; + int64_t real_time_us = rtc::TimeMicros(); + EXPECT_NE(real_time_us, 0); + { + ScopedFakeClock scoped; + EXPECT_EQ(rtc::TimeMicros(), 0); + + scoped.AdvanceTime(webrtc::TimeDelta::Millis(1)); + EXPECT_EQ(rtc::TimeMicros(), 1000); + + scoped.SetTime(webrtc::Timestamp::Micros(kFixedTimeUs)); + EXPECT_EQ(rtc::TimeMicros(), kFixedTimeUs); + + scoped.AdvanceTime(webrtc::TimeDelta::Millis(1)); + EXPECT_EQ(rtc::TimeMicros(), kFixedTimeUs + 1000); + } + + EXPECT_NE(rtc::TimeMicros(), kFixedTimeUs + 1000); + EXPECT_GE(rtc::TimeMicros(), real_time_us); +} +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/fake_mdns_responder.h b/third_party/libwebrtc/rtc_base/fake_mdns_responder.h new file mode 100644 index 0000000000..706c11b913 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/fake_mdns_responder.h @@ -0,0 +1,71 @@ +/* + * 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 RTC_BASE_FAKE_MDNS_RESPONDER_H_ +#define RTC_BASE_FAKE_MDNS_RESPONDER_H_ + +#include <map> +#include <memory> +#include <string> + +#include "absl/strings/string_view.h" +#include "rtc_base/ip_address.h" +#include "rtc_base/mdns_responder_interface.h" +#include "rtc_base/thread.h" + +namespace webrtc { + +// This class posts tasks on the given `thread` to invoke callbacks. It's the +// callback's responsibility to be aware of potential destruction of state it +// depends on, e.g., using WeakPtrFactory or PendingTaskSafetyFlag. +class FakeMdnsResponder : public MdnsResponderInterface { + public: + explicit FakeMdnsResponder(rtc::Thread* thread) : thread_(thread) {} + ~FakeMdnsResponder() = default; + + void CreateNameForAddress(const rtc::IPAddress& addr, + NameCreatedCallback callback) override { + std::string name; + if (addr_name_map_.find(addr) != addr_name_map_.end()) { + name = addr_name_map_[addr]; + } else { + name = std::to_string(next_available_id_++) + ".local"; + addr_name_map_[addr] = name; + } + thread_->PostTask([callback, addr, name]() { callback(addr, name); }); + } + void RemoveNameForAddress(const rtc::IPAddress& addr, + NameRemovedCallback callback) override { + auto it = addr_name_map_.find(addr); + if (it != addr_name_map_.end()) { + addr_name_map_.erase(it); + } + bool result = it != addr_name_map_.end(); + thread_->PostTask([callback, result]() { callback(result); }); + } + + rtc::IPAddress GetMappedAddressForName(absl::string_view name) const { + for (const auto& addr_name_pair : addr_name_map_) { + if (addr_name_pair.second == name) { + return addr_name_pair.first; + } + } + return rtc::IPAddress(); + } + + private: + uint32_t next_available_id_ = 0; + std::map<rtc::IPAddress, std::string> addr_name_map_; + rtc::Thread* const thread_; +}; + +} // namespace webrtc + +#endif // RTC_BASE_FAKE_MDNS_RESPONDER_H_ diff --git a/third_party/libwebrtc/rtc_base/fake_network.h b/third_party/libwebrtc/rtc_base/fake_network.h new file mode 100644 index 0000000000..bc0330606f --- /dev/null +++ b/third_party/libwebrtc/rtc_base/fake_network.h @@ -0,0 +1,139 @@ +/* + * Copyright 2009 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 RTC_BASE_FAKE_NETWORK_H_ +#define RTC_BASE_FAKE_NETWORK_H_ + +#include <memory> +#include <string> +#include <utility> +#include <vector> + +#include "absl/memory/memory.h" +#include "rtc_base/mdns_responder_interface.h" +#include "rtc_base/network.h" +#include "rtc_base/socket_address.h" +#include "rtc_base/string_encode.h" +#include "rtc_base/thread.h" + +namespace rtc { + +const int kFakeIPv4NetworkPrefixLength = 24; +const int kFakeIPv6NetworkPrefixLength = 64; + +// Fake network manager that allows us to manually specify the IPs to use. +class FakeNetworkManager : public NetworkManagerBase { + public: + FakeNetworkManager() {} + + struct Iface { + SocketAddress socket_address; + AdapterType adapter_type; + absl::optional<AdapterType> underlying_vpn_adapter_type; + }; + typedef std::vector<Iface> IfaceList; + + void AddInterface(const SocketAddress& iface) { + // Ensure a unique name for the interface if its name is not given. + AddInterface(iface, "test" + rtc::ToString(next_index_++)); + } + + void AddInterface(const SocketAddress& iface, absl::string_view if_name) { + AddInterface(iface, if_name, ADAPTER_TYPE_UNKNOWN); + } + + void AddInterface( + const SocketAddress& iface, + absl::string_view if_name, + AdapterType type, + absl::optional<AdapterType> underlying_vpn_adapter_type = absl::nullopt) { + SocketAddress address(if_name, 0); + address.SetResolvedIP(iface.ipaddr()); + ifaces_.push_back({address, type, underlying_vpn_adapter_type}); + DoUpdateNetworks(); + } + + void RemoveInterface(const SocketAddress& iface) { + for (IfaceList::iterator it = ifaces_.begin(); it != ifaces_.end(); ++it) { + if (it->socket_address.EqualIPs(iface)) { + ifaces_.erase(it); + break; + } + } + DoUpdateNetworks(); + } + + void StartUpdating() override { + ++start_count_; + if (start_count_ == 1) { + sent_first_update_ = false; + Thread::Current()->PostTask([this] { DoUpdateNetworks(); }); + } else if (sent_first_update_) { + Thread::Current()->PostTask([this] { SignalNetworksChanged(); }); + } + } + + void StopUpdating() override { --start_count_; } + + using NetworkManagerBase::set_default_local_addresses; + using NetworkManagerBase::set_enumeration_permission; + + // rtc::NetworkManager override. + webrtc::MdnsResponderInterface* GetMdnsResponder() const override { + return mdns_responder_.get(); + } + + void set_mdns_responder( + std::unique_ptr<webrtc::MdnsResponderInterface> mdns_responder) { + mdns_responder_ = std::move(mdns_responder); + } + + private: + void DoUpdateNetworks() { + if (start_count_ == 0) + return; + std::vector<std::unique_ptr<Network>> networks; + for (IfaceList::iterator it = ifaces_.begin(); it != ifaces_.end(); ++it) { + int prefix_length = 0; + if (it->socket_address.ipaddr().family() == AF_INET) { + prefix_length = kFakeIPv4NetworkPrefixLength; + } else if (it->socket_address.ipaddr().family() == AF_INET6) { + prefix_length = kFakeIPv6NetworkPrefixLength; + } + IPAddress prefix = TruncateIP(it->socket_address.ipaddr(), prefix_length); + auto net = std::make_unique<Network>( + it->socket_address.hostname(), it->socket_address.hostname(), prefix, + prefix_length, it->adapter_type); + if (it->underlying_vpn_adapter_type.has_value()) { + net->set_underlying_type_for_vpn(*it->underlying_vpn_adapter_type); + } + net->set_default_local_address_provider(this); + net->AddIP(it->socket_address.ipaddr()); + networks.push_back(std::move(net)); + } + bool changed; + MergeNetworkList(std::move(networks), &changed); + if (changed || !sent_first_update_) { + SignalNetworksChanged(); + sent_first_update_ = true; + } + } + + IfaceList ifaces_; + int next_index_ = 0; + int start_count_ = 0; + bool sent_first_update_ = false; + + std::unique_ptr<webrtc::MdnsResponderInterface> mdns_responder_; +}; + +} // namespace rtc + +#endif // RTC_BASE_FAKE_NETWORK_H_ diff --git a/third_party/libwebrtc/rtc_base/fake_ssl_identity.cc b/third_party/libwebrtc/rtc_base/fake_ssl_identity.cc new file mode 100644 index 0000000000..73c843a2e7 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/fake_ssl_identity.cc @@ -0,0 +1,121 @@ +/* + * Copyright 2017 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 "rtc_base/fake_ssl_identity.h" + +#include <memory> +#include <string> +#include <utility> + +#include "absl/strings/string_view.h" +#include "rtc_base/checks.h" +#include "rtc_base/message_digest.h" + +namespace rtc { + +FakeSSLCertificate::FakeSSLCertificate(absl::string_view pem_string) + : pem_string_(pem_string), + digest_algorithm_(DIGEST_SHA_1), + expiration_time_(-1) {} + +FakeSSLCertificate::FakeSSLCertificate(const FakeSSLCertificate&) = default; + +FakeSSLCertificate::~FakeSSLCertificate() = default; + +std::unique_ptr<SSLCertificate> FakeSSLCertificate::Clone() const { + return std::make_unique<FakeSSLCertificate>(*this); +} + +std::string FakeSSLCertificate::ToPEMString() const { + return pem_string_; +} + +void FakeSSLCertificate::ToDER(Buffer* der_buffer) const { + std::string der_string; + RTC_CHECK( + SSLIdentity::PemToDer(kPemTypeCertificate, pem_string_, &der_string)); + der_buffer->SetData(der_string.c_str(), der_string.size()); +} + +int64_t FakeSSLCertificate::CertificateExpirationTime() const { + return expiration_time_; +} + +void FakeSSLCertificate::SetCertificateExpirationTime(int64_t expiration_time) { + expiration_time_ = expiration_time; +} + +void FakeSSLCertificate::set_digest_algorithm(absl::string_view algorithm) { + digest_algorithm_ = std::string(algorithm); +} + +bool FakeSSLCertificate::GetSignatureDigestAlgorithm( + std::string* algorithm) const { + *algorithm = digest_algorithm_; + return true; +} + +bool FakeSSLCertificate::ComputeDigest(absl::string_view algorithm, + unsigned char* digest, + size_t size, + size_t* length) const { + *length = rtc::ComputeDigest(algorithm, pem_string_.c_str(), + pem_string_.size(), digest, size); + return (*length != 0); +} + +FakeSSLIdentity::FakeSSLIdentity(absl::string_view pem_string) + : FakeSSLIdentity(FakeSSLCertificate(pem_string)) {} + +FakeSSLIdentity::FakeSSLIdentity(const std::vector<std::string>& pem_strings) { + std::vector<std::unique_ptr<SSLCertificate>> certs; + certs.reserve(pem_strings.size()); + for (const std::string& pem_string : pem_strings) { + certs.push_back(std::make_unique<FakeSSLCertificate>(pem_string)); + } + cert_chain_ = std::make_unique<SSLCertChain>(std::move(certs)); +} + +FakeSSLIdentity::FakeSSLIdentity(const FakeSSLCertificate& cert) + : cert_chain_(std::make_unique<SSLCertChain>(cert.Clone())) {} + +FakeSSLIdentity::FakeSSLIdentity(const FakeSSLIdentity& o) + : cert_chain_(o.cert_chain_->Clone()) {} + +FakeSSLIdentity::~FakeSSLIdentity() = default; + +std::unique_ptr<SSLIdentity> FakeSSLIdentity::CloneInternal() const { + return std::make_unique<FakeSSLIdentity>(*this); +} + +const SSLCertificate& FakeSSLIdentity::certificate() const { + return cert_chain_->Get(0); +} + +const SSLCertChain& FakeSSLIdentity::cert_chain() const { + return *cert_chain_.get(); +} + +std::string FakeSSLIdentity::PrivateKeyToPEMString() const { + RTC_DCHECK_NOTREACHED(); // Not implemented. + return ""; +} + +std::string FakeSSLIdentity::PublicKeyToPEMString() const { + RTC_DCHECK_NOTREACHED(); // Not implemented. + return ""; +} + +bool FakeSSLIdentity::operator==(const SSLIdentity& other) const { + RTC_DCHECK_NOTREACHED(); // Not implemented. + return false; +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/fake_ssl_identity.h b/third_party/libwebrtc/rtc_base/fake_ssl_identity.h new file mode 100644 index 0000000000..2b4ae2e57a --- /dev/null +++ b/third_party/libwebrtc/rtc_base/fake_ssl_identity.h @@ -0,0 +1,83 @@ +/* + * Copyright 2012 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 RTC_BASE_FAKE_SSL_IDENTITY_H_ +#define RTC_BASE_FAKE_SSL_IDENTITY_H_ + +#include <memory> +#include <vector> + +#include "absl/strings/string_view.h" +#include "rtc_base/ssl_certificate.h" +#include "rtc_base/ssl_identity.h" + +namespace rtc { + +class FakeSSLCertificate : public SSLCertificate { + public: + // SHA-1 is the default digest algorithm because it is available in all build + // configurations used for unit testing. + explicit FakeSSLCertificate(absl::string_view pem_string); + + FakeSSLCertificate(const FakeSSLCertificate&); + ~FakeSSLCertificate() override; + + // SSLCertificate implementation. + std::unique_ptr<SSLCertificate> Clone() const override; + std::string ToPEMString() const override; + void ToDER(Buffer* der_buffer) const override; + int64_t CertificateExpirationTime() const override; + bool GetSignatureDigestAlgorithm(std::string* algorithm) const override; + bool ComputeDigest(absl::string_view algorithm, + unsigned char* digest, + size_t size, + size_t* length) const override; + + void SetCertificateExpirationTime(int64_t expiration_time); + + void set_digest_algorithm(absl::string_view algorithm); + + private: + std::string pem_string_; + std::string digest_algorithm_; + // Expiration time in seconds relative to epoch, 1970-01-01T00:00:00Z (UTC). + int64_t expiration_time_; +}; + +class FakeSSLIdentity : public SSLIdentity { + public: + explicit FakeSSLIdentity(absl::string_view pem_string); + // For a certificate chain. + explicit FakeSSLIdentity(const std::vector<std::string>& pem_strings); + explicit FakeSSLIdentity(const FakeSSLCertificate& cert); + + explicit FakeSSLIdentity(const FakeSSLIdentity& o); + + ~FakeSSLIdentity() override; + + // SSLIdentity implementation. + const SSLCertificate& certificate() const override; + const SSLCertChain& cert_chain() const override; + // Not implemented. + std::string PrivateKeyToPEMString() const override; + // Not implemented. + std::string PublicKeyToPEMString() const override; + // Not implemented. + virtual bool operator==(const SSLIdentity& other) const; + + private: + std::unique_ptr<SSLIdentity> CloneInternal() const override; + + std::unique_ptr<SSLCertChain> cert_chain_; +}; + +} // namespace rtc + +#endif // RTC_BASE_FAKE_SSL_IDENTITY_H_ diff --git a/third_party/libwebrtc/rtc_base/file_rotating_stream.cc b/third_party/libwebrtc/rtc_base/file_rotating_stream.cc new file mode 100644 index 0000000000..c56396f157 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/file_rotating_stream.cc @@ -0,0 +1,428 @@ +/* + * Copyright 2015 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 "rtc_base/file_rotating_stream.h" + +#include <cstdio> +#include <string> +#include <utility> + +#include "absl/strings/string_view.h" + +#if defined(WEBRTC_WIN) +#include <windows.h> + +#include "rtc_base/string_utils.h" +#else +#include <dirent.h> +#include <sys/stat.h> +#include <unistd.h> +#endif // WEBRTC_WIN + +#include "absl/algorithm/container.h" +#include "absl/strings/match.h" +#include "absl/types/optional.h" +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" +#include "rtc_base/strings/string_builder.h" + +// Note: We use fprintf for logging in the write paths of this stream to avoid +// infinite loops when logging. + +namespace rtc { + +namespace { + +const char kCallSessionLogPrefix[] = "webrtc_log"; + +std::string AddTrailingPathDelimiterIfNeeded(absl::string_view directory); + +// `dir` must have a trailing delimiter. `prefix` must not include wild card +// characters. +std::vector<std::string> GetFilesWithPrefix(absl::string_view directory, + absl::string_view prefix); +bool DeleteFile(absl::string_view file); +bool MoveFile(absl::string_view old_file, absl::string_view new_file); +bool IsFile(absl::string_view file); +bool IsFolder(absl::string_view file); +absl::optional<size_t> GetFileSize(absl::string_view file); + +#if defined(WEBRTC_WIN) + +std::string AddTrailingPathDelimiterIfNeeded(absl::string_view directory) { + if (absl::EndsWith(directory, "\\")) { + return std::string(directory); + } + return std::string(directory) + "\\"; +} + +std::vector<std::string> GetFilesWithPrefix(absl::string_view directory, + absl::string_view prefix) { + RTC_DCHECK(absl::EndsWith(directory, "\\")); + WIN32_FIND_DATAW data; + HANDLE handle; + StringBuilder pattern_builder{directory}; + pattern_builder << prefix << "*"; + handle = ::FindFirstFileW(ToUtf16(pattern_builder.str()).c_str(), &data); + if (handle == INVALID_HANDLE_VALUE) + return {}; + + std::vector<std::string> file_list; + do { + StringBuilder file_builder{directory}; + file_builder << ToUtf8(data.cFileName); + file_list.emplace_back(file_builder.Release()); + } while (::FindNextFileW(handle, &data) == TRUE); + + ::FindClose(handle); + return file_list; +} + +bool DeleteFile(absl::string_view file) { + return ::DeleteFileW(ToUtf16(file).c_str()) != 0; +} + +bool MoveFile(absl::string_view old_file, absl::string_view new_file) { + return ::MoveFileW(ToUtf16(old_file).c_str(), ToUtf16(new_file).c_str()) != 0; +} + +bool IsFile(absl::string_view file) { + WIN32_FILE_ATTRIBUTE_DATA data = {0}; + if (0 == ::GetFileAttributesExW(ToUtf16(file).c_str(), GetFileExInfoStandard, + &data)) + return false; + return (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0; +} + +bool IsFolder(absl::string_view file) { + WIN32_FILE_ATTRIBUTE_DATA data = {0}; + if (0 == ::GetFileAttributesExW(ToUtf16(file).c_str(), GetFileExInfoStandard, + &data)) + return false; + return (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == + FILE_ATTRIBUTE_DIRECTORY; +} + +absl::optional<size_t> GetFileSize(absl::string_view file) { + WIN32_FILE_ATTRIBUTE_DATA data = {0}; + if (::GetFileAttributesExW(ToUtf16(file).c_str(), GetFileExInfoStandard, + &data) == 0) + return absl::nullopt; + return data.nFileSizeLow; +} + +#else // defined(WEBRTC_WIN) + +std::string AddTrailingPathDelimiterIfNeeded(absl::string_view directory) { + if (absl::EndsWith(directory, "/")) { + return std::string(directory); + } + return std::string(directory) + "/"; +} + +std::vector<std::string> GetFilesWithPrefix(absl::string_view directory, + absl::string_view prefix) { + RTC_DCHECK(absl::EndsWith(directory, "/")); + std::string directory_str(directory); + DIR* dir = ::opendir(directory_str.c_str()); + if (dir == nullptr) + return {}; + std::vector<std::string> file_list; + for (struct dirent* dirent = ::readdir(dir); dirent; + dirent = ::readdir(dir)) { + std::string name = dirent->d_name; + if (name.compare(0, prefix.size(), prefix.data(), prefix.size()) == 0) { + file_list.emplace_back(directory_str + name); + } + } + ::closedir(dir); + return file_list; +} + +bool DeleteFile(absl::string_view file) { + return ::unlink(std::string(file).c_str()) == 0; +} + +bool MoveFile(absl::string_view old_file, absl::string_view new_file) { + return ::rename(std::string(old_file).c_str(), + std::string(new_file).c_str()) == 0; +} + +bool IsFile(absl::string_view file) { + struct stat st; + int res = ::stat(std::string(file).c_str(), &st); + // Treat symlinks, named pipes, etc. all as files. + return res == 0 && !S_ISDIR(st.st_mode); +} + +bool IsFolder(absl::string_view file) { + struct stat st; + int res = ::stat(std::string(file).c_str(), &st); + return res == 0 && S_ISDIR(st.st_mode); +} + +absl::optional<size_t> GetFileSize(absl::string_view file) { + struct stat st; + if (::stat(std::string(file).c_str(), &st) != 0) + return absl::nullopt; + return st.st_size; +} + +#endif + +} // namespace + +FileRotatingStream::FileRotatingStream(absl::string_view dir_path, + absl::string_view file_prefix, + size_t max_file_size, + size_t num_files) + : dir_path_(AddTrailingPathDelimiterIfNeeded(dir_path)), + file_prefix_(file_prefix), + max_file_size_(max_file_size), + current_file_index_(0), + rotation_index_(0), + current_bytes_written_(0), + disable_buffering_(false) { + RTC_DCHECK_GT(max_file_size, 0); + RTC_DCHECK_GT(num_files, 1); + RTC_DCHECK(IsFolder(dir_path)); + file_names_.clear(); + for (size_t i = 0; i < num_files; ++i) { + file_names_.push_back(GetFilePath(i, num_files)); + } + rotation_index_ = num_files - 1; +} + +FileRotatingStream::~FileRotatingStream() {} + +bool FileRotatingStream::IsOpen() const { + return file_.is_open(); +} + +bool FileRotatingStream::Write(const void* data, size_t data_len) { + if (!file_.is_open()) { + std::fprintf(stderr, "Open() must be called before Write.\n"); + return false; + } + while (data_len > 0) { + // Write as much as will fit in to the current file. + RTC_DCHECK_LT(current_bytes_written_, max_file_size_); + size_t remaining_bytes = max_file_size_ - current_bytes_written_; + size_t write_length = std::min(data_len, remaining_bytes); + + if (!file_.Write(data, write_length)) { + return false; + } + if (disable_buffering_ && !file_.Flush()) { + return false; + } + + current_bytes_written_ += write_length; + + // If we're done with this file, rotate it out. + if (current_bytes_written_ >= max_file_size_) { + RTC_DCHECK_EQ(current_bytes_written_, max_file_size_); + RotateFiles(); + } + data_len -= write_length; + data = + static_cast<const void*>(static_cast<const char*>(data) + write_length); + } + return true; +} + +bool FileRotatingStream::Flush() { + if (!file_.is_open()) { + return false; + } + return file_.Flush(); +} + +void FileRotatingStream::Close() { + CloseCurrentFile(); +} + +bool FileRotatingStream::Open() { + // Delete existing files when opening for write. + std::vector<std::string> matching_files = + GetFilesWithPrefix(dir_path_, file_prefix_); + for (const auto& matching_file : matching_files) { + if (!DeleteFile(matching_file)) { + std::fprintf(stderr, "Failed to delete: %s\n", matching_file.c_str()); + } + } + return OpenCurrentFile(); +} + +bool FileRotatingStream::DisableBuffering() { + disable_buffering_ = true; + return true; +} + +std::string FileRotatingStream::GetFilePath(size_t index) const { + RTC_DCHECK_LT(index, file_names_.size()); + return file_names_[index]; +} + +bool FileRotatingStream::OpenCurrentFile() { + CloseCurrentFile(); + + // Opens the appropriate file in the appropriate mode. + RTC_DCHECK_LT(current_file_index_, file_names_.size()); + std::string file_path = file_names_[current_file_index_]; + + // We should always be writing to the zero-th file. + RTC_DCHECK_EQ(current_file_index_, 0); + int error; + file_ = webrtc::FileWrapper::OpenWriteOnly(file_path, &error); + if (!file_.is_open()) { + std::fprintf(stderr, "Failed to open: %s Error: %d\n", file_path.c_str(), + error); + return false; + } + return true; +} + +void FileRotatingStream::CloseCurrentFile() { + if (!file_.is_open()) { + return; + } + current_bytes_written_ = 0; + file_.Close(); +} + +void FileRotatingStream::RotateFiles() { + CloseCurrentFile(); + // Rotates the files by deleting the file at `rotation_index_`, which is the + // oldest file and then renaming the newer files to have an incremented index. + // See header file comments for example. + RTC_DCHECK_LT(rotation_index_, file_names_.size()); + std::string file_to_delete = file_names_[rotation_index_]; + if (IsFile(file_to_delete)) { + if (!DeleteFile(file_to_delete)) { + std::fprintf(stderr, "Failed to delete: %s\n", file_to_delete.c_str()); + } + } + for (auto i = rotation_index_; i > 0; --i) { + std::string rotated_name = file_names_[i]; + std::string unrotated_name = file_names_[i - 1]; + if (IsFile(unrotated_name)) { + if (!MoveFile(unrotated_name, rotated_name)) { + std::fprintf(stderr, "Failed to move: %s to %s\n", + unrotated_name.c_str(), rotated_name.c_str()); + } + } + } + // Create a new file for 0th index. + OpenCurrentFile(); + OnRotation(); +} + +std::string FileRotatingStream::GetFilePath(size_t index, + size_t num_files) const { + RTC_DCHECK_LT(index, num_files); + + const size_t buffer_size = 32; + char file_postfix[buffer_size]; + // We want to zero pad the index so that it will sort nicely. + const int max_digits = std::snprintf(nullptr, 0, "%zu", num_files - 1); + RTC_DCHECK_LT(1 + max_digits, buffer_size); + std::snprintf(file_postfix, buffer_size, "_%0*zu", max_digits, index); + + return dir_path_ + file_prefix_ + file_postfix; +} + +CallSessionFileRotatingStream::CallSessionFileRotatingStream( + absl::string_view dir_path, + size_t max_total_log_size) + : FileRotatingStream(dir_path, + kCallSessionLogPrefix, + max_total_log_size / 2, + GetNumRotatingLogFiles(max_total_log_size) + 1), + max_total_log_size_(max_total_log_size), + num_rotations_(0) { + RTC_DCHECK_GE(max_total_log_size, 4); +} + +const size_t CallSessionFileRotatingStream::kRotatingLogFileDefaultSize = + 1024 * 1024; + +void CallSessionFileRotatingStream::OnRotation() { + ++num_rotations_; + if (num_rotations_ == 1) { + // On the first rotation adjust the max file size so subsequent files after + // the first are smaller. + SetMaxFileSize(GetRotatingLogSize(max_total_log_size_)); + } else if (num_rotations_ == (GetNumFiles() - 1)) { + // On the next rotation the very first file is going to be deleted. Change + // the rotation index so this doesn't happen. + SetRotationIndex(GetRotationIndex() - 1); + } +} + +size_t CallSessionFileRotatingStream::GetRotatingLogSize( + size_t max_total_log_size) { + size_t num_rotating_log_files = GetNumRotatingLogFiles(max_total_log_size); + size_t rotating_log_size = num_rotating_log_files > 2 + ? kRotatingLogFileDefaultSize + : max_total_log_size / 4; + return rotating_log_size; +} + +size_t CallSessionFileRotatingStream::GetNumRotatingLogFiles( + size_t max_total_log_size) { + // At minimum have two rotating files. Otherwise split the available log size + // evenly across 1MB files. + return std::max((size_t)2, + (max_total_log_size / 2) / kRotatingLogFileDefaultSize); +} + +FileRotatingStreamReader::FileRotatingStreamReader( + absl::string_view dir_path, + absl::string_view file_prefix) { + file_names_ = GetFilesWithPrefix(AddTrailingPathDelimiterIfNeeded(dir_path), + file_prefix); + + // Plain sort of the file names would sort by age, i.e., oldest last. Using + // std::greater gives us the desired chronological older, oldest first. + absl::c_sort(file_names_, std::greater<std::string>()); +} + +FileRotatingStreamReader::~FileRotatingStreamReader() = default; + +size_t FileRotatingStreamReader::GetSize() const { + size_t total_size = 0; + for (const auto& file_name : file_names_) { + total_size += GetFileSize(file_name).value_or(0); + } + return total_size; +} + +size_t FileRotatingStreamReader::ReadAll(void* buffer, size_t size) const { + size_t done = 0; + for (const auto& file_name : file_names_) { + if (done < size) { + webrtc::FileWrapper f = webrtc::FileWrapper::OpenReadOnly(file_name); + if (!f.is_open()) { + break; + } + done += f.Read(static_cast<char*>(buffer) + done, size - done); + } else { + break; + } + } + return done; +} + +CallSessionFileRotatingStreamReader::CallSessionFileRotatingStreamReader( + absl::string_view dir_path) + : FileRotatingStreamReader(dir_path, kCallSessionLogPrefix) {} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/file_rotating_stream.h b/third_party/libwebrtc/rtc_base/file_rotating_stream.h new file mode 100644 index 0000000000..6ae2753098 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/file_rotating_stream.h @@ -0,0 +1,173 @@ +/* + * Copyright 2015 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 RTC_BASE_FILE_ROTATING_STREAM_H_ +#define RTC_BASE_FILE_ROTATING_STREAM_H_ + +#include <stddef.h> + +#include <memory> +#include <string> +#include <vector> + +#include "absl/strings/string_view.h" +#include "rtc_base/system/file_wrapper.h" + +namespace rtc { + +// FileRotatingStream writes to a file in the directory specified in the +// constructor. It rotates the files once the current file is full. The +// individual file size and the number of files used is configurable in the +// constructor. Open() must be called before using this stream. +class FileRotatingStream { + public: + // Use this constructor for writing to a directory. Files in the directory + // matching the prefix will be deleted on open. + FileRotatingStream(absl::string_view dir_path, + absl::string_view file_prefix, + size_t max_file_size, + size_t num_files); + + virtual ~FileRotatingStream(); + + FileRotatingStream(const FileRotatingStream&) = delete; + FileRotatingStream& operator=(const FileRotatingStream&) = delete; + + bool IsOpen() const; + + bool Write(const void* data, size_t data_len); + bool Flush(); + void Close(); + + // Opens the appropriate file(s). Call this before using the stream. + bool Open(); + + // Disabling buffering causes writes to block until disk is updated. This is + // enabled by default for performance. + bool DisableBuffering(); + + // Below two methods are public for testing only. + + // Returns the path used for the i-th newest file, where the 0th file is the + // newest file. The file may or may not exist, this is just used for + // formatting. Index must be less than GetNumFiles(). + std::string GetFilePath(size_t index) const; + + // Returns the number of files that will used by this stream. + size_t GetNumFiles() const { return file_names_.size(); } + + protected: + void SetMaxFileSize(size_t size) { max_file_size_ = size; } + + size_t GetRotationIndex() const { return rotation_index_; } + + void SetRotationIndex(size_t index) { rotation_index_ = index; } + + virtual void OnRotation() {} + + private: + bool OpenCurrentFile(); + void CloseCurrentFile(); + + // Rotates the files by creating a new current file, renaming the + // existing files, and deleting the oldest one. e.g. + // file_0 -> file_1 + // file_1 -> file_2 + // file_2 -> delete + // create new file_0 + void RotateFiles(); + + // Private version of GetFilePath. + std::string GetFilePath(size_t index, size_t num_files) const; + + const std::string dir_path_; + const std::string file_prefix_; + + // File we're currently writing to. + webrtc::FileWrapper file_; + // Convenience storage for file names so we don't generate them over and over. + std::vector<std::string> file_names_; + size_t max_file_size_; + size_t current_file_index_; + // The rotation index indicates the index of the file that will be + // deleted first on rotation. Indices lower than this index will be rotated. + size_t rotation_index_; + // Number of bytes written to current file. We need this because with + // buffering the file size read from disk might not be accurate. + size_t current_bytes_written_; + bool disable_buffering_; +}; + +// CallSessionFileRotatingStream is meant to be used in situations where we will +// have limited disk space. Its purpose is to write logs up to a +// maximum size. Once the maximum size is exceeded, logs from the middle are +// deleted whereas logs from the beginning and end are preserved. The reason for +// this is because we anticipate that in WebRTC the beginning and end of the +// logs are most useful for call diagnostics. +// +// This implementation simply writes to a single file until +// `max_total_log_size` / 2 bytes are written to it, and subsequently writes to +// a set of rotating files. We do this by inheriting FileRotatingStream and +// setting the appropriate internal variables so that we don't delete the last +// (earliest) file on rotate, and that that file's size is bigger. +// +// Open() must be called before using this stream. + +// To read the logs produced by this class, one can use the companion class +// CallSessionFileRotatingStreamReader. +class CallSessionFileRotatingStream : public FileRotatingStream { + public: + // Use this constructor for writing to a directory. Files in the directory + // matching what's used by the stream will be deleted. `max_total_log_size` + // must be at least 4. + CallSessionFileRotatingStream(absl::string_view dir_path, + size_t max_total_log_size); + ~CallSessionFileRotatingStream() override {} + + CallSessionFileRotatingStream(const CallSessionFileRotatingStream&) = delete; + CallSessionFileRotatingStream& operator=( + const CallSessionFileRotatingStream&) = delete; + + protected: + void OnRotation() override; + + private: + static size_t GetRotatingLogSize(size_t max_total_log_size); + static size_t GetNumRotatingLogFiles(size_t max_total_log_size); + static const size_t kRotatingLogFileDefaultSize; + + const size_t max_total_log_size_; + size_t num_rotations_; +}; + +// This is a convenience class, to read all files produced by a +// FileRotatingStream, all in one go. Typical use calls GetSize and ReadData +// only once. The list of file names to read is based on the contents of the log +// directory at construction time. +class FileRotatingStreamReader { + public: + FileRotatingStreamReader(absl::string_view dir_path, + absl::string_view file_prefix); + ~FileRotatingStreamReader(); + size_t GetSize() const; + size_t ReadAll(void* buffer, size_t size) const; + + private: + std::vector<std::string> file_names_; +}; + +class CallSessionFileRotatingStreamReader : public FileRotatingStreamReader { + public: + CallSessionFileRotatingStreamReader(absl::string_view dir_path); +}; + +} // namespace rtc + +#endif // RTC_BASE_FILE_ROTATING_STREAM_H_ diff --git a/third_party/libwebrtc/rtc_base/file_rotating_stream_unittest.cc b/third_party/libwebrtc/rtc_base/file_rotating_stream_unittest.cc new file mode 100644 index 0000000000..1d1e5b62cb --- /dev/null +++ b/third_party/libwebrtc/rtc_base/file_rotating_stream_unittest.cc @@ -0,0 +1,394 @@ +/* + * Copyright 2015 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 "rtc_base/file_rotating_stream.h" + +#include <string.h> + +#include <cstdint> +#include <memory> + +#include "absl/strings/string_view.h" +#include "rtc_base/arraysize.h" +#include "test/gtest.h" +#include "test/testsupport/file_utils.h" + +namespace rtc { + +namespace { + +void CleanupLogDirectory(const FileRotatingStream& stream) { + for (size_t i = 0; i < stream.GetNumFiles(); ++i) { + // Ignore return value, not all files are expected to exist. + webrtc::test::RemoveFile(stream.GetFilePath(i)); + } +} + +} // namespace + +#if defined(WEBRTC_ANDROID) +// Fails on Android: https://bugs.chromium.org/p/webrtc/issues/detail?id=4364. +#define MAYBE_FileRotatingStreamTest DISABLED_FileRotatingStreamTest +#else +#define MAYBE_FileRotatingStreamTest FileRotatingStreamTest +#endif + +class MAYBE_FileRotatingStreamTest : public ::testing::Test { + protected: + static const char* kFilePrefix; + static const size_t kMaxFileSize; + + void Init(absl::string_view dir_name, + absl::string_view file_prefix, + size_t max_file_size, + size_t num_log_files, + bool ensure_trailing_delimiter = true) { + dir_path_ = webrtc::test::OutputPath(); + + // Append per-test output path in order to run within gtest parallel. + dir_path_.append(dir_name.begin(), dir_name.end()); + if (ensure_trailing_delimiter) { + dir_path_.append(std::string(webrtc::test::kPathDelimiter)); + } + ASSERT_TRUE(webrtc::test::CreateDir(dir_path_)); + stream_.reset(new FileRotatingStream(dir_path_, file_prefix, max_file_size, + num_log_files)); + } + + void TearDown() override { + // On windows, open files can't be removed. + stream_->Close(); + CleanupLogDirectory(*stream_); + EXPECT_TRUE(webrtc::test::RemoveDir(dir_path_)); + + stream_.reset(); + } + + // Writes the data to the stream and flushes it. + void WriteAndFlush(const void* data, const size_t data_len) { + EXPECT_TRUE(stream_->Write(data, data_len)); + EXPECT_TRUE(stream_->Flush()); + } + + // Checks that the stream reads in the expected contents and then returns an + // end of stream result. + void VerifyStreamRead(absl::string_view expected_contents, + absl::string_view dir_path, + absl::string_view file_prefix) { + size_t expected_length = expected_contents.size(); + FileRotatingStreamReader reader(dir_path, file_prefix); + EXPECT_EQ(reader.GetSize(), expected_length); + std::unique_ptr<uint8_t[]> buffer(new uint8_t[expected_length]); + memset(buffer.get(), 0, expected_length); + EXPECT_EQ(expected_length, reader.ReadAll(buffer.get(), expected_length)); + EXPECT_EQ(0, + memcmp(expected_contents.data(), buffer.get(), expected_length)); + } + + void VerifyFileContents(absl::string_view expected_contents, + absl::string_view file_path) { + size_t expected_length = expected_contents.size(); + std::unique_ptr<uint8_t[]> buffer(new uint8_t[expected_length + 1]); + webrtc::FileWrapper f = webrtc::FileWrapper::OpenReadOnly(file_path); + ASSERT_TRUE(f.is_open()); + size_t size_read = f.Read(buffer.get(), expected_length + 1); + EXPECT_EQ(size_read, expected_length); + EXPECT_EQ(0, memcmp(expected_contents.data(), buffer.get(), + std::min(expected_length, size_read))); + } + + std::unique_ptr<FileRotatingStream> stream_; + std::string dir_path_; +}; + +const char* MAYBE_FileRotatingStreamTest::kFilePrefix = + "FileRotatingStreamTest"; +const size_t MAYBE_FileRotatingStreamTest::kMaxFileSize = 2; + +// Tests that stream state is correct before and after Open / Close. +TEST_F(MAYBE_FileRotatingStreamTest, State) { + Init("FileRotatingStreamTestState", kFilePrefix, kMaxFileSize, 3); + + EXPECT_FALSE(stream_->IsOpen()); + ASSERT_TRUE(stream_->Open()); + EXPECT_TRUE(stream_->IsOpen()); + stream_->Close(); + EXPECT_FALSE(stream_->IsOpen()); +} + +// Tests that nothing is written to file when data of length zero is written. +TEST_F(MAYBE_FileRotatingStreamTest, EmptyWrite) { + Init("FileRotatingStreamTestEmptyWrite", kFilePrefix, kMaxFileSize, 3); + + ASSERT_TRUE(stream_->Open()); + WriteAndFlush("a", 0); + + std::string logfile_path = stream_->GetFilePath(0); + webrtc::FileWrapper f = webrtc::FileWrapper::OpenReadOnly(logfile_path); + ASSERT_TRUE(f.is_open()); + char buf[1]; + EXPECT_EQ(0u, f.Read(buf, sizeof(buf))); +} + +// Tests that a write operation followed by a read returns the expected data +// and writes to the expected files. +TEST_F(MAYBE_FileRotatingStreamTest, WriteAndRead) { + Init("FileRotatingStreamTestWriteAndRead", kFilePrefix, kMaxFileSize, 3); + + ASSERT_TRUE(stream_->Open()); + // The test is set up to create three log files of length 2. Write and check + // contents. + std::string messages[3] = {"aa", "bb", "cc"}; + for (size_t i = 0; i < arraysize(messages); ++i) { + const std::string& message = messages[i]; + WriteAndFlush(message.c_str(), message.size()); + // Since the max log size is 2, we will be causing rotation. Read from the + // next file. + VerifyFileContents(message, stream_->GetFilePath(1)); + } + // Check that exactly three files exist. + for (size_t i = 0; i < arraysize(messages); ++i) { + EXPECT_TRUE(webrtc::test::FileExists(stream_->GetFilePath(i))); + } + std::string message("d"); + WriteAndFlush(message.c_str(), message.size()); + for (size_t i = 0; i < arraysize(messages); ++i) { + EXPECT_TRUE(webrtc::test::FileExists(stream_->GetFilePath(i))); + } + // TODO(tkchin): Maybe check all the files in the dir. + + // Reopen for read. + std::string expected_contents("bbccd"); + VerifyStreamRead(expected_contents, dir_path_, kFilePrefix); +} + +// Tests that a write operation (with dir name without delimiter) followed by a +// read returns the expected data and writes to the expected files. +TEST_F(MAYBE_FileRotatingStreamTest, WriteWithoutDelimiterAndRead) { + Init("FileRotatingStreamTestWriteWithoutDelimiterAndRead", kFilePrefix, + kMaxFileSize, 3, + /* ensure_trailing_delimiter*/ false); + + ASSERT_TRUE(stream_->Open()); + // The test is set up to create three log files of length 2. Write and check + // contents. + std::string messages[3] = {"aa", "bb", "cc"}; + for (size_t i = 0; i < arraysize(messages); ++i) { + const std::string& message = messages[i]; + WriteAndFlush(message.c_str(), message.size()); + } + std::string message("d"); + WriteAndFlush(message.c_str(), message.size()); + + // Reopen for read. + std::string expected_contents("bbccd"); + VerifyStreamRead(expected_contents, + dir_path_ + std::string(webrtc::test::kPathDelimiter), + kFilePrefix); +} + +// Tests that a write operation followed by a read (without trailing delimiter) +// returns the expected data and writes to the expected files. +TEST_F(MAYBE_FileRotatingStreamTest, WriteAndReadWithoutDelimiter) { + Init("FileRotatingStreamTestWriteAndReadWithoutDelimiter", kFilePrefix, + kMaxFileSize, 3); + + ASSERT_TRUE(stream_->Open()); + // The test is set up to create three log files of length 2. Write and check + // contents. + std::string messages[3] = {"aa", "bb", "cc"}; + for (size_t i = 0; i < arraysize(messages); ++i) { + const std::string& message = messages[i]; + WriteAndFlush(message.c_str(), message.size()); + } + std::string message("d"); + WriteAndFlush(message.c_str(), message.size()); + + // Reopen for read. + std::string expected_contents("bbccd"); + VerifyStreamRead(expected_contents, dir_path_.substr(0, dir_path_.size() - 1), + kFilePrefix); +} + +// Tests that writing data greater than the total capacity of the files +// overwrites the files correctly and is read correctly after. +TEST_F(MAYBE_FileRotatingStreamTest, WriteOverflowAndRead) { + Init("FileRotatingStreamTestWriteOverflowAndRead", kFilePrefix, kMaxFileSize, + 3); + ASSERT_TRUE(stream_->Open()); + // This should cause overflow across all three files, such that the first file + // we wrote to also gets overwritten. + std::string message("foobarbaz"); + WriteAndFlush(message.c_str(), message.size()); + std::string expected_file_contents("z"); + VerifyFileContents(expected_file_contents, stream_->GetFilePath(0)); + std::string expected_stream_contents("arbaz"); + VerifyStreamRead(expected_stream_contents, dir_path_, kFilePrefix); +} + +// Tests that the returned file paths have the right folder and prefix. +TEST_F(MAYBE_FileRotatingStreamTest, GetFilePath) { + Init("FileRotatingStreamTestGetFilePath", kFilePrefix, kMaxFileSize, 20); + // dir_path_ includes a trailing delimiter. + const std::string prefix = dir_path_ + kFilePrefix; + for (auto i = 0; i < 20; ++i) { + EXPECT_EQ(0, stream_->GetFilePath(i).compare(0, prefix.size(), prefix)); + } +} + +#if defined(WEBRTC_ANDROID) +// Fails on Android: https://bugs.chromium.org/p/webrtc/issues/detail?id=4364. +#define MAYBE_CallSessionFileRotatingStreamTest \ + DISABLED_CallSessionFileRotatingStreamTest +#else +#define MAYBE_CallSessionFileRotatingStreamTest \ + CallSessionFileRotatingStreamTest +#endif + +class MAYBE_CallSessionFileRotatingStreamTest : public ::testing::Test { + protected: + void Init(absl::string_view dir_name, size_t max_total_log_size) { + dir_path_ = webrtc::test::OutputPath(); + + // Append per-test output path in order to run within gtest parallel. + dir_path_.append(dir_name.begin(), dir_name.end()); + dir_path_.append(std::string(webrtc::test::kPathDelimiter)); + ASSERT_TRUE(webrtc::test::CreateDir(dir_path_)); + stream_.reset( + new CallSessionFileRotatingStream(dir_path_, max_total_log_size)); + } + + void TearDown() override { + // On windows, open files can't be removed. + stream_->Close(); + CleanupLogDirectory(*stream_); + EXPECT_TRUE(webrtc::test::RemoveDir(dir_path_)); + + stream_.reset(); + } + + // Writes the data to the stream and flushes it. + void WriteAndFlush(const void* data, const size_t data_len) { + EXPECT_TRUE(stream_->Write(data, data_len)); + EXPECT_TRUE(stream_->Flush()); + } + + // Checks that the stream reads in the expected contents and then returns an + // end of stream result. + void VerifyStreamRead(absl::string_view expected_contents, + absl::string_view dir_path) { + size_t expected_length = expected_contents.size(); + CallSessionFileRotatingStreamReader reader(dir_path); + EXPECT_EQ(reader.GetSize(), expected_length); + std::unique_ptr<uint8_t[]> buffer(new uint8_t[expected_length]); + memset(buffer.get(), 0, expected_length); + EXPECT_EQ(expected_length, reader.ReadAll(buffer.get(), expected_length)); + EXPECT_EQ(0, + memcmp(expected_contents.data(), buffer.get(), expected_length)); + } + + std::unique_ptr<CallSessionFileRotatingStream> stream_; + std::string dir_path_; +}; + +// Tests that writing and reading to a stream with the smallest possible +// capacity works. +TEST_F(MAYBE_CallSessionFileRotatingStreamTest, WriteAndReadSmallest) { + Init("CallSessionFileRotatingStreamTestWriteAndReadSmallest", 4); + + ASSERT_TRUE(stream_->Open()); + std::string message("abcde"); + WriteAndFlush(message.c_str(), message.size()); + std::string expected_contents("abe"); + VerifyStreamRead(expected_contents, dir_path_); +} + +// Tests that writing and reading to a stream with capacity lesser than 4MB +// behaves correctly. +TEST_F(MAYBE_CallSessionFileRotatingStreamTest, WriteAndReadSmall) { + Init("CallSessionFileRotatingStreamTestWriteAndReadSmall", 8); + + ASSERT_TRUE(stream_->Open()); + std::string message("123456789"); + WriteAndFlush(message.c_str(), message.size()); + std::string expected_contents("1234789"); + VerifyStreamRead(expected_contents, dir_path_); +} + +// Tests that writing and reading to a stream with capacity greater than 4MB +// behaves correctly. +TEST_F(MAYBE_CallSessionFileRotatingStreamTest, WriteAndReadLarge) { + Init("CallSessionFileRotatingStreamTestWriteAndReadLarge", 6 * 1024 * 1024); + + ASSERT_TRUE(stream_->Open()); + const size_t buffer_size = 1024 * 1024; + std::unique_ptr<uint8_t[]> buffer(new uint8_t[buffer_size]); + for (int i = 0; i < 8; i++) { + memset(buffer.get(), i, buffer_size); + EXPECT_TRUE(stream_->Write(buffer.get(), buffer_size)); + } + + const int expected_vals[] = {0, 1, 2, 6, 7}; + const size_t expected_size = buffer_size * arraysize(expected_vals); + + CallSessionFileRotatingStreamReader reader(dir_path_); + EXPECT_EQ(reader.GetSize(), expected_size); + std::unique_ptr<uint8_t[]> contents(new uint8_t[expected_size + 1]); + EXPECT_EQ(reader.ReadAll(contents.get(), expected_size + 1), expected_size); + for (size_t i = 0; i < arraysize(expected_vals); ++i) { + const uint8_t* block = contents.get() + i * buffer_size; + bool match = true; + for (size_t j = 0; j < buffer_size; j++) { + if (block[j] != expected_vals[i]) { + match = false; + break; + } + } + // EXPECT call at end of loop, to limit the number of messages on failure. + EXPECT_TRUE(match); + } +} + +// Tests that writing and reading to a stream where only the first file is +// written to behaves correctly. +TEST_F(MAYBE_CallSessionFileRotatingStreamTest, WriteAndReadFirstHalf) { + Init("CallSessionFileRotatingStreamTestWriteAndReadFirstHalf", + 6 * 1024 * 1024); + ASSERT_TRUE(stream_->Open()); + const size_t buffer_size = 1024 * 1024; + std::unique_ptr<uint8_t[]> buffer(new uint8_t[buffer_size]); + for (int i = 0; i < 2; i++) { + memset(buffer.get(), i, buffer_size); + EXPECT_TRUE(stream_->Write(buffer.get(), buffer_size)); + } + + const int expected_vals[] = {0, 1}; + const size_t expected_size = buffer_size * arraysize(expected_vals); + + CallSessionFileRotatingStreamReader reader(dir_path_); + EXPECT_EQ(reader.GetSize(), expected_size); + std::unique_ptr<uint8_t[]> contents(new uint8_t[expected_size + 1]); + EXPECT_EQ(reader.ReadAll(contents.get(), expected_size + 1), expected_size); + + for (size_t i = 0; i < arraysize(expected_vals); ++i) { + const uint8_t* block = contents.get() + i * buffer_size; + bool match = true; + for (size_t j = 0; j < buffer_size; j++) { + if (block[j] != expected_vals[i]) { + match = false; + break; + } + } + // EXPECT call at end of loop, to limit the number of messages on failure. + EXPECT_TRUE(match); + } +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/firewall_socket_server.cc b/third_party/libwebrtc/rtc_base/firewall_socket_server.cc new file mode 100644 index 0000000000..db88d19a15 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/firewall_socket_server.cc @@ -0,0 +1,268 @@ +/* + * 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 "rtc_base/firewall_socket_server.h" + +#include <errno.h> +#include <stddef.h> +#include <stdint.h> + +#include <string> + +#include "absl/algorithm/container.h" +#include "rtc_base/async_socket.h" +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" + +namespace rtc { + +class FirewallSocket : public AsyncSocketAdapter { + public: + FirewallSocket(FirewallSocketServer* server, Socket* socket, int type) + : AsyncSocketAdapter(socket), server_(server), type_(type) {} + + int Bind(const SocketAddress& addr) override { + if (!server_->IsBindableIp(addr.ipaddr())) { + SetError(EINVAL); + return SOCKET_ERROR; + } + return AsyncSocketAdapter::Bind(addr); + } + + int Connect(const SocketAddress& addr) override { + if (type_ == SOCK_STREAM) { + if (!server_->Check(FP_TCP, GetLocalAddress(), addr)) { + RTC_LOG(LS_VERBOSE) << "FirewallSocket outbound TCP connection from " + << GetLocalAddress().ToSensitiveString() << " to " + << addr.ToSensitiveString() << " denied"; + // TODO: Handle this asynchronously. + SetError(EHOSTUNREACH); + return SOCKET_ERROR; + } + } + return AsyncSocketAdapter::Connect(addr); + } + int Send(const void* pv, size_t cb) override { + return SendTo(pv, cb, GetRemoteAddress()); + } + int SendTo(const void* pv, size_t cb, const SocketAddress& addr) override { + RTC_DCHECK(type_ == SOCK_DGRAM || type_ == SOCK_STREAM); + FirewallProtocol protocol = (type_ == SOCK_DGRAM) ? FP_UDP : FP_TCP; + if (!server_->Check(protocol, GetLocalAddress(), addr)) { + RTC_LOG(LS_VERBOSE) << "FirewallSocket outbound packet with type " + << type_ << " from " + << GetLocalAddress().ToSensitiveString() << " to " + << addr.ToSensitiveString() << " dropped"; + return static_cast<int>(cb); + } + return AsyncSocketAdapter::SendTo(pv, cb, addr); + } + int Recv(void* pv, size_t cb, int64_t* timestamp) override { + SocketAddress addr; + return RecvFrom(pv, cb, &addr, timestamp); + } + int RecvFrom(void* pv, + size_t cb, + SocketAddress* paddr, + int64_t* timestamp) override { + if (type_ == SOCK_DGRAM) { + while (true) { + int res = AsyncSocketAdapter::RecvFrom(pv, cb, paddr, timestamp); + if (res <= 0) + return res; + if (server_->Check(FP_UDP, *paddr, GetLocalAddress())) + return res; + RTC_LOG(LS_VERBOSE) + << "FirewallSocket inbound UDP packet from " + << paddr->ToSensitiveString() << " to " + << GetLocalAddress().ToSensitiveString() << " dropped"; + } + } + return AsyncSocketAdapter::RecvFrom(pv, cb, paddr, timestamp); + } + + int Listen(int backlog) override { + if (!server_->tcp_listen_enabled()) { + RTC_LOG(LS_VERBOSE) << "FirewallSocket listen attempt denied"; + return -1; + } + + return AsyncSocketAdapter::Listen(backlog); + } + Socket* Accept(SocketAddress* paddr) override { + SocketAddress addr; + while (Socket* sock = AsyncSocketAdapter::Accept(&addr)) { + if (server_->Check(FP_TCP, addr, GetLocalAddress())) { + if (paddr) + *paddr = addr; + return sock; + } + sock->Close(); + delete sock; + RTC_LOG(LS_VERBOSE) << "FirewallSocket inbound TCP connection from " + << addr.ToSensitiveString() << " to " + << GetLocalAddress().ToSensitiveString() << " denied"; + } + return 0; + } + + private: + FirewallSocketServer* server_; + int type_; +}; + +FirewallSocketServer::FirewallSocketServer(SocketServer* server, + FirewallManager* manager, + bool should_delete_server) + : server_(server), + manager_(manager), + should_delete_server_(should_delete_server), + udp_sockets_enabled_(true), + tcp_sockets_enabled_(true), + tcp_listen_enabled_(true) { + if (manager_) + manager_->AddServer(this); +} + +FirewallSocketServer::~FirewallSocketServer() { + if (manager_) + manager_->RemoveServer(this); + + if (server_ && should_delete_server_) { + delete server_; + server_ = nullptr; + } +} + +void FirewallSocketServer::AddRule(bool allow, + FirewallProtocol p, + FirewallDirection d, + const SocketAddress& addr) { + SocketAddress any; + if (d == FD_IN || d == FD_ANY) { + AddRule(allow, p, any, addr); + } + if (d == FD_OUT || d == FD_ANY) { + AddRule(allow, p, addr, any); + } +} + +void FirewallSocketServer::AddRule(bool allow, + FirewallProtocol p, + const SocketAddress& src, + const SocketAddress& dst) { + Rule r; + r.allow = allow; + r.p = p; + r.src = src; + r.dst = dst; + webrtc::MutexLock scope(&mutex_); + rules_.push_back(r); +} + +void FirewallSocketServer::ClearRules() { + webrtc::MutexLock scope(&mutex_); + rules_.clear(); +} + +bool FirewallSocketServer::Check(FirewallProtocol p, + const SocketAddress& src, + const SocketAddress& dst) { + webrtc::MutexLock scope(&mutex_); + for (size_t i = 0; i < rules_.size(); ++i) { + const Rule& r = rules_[i]; + if ((r.p != p) && (r.p != FP_ANY)) + continue; + if ((r.src.ipaddr() != src.ipaddr()) && !r.src.IsNil()) + continue; + if ((r.src.port() != src.port()) && (r.src.port() != 0)) + continue; + if ((r.dst.ipaddr() != dst.ipaddr()) && !r.dst.IsNil()) + continue; + if ((r.dst.port() != dst.port()) && (r.dst.port() != 0)) + continue; + return r.allow; + } + return true; +} + +void FirewallSocketServer::SetUnbindableIps( + const std::vector<rtc::IPAddress>& unbindable_ips) { + unbindable_ips_ = unbindable_ips; +} + +bool FirewallSocketServer::IsBindableIp(const rtc::IPAddress& ip) { + return !absl::c_linear_search(unbindable_ips_, ip); +} + +Socket* FirewallSocketServer::CreateSocket(int family, int type) { + return WrapSocket(server_->CreateSocket(family, type), type); +} + +void FirewallSocketServer::SetMessageQueue(Thread* queue) { + server_->SetMessageQueue(queue); +} + +bool FirewallSocketServer::Wait(webrtc::TimeDelta max_wait_duration, + bool process_io) { + return server_->Wait(max_wait_duration, process_io); +} + +void FirewallSocketServer::WakeUp() { + return server_->WakeUp(); +} + +Socket* FirewallSocketServer::WrapSocket(Socket* sock, int type) { + if (!sock || (type == SOCK_STREAM && !tcp_sockets_enabled_) || + (type == SOCK_DGRAM && !udp_sockets_enabled_)) { + RTC_LOG(LS_VERBOSE) << "FirewallSocketServer socket creation denied"; + delete sock; + return nullptr; + } + return new FirewallSocket(this, sock, type); +} + +FirewallManager::FirewallManager() {} + +FirewallManager::~FirewallManager() { + RTC_DCHECK(servers_.empty()); +} + +void FirewallManager::AddServer(FirewallSocketServer* server) { + webrtc::MutexLock scope(&mutex_); + servers_.push_back(server); +} + +void FirewallManager::RemoveServer(FirewallSocketServer* server) { + webrtc::MutexLock scope(&mutex_); + servers_.erase(std::remove(servers_.begin(), servers_.end(), server), + servers_.end()); +} + +void FirewallManager::AddRule(bool allow, + FirewallProtocol p, + FirewallDirection d, + const SocketAddress& addr) { + webrtc::MutexLock scope(&mutex_); + for (std::vector<FirewallSocketServer*>::const_iterator it = servers_.begin(); + it != servers_.end(); ++it) { + (*it)->AddRule(allow, p, d, addr); + } +} + +void FirewallManager::ClearRules() { + webrtc::MutexLock scope(&mutex_); + for (std::vector<FirewallSocketServer*>::const_iterator it = servers_.begin(); + it != servers_.end(); ++it) { + (*it)->ClearRules(); + } +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/firewall_socket_server.h b/third_party/libwebrtc/rtc_base/firewall_socket_server.h new file mode 100644 index 0000000000..63f9e1ac6c --- /dev/null +++ b/third_party/libwebrtc/rtc_base/firewall_socket_server.h @@ -0,0 +1,129 @@ +/* + * 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 RTC_BASE_FIREWALL_SOCKET_SERVER_H_ +#define RTC_BASE_FIREWALL_SOCKET_SERVER_H_ + +#include <vector> + +#include "rtc_base/ip_address.h" +#include "rtc_base/socket.h" +#include "rtc_base/socket_address.h" +#include "rtc_base/socket_server.h" +#include "rtc_base/synchronization/mutex.h" + +namespace rtc { + +class FirewallManager; + +// This SocketServer shim simulates a rule-based firewall server. + +enum FirewallProtocol { FP_UDP, FP_TCP, FP_ANY }; +enum FirewallDirection { FD_IN, FD_OUT, FD_ANY }; + +class FirewallSocketServer : public SocketServer { + public: + FirewallSocketServer(SocketServer* server, + FirewallManager* manager = nullptr, + bool should_delete_server = false); + ~FirewallSocketServer() override; + + SocketServer* socketserver() const { return server_; } + void set_socketserver(SocketServer* server) { + if (server_ && should_delete_server_) { + delete server_; + server_ = nullptr; + should_delete_server_ = false; + } + server_ = server; + } + + // Settings to control whether CreateSocket or Socket::Listen succeed. + void set_udp_sockets_enabled(bool enabled) { udp_sockets_enabled_ = enabled; } + void set_tcp_sockets_enabled(bool enabled) { tcp_sockets_enabled_ = enabled; } + bool tcp_listen_enabled() const { return tcp_listen_enabled_; } + void set_tcp_listen_enabled(bool enabled) { tcp_listen_enabled_ = enabled; } + + // Rules govern the behavior of Connect/Accept/Send/Recv attempts. + void AddRule(bool allow, + FirewallProtocol p = FP_ANY, + FirewallDirection d = FD_ANY, + const SocketAddress& addr = SocketAddress()); + void AddRule(bool allow, + FirewallProtocol p, + const SocketAddress& src, + const SocketAddress& dst); + void ClearRules(); + + bool Check(FirewallProtocol p, + const SocketAddress& src, + const SocketAddress& dst); + + // Set the IP addresses for which Bind will fail. By default this list is + // empty. This can be used to simulate a real OS that refuses to bind to + // addresses under various circumstances. + // + // No matter how many addresses are added (including INADDR_ANY), the server + // will still allow creating outgoing TCP connections, since they don't + // require explicitly binding a socket. + void SetUnbindableIps(const std::vector<rtc::IPAddress>& unbindable_ips); + bool IsBindableIp(const rtc::IPAddress& ip); + + Socket* CreateSocket(int family, int type) override; + + void SetMessageQueue(Thread* queue) override; + bool Wait(webrtc::TimeDelta max_wait_duration, bool process_io) override; + void WakeUp() override; + + Socket* WrapSocket(Socket* sock, int type); + + private: + SocketServer* server_; + FirewallManager* manager_; + webrtc::Mutex mutex_; + struct Rule { + bool allow; + FirewallProtocol p; + FirewallDirection d; + SocketAddress src; + SocketAddress dst; + }; + std::vector<Rule> rules_; + std::vector<rtc::IPAddress> unbindable_ips_; + bool should_delete_server_; + bool udp_sockets_enabled_; + bool tcp_sockets_enabled_; + bool tcp_listen_enabled_; +}; + +// FirewallManager allows you to manage firewalls in multiple threads together + +class FirewallManager { + public: + FirewallManager(); + ~FirewallManager(); + + void AddServer(FirewallSocketServer* server); + void RemoveServer(FirewallSocketServer* server); + + void AddRule(bool allow, + FirewallProtocol p = FP_ANY, + FirewallDirection d = FD_ANY, + const SocketAddress& addr = SocketAddress()); + void ClearRules(); + + private: + webrtc::Mutex mutex_; + std::vector<FirewallSocketServer*> servers_; +}; + +} // namespace rtc + +#endif // RTC_BASE_FIREWALL_SOCKET_SERVER_H_ diff --git a/third_party/libwebrtc/rtc_base/frequency_tracker.cc b/third_party/libwebrtc/rtc_base/frequency_tracker.cc new file mode 100644 index 0000000000..c3be30e3b8 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/frequency_tracker.cc @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2023 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 "rtc_base/frequency_tracker.h" + +#include "absl/types/optional.h" +#include "api/units/frequency.h" +#include "api/units/time_delta.h" +#include "api/units/timestamp.h" +#include "rtc_base/rate_statistics.h" + +namespace webrtc { + +FrequencyTracker::FrequencyTracker(TimeDelta max_window_size) + : impl_(max_window_size.ms(), 1'000'000) {} + +absl::optional<Frequency> FrequencyTracker::Rate(Timestamp now) const { + if (absl::optional<int64_t> rate = impl_.Rate(now.ms())) { + return Frequency::MilliHertz(*rate); + } + return absl::nullopt; +} + +void FrequencyTracker::Update(int64_t count, Timestamp now) { + impl_.Update(count, now.ms()); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/frequency_tracker.h b/third_party/libwebrtc/rtc_base/frequency_tracker.h new file mode 100644 index 0000000000..3ee2ab0e1a --- /dev/null +++ b/third_party/libwebrtc/rtc_base/frequency_tracker.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2023 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 RTC_BASE_FREQUENCY_TRACKER_H_ +#define RTC_BASE_FREQUENCY_TRACKER_H_ + +#include <stddef.h> +#include <stdint.h> + +#include "absl/types/optional.h" +#include "api/units/frequency.h" +#include "api/units/time_delta.h" +#include "api/units/timestamp.h" +#include "rtc_base/rate_statistics.h" +#include "rtc_base/system/rtc_export.h" + +namespace webrtc { +// Class to estimate frequency (e.g. frame rate) over running window. +// Timestamps used in Update() and Rate() must never decrease for two +// consecutive calls. +// This class is thread unsafe. +class RTC_EXPORT FrequencyTracker { + public: + explicit FrequencyTracker(TimeDelta window_size); + + FrequencyTracker(const FrequencyTracker&) = default; + FrequencyTracker(FrequencyTracker&&) = default; + FrequencyTracker& operator=(const FrequencyTracker&) = delete; + FrequencyTracker& operator=(FrequencyTracker&&) = delete; + + ~FrequencyTracker() = default; + + // Reset instance to original state. + void Reset() { impl_.Reset(); } + + // Update rate with a new data point, moving averaging window as needed. + void Update(int64_t count, Timestamp now); + void Update(Timestamp now) { Update(1, now); } + + // Returns rate, moving averaging window as needed. + // Returns nullopt when rate can't be measured. + absl::optional<Frequency> Rate(Timestamp now) const; + + private: + RateStatistics impl_; +}; +} // namespace webrtc + +#endif // RTC_BASE_FREQUENCY_TRACKER_H_ diff --git a/third_party/libwebrtc/rtc_base/frequency_tracker_gn/moz.build b/third_party/libwebrtc/rtc_base/frequency_tracker_gn/moz.build new file mode 100644 index 0000000000..30c52de724 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/frequency_tracker_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/rtc_base/frequency_tracker.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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("frequency_tracker_gn") diff --git a/third_party/libwebrtc/rtc_base/frequency_tracker_unittest.cc b/third_party/libwebrtc/rtc_base/frequency_tracker_unittest.cc new file mode 100644 index 0000000000..00788c3ee8 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/frequency_tracker_unittest.cc @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2023 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 "rtc_base/frequency_tracker.h" + +#include <cstdlib> +#include <limits> + +#include "absl/types/optional.h" +#include "api/units/frequency.h" +#include "api/units/time_delta.h" +#include "api/units/timestamp.h" +#include "test/gmock.h" +#include "test/gtest.h" + +namespace webrtc { +namespace { + +using ::testing::AllOf; +using ::testing::Gt; +using ::testing::Lt; + +constexpr TimeDelta kWindow = TimeDelta::Millis(500); +constexpr TimeDelta kEpsilon = TimeDelta::Millis(1); + +TEST(FrequencyTrackerTest, ReturnsNulloptInitially) { + Timestamp now = Timestamp::Seconds(12'345); + FrequencyTracker stats(kWindow); + + EXPECT_EQ(stats.Rate(now), absl::nullopt); +} + +TEST(FrequencyTrackerTest, ReturnsNulloptAfterSingleDataPoint) { + Timestamp now = Timestamp::Seconds(12'345); + FrequencyTracker stats(kWindow); + + stats.Update(now); + now += TimeDelta::Millis(10); + + EXPECT_EQ(stats.Rate(now), absl::nullopt); +} + +TEST(FrequencyTrackerTest, ReturnsRateAfterTwoMeasurements) { + Timestamp now = Timestamp::Seconds(12'345); + FrequencyTracker stats(kWindow); + + stats.Update(now); + now += TimeDelta::Millis(1); + stats.Update(now); + + // 1 event per 1 ms ~= 1'000 events per second. + EXPECT_EQ(stats.Rate(now), Frequency::Hertz(1'000)); +} + +TEST(FrequencyTrackerTest, MeasuresConstantRate) { + const Timestamp start = Timestamp::Seconds(12'345); + const TimeDelta kInterval = TimeDelta::Millis(10); + const Frequency kConstantRate = 1 / kInterval; + + Timestamp now = start; + FrequencyTracker stats(kWindow); + + stats.Update(now); + Frequency last_error = Frequency::PlusInfinity(); + for (TimeDelta i = TimeDelta::Zero(); i < kWindow; i += kInterval) { + SCOPED_TRACE(i); + now += kInterval; + stats.Update(now); + + // Until window is full, rate is measured over a smaller window and might + // look larger than the constant rate. + absl::optional<Frequency> rate = stats.Rate(now); + ASSERT_GE(rate, kConstantRate); + + // Expect the estimation error to decrease as the window is extended. + Frequency error = *rate - kConstantRate; + EXPECT_LE(error, last_error); + last_error = error; + } + + // Once window is full, rate measurment should be stable. + for (TimeDelta i = TimeDelta::Zero(); i < kInterval; + i += TimeDelta::Millis(1)) { + SCOPED_TRACE(i); + EXPECT_EQ(stats.Rate(now + i), kConstantRate); + } +} + +TEST(FrequencyTrackerTest, CanMeasureFractionalRate) { + const TimeDelta kInterval = TimeDelta::Millis(134); + Timestamp now = Timestamp::Seconds(12'345); + // FrequencyTracker counts number of events in the window, thus when window is + // fraction of 1 second, number of events per second would always be integer. + const TimeDelta window = TimeDelta::Seconds(2); + + FrequencyTracker framerate(window); + framerate.Update(now); + for (TimeDelta i = TimeDelta::Zero(); i < window; i += kInterval) { + now += kInterval; + framerate.Update(now); + } + + // Should be aproximitly 7.5 fps + EXPECT_THAT(framerate.Rate(now), + AllOf(Gt(Frequency::Hertz(7)), Lt(Frequency::Hertz(8)))); +} + +TEST(FrequencyTrackerTest, IncreasingThenDecreasingRate) { + const int64_t kLargeSize = 1'500; + const int64_t kSmallSize = 300; + const TimeDelta kLargeInterval = TimeDelta::Millis(10); + const TimeDelta kSmallInterval = TimeDelta::Millis(2); + + Timestamp now = Timestamp::Seconds(12'345); + FrequencyTracker stats(kWindow); + + stats.Update(kLargeSize, now); + for (TimeDelta i = TimeDelta::Zero(); i < kWindow; i += kLargeInterval) { + SCOPED_TRACE(i); + now += kLargeInterval; + stats.Update(kLargeSize, now); + } + absl::optional<Frequency> last_rate = stats.Rate(now); + EXPECT_EQ(last_rate, kLargeSize / kLargeInterval); + + // Decrease rate with smaller measurments. + for (TimeDelta i = TimeDelta::Zero(); i < kWindow; i += kLargeInterval) { + SCOPED_TRACE(i); + now += kLargeInterval; + stats.Update(kSmallSize, now); + + absl::optional<Frequency> rate = stats.Rate(now); + EXPECT_LT(rate, last_rate); + + last_rate = rate; + } + EXPECT_EQ(last_rate, kSmallSize / kLargeInterval); + + // Increase rate with more frequent measurments. + for (TimeDelta i = TimeDelta::Zero(); i < kWindow; i += kSmallInterval) { + SCOPED_TRACE(i); + now += kSmallInterval; + stats.Update(kSmallSize, now); + + absl::optional<Frequency> rate = stats.Rate(now); + EXPECT_GE(rate, last_rate); + + last_rate = rate; + } + EXPECT_EQ(last_rate, kSmallSize / kSmallInterval); +} + +TEST(FrequencyTrackerTest, ResetAfterSilence) { + const TimeDelta kInterval = TimeDelta::Millis(10); + const int64_t kPixels = 640 * 360; + + Timestamp now = Timestamp::Seconds(12'345); + FrequencyTracker pixel_rate(kWindow); + + // Feed data until window has been filled. + pixel_rate.Update(kPixels, now); + for (TimeDelta i = TimeDelta::Zero(); i < kWindow; i += kInterval) { + now += kInterval; + pixel_rate.Update(kPixels, now); + } + ASSERT_GT(pixel_rate.Rate(now), Frequency::Zero()); + + now += kWindow + kEpsilon; + // Silence over window size should trigger auto reset for coming sample. + EXPECT_EQ(pixel_rate.Rate(now), absl::nullopt); + pixel_rate.Update(kPixels, now); + // Single measurment after reset is not enough to estimate the rate. + EXPECT_EQ(pixel_rate.Rate(now), absl::nullopt); + + // Manual reset, add the same check again. + pixel_rate.Reset(); + EXPECT_EQ(pixel_rate.Rate(now), absl::nullopt); + now += kInterval; + pixel_rate.Update(kPixels, now); + EXPECT_EQ(pixel_rate.Rate(now), absl::nullopt); +} + +TEST(FrequencyTrackerTest, ReturnsNulloptWhenOverflows) { + Timestamp now = Timestamp::Seconds(12'345); + FrequencyTracker stats(kWindow); + + int64_t very_large_number = std::numeric_limits<int64_t>::max(); + stats.Update(very_large_number, now); + now += kEpsilon; + stats.Update(very_large_number, now); + + EXPECT_EQ(stats.Rate(now), absl::nullopt); +} + +} // namespace +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/gtest_prod_gn/moz.build b/third_party/libwebrtc/rtc_base/gtest_prod_gn/moz.build new file mode 100644 index 0000000000..eb85347810 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/gtest_prod_gn/moz.build @@ -0,0 +1,205 @@ +# 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("gtest_prod_gn") diff --git a/third_party/libwebrtc/rtc_base/gtest_prod_util.h b/third_party/libwebrtc/rtc_base/gtest_prod_util.h new file mode 100644 index 0000000000..0661cd7bd9 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/gtest_prod_util.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2012 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 RTC_BASE_GTEST_PROD_UTIL_H_ +#define RTC_BASE_GTEST_PROD_UTIL_H_ + +// Define our own version of FRIEND_TEST here rather than including +// gtest_prod.h to avoid depending on any part of GTest in production code. +#define FRIEND_TEST_WEBRTC(test_case_name, test_name) \ + friend class test_case_name##_##test_name##_Test + +// This file is a plain copy of Chromium's base/gtest_prod_util.h. +// +// This is a wrapper for gtest's FRIEND_TEST macro that friends +// test with all possible prefixes. This is very helpful when changing the test +// prefix, because the friend declarations don't need to be updated. +// +// Example usage: +// +// class MyClass { +// private: +// void MyMethod(); +// FRIEND_TEST_ALL_PREFIXES(MyClassTest, MyMethod); +// }; +#define FRIEND_TEST_ALL_PREFIXES(test_case_name, test_name) \ + FRIEND_TEST_WEBRTC(test_case_name, test_name); \ + FRIEND_TEST_WEBRTC(test_case_name, DISABLED_##test_name); \ + FRIEND_TEST_WEBRTC(test_case_name, FLAKY_##test_name); \ + FRIEND_TEST_WEBRTC(test_case_name, FAILS_##test_name) + +#endif // RTC_BASE_GTEST_PROD_UTIL_H_ diff --git a/third_party/libwebrtc/rtc_base/gunit.cc b/third_party/libwebrtc/rtc_base/gunit.cc new file mode 100644 index 0000000000..7cd60fe9ee --- /dev/null +++ b/third_party/libwebrtc/rtc_base/gunit.cc @@ -0,0 +1,43 @@ +/* + * 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. + */ + +#include "rtc_base/gunit.h" + +#include <string> + +#include "absl/strings/match.h" +#include "absl/strings/string_view.h" + +::testing::AssertionResult AssertStartsWith(const char* text_expr, + const char* prefix_expr, + absl::string_view text, + absl::string_view prefix) { + if (absl::StartsWith(text, prefix)) { + return ::testing::AssertionSuccess(); + } else { + return ::testing::AssertionFailure() + << text_expr << "\nwhich is\n\"" << text + << "\"\ndoes not start with\n" + << prefix_expr << "\nwhich is\n\"" << prefix << "\""; + } +} + +::testing::AssertionResult AssertStringContains(const char* str_expr, + const char* substr_expr, + absl::string_view str, + absl::string_view substr) { + if (str.find(substr) != absl::string_view::npos) { + return ::testing::AssertionSuccess(); + } else { + return ::testing::AssertionFailure() + << str_expr << "\nwhich is\n\"" << str << "\"\ndoes not contain\n" + << substr_expr << "\nwhich is\n\"" << substr << "\""; + } +} diff --git a/third_party/libwebrtc/rtc_base/gunit.h b/third_party/libwebrtc/rtc_base/gunit.h new file mode 100644 index 0000000000..6bc1419729 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/gunit.h @@ -0,0 +1,169 @@ +/* + * 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 RTC_BASE_GUNIT_H_ +#define RTC_BASE_GUNIT_H_ + +#include "absl/strings/string_view.h" +#include "rtc_base/fake_clock.h" +#include "rtc_base/logging.h" +#include "rtc_base/thread.h" +#include "test/gtest.h" + +// Wait until "ex" is true, or "timeout" expires. +#define WAIT(ex, timeout) \ + for (int64_t start = rtc::SystemTimeMillis(); \ + !(ex) && rtc::SystemTimeMillis() < start + (timeout);) { \ + rtc::Thread::Current()->ProcessMessages(0); \ + rtc::Thread::Current()->SleepMs(1); \ + } + +// This returns the result of the test in res, so that we don't re-evaluate +// the expression in the XXXX_WAIT macros below, since that causes problems +// when the expression is only true the first time you check it. +#define WAIT_(ex, timeout, res) \ + do { \ + int64_t start = rtc::SystemTimeMillis(); \ + res = (ex) && true; \ + while (!res && rtc::SystemTimeMillis() < start + (timeout)) { \ + rtc::Thread::Current()->ProcessMessages(0); \ + rtc::Thread::Current()->SleepMs(1); \ + res = (ex) && true; \ + } \ + } while (0) + +// The typical EXPECT_XXXX and ASSERT_XXXXs, but done until true or a timeout. +// One can add failure message by appending "<< msg". +#define EXPECT_TRUE_WAIT(ex, timeout) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (bool res = true) { \ + WAIT_(ex, timeout, res); \ + if (!res) \ + goto GTEST_CONCAT_TOKEN_(gunit_label_, __LINE__); \ + } else \ + GTEST_CONCAT_TOKEN_(gunit_label_, __LINE__) : EXPECT_TRUE(ex) + +#define EXPECT_EQ_WAIT(v1, v2, timeout) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (bool res = true) { \ + WAIT_(v1 == v2, timeout, res); \ + if (!res) \ + goto GTEST_CONCAT_TOKEN_(gunit_label_, __LINE__); \ + } else \ + GTEST_CONCAT_TOKEN_(gunit_label_, __LINE__) : EXPECT_EQ(v1, v2) + +#define ASSERT_TRUE_WAIT(ex, timeout) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (bool res = true) { \ + WAIT_(ex, timeout, res); \ + if (!res) \ + goto GTEST_CONCAT_TOKEN_(gunit_label_, __LINE__); \ + } else \ + GTEST_CONCAT_TOKEN_(gunit_label_, __LINE__) : ASSERT_TRUE(ex) + +#define ASSERT_EQ_WAIT(v1, v2, timeout) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (bool res = true) { \ + WAIT_(v1 == v2, timeout, res); \ + if (!res) \ + goto GTEST_CONCAT_TOKEN_(gunit_label_, __LINE__); \ + } else \ + GTEST_CONCAT_TOKEN_(gunit_label_, __LINE__) : ASSERT_EQ(v1, v2) + +// Version with a "soft" timeout and a margin. This logs if the timeout is +// exceeded, but it only fails if the expression still isn't true after the +// margin time passes. +#define EXPECT_TRUE_WAIT_MARGIN(ex, timeout, margin) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (bool res = true) { \ + WAIT_(ex, timeout, res); \ + if (res) \ + break; \ + RTC_LOG(LS_WARNING) << "Expression " << #ex << " still not true after " \ + << (timeout) << "ms; waiting an additional " << margin \ + << "ms"; \ + WAIT_(ex, margin, res); \ + if (!res) \ + goto GTEST_CONCAT_TOKEN_(gunit_label_, __LINE__); \ + } else \ + GTEST_CONCAT_TOKEN_(gunit_label_, __LINE__) : EXPECT_TRUE(ex) + +// Wait until "ex" is true, or "timeout" expires, using fake clock where +// messages are processed every millisecond. +// TODO(pthatcher): Allow tests to control how many milliseconds to advance. +#define SIMULATED_WAIT(ex, timeout, clock) \ + for (int64_t start = rtc::TimeMillis(); \ + !(ex) && rtc::TimeMillis() < start + (timeout);) { \ + (clock).AdvanceTime(webrtc::TimeDelta::Millis(1)); \ + } + +// This returns the result of the test in res, so that we don't re-evaluate +// the expression in the XXXX_WAIT macros below, since that causes problems +// when the expression is only true the first time you check it. +#define SIMULATED_WAIT_(ex, timeout, res, clock) \ + do { \ + int64_t start = rtc::TimeMillis(); \ + res = (ex); \ + while (!res && rtc::TimeMillis() < start + (timeout)) { \ + (clock).AdvanceTime(webrtc::TimeDelta::Millis(1)); \ + res = (ex); \ + } \ + } while (0) + +// The typical EXPECT_XXXX, but done until true or a timeout with a fake clock. +#define EXPECT_TRUE_SIMULATED_WAIT(ex, timeout, clock) \ + do { \ + bool res; \ + SIMULATED_WAIT_(ex, timeout, res, clock); \ + if (!res) { \ + EXPECT_TRUE(ex); \ + } \ + } while (0) + +#define EXPECT_EQ_SIMULATED_WAIT(v1, v2, timeout, clock) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (bool res = true) { \ + SIMULATED_WAIT_(v1 == v2, timeout, res, clock); \ + if (!res) \ + goto GTEST_CONCAT_TOKEN_(gunit_label_, __LINE__); \ + } else \ + GTEST_CONCAT_TOKEN_(gunit_label_, __LINE__) : EXPECT_EQ(v1, v2) + +#define ASSERT_TRUE_SIMULATED_WAIT(ex, timeout, clock) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (bool res = true) { \ + SIMULATED_WAIT_(ex, timeout, res, clock); \ + if (!res) \ + goto GTEST_CONCAT_TOKEN_(gunit_label_, __LINE__); \ + } else \ + GTEST_CONCAT_TOKEN_(gunit_label_, __LINE__) : ASSERT_TRUE(ex) + +#define ASSERT_EQ_SIMULATED_WAIT(v1, v2, timeout, clock) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (bool res = true) { \ + SIMULATED_WAIT_(v1 == v2, timeout, res, clock); \ + if (!res) \ + goto GTEST_CONCAT_TOKEN_(gunit_label_, __LINE__); \ + } else \ + GTEST_CONCAT_TOKEN_(gunit_label_, __LINE__) : ASSERT_EQ(v1, v2) + +// Usage: EXPECT_PRED_FORMAT2(AssertStartsWith, text, "prefix"); +testing::AssertionResult AssertStartsWith(const char* text_expr, + const char* prefix_expr, + absl::string_view text, + absl::string_view prefix); + +// Usage: EXPECT_PRED_FORMAT2(AssertStringContains, str, "substring"); +testing::AssertionResult AssertStringContains(const char* str_expr, + const char* substr_expr, + absl::string_view str, + absl::string_view substr); + +#endif // RTC_BASE_GUNIT_H_ diff --git a/third_party/libwebrtc/rtc_base/helpers.cc b/third_party/libwebrtc/rtc_base/helpers.cc new file mode 100644 index 0000000000..84cbe5fba1 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/helpers.cc @@ -0,0 +1,231 @@ +/* + * 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 "rtc_base/helpers.h" + +#include <openssl/rand.h> + +#include <cstdint> +#include <limits> +#include <memory> + +#include "absl/strings/string_view.h" +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" +#include "rtc_base/synchronization/mutex.h" + +// Protect against max macro inclusion. +#undef max + +namespace rtc { + +namespace { + +// The OpenSSL RNG. +class SecureRandomGenerator : public RandomGenerator { + public: + SecureRandomGenerator() {} + ~SecureRandomGenerator() override {} + bool Init(const void* seed, size_t len) override { return true; } + bool Generate(void* buf, size_t len) override { + return (RAND_bytes(reinterpret_cast<unsigned char*>(buf), len) > 0); + } +}; + +// A test random generator, for predictable output. +class TestRandomGenerator : public RandomGenerator { + public: + TestRandomGenerator() : seed_(7) {} + ~TestRandomGenerator() override {} + bool Init(const void* seed, size_t len) override { return true; } + bool Generate(void* buf, size_t len) override { + for (size_t i = 0; i < len; ++i) { + static_cast<uint8_t*>(buf)[i] = static_cast<uint8_t>(GetRandom()); + } + return true; + } + + private: + int GetRandom() { + return ((seed_ = seed_ * 214013L + 2531011L) >> 16) & 0x7fff; + } + int seed_; +}; + +// TODO: Use Base64::Base64Table instead. +static const char kBase64[64] = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'}; + +static const char kHex[16] = {'0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + +static const char kUuidDigit17[4] = {'8', '9', 'a', 'b'}; + +// Lock for the global random generator, only needed to serialize changing the +// generator. +webrtc::Mutex& GetRandomGeneratorLock() { + static webrtc::Mutex& mutex = *new webrtc::Mutex(); + return mutex; +} + +// This round about way of creating a global RNG is to safe-guard against +// indeterminant static initialization order. +std::unique_ptr<RandomGenerator>& GetGlobalRng() { + static std::unique_ptr<RandomGenerator>& global_rng = + *new std::unique_ptr<RandomGenerator>(new SecureRandomGenerator()); + + return global_rng; +} + +RandomGenerator& Rng() { + return *GetGlobalRng(); +} + +} // namespace + +void SetDefaultRandomGenerator() { + webrtc::MutexLock lock(&GetRandomGeneratorLock()); + GetGlobalRng().reset(new SecureRandomGenerator()); +} + +void SetRandomGenerator(std::unique_ptr<RandomGenerator> generator) { + webrtc::MutexLock lock(&GetRandomGeneratorLock()); + GetGlobalRng() = std::move(generator); +} + +void SetRandomTestMode(bool test) { + webrtc::MutexLock lock(&GetRandomGeneratorLock()); + if (!test) { + GetGlobalRng().reset(new SecureRandomGenerator()); + } else { + GetGlobalRng().reset(new TestRandomGenerator()); + } +} + +bool InitRandom(int seed) { + return InitRandom(reinterpret_cast<const char*>(&seed), sizeof(seed)); +} + +bool InitRandom(const char* seed, size_t len) { + if (!Rng().Init(seed, len)) { + RTC_LOG(LS_ERROR) << "Failed to init random generator!"; + return false; + } + return true; +} + +std::string CreateRandomString(size_t len) { + std::string str; + RTC_CHECK(CreateRandomString(len, &str)); + return str; +} + +static bool CreateRandomString(size_t len, + const char* table, + int table_size, + std::string* str) { + str->clear(); + // Avoid biased modulo division below. + if (256 % table_size) { + RTC_LOG(LS_ERROR) << "Table size must divide 256 evenly!"; + return false; + } + std::unique_ptr<uint8_t[]> bytes(new uint8_t[len]); + if (!Rng().Generate(bytes.get(), len)) { + RTC_LOG(LS_ERROR) << "Failed to generate random string!"; + return false; + } + str->reserve(len); + for (size_t i = 0; i < len; ++i) { + str->push_back(table[bytes[i] % table_size]); + } + return true; +} + +bool CreateRandomString(size_t len, std::string* str) { + return CreateRandomString(len, kBase64, 64, str); +} + +bool CreateRandomString(size_t len, absl::string_view table, std::string* str) { + return CreateRandomString(len, table.data(), static_cast<int>(table.size()), + str); +} + +bool CreateRandomData(size_t length, std::string* data) { + data->resize(length); + // std::string is guaranteed to use contiguous memory in c++11 so we can + // safely write directly to it. + return Rng().Generate(&data->at(0), length); +} + +// Version 4 UUID is of the form: +// xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx +// Where 'x' is a hex digit, and 'y' is 8, 9, a or b. +std::string CreateRandomUuid() { + std::string str; + std::unique_ptr<uint8_t[]> bytes(new uint8_t[31]); + RTC_CHECK(Rng().Generate(bytes.get(), 31)); + str.reserve(36); + for (size_t i = 0; i < 8; ++i) { + str.push_back(kHex[bytes[i] % 16]); + } + str.push_back('-'); + for (size_t i = 8; i < 12; ++i) { + str.push_back(kHex[bytes[i] % 16]); + } + str.push_back('-'); + str.push_back('4'); + for (size_t i = 12; i < 15; ++i) { + str.push_back(kHex[bytes[i] % 16]); + } + str.push_back('-'); + str.push_back(kUuidDigit17[bytes[15] % 4]); + for (size_t i = 16; i < 19; ++i) { + str.push_back(kHex[bytes[i] % 16]); + } + str.push_back('-'); + for (size_t i = 19; i < 31; ++i) { + str.push_back(kHex[bytes[i] % 16]); + } + return str; +} + +uint32_t CreateRandomId() { + uint32_t id; + RTC_CHECK(Rng().Generate(&id, sizeof(id))); + return id; +} + +uint64_t CreateRandomId64() { + return static_cast<uint64_t>(CreateRandomId()) << 32 | CreateRandomId(); +} + +uint32_t CreateRandomNonZeroId() { + uint32_t id; + do { + id = CreateRandomId(); + } while (id == 0); + return id; +} + +double CreateRandomDouble() { + return CreateRandomId() / (std::numeric_limits<uint32_t>::max() + + std::numeric_limits<double>::epsilon()); +} + +double GetNextMovingAverage(double prev_average, double cur, double ratio) { + return (ratio * prev_average + cur) / (ratio + 1); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/helpers.h b/third_party/libwebrtc/rtc_base/helpers.h new file mode 100644 index 0000000000..51ca672ab5 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/helpers.h @@ -0,0 +1,92 @@ +/* + * 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 RTC_BASE_HELPERS_H_ +#define RTC_BASE_HELPERS_H_ + +#include <stddef.h> +#include <stdint.h> + +#include <memory> +#include <string> + +#include "absl/strings/string_view.h" +#include "rtc_base/system/rtc_export.h" + +namespace rtc { + +// Interface for RNG implementations. +class RandomGenerator { + public: + virtual ~RandomGenerator() {} + virtual bool Init(const void* seed, size_t len) = 0; + virtual bool Generate(void* buf, size_t len) = 0; +}; + +// Sets the default random generator as the source of randomness. The default +// source uses the OpenSSL RNG and provides cryptographically secure randomness. +void SetDefaultRandomGenerator(); + +// Set a custom random generator. Results produced by CreateRandomXyz +// are cryptographically random iff the output of the supplied generator is +// cryptographically random. +void SetRandomGenerator(std::unique_ptr<RandomGenerator> generator); + +// For testing, we can return predictable data. +void SetRandomTestMode(bool test); + +// Initializes the RNG, and seeds it with the specified entropy. +bool InitRandom(int seed); +bool InitRandom(const char* seed, size_t len); + +// Generates a (cryptographically) random string of the given length. +// We generate base64 values so that they will be printable. +RTC_EXPORT std::string CreateRandomString(size_t length); + +// Generates a (cryptographically) random string of the given length. +// We generate base64 values so that they will be printable. +// Return false if the random number generator failed. +RTC_EXPORT bool CreateRandomString(size_t length, std::string* str); + +// Generates a (cryptographically) random string of the given length, +// with characters from the given table. Return false if the random +// number generator failed. +// For ease of implementation, the function requires that the table +// size evenly divide 256; otherwise, it returns false. +RTC_EXPORT bool CreateRandomString(size_t length, + absl::string_view table, + std::string* str); + +// Generates (cryptographically) random data of the given length. +// Return false if the random number generator failed. +bool CreateRandomData(size_t length, std::string* data); + +// Generates a (cryptographically) random UUID version 4 string. +std::string CreateRandomUuid(); + +// Generates a random id. +uint32_t CreateRandomId(); + +// Generates a 64 bit random id. +RTC_EXPORT uint64_t CreateRandomId64(); + +// Generates a random id > 0. +uint32_t CreateRandomNonZeroId(); + +// Generates a random double between 0.0 (inclusive) and 1.0 (exclusive). +double CreateRandomDouble(); + +// Compute moving average with the given ratio between the previous average +// value and the current value. +double GetNextMovingAverage(double prev_average, double cur, double ratio); + +} // namespace rtc + +#endif // RTC_BASE_HELPERS_H_ diff --git a/third_party/libwebrtc/rtc_base/helpers_unittest.cc b/third_party/libwebrtc/rtc_base/helpers_unittest.cc new file mode 100644 index 0000000000..015b4d0a7c --- /dev/null +++ b/third_party/libwebrtc/rtc_base/helpers_unittest.cc @@ -0,0 +1,171 @@ +/* + * 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 "rtc_base/helpers.h" + +#include <string.h> + +#include <cstring> +#include <string> + +#include "rtc_base/buffer.h" +#include "test/gmock.h" +#include "test/gtest.h" + +namespace rtc { +namespace { + +using ::testing::_; +using ::testing::DoAll; +using ::testing::Invoke; +using ::testing::IsEmpty; +using ::testing::Not; +using ::testing::Return; +using ::testing::WithArg; +using ::testing::WithArgs; + +TEST(RandomTest, TestCreateRandomId) { + CreateRandomId(); +} + +TEST(RandomTest, TestCreateRandomDouble) { + for (int i = 0; i < 100; ++i) { + double r = CreateRandomDouble(); + EXPECT_GE(r, 0.0); + EXPECT_LT(r, 1.0); + } +} + +TEST(RandomTest, TestCreateNonZeroRandomId) { + EXPECT_NE(0U, CreateRandomNonZeroId()); +} + +TEST(RandomTest, TestCreateRandomString) { + std::string random = CreateRandomString(256); + EXPECT_EQ(256U, random.size()); + std::string random2; + EXPECT_TRUE(CreateRandomString(256, &random2)); + EXPECT_NE(random, random2); + EXPECT_EQ(256U, random2.size()); +} + +TEST(RandomTest, TestCreateRandomData) { + static size_t kRandomDataLength = 32; + std::string random1; + std::string random2; + EXPECT_TRUE(CreateRandomData(kRandomDataLength, &random1)); + EXPECT_EQ(kRandomDataLength, random1.size()); + EXPECT_TRUE(CreateRandomData(kRandomDataLength, &random2)); + EXPECT_EQ(kRandomDataLength, random2.size()); + EXPECT_NE(0, memcmp(random1.data(), random2.data(), kRandomDataLength)); +} + +TEST(RandomTest, TestCreateRandomStringEvenlyDivideTable) { + static std::string kUnbiasedTable("01234567"); + std::string random; + EXPECT_TRUE(CreateRandomString(256, kUnbiasedTable, &random)); + EXPECT_EQ(256U, random.size()); + + static std::string kBiasedTable("0123456789"); + EXPECT_FALSE(CreateRandomString(256, kBiasedTable, &random)); + EXPECT_EQ(0U, random.size()); +} + +TEST(RandomTest, TestCreateRandomUuid) { + std::string random = CreateRandomUuid(); + EXPECT_EQ(36U, random.size()); +} + +TEST(RandomTest, TestCreateRandomForTest) { + // Make sure we get the output we expect. + SetRandomTestMode(true); + EXPECT_EQ(2154761789U, CreateRandomId()); + EXPECT_EQ("h0ISP4S5SJKH/9EY", CreateRandomString(16)); + EXPECT_EQ("41706e92-cdd3-46d9-a22d-8ff1737ffb11", CreateRandomUuid()); + static size_t kRandomDataLength = 32; + std::string random; + EXPECT_TRUE(CreateRandomData(kRandomDataLength, &random)); + EXPECT_EQ(kRandomDataLength, random.size()); + Buffer expected( + "\xbd\x52\x2a\x4b\x97\x93\x2f\x1c" + "\xc4\x72\xab\xa2\x88\x68\x3e\xcc" + "\xa3\x8d\xaf\x13\x3b\xbc\x83\xbb" + "\x16\xf1\xcf\x56\x0c\xf5\x4a\x8b", + kRandomDataLength); + EXPECT_EQ(0, memcmp(expected.data(), random.data(), kRandomDataLength)); + + // Reset and make sure we get the same output. + SetRandomTestMode(true); + EXPECT_EQ(2154761789U, CreateRandomId()); + EXPECT_EQ("h0ISP4S5SJKH/9EY", CreateRandomString(16)); + EXPECT_EQ("41706e92-cdd3-46d9-a22d-8ff1737ffb11", CreateRandomUuid()); + EXPECT_TRUE(CreateRandomData(kRandomDataLength, &random)); + EXPECT_EQ(kRandomDataLength, random.size()); + EXPECT_EQ(0, memcmp(expected.data(), random.data(), kRandomDataLength)); + + // Test different character sets. + SetRandomTestMode(true); + std::string str; + EXPECT_TRUE(CreateRandomString(16, "a", &str)); + EXPECT_EQ("aaaaaaaaaaaaaaaa", str); + EXPECT_TRUE(CreateRandomString(16, "abcd", &str)); + EXPECT_EQ("dbaaabdaccbcabbd", str); + + // Turn off test mode for other tests. + SetRandomTestMode(false); +} + +class MockRandomGenerator : public RandomGenerator { + public: + MOCK_METHOD(void, Die, ()); + ~MockRandomGenerator() override { Die(); } + + MOCK_METHOD(bool, Init, (const void* seed, size_t len), (override)); + MOCK_METHOD(bool, Generate, (void* buf, size_t len), (override)); +}; + +TEST(RandomTest, TestSetRandomGenerator) { + std::unique_ptr<MockRandomGenerator> will_move = + std::make_unique<MockRandomGenerator>(); + MockRandomGenerator* generator = will_move.get(); + SetRandomGenerator(std::move(will_move)); + + EXPECT_CALL(*generator, Init(_, sizeof(int))).WillOnce(Return(true)); + EXPECT_TRUE(InitRandom(5)); + + std::string seed = "seed"; + EXPECT_CALL(*generator, Init(seed.data(), seed.size())) + .WillOnce(Return(true)); + EXPECT_TRUE(InitRandom(seed.data(), seed.size())); + + uint32_t id = 4658; + EXPECT_CALL(*generator, Generate(_, sizeof(uint32_t))) + .WillOnce(DoAll(WithArg<0>(Invoke([&id](void* p) { + std::memcpy(p, &id, sizeof(uint32_t)); + })), + Return(true))); + EXPECT_EQ(CreateRandomId(), id); + + EXPECT_CALL(*generator, Generate) + .WillOnce(DoAll( + WithArgs<0, 1>([](void* p, size_t len) { std::memset(p, 0, len); }), + Return(true))); + EXPECT_THAT(CreateRandomUuid(), Not(IsEmpty())); + + // Set the default random generator, and expect that mock generator is + // not used beyond this point. + EXPECT_CALL(*generator, Die); + EXPECT_CALL(*generator, Generate).Times(0); + SetDefaultRandomGenerator(); + EXPECT_THAT(CreateRandomUuid(), Not(IsEmpty())); +} + +} // namespace +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/histogram_percentile_counter_gn/moz.build b/third_party/libwebrtc/rtc_base/histogram_percentile_counter_gn/moz.build new file mode 100644 index 0000000000..ee30758d89 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/histogram_percentile_counter_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/rtc_base/numerics/histogram_percentile_counter.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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("histogram_percentile_counter_gn") diff --git a/third_party/libwebrtc/rtc_base/http_common.cc b/third_party/libwebrtc/rtc_base/http_common.cc new file mode 100644 index 0000000000..621b854b53 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/http_common.cc @@ -0,0 +1,555 @@ +/* + * 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 <time.h> + +#include "absl/strings/string_view.h" + +#if defined(WEBRTC_WIN) +#include <windows.h> +#include <winsock2.h> +#include <ws2tcpip.h> + +#define SECURITY_WIN32 +#include <security.h> +#endif + +#include <ctype.h> // for isspace +#include <stdio.h> // for sprintf + +#include <utility> // for pair +#include <vector> + +#include "absl/strings/match.h" +#include "rtc_base/crypt_string.h" // for CryptString +#include "rtc_base/http_common.h" +#include "rtc_base/logging.h" +#include "rtc_base/message_digest.h" +#include "rtc_base/socket_address.h" +#include "rtc_base/string_utils.h" +#include "rtc_base/strings/string_builder.h" +#include "rtc_base/third_party/base64/base64.h" // for Base64 +#include "rtc_base/zero_memory.h" // for ExplicitZeroMemory + +namespace rtc { +namespace { +#if defined(WEBRTC_WIN) && !defined(WINUWP) +/////////////////////////////////////////////////////////////////////////////// +// ConstantToLabel can be used to easily generate string names from constant +// values. This can be useful for logging descriptive names of error messages. +// Usage: +// const ConstantToLabel LIBRARY_ERRORS[] = { +// KLABEL(SOME_ERROR), +// KLABEL(SOME_OTHER_ERROR), +// ... +// LASTLABEL +// } +// +// int err = LibraryFunc(); +// LOG(LS_ERROR) << "LibraryFunc returned: " +// << GetErrorName(err, LIBRARY_ERRORS); +struct ConstantToLabel { + int value; + const char* label; +}; + +const char* LookupLabel(int value, const ConstantToLabel entries[]) { + for (int i = 0; entries[i].label; ++i) { + if (value == entries[i].value) { + return entries[i].label; + } + } + return 0; +} + +std::string GetErrorName(int err, const ConstantToLabel* err_table) { + if (err == 0) + return "No error"; + + if (err_table != 0) { + if (const char* value = LookupLabel(err, err_table)) + return value; + } + + char buffer[16]; + snprintf(buffer, sizeof(buffer), "0x%08x", err); + return buffer; +} + +#define KLABEL(x) \ + { x, #x } +#define LASTLABEL \ + { 0, 0 } + +const ConstantToLabel SECURITY_ERRORS[] = { + KLABEL(SEC_I_COMPLETE_AND_CONTINUE), + KLABEL(SEC_I_COMPLETE_NEEDED), + KLABEL(SEC_I_CONTEXT_EXPIRED), + KLABEL(SEC_I_CONTINUE_NEEDED), + KLABEL(SEC_I_INCOMPLETE_CREDENTIALS), + KLABEL(SEC_I_RENEGOTIATE), + KLABEL(SEC_E_CERT_EXPIRED), + KLABEL(SEC_E_INCOMPLETE_MESSAGE), + KLABEL(SEC_E_INSUFFICIENT_MEMORY), + KLABEL(SEC_E_INTERNAL_ERROR), + KLABEL(SEC_E_INVALID_HANDLE), + KLABEL(SEC_E_INVALID_TOKEN), + KLABEL(SEC_E_LOGON_DENIED), + KLABEL(SEC_E_NO_AUTHENTICATING_AUTHORITY), + KLABEL(SEC_E_NO_CREDENTIALS), + KLABEL(SEC_E_NOT_OWNER), + KLABEL(SEC_E_OK), + KLABEL(SEC_E_SECPKG_NOT_FOUND), + KLABEL(SEC_E_TARGET_UNKNOWN), + KLABEL(SEC_E_UNKNOWN_CREDENTIALS), + KLABEL(SEC_E_UNSUPPORTED_FUNCTION), + KLABEL(SEC_E_UNTRUSTED_ROOT), + KLABEL(SEC_E_WRONG_PRINCIPAL), + LASTLABEL}; +#undef KLABEL +#undef LASTLABEL +#endif // defined(WEBRTC_WIN) && !defined(WINUWP) + +typedef std::pair<std::string, std::string> HttpAttribute; +typedef std::vector<HttpAttribute> HttpAttributeList; + +inline bool IsEndOfAttributeName(size_t pos, absl::string_view data) { + if (pos >= data.size()) + return true; + if (isspace(static_cast<unsigned char>(data[pos]))) + return true; + // The reason for this complexity is that some attributes may contain trailing + // equal signs (like base64 tokens in Negotiate auth headers) + if ((pos + 1 < data.size()) && (data[pos] == '=') && + !isspace(static_cast<unsigned char>(data[pos + 1])) && + (data[pos + 1] != '=')) { + return true; + } + return false; +} + +void HttpParseAttributes(absl::string_view data, + HttpAttributeList& attributes) { + size_t pos = 0; + const size_t len = data.size(); + while (true) { + // Skip leading whitespace + while ((pos < len) && isspace(static_cast<unsigned char>(data[pos]))) { + ++pos; + } + + // End of attributes? + if (pos >= len) + return; + + // Find end of attribute name + size_t start = pos; + while (!IsEndOfAttributeName(pos, data)) { + ++pos; + } + + HttpAttribute attribute; + attribute.first.assign(data.data() + start, data.data() + pos); + + // Attribute has value? + if ((pos < len) && (data[pos] == '=')) { + ++pos; // Skip '=' + // Check if quoted value + if ((pos < len) && (data[pos] == '"')) { + while (++pos < len) { + if (data[pos] == '"') { + ++pos; + break; + } + if ((data[pos] == '\\') && (pos + 1 < len)) + ++pos; + attribute.second.append(1, data[pos]); + } + } else { + while ((pos < len) && !isspace(static_cast<unsigned char>(data[pos])) && + (data[pos] != ',')) { + attribute.second.append(1, data[pos++]); + } + } + } + + attributes.push_back(attribute); + if ((pos < len) && (data[pos] == ',')) + ++pos; // Skip ',' + } +} + +bool HttpHasAttribute(const HttpAttributeList& attributes, + absl::string_view name, + std::string* value) { + for (HttpAttributeList::const_iterator it = attributes.begin(); + it != attributes.end(); ++it) { + if (it->first == name) { + if (value) { + *value = it->second; + } + return true; + } + } + return false; +} + +bool HttpHasNthAttribute(HttpAttributeList& attributes, + size_t index, + std::string* name, + std::string* value) { + if (index >= attributes.size()) + return false; + + if (name) + *name = attributes[index].first; + if (value) + *value = attributes[index].second; + return true; +} + +std::string quote(absl::string_view str) { + std::string result; + result.push_back('"'); + for (size_t i = 0; i < str.size(); ++i) { + if ((str[i] == '"') || (str[i] == '\\')) + result.push_back('\\'); + result.push_back(str[i]); + } + result.push_back('"'); + return result; +} + +#if defined(WEBRTC_WIN) && !defined(WINUWP) +struct NegotiateAuthContext : public HttpAuthContext { + CredHandle cred; + CtxtHandle ctx; + size_t steps; + bool specified_credentials; + + NegotiateAuthContext(absl::string_view auth, CredHandle c1, CtxtHandle c2) + : HttpAuthContext(auth), + cred(c1), + ctx(c2), + steps(0), + specified_credentials(false) {} + + ~NegotiateAuthContext() override { + DeleteSecurityContext(&ctx); + FreeCredentialsHandle(&cred); + } +}; +#endif // defined(WEBRTC_WIN) && !defined(WINUWP) + +} // anonymous namespace + +HttpAuthResult HttpAuthenticate(absl::string_view challenge, + const SocketAddress& server, + absl::string_view method, + absl::string_view uri, + absl::string_view username, + const CryptString& password, + HttpAuthContext*& context, + std::string& response, + std::string& auth_method) { + HttpAttributeList args; + HttpParseAttributes(challenge, args); + HttpHasNthAttribute(args, 0, &auth_method, nullptr); + + if (context && (context->auth_method != auth_method)) + return HAR_IGNORE; + + // BASIC + if (absl::EqualsIgnoreCase(auth_method, "basic")) { + if (context) + return HAR_CREDENTIALS; // Bad credentials + if (username.empty()) + return HAR_CREDENTIALS; // Missing credentials + + context = new HttpAuthContext(auth_method); + + // TODO(bugs.webrtc.org/8905): Convert sensitive to a CryptString and also + // return response as CryptString so contents get securely deleted + // automatically. + // std::string decoded = username + ":" + password; + size_t len = username.size() + password.GetLength() + 2; + char* sensitive = new char[len]; + size_t pos = strcpyn(sensitive, len, username); + pos += strcpyn(sensitive + pos, len - pos, ":"); + password.CopyTo(sensitive + pos, true); + + response = auth_method; + response.append(" "); + // TODO: create a sensitive-source version of Base64::encode + response.append(Base64::Encode(sensitive)); + ExplicitZeroMemory(sensitive, len); + delete[] sensitive; + return HAR_RESPONSE; + } + + // DIGEST + if (absl::EqualsIgnoreCase(auth_method, "digest")) { + if (context) + return HAR_CREDENTIALS; // Bad credentials + if (username.empty()) + return HAR_CREDENTIALS; // Missing credentials + + context = new HttpAuthContext(auth_method); + + std::string cnonce, ncount; + char buffer[256]; + snprintf(buffer, sizeof(buffer), "%d", static_cast<int>(time(0))); + cnonce = MD5(buffer); + ncount = "00000001"; + + std::string realm, nonce, qop, opaque; + HttpHasAttribute(args, "realm", &realm); + HttpHasAttribute(args, "nonce", &nonce); + bool has_qop = HttpHasAttribute(args, "qop", &qop); + bool has_opaque = HttpHasAttribute(args, "opaque", &opaque); + + // TODO(bugs.webrtc.org/8905): Convert sensitive to a CryptString and also + // return response as CryptString so contents get securely deleted + // automatically. + // std::string A1 = username + ":" + realm + ":" + password; + size_t len = username.size() + realm.size() + password.GetLength() + 3; + char* sensitive = new char[len]; // A1 + size_t pos = strcpyn(sensitive, len, username); + pos += strcpyn(sensitive + pos, len - pos, ":"); + pos += strcpyn(sensitive + pos, len - pos, realm); + pos += strcpyn(sensitive + pos, len - pos, ":"); + password.CopyTo(sensitive + pos, true); + + std::string A2 = std::string(method) + ":" + std::string(uri); + std::string middle; + if (has_qop) { + qop = "auth"; + middle = nonce + ":" + ncount + ":" + cnonce + ":" + qop; + } else { + middle = nonce; + } + std::string HA1 = MD5(sensitive); + ExplicitZeroMemory(sensitive, len); + delete[] sensitive; + std::string HA2 = MD5(A2); + std::string dig_response = MD5(HA1 + ":" + middle + ":" + HA2); + + rtc::StringBuilder ss; + ss << auth_method; + ss << " username=" << quote(username); + ss << ", realm=" << quote(realm); + ss << ", nonce=" << quote(nonce); + ss << ", uri=" << quote(uri); + if (has_qop) { + ss << ", qop=" << qop; + ss << ", nc=" << ncount; + ss << ", cnonce=" << quote(cnonce); + } + ss << ", response=\"" << dig_response << "\""; + if (has_opaque) { + ss << ", opaque=" << quote(opaque); + } + response = ss.str(); + return HAR_RESPONSE; + } + +#if defined(WEBRTC_WIN) && !defined(WINUWP) +#if 1 + bool want_negotiate = absl::EqualsIgnoreCase(auth_method, "negotiate"); + bool want_ntlm = absl::EqualsIgnoreCase(auth_method, "ntlm"); + // SPNEGO & NTLM + if (want_negotiate || want_ntlm) { + const size_t MAX_MESSAGE = 12000, MAX_SPN = 256; + char out_buf[MAX_MESSAGE], spn[MAX_SPN]; + +#if 0 // Requires funky windows versions + DWORD len = MAX_SPN; + if (DsMakeSpn("HTTP", server.HostAsURIString().c_str(), nullptr, + server.port(), + 0, &len, spn) != ERROR_SUCCESS) { + RTC_LOG_F(LS_WARNING) << "(Negotiate) - DsMakeSpn failed"; + return HAR_IGNORE; + } +#else + snprintf(spn, MAX_SPN, "HTTP/%s", server.ToString().c_str()); +#endif + + SecBuffer out_sec; + out_sec.pvBuffer = out_buf; + out_sec.cbBuffer = sizeof(out_buf); + out_sec.BufferType = SECBUFFER_TOKEN; + + SecBufferDesc out_buf_desc; + out_buf_desc.ulVersion = 0; + out_buf_desc.cBuffers = 1; + out_buf_desc.pBuffers = &out_sec; + + const ULONG NEG_FLAGS_DEFAULT = + // ISC_REQ_ALLOCATE_MEMORY + ISC_REQ_CONFIDENTIALITY + //| ISC_REQ_EXTENDED_ERROR + //| ISC_REQ_INTEGRITY + | ISC_REQ_REPLAY_DETECT | ISC_REQ_SEQUENCE_DETECT + //| ISC_REQ_STREAM + //| ISC_REQ_USE_SUPPLIED_CREDS + ; + + ::TimeStamp lifetime; + SECURITY_STATUS ret = S_OK; + ULONG ret_flags = 0, flags = NEG_FLAGS_DEFAULT; + + bool specify_credentials = !username.empty(); + size_t steps = 0; + + // uint32_t now = Time(); + + NegotiateAuthContext* neg = static_cast<NegotiateAuthContext*>(context); + if (neg) { + const size_t max_steps = 10; + if (++neg->steps >= max_steps) { + RTC_LOG(LS_WARNING) << "AsyncHttpsProxySocket::Authenticate(Negotiate) " + "too many retries"; + return HAR_ERROR; + } + steps = neg->steps; + + std::string challenge, decoded_challenge; + if (HttpHasNthAttribute(args, 1, &challenge, nullptr) && + Base64::Decode(challenge, Base64::DO_STRICT, &decoded_challenge, + nullptr)) { + SecBuffer in_sec; + in_sec.pvBuffer = const_cast<char*>(decoded_challenge.data()); + in_sec.cbBuffer = static_cast<unsigned long>(decoded_challenge.size()); + in_sec.BufferType = SECBUFFER_TOKEN; + + SecBufferDesc in_buf_desc; + in_buf_desc.ulVersion = 0; + in_buf_desc.cBuffers = 1; + in_buf_desc.pBuffers = &in_sec; + + ret = InitializeSecurityContextA( + &neg->cred, &neg->ctx, spn, flags, 0, SECURITY_NATIVE_DREP, + &in_buf_desc, 0, &neg->ctx, &out_buf_desc, &ret_flags, &lifetime); + if (FAILED(ret)) { + RTC_LOG(LS_ERROR) << "InitializeSecurityContext returned: " + << GetErrorName(ret, SECURITY_ERRORS); + return HAR_ERROR; + } + } else if (neg->specified_credentials) { + // Try again with default credentials + specify_credentials = false; + delete context; + context = neg = 0; + } else { + return HAR_CREDENTIALS; + } + } + + if (!neg) { + unsigned char userbuf[256], passbuf[256], domainbuf[16]; + SEC_WINNT_AUTH_IDENTITY_A auth_id, *pauth_id = 0; + if (specify_credentials) { + memset(&auth_id, 0, sizeof(auth_id)); + size_t len = password.GetLength() + 1; + char* sensitive = new char[len]; + password.CopyTo(sensitive, true); + absl::string_view::size_type pos = username.find('\\'); + if (pos == absl::string_view::npos) { + auth_id.UserLength = static_cast<unsigned long>( + std::min(sizeof(userbuf) - 1, username.size())); + memcpy(userbuf, username.data(), auth_id.UserLength); + userbuf[auth_id.UserLength] = 0; + auth_id.DomainLength = 0; + domainbuf[auth_id.DomainLength] = 0; + auth_id.PasswordLength = static_cast<unsigned long>( + std::min(sizeof(passbuf) - 1, password.GetLength())); + memcpy(passbuf, sensitive, auth_id.PasswordLength); + passbuf[auth_id.PasswordLength] = 0; + } else { + auth_id.UserLength = static_cast<unsigned long>( + std::min(sizeof(userbuf) - 1, username.size() - pos - 1)); + memcpy(userbuf, username.data() + pos + 1, auth_id.UserLength); + userbuf[auth_id.UserLength] = 0; + auth_id.DomainLength = + static_cast<unsigned long>(std::min(sizeof(domainbuf) - 1, pos)); + memcpy(domainbuf, username.data(), auth_id.DomainLength); + domainbuf[auth_id.DomainLength] = 0; + auth_id.PasswordLength = static_cast<unsigned long>( + std::min(sizeof(passbuf) - 1, password.GetLength())); + memcpy(passbuf, sensitive, auth_id.PasswordLength); + passbuf[auth_id.PasswordLength] = 0; + } + ExplicitZeroMemory(sensitive, len); + delete[] sensitive; + auth_id.User = userbuf; + auth_id.Domain = domainbuf; + auth_id.Password = passbuf; + auth_id.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI; + pauth_id = &auth_id; + RTC_LOG(LS_VERBOSE) + << "Negotiate protocol: Using specified credentials"; + } else { + RTC_LOG(LS_VERBOSE) << "Negotiate protocol: Using default credentials"; + } + + CredHandle cred; + ret = AcquireCredentialsHandleA( + 0, const_cast<char*>(want_negotiate ? NEGOSSP_NAME_A : NTLMSP_NAME_A), + SECPKG_CRED_OUTBOUND, 0, pauth_id, 0, 0, &cred, &lifetime); + if (ret != SEC_E_OK) { + RTC_LOG(LS_ERROR) << "AcquireCredentialsHandle error: " + << GetErrorName(ret, SECURITY_ERRORS); + return HAR_IGNORE; + } + + // CSecBufferBundle<5, CSecBufferBase::FreeSSPI> sb_out; + + CtxtHandle ctx; + ret = InitializeSecurityContextA(&cred, 0, spn, flags, 0, + SECURITY_NATIVE_DREP, 0, 0, &ctx, + &out_buf_desc, &ret_flags, &lifetime); + if (FAILED(ret)) { + RTC_LOG(LS_ERROR) << "InitializeSecurityContext returned: " + << GetErrorName(ret, SECURITY_ERRORS); + FreeCredentialsHandle(&cred); + return HAR_IGNORE; + } + + RTC_DCHECK(!context); + context = neg = new NegotiateAuthContext(auth_method, cred, ctx); + neg->specified_credentials = specify_credentials; + neg->steps = steps; + } + + if ((ret == SEC_I_COMPLETE_NEEDED) || + (ret == SEC_I_COMPLETE_AND_CONTINUE)) { + ret = CompleteAuthToken(&neg->ctx, &out_buf_desc); + RTC_LOG(LS_VERBOSE) << "CompleteAuthToken returned: " + << GetErrorName(ret, SECURITY_ERRORS); + if (FAILED(ret)) { + return HAR_ERROR; + } + } + + std::string decoded(out_buf, out_buf + out_sec.cbBuffer); + response = auth_method; + response.append(" "); + response.append(Base64::Encode(decoded)); + return HAR_RESPONSE; + } +#endif +#endif // defined(WEBRTC_WIN) && !defined(WINUWP) + + return HAR_IGNORE; +} + +////////////////////////////////////////////////////////////////////// + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/http_common.h b/third_party/libwebrtc/rtc_base/http_common.h new file mode 100644 index 0000000000..06e42c6703 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/http_common.h @@ -0,0 +1,53 @@ +/* + * 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 RTC_BASE_HTTP_COMMON_H_ +#define RTC_BASE_HTTP_COMMON_H_ + +#include <string> + +#include "absl/strings/string_view.h" + +namespace rtc { + +class CryptString; +class SocketAddress; + +////////////////////////////////////////////////////////////////////// +// Http Authentication +////////////////////////////////////////////////////////////////////// + +struct HttpAuthContext { + std::string auth_method; + HttpAuthContext(absl::string_view auth) : auth_method(auth) {} + virtual ~HttpAuthContext() {} +}; + +enum HttpAuthResult { HAR_RESPONSE, HAR_IGNORE, HAR_CREDENTIALS, HAR_ERROR }; + +// 'context' is used by this function to record information between calls. +// Start by passing a null pointer, then pass the same pointer each additional +// call. When the authentication attempt is finished, delete the context. +// TODO(bugs.webrtc.org/8905): Change "response" to "ZeroOnFreeBuffer". +HttpAuthResult HttpAuthenticate(absl::string_view challenge, + const SocketAddress& server, + absl::string_view method, + absl::string_view uri, + absl::string_view username, + const CryptString& password, + HttpAuthContext*& context, + std::string& response, + std::string& auth_method); + +////////////////////////////////////////////////////////////////////// + +} // namespace rtc + +#endif // RTC_BASE_HTTP_COMMON_H_ diff --git a/third_party/libwebrtc/rtc_base/ifaddrs_android.cc b/third_party/libwebrtc/rtc_base/ifaddrs_android.cc new file mode 100644 index 0000000000..6474fb7244 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/ifaddrs_android.cc @@ -0,0 +1,227 @@ +/* + * Copyright 2012 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. + */ + +#if defined(WEBRTC_ANDROID) +#include "rtc_base/ifaddrs_android.h" + +#include <errno.h> +#include <linux/netlink.h> +#include <linux/rtnetlink.h> +#include <net/if.h> +#include <netinet/in.h> +#include <stdlib.h> +#include <string.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <sys/utsname.h> +#include <unistd.h> + +#include "absl/cleanup/cleanup.h" + +namespace { + +struct netlinkrequest { + nlmsghdr header; + ifaddrmsg msg; +}; + +const int kMaxReadSize = 4096; + +} // namespace + +namespace rtc { + +int set_ifname(struct ifaddrs* ifaddr, int interface) { + char buf[IFNAMSIZ] = {0}; + char* name = if_indextoname(interface, buf); + if (name == nullptr) { + return -1; + } + ifaddr->ifa_name = new char[strlen(name) + 1]; + strncpy(ifaddr->ifa_name, name, strlen(name) + 1); + return 0; +} + +int set_flags(struct ifaddrs* ifaddr) { + int fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd == -1) { + return -1; + } + ifreq ifr; + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, ifaddr->ifa_name, IFNAMSIZ - 1); + int rc = ioctl(fd, SIOCGIFFLAGS, &ifr); + close(fd); + if (rc == -1) { + return -1; + } + ifaddr->ifa_flags = ifr.ifr_flags; + return 0; +} + +int set_addresses(struct ifaddrs* ifaddr, + ifaddrmsg* msg, + void* data, + size_t len) { + if (msg->ifa_family == AF_INET) { + sockaddr_in* sa = new sockaddr_in; + sa->sin_family = AF_INET; + memcpy(&sa->sin_addr, data, len); + ifaddr->ifa_addr = reinterpret_cast<sockaddr*>(sa); + } else if (msg->ifa_family == AF_INET6) { + sockaddr_in6* sa = new sockaddr_in6; + sa->sin6_family = AF_INET6; + sa->sin6_scope_id = msg->ifa_index; + memcpy(&sa->sin6_addr, data, len); + ifaddr->ifa_addr = reinterpret_cast<sockaddr*>(sa); + } else { + return -1; + } + return 0; +} + +int make_prefixes(struct ifaddrs* ifaddr, int family, int prefixlen) { + char* prefix = nullptr; + if (family == AF_INET) { + sockaddr_in* mask = new sockaddr_in; + mask->sin_family = AF_INET; + memset(&mask->sin_addr, 0, sizeof(in_addr)); + ifaddr->ifa_netmask = reinterpret_cast<sockaddr*>(mask); + if (prefixlen > 32) { + prefixlen = 32; + } + prefix = reinterpret_cast<char*>(&mask->sin_addr); + } else if (family == AF_INET6) { + sockaddr_in6* mask = new sockaddr_in6; + mask->sin6_family = AF_INET6; + memset(&mask->sin6_addr, 0, sizeof(in6_addr)); + ifaddr->ifa_netmask = reinterpret_cast<sockaddr*>(mask); + if (prefixlen > 128) { + prefixlen = 128; + } + prefix = reinterpret_cast<char*>(&mask->sin6_addr); + } else { + return -1; + } + for (int i = 0; i < (prefixlen / 8); i++) { + *prefix++ = 0xFF; + } + char remainder = 0xff; + remainder <<= (8 - prefixlen % 8); + *prefix = remainder; + return 0; +} + +int populate_ifaddrs(struct ifaddrs* ifaddr, + ifaddrmsg* msg, + void* bytes, + size_t len) { + if (set_ifname(ifaddr, msg->ifa_index) != 0) { + return -1; + } + if (set_flags(ifaddr) != 0) { + return -1; + } + if (set_addresses(ifaddr, msg, bytes, len) != 0) { + return -1; + } + if (make_prefixes(ifaddr, msg->ifa_family, msg->ifa_prefixlen) != 0) { + return -1; + } + return 0; +} + +int getifaddrs(struct ifaddrs** result) { + *result = nullptr; + int fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + if (fd < 0) { + return -1; + } + absl::Cleanup close_file = [fd] { close(fd); }; + + netlinkrequest ifaddr_request; + memset(&ifaddr_request, 0, sizeof(ifaddr_request)); + ifaddr_request.header.nlmsg_flags = NLM_F_ROOT | NLM_F_REQUEST; + ifaddr_request.header.nlmsg_type = RTM_GETADDR; + ifaddr_request.header.nlmsg_len = NLMSG_LENGTH(sizeof(ifaddrmsg)); + + ssize_t count = send(fd, &ifaddr_request, ifaddr_request.header.nlmsg_len, 0); + if (static_cast<size_t>(count) != ifaddr_request.header.nlmsg_len) { + return -1; + } + struct ifaddrs* start = nullptr; + absl::Cleanup cleanup_start = [&start] { freeifaddrs(start); }; + struct ifaddrs* current = nullptr; + char buf[kMaxReadSize]; + ssize_t amount_read = recv(fd, &buf, kMaxReadSize, 0); + while (amount_read > 0) { + nlmsghdr* header = reinterpret_cast<nlmsghdr*>(&buf[0]); + size_t header_size = static_cast<size_t>(amount_read); + for (; NLMSG_OK(header, header_size); + header = NLMSG_NEXT(header, header_size)) { + switch (header->nlmsg_type) { + case NLMSG_DONE: + // Success. Return `start`. Cancel `start` cleanup because it + // becomes callers responsibility. + std::move(cleanup_start).Cancel(); + *result = start; + return 0; + case NLMSG_ERROR: + return -1; + case RTM_NEWADDR: { + ifaddrmsg* address_msg = + reinterpret_cast<ifaddrmsg*>(NLMSG_DATA(header)); + rtattr* rta = IFA_RTA(address_msg); + ssize_t payload_len = IFA_PAYLOAD(header); + while (RTA_OK(rta, payload_len)) { + if ((address_msg->ifa_family == AF_INET && + rta->rta_type == IFA_LOCAL) || + (address_msg->ifa_family == AF_INET6 && + rta->rta_type == IFA_ADDRESS)) { + ifaddrs* newest = new ifaddrs; + memset(newest, 0, sizeof(ifaddrs)); + if (current) { + current->ifa_next = newest; + } else { + start = newest; + } + if (populate_ifaddrs(newest, address_msg, RTA_DATA(rta), + RTA_PAYLOAD(rta)) != 0) { + return -1; + } + current = newest; + } + rta = RTA_NEXT(rta, payload_len); + } + break; + } + } + } + amount_read = recv(fd, &buf, kMaxReadSize, 0); + } + return -1; +} + +void freeifaddrs(struct ifaddrs* addrs) { + struct ifaddrs* last = nullptr; + struct ifaddrs* cursor = addrs; + while (cursor) { + delete[] cursor->ifa_name; + delete cursor->ifa_addr; + delete cursor->ifa_netmask; + last = cursor; + cursor = cursor->ifa_next; + delete last; + } +} + +} // namespace rtc +#endif // defined(WEBRTC_ANDROID) diff --git a/third_party/libwebrtc/rtc_base/ifaddrs_android.h b/third_party/libwebrtc/rtc_base/ifaddrs_android.h new file mode 100644 index 0000000000..1a5b662f06 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/ifaddrs_android.h @@ -0,0 +1,38 @@ +/* + * Copyright 2013 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 RTC_BASE_IFADDRS_ANDROID_H_ +#define RTC_BASE_IFADDRS_ANDROID_H_ + +#include <stdio.h> +#include <sys/socket.h> + +// Implementation of getifaddrs for Android. +// Fills out a list of ifaddr structs (see below) which contain information +// about every network interface available on the host. +// See 'man getifaddrs' on Linux or OS X (nb: it is not a POSIX function). +struct ifaddrs { + struct ifaddrs* ifa_next; + char* ifa_name; + unsigned int ifa_flags; + struct sockaddr* ifa_addr; + struct sockaddr* ifa_netmask; + // Real ifaddrs has broadcast, point to point and data members. + // We don't need them (yet?). +}; + +namespace rtc { + +int getifaddrs(struct ifaddrs** result); +void freeifaddrs(struct ifaddrs* addrs); + +} // namespace rtc + +#endif // RTC_BASE_IFADDRS_ANDROID_H_ diff --git a/third_party/libwebrtc/rtc_base/ifaddrs_android_gn/moz.build b/third_party/libwebrtc/rtc_base/ifaddrs_android_gn/moz.build new file mode 100644 index 0000000000..7985a5f7fe --- /dev/null +++ b/third_party/libwebrtc/rtc_base/ifaddrs_android_gn/moz.build @@ -0,0 +1,100 @@ +# 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["ANDROID"] = True +DEFINES["ANDROID_NDK_VERSION_ROLL"] = "r22_1" +DEFINES["HAVE_SYS_UIO_H"] = True +DEFINES["RTC_DAV1D_IN_INTERNAL_DECODER_FACTORY"] = True +DEFINES["RTC_ENABLE_VP9"] = True +DEFINES["WEBRTC_ANDROID"] = True +DEFINES["WEBRTC_ANDROID_OPENSLES"] = True +DEFINES["WEBRTC_ENABLE_LIBEVENT"] = True +DEFINES["WEBRTC_ENABLE_PROTOBUF"] = "0" +DEFINES["WEBRTC_LIBRARY_IMPL"] = True +DEFINES["WEBRTC_LINUX"] = True +DEFINES["WEBRTC_MOZILLA_BUILD"] = True +DEFINES["WEBRTC_NON_STATIC_TRACE_EVENT_HANDLERS"] = "0" +DEFINES["WEBRTC_POSIX"] = True +DEFINES["WEBRTC_STRICT_FIELD_TRIALS"] = "0" +DEFINES["_GNU_SOURCE"] = True +DEFINES["__STDC_CONSTANT_MACROS"] = True +DEFINES["__STDC_FORMAT_MACROS"] = True + +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" +] + +OS_LIBS += [ + "GLESv2", + "log" +] + +UNIFIED_SOURCES += [ + "/third_party/libwebrtc/rtc_base/ifaddrs_android.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" + DEFINES["_DEBUG"] = True + +if CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +Library("ifaddrs_android_gn") diff --git a/third_party/libwebrtc/rtc_base/ifaddrs_converter.cc b/third_party/libwebrtc/rtc_base/ifaddrs_converter.cc new file mode 100644 index 0000000000..d963efd6ef --- /dev/null +++ b/third_party/libwebrtc/rtc_base/ifaddrs_converter.cc @@ -0,0 +1,62 @@ +/* + * Copyright 2015 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 "rtc_base/ifaddrs_converter.h" + +namespace rtc { + +IfAddrsConverter::IfAddrsConverter() {} + +IfAddrsConverter::~IfAddrsConverter() {} + +bool IfAddrsConverter::ConvertIfAddrsToIPAddress( + const struct ifaddrs* interface, + InterfaceAddress* ip, + IPAddress* mask) { + switch (interface->ifa_addr->sa_family) { + case AF_INET: { + *ip = InterfaceAddress(IPAddress( + reinterpret_cast<sockaddr_in*>(interface->ifa_addr)->sin_addr)); + *mask = IPAddress( + reinterpret_cast<sockaddr_in*>(interface->ifa_netmask)->sin_addr); + return true; + } + case AF_INET6: { + int ip_attributes = IPV6_ADDRESS_FLAG_NONE; + if (!ConvertNativeAttributesToIPAttributes(interface, &ip_attributes)) { + return false; + } + *ip = InterfaceAddress( + reinterpret_cast<sockaddr_in6*>(interface->ifa_addr)->sin6_addr, + ip_attributes); + *mask = IPAddress( + reinterpret_cast<sockaddr_in6*>(interface->ifa_netmask)->sin6_addr); + return true; + } + default: { + return false; + } + } +} + +bool IfAddrsConverter::ConvertNativeAttributesToIPAttributes( + const struct ifaddrs* interface, + int* ip_attributes) { + *ip_attributes = IPV6_ADDRESS_FLAG_NONE; + return true; +} + +#if !defined(WEBRTC_MAC) +// For MAC and IOS, it's defined in macifaddrs_converter.cc +IfAddrsConverter* CreateIfAddrsConverter() { + return new IfAddrsConverter(); +} +#endif +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/ifaddrs_converter.h b/third_party/libwebrtc/rtc_base/ifaddrs_converter.h new file mode 100644 index 0000000000..bd6957d01e --- /dev/null +++ b/third_party/libwebrtc/rtc_base/ifaddrs_converter.h @@ -0,0 +1,45 @@ +/* + * Copyright 2015 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 RTC_BASE_IFADDRS_CONVERTER_H_ +#define RTC_BASE_IFADDRS_CONVERTER_H_ + +#if defined(WEBRTC_ANDROID) +#include "rtc_base/ifaddrs_android.h" +#else +#include <ifaddrs.h> +#endif // WEBRTC_ANDROID + +#include "rtc_base/ip_address.h" + +namespace rtc { + +// This class converts native interface addresses to our internal IPAddress +// class. Subclasses should override ConvertNativeToIPAttributes to implement +// the different ways of retrieving IPv6 attributes for various POSIX platforms. +class IfAddrsConverter { + public: + IfAddrsConverter(); + virtual ~IfAddrsConverter(); + virtual bool ConvertIfAddrsToIPAddress(const struct ifaddrs* interface, + InterfaceAddress* ipaddress, + IPAddress* mask); + + protected: + virtual bool ConvertNativeAttributesToIPAttributes( + const struct ifaddrs* interface, + int* ip_attributes); +}; + +IfAddrsConverter* CreateIfAddrsConverter(); + +} // namespace rtc + +#endif // RTC_BASE_IFADDRS_CONVERTER_H_ diff --git a/third_party/libwebrtc/rtc_base/ignore_wundef.h b/third_party/libwebrtc/rtc_base/ignore_wundef.h new file mode 100644 index 0000000000..1564096464 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/ignore_wundef.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2016 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 RTC_BASE_IGNORE_WUNDEF_H_ +#define RTC_BASE_IGNORE_WUNDEF_H_ + +// If a header file uses #if on possibly undefined macros (and it's for some +// reason not possible to just fix the header file), include it like this: +// +// RTC_PUSH_IGNORING_WUNDEF() +// #include "misbehaving_header.h" +// RTC_POP_IGNORING_WUNDEF() +// +// This will cause the compiler to not emit -Wundef warnings for that file. + +#ifdef __clang__ +#define RTC_PUSH_IGNORING_WUNDEF() \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Wundef\"") +#define RTC_POP_IGNORING_WUNDEF() _Pragma("clang diagnostic pop") +#else +#define RTC_PUSH_IGNORING_WUNDEF() +#define RTC_POP_IGNORING_WUNDEF() +#endif // __clang__ + +#endif // RTC_BASE_IGNORE_WUNDEF_H_ diff --git a/third_party/libwebrtc/rtc_base/ignore_wundef_gn/moz.build b/third_party/libwebrtc/rtc_base/ignore_wundef_gn/moz.build new file mode 100644 index 0000000000..15c6052f7b --- /dev/null +++ b/third_party/libwebrtc/rtc_base/ignore_wundef_gn/moz.build @@ -0,0 +1,205 @@ +# 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("ignore_wundef_gn") diff --git a/third_party/libwebrtc/rtc_base/internal/default_socket_server.cc b/third_party/libwebrtc/rtc_base/internal/default_socket_server.cc new file mode 100644 index 0000000000..5632b989fc --- /dev/null +++ b/third_party/libwebrtc/rtc_base/internal/default_socket_server.cc @@ -0,0 +1,33 @@ +/* + * 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. + */ + +#include "rtc_base/internal/default_socket_server.h" + +#include <memory> + +#include "rtc_base/socket_server.h" + +#if defined(__native_client__) +#include "rtc_base/null_socket_server.h" +#else +#include "rtc_base/physical_socket_server.h" +#endif + +namespace rtc { + +std::unique_ptr<SocketServer> CreateDefaultSocketServer() { +#if defined(__native_client__) + return std::unique_ptr<SocketServer>(new rtc::NullSocketServer); +#else + return std::unique_ptr<SocketServer>(new rtc::PhysicalSocketServer); +#endif +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/internal/default_socket_server.h b/third_party/libwebrtc/rtc_base/internal/default_socket_server.h new file mode 100644 index 0000000000..5b3489f613 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/internal/default_socket_server.h @@ -0,0 +1,24 @@ +/* + * 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 RTC_BASE_INTERNAL_DEFAULT_SOCKET_SERVER_H_ +#define RTC_BASE_INTERNAL_DEFAULT_SOCKET_SERVER_H_ + +#include <memory> + +#include "rtc_base/socket_server.h" + +namespace rtc { + +std::unique_ptr<SocketServer> CreateDefaultSocketServer(); + +} // namespace rtc + +#endif // RTC_BASE_INTERNAL_DEFAULT_SOCKET_SERVER_H_ diff --git a/third_party/libwebrtc/rtc_base/ip_address.cc b/third_party/libwebrtc/rtc_base/ip_address.cc new file mode 100644 index 0000000000..9e436e3c78 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/ip_address.cc @@ -0,0 +1,578 @@ +/* + * 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. + */ + +#if defined(WEBRTC_POSIX) +#include <netinet/in.h> +#include <sys/socket.h> + +#include "absl/strings/string_view.h" +#ifdef OPENBSD +#include <netinet/in_systm.h> +#endif +#ifndef __native_client__ +#include <netinet/ip.h> +#endif +#include <netdb.h> +#endif + +#include "rtc_base/byte_order.h" +#include "rtc_base/ip_address.h" +#include "rtc_base/net_helpers.h" +#include "rtc_base/string_utils.h" + +#if defined(WEBRTC_WIN) +#include "rtc_base/win32.h" +#endif // WEBRTC_WIN + +namespace rtc { + +// Prefixes used for categorizing IPv6 addresses. +static const in6_addr kV4MappedPrefix = { + {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0}}}; +static const in6_addr k6To4Prefix = {{{0x20, 0x02, 0}}}; +static const in6_addr kTeredoPrefix = {{{0x20, 0x01, 0x00, 0x00}}}; +static const in6_addr kV4CompatibilityPrefix = {{{0}}}; +static const in6_addr k6BonePrefix = {{{0x3f, 0xfe, 0}}}; +static const in6_addr kPrivateNetworkPrefix = {{{0xFD}}}; + +static bool IPIsHelper(const IPAddress& ip, + const in6_addr& tomatch, + int length); +static in_addr ExtractMappedAddress(const in6_addr& addr); + +uint32_t IPAddress::v4AddressAsHostOrderInteger() const { + if (family_ == AF_INET) { + return NetworkToHost32(u_.ip4.s_addr); + } else { + return 0; + } +} + +int IPAddress::overhead() const { + switch (family_) { + case AF_INET: // IPv4 + return 20; + case AF_INET6: // IPv6 + return 40; + default: + return 0; + } +} + +bool IPAddress::IsNil() const { + return IPIsUnspec(*this); +} + +size_t IPAddress::Size() const { + switch (family_) { + case AF_INET: + return sizeof(in_addr); + case AF_INET6: + return sizeof(in6_addr); + } + return 0; +} + +bool IPAddress::operator==(const IPAddress& other) const { + if (family_ != other.family_) { + return false; + } + if (family_ == AF_INET) { + return memcmp(&u_.ip4, &other.u_.ip4, sizeof(u_.ip4)) == 0; + } + if (family_ == AF_INET6) { + return memcmp(&u_.ip6, &other.u_.ip6, sizeof(u_.ip6)) == 0; + } + return family_ == AF_UNSPEC; +} + +bool IPAddress::operator!=(const IPAddress& other) const { + return !((*this) == other); +} + +bool IPAddress::operator>(const IPAddress& other) const { + return (*this) != other && !((*this) < other); +} + +bool IPAddress::operator<(const IPAddress& other) const { + // IPv4 is 'less than' IPv6 + if (family_ != other.family_) { + if (family_ == AF_UNSPEC) { + return true; + } + if (family_ == AF_INET && other.family_ == AF_INET6) { + return true; + } + return false; + } + // Comparing addresses of the same family. + switch (family_) { + case AF_INET: { + return NetworkToHost32(u_.ip4.s_addr) < + NetworkToHost32(other.u_.ip4.s_addr); + } + case AF_INET6: { + return memcmp(&u_.ip6.s6_addr, &other.u_.ip6.s6_addr, 16) < 0; + } + } + // Catches AF_UNSPEC and invalid addresses. + return false; +} + +in6_addr IPAddress::ipv6_address() const { + return u_.ip6; +} + +in_addr IPAddress::ipv4_address() const { + return u_.ip4; +} + +std::string IPAddress::ToString() const { + if (family_ != AF_INET && family_ != AF_INET6) { + return std::string(); + } + char buf[INET6_ADDRSTRLEN] = {0}; + const void* src = &u_.ip4; + if (family_ == AF_INET6) { + src = &u_.ip6; + } + if (!rtc::inet_ntop(family_, src, buf, sizeof(buf))) { + return std::string(); + } + return std::string(buf); +} + +std::string IPAddress::ToSensitiveString() const { + switch (family_) { + case AF_INET: { + std::string address = ToString(); + size_t find_pos = address.rfind('.'); + if (find_pos == std::string::npos) + return std::string(); + address.resize(find_pos); + address += ".x"; + return address; + } + case AF_INET6: { + std::string result; + result.resize(INET6_ADDRSTRLEN); + in6_addr addr = ipv6_address(); + size_t len = snprintf(&(result[0]), result.size(), "%x:%x:%x:x:x:x:x:x", + (addr.s6_addr[0] << 8) + addr.s6_addr[1], + (addr.s6_addr[2] << 8) + addr.s6_addr[3], + (addr.s6_addr[4] << 8) + addr.s6_addr[5]); + result.resize(len); + return result; + } + } + return std::string(); +} + +IPAddress IPAddress::Normalized() const { + if (family_ != AF_INET6) { + return *this; + } + if (!IPIsV4Mapped(*this)) { + return *this; + } + in_addr addr = ExtractMappedAddress(u_.ip6); + return IPAddress(addr); +} + +IPAddress IPAddress::AsIPv6Address() const { + if (family_ != AF_INET) { + return *this; + } + in6_addr v6addr = kV4MappedPrefix; + ::memcpy(&v6addr.s6_addr[12], &u_.ip4.s_addr, sizeof(u_.ip4.s_addr)); + return IPAddress(v6addr); +} + +bool InterfaceAddress::operator==(const InterfaceAddress& other) const { + return ipv6_flags_ == other.ipv6_flags() && + static_cast<const IPAddress&>(*this) == other; +} + +bool InterfaceAddress::operator!=(const InterfaceAddress& other) const { + return !((*this) == other); +} + +const InterfaceAddress& InterfaceAddress::operator=( + const InterfaceAddress& other) { + ipv6_flags_ = other.ipv6_flags_; + static_cast<IPAddress&>(*this) = other; + return *this; +} + +std::string InterfaceAddress::ToString() const { + std::string result = IPAddress::ToString(); + + if (family() == AF_INET6) + result += "|flags:0x" + rtc::ToHex(ipv6_flags()); + + return result; +} + +static bool IPIsPrivateNetworkV4(const IPAddress& ip) { + uint32_t ip_in_host_order = ip.v4AddressAsHostOrderInteger(); + return ((ip_in_host_order >> 24) == 10) || + ((ip_in_host_order >> 20) == ((172 << 4) | 1)) || + ((ip_in_host_order >> 16) == ((192 << 8) | 168)); +} + +static bool IPIsPrivateNetworkV6(const IPAddress& ip) { + return IPIsHelper(ip, kPrivateNetworkPrefix, 8); +} + +bool IPIsPrivateNetwork(const IPAddress& ip) { + switch (ip.family()) { + case AF_INET: { + return IPIsPrivateNetworkV4(ip); + } + case AF_INET6: { + return IPIsPrivateNetworkV6(ip); + } + } + return false; +} + +static bool IPIsSharedNetworkV4(const IPAddress& ip) { + uint32_t ip_in_host_order = ip.v4AddressAsHostOrderInteger(); + return (ip_in_host_order >> 22) == ((100 << 2) | 1); +} + +bool IPIsSharedNetwork(const IPAddress& ip) { + if (ip.family() == AF_INET) { + return IPIsSharedNetworkV4(ip); + } + return false; +} + +in_addr ExtractMappedAddress(const in6_addr& in6) { + in_addr ipv4; + ::memcpy(&ipv4.s_addr, &in6.s6_addr[12], sizeof(ipv4.s_addr)); + return ipv4; +} + +bool IPFromAddrInfo(struct addrinfo* info, IPAddress* out) { + if (!info || !info->ai_addr) { + return false; + } + if (info->ai_addr->sa_family == AF_INET) { + sockaddr_in* addr = reinterpret_cast<sockaddr_in*>(info->ai_addr); + *out = IPAddress(addr->sin_addr); + return true; + } else if (info->ai_addr->sa_family == AF_INET6) { + sockaddr_in6* addr = reinterpret_cast<sockaddr_in6*>(info->ai_addr); + *out = IPAddress(addr->sin6_addr); + return true; + } + return false; +} + +bool IPFromString(absl::string_view str, IPAddress* out) { + if (!out) { + return false; + } + in_addr addr; + if (rtc::inet_pton(AF_INET, str, &addr) == 0) { + in6_addr addr6; + if (rtc::inet_pton(AF_INET6, str, &addr6) == 0) { + *out = IPAddress(); + return false; + } + *out = IPAddress(addr6); + } else { + *out = IPAddress(addr); + } + return true; +} + +bool IPFromString(absl::string_view str, int flags, InterfaceAddress* out) { + IPAddress ip; + if (!IPFromString(str, &ip)) { + return false; + } + + *out = InterfaceAddress(ip, flags); + return true; +} + +bool IPIsAny(const IPAddress& ip) { + switch (ip.family()) { + case AF_INET: + return ip == IPAddress(INADDR_ANY); + case AF_INET6: + return ip == IPAddress(in6addr_any) || ip == IPAddress(kV4MappedPrefix); + case AF_UNSPEC: + return false; + } + return false; +} + +static bool IPIsLoopbackV4(const IPAddress& ip) { + uint32_t ip_in_host_order = ip.v4AddressAsHostOrderInteger(); + return ((ip_in_host_order >> 24) == 127); +} + +static bool IPIsLoopbackV6(const IPAddress& ip) { + return ip == IPAddress(in6addr_loopback); +} + +bool IPIsLoopback(const IPAddress& ip) { + switch (ip.family()) { + case AF_INET: { + return IPIsLoopbackV4(ip); + } + case AF_INET6: { + return IPIsLoopbackV6(ip); + } + } + return false; +} + +bool IPIsPrivate(const IPAddress& ip) { + return IPIsLinkLocal(ip) || IPIsLoopback(ip) || IPIsPrivateNetwork(ip) || + IPIsSharedNetwork(ip); +} + +bool IPIsUnspec(const IPAddress& ip) { + return ip.family() == AF_UNSPEC; +} + +size_t HashIP(const IPAddress& ip) { + switch (ip.family()) { + case AF_INET: { + return ip.ipv4_address().s_addr; + } + case AF_INET6: { + in6_addr v6addr = ip.ipv6_address(); + const uint32_t* v6_as_ints = + reinterpret_cast<const uint32_t*>(&v6addr.s6_addr); + return v6_as_ints[0] ^ v6_as_ints[1] ^ v6_as_ints[2] ^ v6_as_ints[3]; + } + } + return 0; +} + +IPAddress TruncateIP(const IPAddress& ip, int length) { + if (length < 0) { + return IPAddress(); + } + if (ip.family() == AF_INET) { + if (length > 31) { + return ip; + } + if (length == 0) { + return IPAddress(INADDR_ANY); + } + int mask = (0xFFFFFFFF << (32 - length)); + uint32_t host_order_ip = NetworkToHost32(ip.ipv4_address().s_addr); + in_addr masked; + masked.s_addr = HostToNetwork32(host_order_ip & mask); + return IPAddress(masked); + } else if (ip.family() == AF_INET6) { + if (length > 127) { + return ip; + } + if (length == 0) { + return IPAddress(in6addr_any); + } + in6_addr v6addr = ip.ipv6_address(); + int position = length / 32; + int inner_length = 32 - (length - (position * 32)); + // Note: 64bit mask constant needed to allow possible 32-bit left shift. + uint32_t inner_mask = 0xFFFFFFFFLL << inner_length; + uint32_t* v6_as_ints = reinterpret_cast<uint32_t*>(&v6addr.s6_addr); + for (int i = 0; i < 4; ++i) { + if (i == position) { + uint32_t host_order_inner = NetworkToHost32(v6_as_ints[i]); + v6_as_ints[i] = HostToNetwork32(host_order_inner & inner_mask); + } else if (i > position) { + v6_as_ints[i] = 0; + } + } + return IPAddress(v6addr); + } + return IPAddress(); +} + +int CountIPMaskBits(const IPAddress& mask) { + uint32_t word_to_count = 0; + int bits = 0; + switch (mask.family()) { + case AF_INET: { + word_to_count = NetworkToHost32(mask.ipv4_address().s_addr); + break; + } + case AF_INET6: { + in6_addr v6addr = mask.ipv6_address(); + const uint32_t* v6_as_ints = + reinterpret_cast<const uint32_t*>(&v6addr.s6_addr); + int i = 0; + for (; i < 4; ++i) { + if (v6_as_ints[i] != 0xFFFFFFFF) { + break; + } + } + if (i < 4) { + word_to_count = NetworkToHost32(v6_as_ints[i]); + } + bits = (i * 32); + break; + } + default: { + return 0; + } + } + if (word_to_count == 0) { + return bits; + } + + // Public domain bit-twiddling hack from: + // http://graphics.stanford.edu/~seander/bithacks.html + // Counts the trailing 0s in the word. + unsigned int zeroes = 32; + // This could also be written word_to_count &= -word_to_count, but + // MSVC emits warning C4146 when negating an unsigned number. + word_to_count &= ~word_to_count + 1; // Isolate lowest set bit. + if (word_to_count) + zeroes--; + if (word_to_count & 0x0000FFFF) + zeroes -= 16; + if (word_to_count & 0x00FF00FF) + zeroes -= 8; + if (word_to_count & 0x0F0F0F0F) + zeroes -= 4; + if (word_to_count & 0x33333333) + zeroes -= 2; + if (word_to_count & 0x55555555) + zeroes -= 1; + + return bits + (32 - zeroes); +} + +bool IPIsHelper(const IPAddress& ip, const in6_addr& tomatch, int length) { + // Helper method for checking IP prefix matches (but only on whole byte + // lengths). Length is in bits. + in6_addr addr = ip.ipv6_address(); + return ::memcmp(&addr, &tomatch, (length >> 3)) == 0; +} + +bool IPIs6Bone(const IPAddress& ip) { + return IPIsHelper(ip, k6BonePrefix, 16); +} + +bool IPIs6To4(const IPAddress& ip) { + return IPIsHelper(ip, k6To4Prefix, 16); +} + +static bool IPIsLinkLocalV4(const IPAddress& ip) { + uint32_t ip_in_host_order = ip.v4AddressAsHostOrderInteger(); + return ((ip_in_host_order >> 16) == ((169 << 8) | 254)); +} + +static bool IPIsLinkLocalV6(const IPAddress& ip) { + // Can't use the helper because the prefix is 10 bits. + in6_addr addr = ip.ipv6_address(); + return (addr.s6_addr[0] == 0xFE) && ((addr.s6_addr[1] & 0xC0) == 0x80); +} + +bool IPIsLinkLocal(const IPAddress& ip) { + switch (ip.family()) { + case AF_INET: { + return IPIsLinkLocalV4(ip); + } + case AF_INET6: { + return IPIsLinkLocalV6(ip); + } + } + return false; +} + +// According to http://www.ietf.org/rfc/rfc2373.txt, Appendix A, page 19. An +// address which contains MAC will have its 11th and 12th bytes as FF:FE as well +// as the U/L bit as 1. +bool IPIsMacBased(const IPAddress& ip) { + in6_addr addr = ip.ipv6_address(); + return ((addr.s6_addr[8] & 0x02) && addr.s6_addr[11] == 0xFF && + addr.s6_addr[12] == 0xFE); +} + +bool IPIsSiteLocal(const IPAddress& ip) { + // Can't use the helper because the prefix is 10 bits. + in6_addr addr = ip.ipv6_address(); + return addr.s6_addr[0] == 0xFE && (addr.s6_addr[1] & 0xC0) == 0xC0; +} + +bool IPIsULA(const IPAddress& ip) { + // Can't use the helper because the prefix is 7 bits. + in6_addr addr = ip.ipv6_address(); + return (addr.s6_addr[0] & 0xFE) == 0xFC; +} + +bool IPIsTeredo(const IPAddress& ip) { + return IPIsHelper(ip, kTeredoPrefix, 32); +} + +bool IPIsV4Compatibility(const IPAddress& ip) { + return IPIsHelper(ip, kV4CompatibilityPrefix, 96); +} + +bool IPIsV4Mapped(const IPAddress& ip) { + return IPIsHelper(ip, kV4MappedPrefix, 96); +} + +int IPAddressPrecedence(const IPAddress& ip) { + // Precedence values from RFC 3484-bis. Prefers native v4 over 6to4/Teredo. + if (ip.family() == AF_INET) { + return 30; + } else if (ip.family() == AF_INET6) { + if (IPIsLoopback(ip)) { + return 60; + } else if (IPIsULA(ip)) { + return 50; + } else if (IPIsV4Mapped(ip)) { + return 30; + } else if (IPIs6To4(ip)) { + return 20; + } else if (IPIsTeredo(ip)) { + return 10; + } else if (IPIsV4Compatibility(ip) || IPIsSiteLocal(ip) || IPIs6Bone(ip)) { + return 1; + } else { + // A 'normal' IPv6 address. + return 40; + } + } + return 0; +} + +IPAddress GetLoopbackIP(int family) { + if (family == AF_INET) { + return rtc::IPAddress(INADDR_LOOPBACK); + } + if (family == AF_INET6) { + return rtc::IPAddress(in6addr_loopback); + } + return rtc::IPAddress(); +} + +IPAddress GetAnyIP(int family) { + if (family == AF_INET) { + return rtc::IPAddress(INADDR_ANY); + } + if (family == AF_INET6) { + return rtc::IPAddress(in6addr_any); + } + return rtc::IPAddress(); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/ip_address.h b/third_party/libwebrtc/rtc_base/ip_address.h new file mode 100644 index 0000000000..897e165565 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/ip_address.h @@ -0,0 +1,206 @@ +/* + * Copyright 2011 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 RTC_BASE_IP_ADDRESS_H_ +#define RTC_BASE_IP_ADDRESS_H_ + +#if defined(WEBRTC_POSIX) +#include <arpa/inet.h> +#include <netdb.h> +#include <netinet/in.h> +#include <sys/socket.h> + +#include "absl/strings/string_view.h" +#endif +#if defined(WEBRTC_WIN) +#include <winsock2.h> +#include <ws2tcpip.h> +#endif +#include <string.h> + +#include <string> + +#include "rtc_base/byte_order.h" +#if defined(WEBRTC_WIN) +#include "rtc_base/win32.h" +#endif +#include "absl/strings/string_view.h" +#include "rtc_base/system/rtc_export.h" +namespace rtc { + +enum IPv6AddressFlag { + IPV6_ADDRESS_FLAG_NONE = 0x00, + + // Temporary address is dynamic by nature and will not carry MAC + // address. + IPV6_ADDRESS_FLAG_TEMPORARY = 1 << 0, + + // Temporary address could become deprecated once the preferred + // lifetime is reached. It is still valid but just shouldn't be used + // to create new connection. + IPV6_ADDRESS_FLAG_DEPRECATED = 1 << 1, +}; + +// Version-agnostic IP address class, wraps a union of in_addr and in6_addr. +class RTC_EXPORT IPAddress { + public: + IPAddress() : family_(AF_UNSPEC) { ::memset(&u_, 0, sizeof(u_)); } + + explicit IPAddress(const in_addr& ip4) : family_(AF_INET) { + memset(&u_, 0, sizeof(u_)); + u_.ip4 = ip4; + } + + explicit IPAddress(const in6_addr& ip6) : family_(AF_INET6) { u_.ip6 = ip6; } + + explicit IPAddress(uint32_t ip_in_host_byte_order) : family_(AF_INET) { + memset(&u_, 0, sizeof(u_)); + u_.ip4.s_addr = HostToNetwork32(ip_in_host_byte_order); + } + + IPAddress(const IPAddress& other) : family_(other.family_) { + ::memcpy(&u_, &other.u_, sizeof(u_)); + } + + virtual ~IPAddress() {} + + const IPAddress& operator=(const IPAddress& other) { + family_ = other.family_; + ::memcpy(&u_, &other.u_, sizeof(u_)); + return *this; + } + + bool operator==(const IPAddress& other) const; + bool operator!=(const IPAddress& other) const; + bool operator<(const IPAddress& other) const; + bool operator>(const IPAddress& other) const; + +#ifdef WEBRTC_UNIT_TEST + inline std::ostream& operator<<( // no-presubmit-check TODO(webrtc:8982) + std::ostream& os) { // no-presubmit-check TODO(webrtc:8982) + return os << ToString(); + } +#endif // WEBRTC_UNIT_TEST + + int family() const { return family_; } + in_addr ipv4_address() const; + in6_addr ipv6_address() const; + + // Returns the number of bytes needed to store the raw address. + size_t Size() const; + + // Wraps inet_ntop. + std::string ToString() const; + + // Same as ToString but anonymizes it by hiding the last part. + std::string ToSensitiveString() const; + + // Returns an unmapped address from a possibly-mapped address. + // Returns the same address if this isn't a mapped address. + IPAddress Normalized() const; + + // Returns this address as an IPv6 address. + // Maps v4 addresses (as ::ffff:a.b.c.d), returns v6 addresses unchanged. + IPAddress AsIPv6Address() const; + + // For socketaddress' benefit. Returns the IP in host byte order. + uint32_t v4AddressAsHostOrderInteger() const; + + // Get the network layer overhead per packet based on the IP address family. + int overhead() const; + + // Whether this is an unspecified IP address. + bool IsNil() const; + + private: + int family_; + union { + in_addr ip4; + in6_addr ip6; + } u_; +}; + +// IP class which could represent IPv6 address flags which is only +// meaningful in IPv6 case. +class RTC_EXPORT InterfaceAddress : public IPAddress { + public: + InterfaceAddress() : ipv6_flags_(IPV6_ADDRESS_FLAG_NONE) {} + + explicit InterfaceAddress(IPAddress ip) + : IPAddress(ip), ipv6_flags_(IPV6_ADDRESS_FLAG_NONE) {} + + InterfaceAddress(IPAddress addr, int ipv6_flags) + : IPAddress(addr), ipv6_flags_(ipv6_flags) {} + + InterfaceAddress(const in6_addr& ip6, int ipv6_flags) + : IPAddress(ip6), ipv6_flags_(ipv6_flags) {} + + InterfaceAddress(const InterfaceAddress& other) = default; + const InterfaceAddress& operator=(const InterfaceAddress& other); + + bool operator==(const InterfaceAddress& other) const; + bool operator!=(const InterfaceAddress& other) const; + + int ipv6_flags() const { return ipv6_flags_; } + + std::string ToString() const; + + private: + int ipv6_flags_; +}; + +bool IPFromAddrInfo(struct addrinfo* info, IPAddress* out); +RTC_EXPORT bool IPFromString(absl::string_view str, IPAddress* out); +RTC_EXPORT bool IPFromString(absl::string_view str, + int flags, + InterfaceAddress* out); +bool IPIsAny(const IPAddress& ip); +bool IPIsLoopback(const IPAddress& ip); +bool IPIsLinkLocal(const IPAddress& ip); +// Identify a private network address like "192.168.111.222" +// (see https://en.wikipedia.org/wiki/Private_network ) +bool IPIsPrivateNetwork(const IPAddress& ip); +// Identify a shared network address like "100.72.16.122" +// (see RFC6598) +bool IPIsSharedNetwork(const IPAddress& ip); +// Identify if an IP is "private", that is a loopback +// or an address belonging to a link-local, a private network or a shared +// network. +RTC_EXPORT bool IPIsPrivate(const IPAddress& ip); +RTC_EXPORT bool IPIsUnspec(const IPAddress& ip); +size_t HashIP(const IPAddress& ip); + +// These are only really applicable for IPv6 addresses. +bool IPIs6Bone(const IPAddress& ip); +bool IPIs6To4(const IPAddress& ip); +RTC_EXPORT bool IPIsMacBased(const IPAddress& ip); +bool IPIsSiteLocal(const IPAddress& ip); +bool IPIsTeredo(const IPAddress& ip); +bool IPIsULA(const IPAddress& ip); +bool IPIsV4Compatibility(const IPAddress& ip); +bool IPIsV4Mapped(const IPAddress& ip); + +// Returns the precedence value for this IP as given in RFC3484. +int IPAddressPrecedence(const IPAddress& ip); + +// Returns 'ip' truncated to be 'length' bits long. +RTC_EXPORT IPAddress TruncateIP(const IPAddress& ip, int length); + +IPAddress GetLoopbackIP(int family); +IPAddress GetAnyIP(int family); + +// Returns the number of contiguously set bits, counting from the MSB in network +// byte order, in this IPAddress. Bits after the first 0 encountered are not +// counted. +int CountIPMaskBits(const IPAddress& mask); + +} // namespace rtc + +#endif // RTC_BASE_IP_ADDRESS_H_ diff --git a/third_party/libwebrtc/rtc_base/ip_address_gn/moz.build b/third_party/libwebrtc/rtc_base/ip_address_gn/moz.build new file mode 100644 index 0000000000..a893dab3c2 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/ip_address_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/rtc_base/ip_address.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_ENABLE_LIBEVENT"] = 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 += [ + "GLESv2", + "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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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" + ] + +if CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("ip_address_gn") diff --git a/third_party/libwebrtc/rtc_base/ip_address_unittest.cc b/third_party/libwebrtc/rtc_base/ip_address_unittest.cc new file mode 100644 index 0000000000..aee9b93dd9 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/ip_address_unittest.cc @@ -0,0 +1,977 @@ +/* + * 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 "rtc_base/ip_address.h" + +#include "absl/strings/string_view.h" +#include "test/gtest.h" + +namespace rtc { + +static const unsigned int kIPv4AddrSize = 4; +static const unsigned int kIPv6AddrSize = 16; +static const unsigned int kIPv4RFC1918Addr = 0xC0A80701; +static const unsigned int kIPv4PublicAddr = 0x01020304; +static const unsigned int kIPv4RFC6598Addr = 0x64410801; +static const unsigned int kIPv4LinkLocalAddr = 0xA9FE10C1; // 169.254.16.193 +static const in6_addr kIPv6LinkLocalAddr = { + {{0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x30, 0x5b, 0xff, + 0xfe, 0xe5, 0x00, 0xc3}}}; +static const in6_addr kIPv6PublicAddr = { + {{0x24, 0x01, 0xfa, 0x00, 0x00, 0x04, 0x10, 0x00, 0xbe, 0x30, 0x5b, 0xff, + 0xfe, 0xe5, 0x00, 0xc3}}}; +static const in6_addr kIPv6PublicAddr2 = { + {{0x24, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0xbe, 0x30, 0x5b, 0xff, + 0xfe, 0xe5, 0x00, 0xc3}}}; +static const in6_addr kIPv4MappedAnyAddr = { + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00}}}; +static const in6_addr kIPv4MappedRFC1918Addr = { + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xc0, 0xa8, 0x07, 0x01}}}; +static const in6_addr kIPv4MappedPublicAddr = { + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x01, 0x02, 0x03, 0x04}}}; + +static const std::string kIPv4AnyAddrString = "0.0.0.0"; +static const std::string kIPv4LoopbackAddrString = "127.0.0.1"; +static const std::string kIPv4RFC1918AddrString = "192.168.7.1"; +static const std::string kIPv4RFC6598AddrString = "100.65.8.1"; +static const std::string kIPv4PublicAddrString = "1.2.3.4"; +static const std::string kIPv4PublicAddrAnonymizedString = "1.2.3.x"; +static const std::string kIPv6AnyAddrString = "::"; +static const std::string kIPv6LoopbackAddrString = "::1"; +static const std::string kIPv6LinkLocalAddrString = "fe80::be30:5bff:fee5:c3"; +static const std::string kIPv6EuiAddrString = + "2620:0:1008:1201:a248:1cff:fe98:360"; +static const std::string kIPv6TemporaryAddrString = + "2620:0:1008:1201:2089:6dda:385e:80c0"; +static const std::string kIPv6PublicAddrString = + "2401:fa00:4:1000:be30:5bff:fee5:c3"; +static const std::string kIPv6PublicAddr2String = + "2401::1000:be30:5bff:fee5:c3"; +static const std::string kIPv6PublicAddrAnonymizedString = + "2401:fa00:4:x:x:x:x:x"; +static const std::string kIPv6PublicAddr2AnonymizedString = + "2401:0:0:x:x:x:x:x"; +static const std::string kIPv4MappedV4StyleAddrString = "::ffff:192.168.7.1"; + +static const std::string kIPv4BrokenString1 = "192.168.7."; +static const std::string kIPv4BrokenString2 = "192.168.7.1.1"; +static const std::string kIPv4BrokenString3 = "192.168.7.1:80"; +static const std::string kIPv4BrokenString4 = "192.168.7.ONE"; +static const std::string kIPv4BrokenString5 = "-192.168.7.1"; +static const std::string kIPv4BrokenString6 = "256.168.7.1"; +static const std::string kIPv6BrokenString1 = "2401:fa00:4:1000:be30"; +static const std::string kIPv6BrokenString2 = + "2401:fa00:4:1000:be30:5bff:fee5:c3:1"; +static const std::string kIPv6BrokenString3 = + "[2401:fa00:4:1000:be30:5bff:fee5:c3]:1"; +static const std::string kIPv6BrokenString4 = "2401::4::be30"; +static const std::string kIPv6BrokenString5 = "2401:::4:fee5:be30"; +static const std::string kIPv6BrokenString6 = + "2401f:fa00:4:1000:be30:5bff:fee5:c3"; +static const std::string kIPv6BrokenString7 = + "2401:ga00:4:1000:be30:5bff:fee5:c3"; +static const std::string kIPv6BrokenString8 = + "2401:fa000:4:1000:be30:5bff:fee5:c3"; +static const std::string kIPv6BrokenString9 = + "2401:fal0:4:1000:be30:5bff:fee5:c3"; +static const std::string kIPv6BrokenString10 = "::ffff:192.168.7."; +static const std::string kIPv6BrokenString11 = "::ffff:192.168.7.1.1.1"; +static const std::string kIPv6BrokenString12 = "::fffe:192.168.7.1"; +static const std::string kIPv6BrokenString13 = "::ffff:192.168.7.ff"; +static const std::string kIPv6BrokenString14 = + "0x2401:fa00:4:1000:be30:5bff:fee5:c3"; + +bool AreEqual(const IPAddress& addr, const IPAddress& addr2) { + if ((IPIsAny(addr) != IPIsAny(addr2)) || + (IPIsLoopback(addr) != IPIsLoopback(addr2)) || + (IPIsPrivate(addr) != IPIsPrivate(addr2)) || + (HashIP(addr) != HashIP(addr2)) || (addr.Size() != addr2.Size()) || + (addr.family() != addr2.family()) || + (addr.ToString() != addr2.ToString())) { + return false; + } + in_addr v4addr, v4addr2; + v4addr = addr.ipv4_address(); + v4addr2 = addr2.ipv4_address(); + if (0 != memcmp(&v4addr, &v4addr2, sizeof(v4addr))) { + return false; + } + in6_addr v6addr, v6addr2; + v6addr = addr.ipv6_address(); + v6addr2 = addr2.ipv6_address(); + if (0 != memcmp(&v6addr, &v6addr2, sizeof(v6addr))) { + return false; + } + return true; +} + +bool BrokenIPStringFails(absl::string_view broken) { + IPAddress addr(0); // Intentionally make it v4. + if (IPFromString(kIPv4BrokenString1, &addr)) { + return false; + } + return addr.family() == AF_UNSPEC; +} + +bool CheckMaskCount(absl::string_view mask, int expected_length) { + IPAddress addr; + return IPFromString(mask, &addr) && + (expected_length == CountIPMaskBits(addr)); +} + +bool TryInvalidMaskCount(absl::string_view mask) { + // We don't care about the result at all, but we do want to know if + // CountIPMaskBits is going to crash or infinite loop or something. + IPAddress addr; + if (!IPFromString(mask, &addr)) { + return false; + } + CountIPMaskBits(addr); + return true; +} + +bool CheckTruncateIP(absl::string_view initial, + int truncate_length, + absl::string_view expected_result) { + IPAddress addr, expected; + IPFromString(initial, &addr); + IPFromString(expected_result, &expected); + IPAddress truncated = TruncateIP(addr, truncate_length); + return truncated == expected; +} + +TEST(IPAddressTest, TestDefaultCtor) { + IPAddress addr; + EXPECT_FALSE(IPIsAny(addr)); + EXPECT_FALSE(IPIsLoopback(addr)); + EXPECT_FALSE(IPIsPrivate(addr)); + + EXPECT_EQ(0U, addr.Size()); + EXPECT_EQ(AF_UNSPEC, addr.family()); + EXPECT_EQ("", addr.ToString()); +} + +TEST(IPAddressTest, TestInAddrCtor) { + in_addr v4addr; + + // Test V4 Any address. + v4addr.s_addr = INADDR_ANY; + IPAddress addr(v4addr); + EXPECT_TRUE(IPIsAny(addr)); + EXPECT_FALSE(IPIsLoopback(addr)); + EXPECT_FALSE(IPIsPrivate(addr)); + EXPECT_EQ(kIPv4AddrSize, addr.Size()); + EXPECT_EQ(kIPv4AnyAddrString, addr.ToString()); + + // Test a V4 loopback address. + v4addr.s_addr = htonl(INADDR_LOOPBACK); + addr = IPAddress(v4addr); + EXPECT_FALSE(IPIsAny(addr)); + EXPECT_TRUE(IPIsLoopback(addr)); + EXPECT_FALSE(IPIsSharedNetwork(addr)); + EXPECT_TRUE(IPIsPrivate(addr)); + EXPECT_EQ(kIPv4AddrSize, addr.Size()); + EXPECT_EQ(kIPv4LoopbackAddrString, addr.ToString()); + + // Test an RFC1918 address. + v4addr.s_addr = htonl(kIPv4RFC1918Addr); + addr = IPAddress(v4addr); + EXPECT_FALSE(IPIsAny(addr)); + EXPECT_FALSE(IPIsLoopback(addr)); + EXPECT_FALSE(IPIsSharedNetwork(addr)); + EXPECT_TRUE(IPIsPrivate(addr)); + EXPECT_EQ(kIPv4AddrSize, addr.Size()); + EXPECT_EQ(kIPv4RFC1918AddrString, addr.ToString()); + + // Test an shared (RFC6598) address. + v4addr.s_addr = htonl(kIPv4RFC6598Addr); + addr = IPAddress(v4addr); + EXPECT_FALSE(IPIsAny(addr)); + EXPECT_FALSE(IPIsLoopback(addr)); + EXPECT_TRUE(IPIsPrivate(addr)); + EXPECT_TRUE(IPIsSharedNetwork(addr)); + EXPECT_EQ(kIPv4AddrSize, addr.Size()); + EXPECT_EQ(kIPv4RFC6598AddrString, addr.ToString()); + + // Test a 'normal' v4 address. + v4addr.s_addr = htonl(kIPv4PublicAddr); + addr = IPAddress(v4addr); + EXPECT_FALSE(IPIsAny(addr)); + EXPECT_FALSE(IPIsLoopback(addr)); + EXPECT_FALSE(IPIsPrivate(addr)); + EXPECT_EQ(kIPv4AddrSize, addr.Size()); + EXPECT_EQ(kIPv4PublicAddrString, addr.ToString()); +} + +TEST(IPAddressTest, TestInAddr6Ctor) { + // Test v6 empty. + IPAddress addr(in6addr_any); + EXPECT_TRUE(IPIsAny(addr)); + EXPECT_FALSE(IPIsLoopback(addr)); + EXPECT_FALSE(IPIsPrivate(addr)); + EXPECT_EQ(kIPv6AddrSize, addr.Size()); + EXPECT_EQ(kIPv6AnyAddrString, addr.ToString()); + + // Test v6 loopback. + addr = IPAddress(in6addr_loopback); + EXPECT_FALSE(IPIsAny(addr)); + EXPECT_TRUE(IPIsLoopback(addr)); + EXPECT_FALSE(IPIsSharedNetwork(addr)); + EXPECT_TRUE(IPIsPrivate(addr)); + EXPECT_EQ(kIPv6AddrSize, addr.Size()); + EXPECT_EQ(kIPv6LoopbackAddrString, addr.ToString()); + + // Test v6 link-local. + addr = IPAddress(kIPv6LinkLocalAddr); + EXPECT_FALSE(IPIsAny(addr)); + EXPECT_FALSE(IPIsLoopback(addr)); + EXPECT_FALSE(IPIsSharedNetwork(addr)); + EXPECT_TRUE(IPIsPrivate(addr)); + EXPECT_EQ(kIPv6AddrSize, addr.Size()); + EXPECT_EQ(kIPv6LinkLocalAddrString, addr.ToString()); + + // Test v6 global address. + addr = IPAddress(kIPv6PublicAddr); + EXPECT_FALSE(IPIsAny(addr)); + EXPECT_FALSE(IPIsLoopback(addr)); + EXPECT_FALSE(IPIsPrivate(addr)); + EXPECT_EQ(kIPv6AddrSize, addr.Size()); + EXPECT_EQ(kIPv6PublicAddrString, addr.ToString()); +} + +TEST(IPAddressTest, TestUint32Ctor) { + // Test V4 Any address. + IPAddress addr(0); + EXPECT_TRUE(IPIsAny(addr)); + EXPECT_FALSE(IPIsLoopback(addr)); + EXPECT_FALSE(IPIsPrivate(addr)); + EXPECT_EQ(kIPv4AddrSize, addr.Size()); + EXPECT_EQ(kIPv4AnyAddrString, addr.ToString()); + + // Test a V4 loopback address. + addr = IPAddress(INADDR_LOOPBACK); + EXPECT_FALSE(IPIsAny(addr)); + EXPECT_TRUE(IPIsLoopback(addr)); + EXPECT_FALSE(IPIsSharedNetwork(addr)); + EXPECT_TRUE(IPIsPrivate(addr)); + EXPECT_EQ(kIPv4AddrSize, addr.Size()); + EXPECT_EQ(kIPv4LoopbackAddrString, addr.ToString()); + + // Test an RFC1918 address. + addr = IPAddress(kIPv4RFC1918Addr); + EXPECT_FALSE(IPIsAny(addr)); + EXPECT_FALSE(IPIsLoopback(addr)); + EXPECT_FALSE(IPIsSharedNetwork(addr)); + EXPECT_TRUE(IPIsPrivate(addr)); + EXPECT_EQ(kIPv4AddrSize, addr.Size()); + EXPECT_EQ(kIPv4RFC1918AddrString, addr.ToString()); + + // Test a 'normal' v4 address. + addr = IPAddress(kIPv4PublicAddr); + EXPECT_FALSE(IPIsAny(addr)); + EXPECT_FALSE(IPIsLoopback(addr)); + EXPECT_FALSE(IPIsPrivate(addr)); + EXPECT_EQ(kIPv4AddrSize, addr.Size()); + EXPECT_EQ(kIPv4PublicAddrString, addr.ToString()); +} + +TEST(IPAddressTest, TestCopyCtor) { + in_addr v4addr; + v4addr.s_addr = htonl(kIPv4PublicAddr); + IPAddress addr(v4addr); + IPAddress addr2(addr); + + EXPECT_TRUE(AreEqual(addr, addr2)); + + addr = IPAddress(INADDR_ANY); + addr2 = IPAddress(addr); + EXPECT_TRUE(AreEqual(addr, addr2)); + + addr = IPAddress(INADDR_LOOPBACK); + addr2 = IPAddress(addr); + EXPECT_TRUE(AreEqual(addr, addr2)); + + addr = IPAddress(kIPv4PublicAddr); + addr2 = IPAddress(addr); + EXPECT_TRUE(AreEqual(addr, addr2)); + + addr = IPAddress(kIPv4RFC1918Addr); + addr2 = IPAddress(addr); + EXPECT_TRUE(AreEqual(addr, addr2)); + + addr = IPAddress(in6addr_any); + addr2 = IPAddress(addr); + EXPECT_TRUE(AreEqual(addr, addr2)); + + addr = IPAddress(in6addr_loopback); + addr2 = IPAddress(addr); + EXPECT_TRUE(AreEqual(addr, addr2)); + + addr = IPAddress(kIPv6LinkLocalAddr); + addr2 = IPAddress(addr); + EXPECT_TRUE(AreEqual(addr, addr2)); + + addr = IPAddress(kIPv6PublicAddr); + addr2 = IPAddress(addr); + EXPECT_TRUE(AreEqual(addr, addr2)); +} + +TEST(IPAddressTest, TestEquality) { + // Check v4 equality + in_addr v4addr, v4addr2; + v4addr.s_addr = htonl(kIPv4PublicAddr); + v4addr2.s_addr = htonl(kIPv4PublicAddr + 1); + IPAddress addr(v4addr); + IPAddress addr2(v4addr2); + IPAddress addr3(v4addr); + + EXPECT_TRUE(addr == addr); + EXPECT_TRUE(addr2 == addr2); + EXPECT_TRUE(addr3 == addr3); + EXPECT_TRUE(addr == addr3); + EXPECT_TRUE(addr3 == addr); + EXPECT_FALSE(addr2 == addr); + EXPECT_FALSE(addr2 == addr3); + EXPECT_FALSE(addr == addr2); + EXPECT_FALSE(addr3 == addr2); + + // Check v6 equality + IPAddress addr4(kIPv6PublicAddr); + IPAddress addr5(kIPv6LinkLocalAddr); + IPAddress addr6(kIPv6PublicAddr); + + EXPECT_TRUE(addr4 == addr4); + EXPECT_TRUE(addr5 == addr5); + EXPECT_TRUE(addr4 == addr6); + EXPECT_TRUE(addr6 == addr4); + EXPECT_FALSE(addr4 == addr5); + EXPECT_FALSE(addr5 == addr4); + EXPECT_FALSE(addr6 == addr5); + EXPECT_FALSE(addr5 == addr6); + + // Check v4/v6 cross-equality + EXPECT_FALSE(addr == addr4); + EXPECT_FALSE(addr == addr5); + EXPECT_FALSE(addr == addr6); + EXPECT_FALSE(addr4 == addr); + EXPECT_FALSE(addr5 == addr); + EXPECT_FALSE(addr6 == addr); + EXPECT_FALSE(addr2 == addr4); + EXPECT_FALSE(addr2 == addr5); + EXPECT_FALSE(addr2 == addr6); + EXPECT_FALSE(addr4 == addr2); + EXPECT_FALSE(addr5 == addr2); + EXPECT_FALSE(addr6 == addr2); + EXPECT_FALSE(addr3 == addr4); + EXPECT_FALSE(addr3 == addr5); + EXPECT_FALSE(addr3 == addr6); + EXPECT_FALSE(addr4 == addr3); + EXPECT_FALSE(addr5 == addr3); + EXPECT_FALSE(addr6 == addr3); + + // Special cases: loopback and any. + // They're special but they're still not equal. + IPAddress v4loopback(htonl(INADDR_LOOPBACK)); + IPAddress v6loopback(in6addr_loopback); + EXPECT_FALSE(v4loopback == v6loopback); + + IPAddress v4any(0); + IPAddress v6any(in6addr_any); + EXPECT_FALSE(v4any == v6any); +} + +TEST(IPAddressTest, TestComparison) { + // Defined in 'ascending' order. + // v6 > v4, and intra-family sorting is purely numerical + IPAddress addr0; // AF_UNSPEC + IPAddress addr1(INADDR_ANY); // 0.0.0.0 + IPAddress addr2(kIPv4PublicAddr); // 1.2.3.4 + IPAddress addr3(INADDR_LOOPBACK); // 127.0.0.1 + IPAddress addr4(kIPv4RFC1918Addr); // 192.168.7.1. + IPAddress addr5(in6addr_any); // :: + IPAddress addr6(in6addr_loopback); // ::1 + IPAddress addr7(kIPv6PublicAddr); // 2401.... + IPAddress addr8(kIPv6LinkLocalAddr); // fe80.... + + EXPECT_TRUE(addr0 < addr1); + EXPECT_TRUE(addr1 < addr2); + EXPECT_TRUE(addr2 < addr3); + EXPECT_TRUE(addr3 < addr4); + EXPECT_TRUE(addr4 < addr5); + EXPECT_TRUE(addr5 < addr6); + EXPECT_TRUE(addr6 < addr7); + EXPECT_TRUE(addr7 < addr8); + + EXPECT_FALSE(addr0 > addr1); + EXPECT_FALSE(addr1 > addr2); + EXPECT_FALSE(addr2 > addr3); + EXPECT_FALSE(addr3 > addr4); + EXPECT_FALSE(addr4 > addr5); + EXPECT_FALSE(addr5 > addr6); + EXPECT_FALSE(addr6 > addr7); + EXPECT_FALSE(addr7 > addr8); + + EXPECT_FALSE(addr0 > addr0); + EXPECT_FALSE(addr1 > addr1); + EXPECT_FALSE(addr2 > addr2); + EXPECT_FALSE(addr3 > addr3); + EXPECT_FALSE(addr4 > addr4); + EXPECT_FALSE(addr5 > addr5); + EXPECT_FALSE(addr6 > addr6); + EXPECT_FALSE(addr7 > addr7); + EXPECT_FALSE(addr8 > addr8); + + EXPECT_FALSE(addr0 < addr0); + EXPECT_FALSE(addr1 < addr1); + EXPECT_FALSE(addr2 < addr2); + EXPECT_FALSE(addr3 < addr3); + EXPECT_FALSE(addr4 < addr4); + EXPECT_FALSE(addr5 < addr5); + EXPECT_FALSE(addr6 < addr6); + EXPECT_FALSE(addr7 < addr7); + EXPECT_FALSE(addr8 < addr8); +} + +TEST(IPAddressTest, TestFromString) { + IPAddress addr; + IPAddress addr2; + addr2 = IPAddress(INADDR_ANY); + + EXPECT_TRUE(IPFromString(kIPv4AnyAddrString, &addr)); + EXPECT_EQ(addr.ToString(), kIPv4AnyAddrString); + EXPECT_TRUE(AreEqual(addr, addr2)); + + addr2 = IPAddress(INADDR_LOOPBACK); + EXPECT_TRUE(IPFromString(kIPv4LoopbackAddrString, &addr)); + EXPECT_EQ(addr.ToString(), kIPv4LoopbackAddrString); + EXPECT_TRUE(AreEqual(addr, addr2)); + + addr2 = IPAddress(kIPv4RFC1918Addr); + EXPECT_TRUE(IPFromString(kIPv4RFC1918AddrString, &addr)); + EXPECT_EQ(addr.ToString(), kIPv4RFC1918AddrString); + EXPECT_TRUE(AreEqual(addr, addr2)); + + addr2 = IPAddress(kIPv4PublicAddr); + EXPECT_TRUE(IPFromString(kIPv4PublicAddrString, &addr)); + EXPECT_EQ(addr.ToString(), kIPv4PublicAddrString); + EXPECT_TRUE(AreEqual(addr, addr2)); + + addr2 = IPAddress(in6addr_any); + EXPECT_TRUE(IPFromString(kIPv6AnyAddrString, &addr)); + EXPECT_EQ(addr.ToString(), kIPv6AnyAddrString); + EXPECT_TRUE(AreEqual(addr, addr2)); + + addr2 = IPAddress(in6addr_loopback); + EXPECT_TRUE(IPFromString(kIPv6LoopbackAddrString, &addr)); + EXPECT_EQ(addr.ToString(), kIPv6LoopbackAddrString); + EXPECT_TRUE(AreEqual(addr, addr2)); + + addr2 = IPAddress(kIPv6LinkLocalAddr); + EXPECT_TRUE(IPFromString(kIPv6LinkLocalAddrString, &addr)); + EXPECT_EQ(addr.ToString(), kIPv6LinkLocalAddrString); + EXPECT_TRUE(AreEqual(addr, addr2)); + + addr2 = IPAddress(kIPv6PublicAddr); + EXPECT_TRUE(IPFromString(kIPv6PublicAddrString, &addr)); + EXPECT_EQ(addr.ToString(), kIPv6PublicAddrString); + EXPECT_TRUE(AreEqual(addr, addr2)); + + addr2 = IPAddress(kIPv4MappedRFC1918Addr); + EXPECT_TRUE(IPFromString(kIPv4MappedV4StyleAddrString, &addr)); + EXPECT_TRUE(AreEqual(addr, addr2)); + + // Broken cases, should set addr to AF_UNSPEC. + EXPECT_PRED1(BrokenIPStringFails, kIPv4BrokenString1); + EXPECT_PRED1(BrokenIPStringFails, kIPv4BrokenString2); + EXPECT_PRED1(BrokenIPStringFails, kIPv4BrokenString3); + EXPECT_PRED1(BrokenIPStringFails, kIPv4BrokenString4); + EXPECT_PRED1(BrokenIPStringFails, kIPv4BrokenString5); + EXPECT_PRED1(BrokenIPStringFails, kIPv4BrokenString6); + EXPECT_PRED1(BrokenIPStringFails, kIPv6BrokenString1); + EXPECT_PRED1(BrokenIPStringFails, kIPv6BrokenString2); + EXPECT_PRED1(BrokenIPStringFails, kIPv6BrokenString3); + EXPECT_PRED1(BrokenIPStringFails, kIPv6BrokenString4); + EXPECT_PRED1(BrokenIPStringFails, kIPv6BrokenString5); + EXPECT_PRED1(BrokenIPStringFails, kIPv6BrokenString6); + EXPECT_PRED1(BrokenIPStringFails, kIPv6BrokenString7); + EXPECT_PRED1(BrokenIPStringFails, kIPv6BrokenString8); + EXPECT_PRED1(BrokenIPStringFails, kIPv6BrokenString9); + EXPECT_PRED1(BrokenIPStringFails, kIPv6BrokenString10); + EXPECT_PRED1(BrokenIPStringFails, kIPv6BrokenString11); + EXPECT_PRED1(BrokenIPStringFails, kIPv6BrokenString12); + EXPECT_PRED1(BrokenIPStringFails, kIPv6BrokenString13); + EXPECT_PRED1(BrokenIPStringFails, kIPv6BrokenString14); +} + +TEST(IPAddressTest, TestIPFromAddrInfo) { + struct sockaddr_in expected4; + struct sockaddr_in6 expected6; + struct addrinfo test_info; + struct addrinfo next_info; + memset(&next_info, 'A', sizeof(next_info)); + test_info.ai_next = &next_info; + // Check that we can get an IPv4 address out. + test_info.ai_addr = reinterpret_cast<struct sockaddr*>(&expected4); + expected4.sin_addr.s_addr = HostToNetwork32(kIPv4PublicAddr); + expected4.sin_family = AF_INET; + IPAddress expected(kIPv4PublicAddr); + IPAddress addr; + EXPECT_TRUE(IPFromAddrInfo(&test_info, &addr)); + EXPECT_EQ(expected, addr); + // Check that we can get an IPv6 address out. + expected6.sin6_addr = kIPv6PublicAddr; + expected6.sin6_family = AF_INET6; + expected = IPAddress(kIPv6PublicAddr); + test_info.ai_addr = reinterpret_cast<struct sockaddr*>(&expected6); + EXPECT_TRUE(IPFromAddrInfo(&test_info, &addr)); + EXPECT_EQ(expected, addr); + // Check that unspec fails. + expected6.sin6_family = AF_UNSPEC; + EXPECT_FALSE(IPFromAddrInfo(&test_info, &addr)); + // Check a zeroed out addrinfo doesn't crash us. + memset(&next_info, 0, sizeof(next_info)); + EXPECT_FALSE(IPFromAddrInfo(&next_info, &addr)); +} + +TEST(IPAddressTest, TestIsPrivate) { + EXPECT_FALSE(IPIsPrivate(IPAddress(INADDR_ANY))); + EXPECT_FALSE(IPIsPrivate(IPAddress(kIPv4PublicAddr))); + EXPECT_FALSE(IPIsPrivate(IPAddress(in6addr_any))); + EXPECT_FALSE(IPIsPrivate(IPAddress(kIPv6PublicAddr))); + EXPECT_FALSE(IPIsPrivate(IPAddress(kIPv4MappedAnyAddr))); + EXPECT_FALSE(IPIsPrivate(IPAddress(kIPv4MappedPublicAddr))); + + EXPECT_TRUE(IPIsPrivate(IPAddress(kIPv4RFC1918Addr))); + EXPECT_TRUE(IPIsPrivate(IPAddress(kIPv4RFC6598Addr))); + EXPECT_TRUE(IPIsPrivate(IPAddress(INADDR_LOOPBACK))); + EXPECT_TRUE(IPIsPrivate(IPAddress(in6addr_loopback))); + EXPECT_TRUE(IPIsPrivate(IPAddress(kIPv6LinkLocalAddr))); +} + +TEST(IPAddressTest, TestIsNil) { + IPAddress addr; + EXPECT_TRUE(IPAddress().IsNil()); + + EXPECT_TRUE(IPFromString(kIPv6AnyAddrString, &addr)); + EXPECT_FALSE(addr.IsNil()); + + EXPECT_TRUE(IPFromString(kIPv4AnyAddrString, &addr)); + EXPECT_FALSE(addr.IsNil()); + + EXPECT_FALSE(IPAddress(kIPv4PublicAddr).IsNil()); +} + +TEST(IPAddressTest, TestIsLoopback) { + EXPECT_FALSE(IPIsLoopback(IPAddress(INADDR_ANY))); + EXPECT_FALSE(IPIsLoopback(IPAddress(kIPv4PublicAddr))); + EXPECT_FALSE(IPIsLoopback(IPAddress(in6addr_any))); + EXPECT_FALSE(IPIsLoopback(IPAddress(kIPv4RFC6598Addr))); + EXPECT_FALSE(IPIsLoopback(IPAddress(kIPv6PublicAddr))); + EXPECT_FALSE(IPIsLoopback(IPAddress(kIPv4MappedAnyAddr))); + EXPECT_FALSE(IPIsLoopback(IPAddress(kIPv4MappedPublicAddr))); + + EXPECT_TRUE(IPIsLoopback(IPAddress(INADDR_LOOPBACK))); + // Try an address in the loopback range (127.0.0.0/8) other than the typical + // 127.0.0.1. + EXPECT_TRUE(IPIsLoopback(IPAddress(0x7f010203))); + EXPECT_TRUE(IPIsLoopback(IPAddress(in6addr_loopback))); +} + +TEST(IPAddressTest, TestIsLinkLocal) { + // "any" addresses + EXPECT_FALSE(IPIsLinkLocal(IPAddress(INADDR_ANY))); + EXPECT_FALSE(IPIsLinkLocal(IPAddress(in6addr_any))); + // loopback addresses + EXPECT_FALSE(IPIsLinkLocal(IPAddress(INADDR_LOOPBACK))); + EXPECT_FALSE(IPIsLinkLocal(IPAddress(in6addr_loopback))); + // shared addresses + EXPECT_FALSE(IPIsLinkLocal(IPAddress(kIPv4RFC6598Addr))); + // public addresses + EXPECT_FALSE(IPIsLinkLocal(IPAddress(kIPv4PublicAddr))); + EXPECT_FALSE(IPIsLinkLocal(IPAddress(kIPv6PublicAddr))); + // private network addresses + EXPECT_FALSE(IPIsLinkLocal(IPAddress(kIPv4RFC1918Addr))); + // mapped addresses + EXPECT_FALSE(IPIsLinkLocal(IPAddress(kIPv4MappedAnyAddr))); + EXPECT_FALSE(IPIsLinkLocal(IPAddress(kIPv4MappedPublicAddr))); + EXPECT_FALSE(IPIsLinkLocal(IPAddress(kIPv4MappedRFC1918Addr))); + + // link-local network addresses + EXPECT_TRUE(IPIsLinkLocal(IPAddress(kIPv4LinkLocalAddr))); + EXPECT_TRUE(IPIsLinkLocal(IPAddress(kIPv6LinkLocalAddr))); +} + +// Verify that IPIsAny catches all cases of "any" address. +TEST(IPAddressTest, TestIsAny) { + IPAddress addr; + + EXPECT_TRUE(IPFromString(kIPv6AnyAddrString, &addr)); + EXPECT_TRUE(IPIsAny(addr)); + + EXPECT_TRUE(IPFromString(kIPv4AnyAddrString, &addr)); + EXPECT_TRUE(IPIsAny(addr)); + + EXPECT_TRUE(IPIsAny(IPAddress(kIPv4MappedAnyAddr))); +} + +TEST(IPAddressTest, TestIsEui64) { + IPAddress addr; + EXPECT_TRUE(IPFromString(kIPv6EuiAddrString, &addr)); + EXPECT_TRUE(IPIsMacBased(addr)); + + EXPECT_TRUE(IPFromString(kIPv6TemporaryAddrString, &addr)); + EXPECT_FALSE(IPIsMacBased(addr)); + + EXPECT_TRUE(IPFromString(kIPv6LinkLocalAddrString, &addr)); + EXPECT_TRUE(IPIsMacBased(addr)); + + EXPECT_TRUE(IPFromString(kIPv6AnyAddrString, &addr)); + EXPECT_FALSE(IPIsMacBased(addr)); + + EXPECT_TRUE(IPFromString(kIPv6LoopbackAddrString, &addr)); + EXPECT_FALSE(IPIsMacBased(addr)); +} + +TEST(IPAddressTest, TestNormalized) { + // Check normalizing a ::ffff:a.b.c.d address. + IPAddress addr; + EXPECT_TRUE(IPFromString(kIPv4MappedV4StyleAddrString, &addr)); + IPAddress addr2(kIPv4RFC1918Addr); + addr = addr.Normalized(); + EXPECT_EQ(addr2, addr); + + // Check normalizing a ::ffff:aabb:ccdd address. + addr = IPAddress(kIPv4MappedPublicAddr); + addr2 = IPAddress(kIPv4PublicAddr); + addr = addr.Normalized(); + EXPECT_EQ(addr, addr2); + + // Check that a non-mapped v6 addresses isn't altered. + addr = IPAddress(kIPv6PublicAddr); + addr2 = IPAddress(kIPv6PublicAddr); + addr = addr.Normalized(); + EXPECT_EQ(addr, addr2); + + // Check that addresses that look a bit like mapped addresses aren't altered + EXPECT_TRUE(IPFromString("fe80::ffff:0102:0304", &addr)); + addr2 = addr; + addr = addr.Normalized(); + EXPECT_EQ(addr, addr2); + EXPECT_TRUE(IPFromString("::0102:0304", &addr)); + addr2 = addr; + addr = addr.Normalized(); + EXPECT_EQ(addr, addr2); + // This string should 'work' as an IP address but is not a mapped address, + // so it shouldn't change on normalization. + EXPECT_TRUE(IPFromString("::192.168.7.1", &addr)); + addr2 = addr; + addr = addr.Normalized(); + EXPECT_EQ(addr, addr2); + + // Check that v4 addresses aren't altered. + addr = IPAddress(htonl(kIPv4PublicAddr)); + addr2 = IPAddress(htonl(kIPv4PublicAddr)); + addr = addr.Normalized(); + EXPECT_EQ(addr, addr2); +} + +TEST(IPAddressTest, TestAsIPv6Address) { + IPAddress addr(kIPv4PublicAddr); + IPAddress addr2(kIPv4MappedPublicAddr); + addr = addr.AsIPv6Address(); + EXPECT_EQ(addr, addr2); + + addr = IPAddress(kIPv4MappedPublicAddr); + addr2 = IPAddress(kIPv4MappedPublicAddr); + addr = addr.AsIPv6Address(); + EXPECT_EQ(addr, addr2); + + addr = IPAddress(kIPv6PublicAddr); + addr2 = IPAddress(kIPv6PublicAddr); + addr = addr.AsIPv6Address(); + EXPECT_EQ(addr, addr2); +} + +TEST(IPAddressTest, TestCountIPMaskBits) { + IPAddress mask; + // IPv4 on byte boundaries + EXPECT_PRED2(CheckMaskCount, "255.255.255.255", 32); + EXPECT_PRED2(CheckMaskCount, "255.255.255.0", 24); + EXPECT_PRED2(CheckMaskCount, "255.255.0.0", 16); + EXPECT_PRED2(CheckMaskCount, "255.0.0.0", 8); + EXPECT_PRED2(CheckMaskCount, "0.0.0.0", 0); + + // IPv4 not on byte boundaries + EXPECT_PRED2(CheckMaskCount, "128.0.0.0", 1); + EXPECT_PRED2(CheckMaskCount, "224.0.0.0", 3); + EXPECT_PRED2(CheckMaskCount, "255.248.0.0", 13); + EXPECT_PRED2(CheckMaskCount, "255.255.224.0", 19); + EXPECT_PRED2(CheckMaskCount, "255.255.255.252", 30); + + // V6 on byte boundaries + EXPECT_PRED2(CheckMaskCount, "::", 0); + EXPECT_PRED2(CheckMaskCount, "ff00::", 8); + EXPECT_PRED2(CheckMaskCount, "ffff::", 16); + EXPECT_PRED2(CheckMaskCount, "ffff:ff00::", 24); + EXPECT_PRED2(CheckMaskCount, "ffff:ffff::", 32); + EXPECT_PRED2(CheckMaskCount, "ffff:ffff:ff00::", 40); + EXPECT_PRED2(CheckMaskCount, "ffff:ffff:ffff::", 48); + EXPECT_PRED2(CheckMaskCount, "ffff:ffff:ffff:ff00::", 56); + EXPECT_PRED2(CheckMaskCount, "ffff:ffff:ffff:ffff::", 64); + EXPECT_PRED2(CheckMaskCount, "ffff:ffff:ffff:ffff:ff00::", 72); + EXPECT_PRED2(CheckMaskCount, "ffff:ffff:ffff:ffff:ffff::", 80); + EXPECT_PRED2(CheckMaskCount, "ffff:ffff:ffff:ffff:ffff:ff00::", 88); + EXPECT_PRED2(CheckMaskCount, "ffff:ffff:ffff:ffff:ffff:ffff::", 96); + EXPECT_PRED2(CheckMaskCount, "ffff:ffff:ffff:ffff:ffff:ffff:ff00:0000", 104); + EXPECT_PRED2(CheckMaskCount, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:0000", 112); + EXPECT_PRED2(CheckMaskCount, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ff00", 120); + EXPECT_PRED2(CheckMaskCount, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", 128); + + // V6 not on byte boundaries. + EXPECT_PRED2(CheckMaskCount, "8000::", 1); + EXPECT_PRED2(CheckMaskCount, "ff80::", 9); + EXPECT_PRED2(CheckMaskCount, "ffff:fe00::", 23); + EXPECT_PRED2(CheckMaskCount, "ffff:fffe::", 31); + EXPECT_PRED2(CheckMaskCount, "ffff:ffff:e000::", 35); + EXPECT_PRED2(CheckMaskCount, "ffff:ffff:ffe0::", 43); + EXPECT_PRED2(CheckMaskCount, "ffff:ffff:ffff:f800::", 53); + EXPECT_PRED2(CheckMaskCount, "ffff:ffff:ffff:fff8::", 61); + EXPECT_PRED2(CheckMaskCount, "ffff:ffff:ffff:ffff:fc00::", 70); + EXPECT_PRED2(CheckMaskCount, "ffff:ffff:ffff:ffff:fffc::", 78); + EXPECT_PRED2(CheckMaskCount, "ffff:ffff:ffff:ffff:ffff:8000::", 81); + EXPECT_PRED2(CheckMaskCount, "ffff:ffff:ffff:ffff:ffff:ff80::", 89); + EXPECT_PRED2(CheckMaskCount, "ffff:ffff:ffff:ffff:ffff:ffff:fe00::", 103); + EXPECT_PRED2(CheckMaskCount, "ffff:ffff:ffff:ffff:ffff:ffff:fffe:0000", 111); + EXPECT_PRED2(CheckMaskCount, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:fc00", 118); + EXPECT_PRED2(CheckMaskCount, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffc", 126); + + // Non-contiguous ranges. These are invalid but lets test them + // to make sure they don't crash anything or infinite loop or something. + EXPECT_PRED1(TryInvalidMaskCount, "217.0.0.0"); + EXPECT_PRED1(TryInvalidMaskCount, "255.185.0.0"); + EXPECT_PRED1(TryInvalidMaskCount, "255.255.251.0"); + EXPECT_PRED1(TryInvalidMaskCount, "255.255.251.255"); + EXPECT_PRED1(TryInvalidMaskCount, "255.255.254.201"); + EXPECT_PRED1(TryInvalidMaskCount, "::1"); + EXPECT_PRED1(TryInvalidMaskCount, "fe80::1"); + EXPECT_PRED1(TryInvalidMaskCount, "ff80::1"); + EXPECT_PRED1(TryInvalidMaskCount, "ffff::1"); + EXPECT_PRED1(TryInvalidMaskCount, "ffff:ff00:1::1"); + EXPECT_PRED1(TryInvalidMaskCount, "ffff:ffff::ffff:1"); + EXPECT_PRED1(TryInvalidMaskCount, "ffff:ffff:ff00:1::"); + EXPECT_PRED1(TryInvalidMaskCount, "ffff:ffff:ffff::ff00"); + EXPECT_PRED1(TryInvalidMaskCount, "ffff:ffff:ffff:ff00:1234::"); + EXPECT_PRED1(TryInvalidMaskCount, "ffff:ffff:ffff:ffff:0012::ffff"); + EXPECT_PRED1(TryInvalidMaskCount, "ffff:ffff:ffff:ffff:ff01::"); + EXPECT_PRED1(TryInvalidMaskCount, "ffff:ffff:ffff:ffff:ffff:7f00::"); + EXPECT_PRED1(TryInvalidMaskCount, "ffff:ffff:ffff:ffff:ffff:ff7a::"); + EXPECT_PRED1(TryInvalidMaskCount, "ffff:ffff:ffff:ffff:ffff:ffff:7f00:0000"); + EXPECT_PRED1(TryInvalidMaskCount, "ffff:ffff:ffff:ffff:ffff:ffff:ff70:0000"); + EXPECT_PRED1(TryInvalidMaskCount, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:0211"); + EXPECT_PRED1(TryInvalidMaskCount, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ff7f"); +} + +TEST(IPAddressTest, TestTruncateIP) { + EXPECT_PRED3(CheckTruncateIP, "255.255.255.255", 24, "255.255.255.0"); + EXPECT_PRED3(CheckTruncateIP, "255.255.255.255", 16, "255.255.0.0"); + EXPECT_PRED3(CheckTruncateIP, "255.255.255.255", 8, "255.0.0.0"); + EXPECT_PRED3(CheckTruncateIP, "202.67.7.255", 24, "202.67.7.0"); + EXPECT_PRED3(CheckTruncateIP, "202.129.65.205", 16, "202.129.0.0"); + EXPECT_PRED3(CheckTruncateIP, "55.25.2.77", 8, "55.0.0.0"); + EXPECT_PRED3(CheckTruncateIP, "74.128.99.254", 1, "0.0.0.0"); + EXPECT_PRED3(CheckTruncateIP, "106.55.99.254", 3, "96.0.0.0"); + EXPECT_PRED3(CheckTruncateIP, "172.167.53.222", 13, "172.160.0.0"); + EXPECT_PRED3(CheckTruncateIP, "255.255.224.0", 18, "255.255.192.0"); + EXPECT_PRED3(CheckTruncateIP, "255.255.255.252", 28, "255.255.255.240"); + + EXPECT_PRED3(CheckTruncateIP, "fe80:1111:2222:3333:4444:5555:6666:7777", 1, + "8000::"); + EXPECT_PRED3(CheckTruncateIP, "fff0:1111:2222:3333:4444:5555:6666:7777", 9, + "ff80::"); + EXPECT_PRED3(CheckTruncateIP, "ffff:ff80:1111:2222:3333:4444:5555:6666", 23, + "ffff:fe00::"); + EXPECT_PRED3(CheckTruncateIP, "ffff:ff80:1111:2222:3333:4444:5555:6666", 32, + "ffff:ff80::"); + EXPECT_PRED3(CheckTruncateIP, "2400:f9af:e456:1111:2222:3333:4444:5555", 35, + "2400:f9af:e000::"); + EXPECT_PRED3(CheckTruncateIP, "9999:1111:2233:4444:5555:6666:7777:8888", 53, + "9999:1111:2233:4000::"); + EXPECT_PRED3(CheckTruncateIP, "9999:1111:2233:4567:5555:6666:7777:8888", 64, + "9999:1111:2233:4567::"); + EXPECT_PRED3(CheckTruncateIP, "1111:2222:3333:4444:5555:6666:7777:8888", 68, + "1111:2222:3333:4444:5000::"); + EXPECT_PRED3(CheckTruncateIP, "1111:2222:3333:4444:5555:6666:7777:8888", 92, + "1111:2222:3333:4444:5555:6660::"); + EXPECT_PRED3(CheckTruncateIP, "1111:2222:3333:4444:5555:6666:7777:8888", 96, + "1111:2222:3333:4444:5555:6666::"); + EXPECT_PRED3(CheckTruncateIP, "1111:2222:3333:4444:5555:6666:7777:8888", 105, + "1111:2222:3333:4444:5555:6666:7700::"); + EXPECT_PRED3(CheckTruncateIP, "1111:2222:3333:4444:5555:6666:7777:8888", 124, + "1111:2222:3333:4444:5555:6666:7777:8880"); + + // Slightly degenerate cases + EXPECT_PRED3(CheckTruncateIP, "202.165.33.127", 32, "202.165.33.127"); + EXPECT_PRED3(CheckTruncateIP, "235.105.77.12", 0, "0.0.0.0"); + EXPECT_PRED3(CheckTruncateIP, "1111:2222:3333:4444:5555:6666:7777:8888", 128, + "1111:2222:3333:4444:5555:6666:7777:8888"); + EXPECT_PRED3(CheckTruncateIP, "1111:2222:3333:4444:5555:6666:7777:8888", 0, + "::"); +} + +TEST(IPAddressTest, TestCategorizeIPv6) { + // Test determining if an IPAddress is 6Bone/6To4/Teredo/etc. + // IPv4 address, should be none of these (not even v4compat/v4mapped). + IPAddress v4_addr(kIPv4PublicAddr); + EXPECT_FALSE(IPIs6Bone(v4_addr)); + EXPECT_FALSE(IPIs6To4(v4_addr)); + EXPECT_FALSE(IPIsSiteLocal(v4_addr)); + EXPECT_FALSE(IPIsTeredo(v4_addr)); + EXPECT_FALSE(IPIsULA(v4_addr)); + EXPECT_FALSE(IPIsV4Compatibility(v4_addr)); + EXPECT_FALSE(IPIsV4Mapped(v4_addr)); + // Linklocal (fe80::/16) adddress; should be none of these. + IPAddress linklocal_addr(kIPv6LinkLocalAddr); + EXPECT_FALSE(IPIs6Bone(linklocal_addr)); + EXPECT_FALSE(IPIs6To4(linklocal_addr)); + EXPECT_FALSE(IPIsSiteLocal(linklocal_addr)); + EXPECT_FALSE(IPIsTeredo(linklocal_addr)); + EXPECT_FALSE(IPIsULA(linklocal_addr)); + EXPECT_FALSE(IPIsV4Compatibility(linklocal_addr)); + EXPECT_FALSE(IPIsV4Mapped(linklocal_addr)); + // 'Normal' IPv6 address, should also be none of these. + IPAddress normal_addr(kIPv6PublicAddr); + EXPECT_FALSE(IPIs6Bone(normal_addr)); + EXPECT_FALSE(IPIs6To4(normal_addr)); + EXPECT_FALSE(IPIsSiteLocal(normal_addr)); + EXPECT_FALSE(IPIsTeredo(normal_addr)); + EXPECT_FALSE(IPIsULA(normal_addr)); + EXPECT_FALSE(IPIsV4Compatibility(normal_addr)); + EXPECT_FALSE(IPIsV4Mapped(normal_addr)); + // IPv4 mapped address (::ffff:123.123.123.123) + IPAddress v4mapped_addr(kIPv4MappedPublicAddr); + EXPECT_TRUE(IPIsV4Mapped(v4mapped_addr)); + EXPECT_FALSE(IPIsV4Compatibility(v4mapped_addr)); + EXPECT_FALSE(IPIs6Bone(v4mapped_addr)); + EXPECT_FALSE(IPIs6To4(v4mapped_addr)); + EXPECT_FALSE(IPIsSiteLocal(v4mapped_addr)); + EXPECT_FALSE(IPIsTeredo(v4mapped_addr)); + EXPECT_FALSE(IPIsULA(v4mapped_addr)); + // IPv4 compatibility address (::123.123.123.123) + IPAddress v4compat_addr; + IPFromString("::192.168.7.1", &v4compat_addr); + EXPECT_TRUE(IPIsV4Compatibility(v4compat_addr)); + EXPECT_FALSE(IPIs6Bone(v4compat_addr)); + EXPECT_FALSE(IPIs6To4(v4compat_addr)); + EXPECT_FALSE(IPIsSiteLocal(v4compat_addr)); + EXPECT_FALSE(IPIsTeredo(v4compat_addr)); + EXPECT_FALSE(IPIsULA(v4compat_addr)); + EXPECT_FALSE(IPIsV4Mapped(v4compat_addr)); + // 6Bone address (3FFE::/16) + IPAddress sixbone_addr; + IPFromString("3FFE:123:456::789:123", &sixbone_addr); + EXPECT_TRUE(IPIs6Bone(sixbone_addr)); + EXPECT_FALSE(IPIs6To4(sixbone_addr)); + EXPECT_FALSE(IPIsSiteLocal(sixbone_addr)); + EXPECT_FALSE(IPIsTeredo(sixbone_addr)); + EXPECT_FALSE(IPIsULA(sixbone_addr)); + EXPECT_FALSE(IPIsV4Mapped(sixbone_addr)); + EXPECT_FALSE(IPIsV4Compatibility(sixbone_addr)); + // Unique Local Address (FC::/7) + IPAddress ula_addr; + IPFromString("FC00:123:456::789:123", &ula_addr); + EXPECT_TRUE(IPIsULA(ula_addr)); + EXPECT_FALSE(IPIs6Bone(ula_addr)); + EXPECT_FALSE(IPIs6To4(ula_addr)); + EXPECT_FALSE(IPIsSiteLocal(ula_addr)); + EXPECT_FALSE(IPIsTeredo(ula_addr)); + EXPECT_FALSE(IPIsV4Mapped(ula_addr)); + EXPECT_FALSE(IPIsV4Compatibility(ula_addr)); + // 6To4 Address (2002::/16) + IPAddress sixtofour_addr; + IPFromString("2002:123:456::789:123", &sixtofour_addr); + EXPECT_TRUE(IPIs6To4(sixtofour_addr)); + EXPECT_FALSE(IPIs6Bone(sixtofour_addr)); + EXPECT_FALSE(IPIsSiteLocal(sixtofour_addr)); + EXPECT_FALSE(IPIsTeredo(sixtofour_addr)); + EXPECT_FALSE(IPIsULA(sixtofour_addr)); + EXPECT_FALSE(IPIsV4Compatibility(sixtofour_addr)); + EXPECT_FALSE(IPIsV4Mapped(sixtofour_addr)); + // Site Local address (FEC0::/10) + IPAddress sitelocal_addr; + IPFromString("FEC0:123:456::789:123", &sitelocal_addr); + EXPECT_TRUE(IPIsSiteLocal(sitelocal_addr)); + EXPECT_FALSE(IPIs6Bone(sitelocal_addr)); + EXPECT_FALSE(IPIs6To4(sitelocal_addr)); + EXPECT_FALSE(IPIsTeredo(sitelocal_addr)); + EXPECT_FALSE(IPIsULA(sitelocal_addr)); + EXPECT_FALSE(IPIsV4Compatibility(sitelocal_addr)); + EXPECT_FALSE(IPIsV4Mapped(sitelocal_addr)); + // Teredo Address (2001:0000::/32) + IPAddress teredo_addr; + IPFromString("2001:0000:123:456::789:123", &teredo_addr); + EXPECT_TRUE(IPIsTeredo(teredo_addr)); + EXPECT_FALSE(IPIsSiteLocal(teredo_addr)); + EXPECT_FALSE(IPIs6Bone(teredo_addr)); + EXPECT_FALSE(IPIs6To4(teredo_addr)); + EXPECT_FALSE(IPIsULA(teredo_addr)); + EXPECT_FALSE(IPIsV4Compatibility(teredo_addr)); + EXPECT_FALSE(IPIsV4Mapped(teredo_addr)); +} + +TEST(IPAddressTest, TestToSensitiveString) { + IPAddress addr_v4 = IPAddress(kIPv4PublicAddr); + IPAddress addr_v6 = IPAddress(kIPv6PublicAddr); + IPAddress addr_v6_2 = IPAddress(kIPv6PublicAddr2); + EXPECT_EQ(kIPv4PublicAddrString, addr_v4.ToString()); + EXPECT_EQ(kIPv6PublicAddrString, addr_v6.ToString()); + EXPECT_EQ(kIPv6PublicAddr2String, addr_v6_2.ToString()); + EXPECT_EQ(kIPv4PublicAddrAnonymizedString, addr_v4.ToSensitiveString()); + EXPECT_EQ(kIPv6PublicAddrAnonymizedString, addr_v6.ToSensitiveString()); + EXPECT_EQ(kIPv6PublicAddr2AnonymizedString, addr_v6_2.ToSensitiveString()); +} + +TEST(IPAddressTest, TestInterfaceAddress) { + in6_addr addr; + InterfaceAddress addr1(kIPv6PublicAddr, IPV6_ADDRESS_FLAG_TEMPORARY); + EXPECT_EQ(addr1.ipv6_flags(), IPV6_ADDRESS_FLAG_TEMPORARY); + EXPECT_EQ(addr1.family(), AF_INET6); + + addr = addr1.ipv6_address(); + EXPECT_TRUE(IN6_ARE_ADDR_EQUAL(&addr, &kIPv6PublicAddr)); + + InterfaceAddress addr2 = addr1; + EXPECT_EQ(addr1, addr2); + EXPECT_EQ(addr2.ipv6_flags(), IPV6_ADDRESS_FLAG_TEMPORARY); + addr = addr2.ipv6_address(); + EXPECT_TRUE(IN6_ARE_ADDR_EQUAL(&addr, &kIPv6PublicAddr)); + + InterfaceAddress addr3(addr1); + EXPECT_EQ(addr1, addr3); + EXPECT_EQ(addr3.ipv6_flags(), IPV6_ADDRESS_FLAG_TEMPORARY); + addr = addr3.ipv6_address(); + EXPECT_TRUE(IN6_ARE_ADDR_EQUAL(&addr, &kIPv6PublicAddr)); + + InterfaceAddress addr4(kIPv6PublicAddr, IPV6_ADDRESS_FLAG_DEPRECATED); + EXPECT_NE(addr1, addr4); + + // When you compare them as IPAddress, since operator== + // is not virtual, it'll be equal. + IPAddress* paddr1 = &addr1; + IPAddress* paddr4 = &addr4; + EXPECT_EQ(*paddr1, *paddr4); + + InterfaceAddress addr5(kIPv6LinkLocalAddr, IPV6_ADDRESS_FLAG_TEMPORARY); + EXPECT_NE(addr1, addr5); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/java/src/org/webrtc/ContextUtils.java b/third_party/libwebrtc/rtc_base/java/src/org/webrtc/ContextUtils.java new file mode 100644 index 0000000000..e36ab72878 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/java/src/org/webrtc/ContextUtils.java @@ -0,0 +1,45 @@ +/* + * Copyright 2017 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. + */ + +package org.webrtc; + +import android.content.Context; + +/** + * Class for storing the application context and retrieving it in a static context. Similar to + * org.chromium.base.ContextUtils. + */ +public class ContextUtils { + private static final String TAG = "ContextUtils"; + private static Context applicationContext; + + /** + * Stores the application context that will be returned by getApplicationContext. This is called + * by PeerConnectionFactory.initialize. The application context must be set before creating + * a PeerConnectionFactory and must not be modified while it is alive. + */ + public static void initialize(Context applicationContext) { + if (applicationContext == null) { + throw new IllegalArgumentException( + "Application context cannot be null for ContextUtils.initialize."); + } + ContextUtils.applicationContext = applicationContext; + } + + /** + * Returns the stored application context. + * + * @deprecated crbug.com/webrtc/8937 + */ + @Deprecated + public static Context getApplicationContext() { + return applicationContext; + } +} diff --git a/third_party/libwebrtc/rtc_base/java/src/org/webrtc/Loggable.java b/third_party/libwebrtc/rtc_base/java/src/org/webrtc/Loggable.java new file mode 100644 index 0000000000..cd66aa1214 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/java/src/org/webrtc/Loggable.java @@ -0,0 +1,22 @@ +/* + * 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. + */ + +package org.webrtc; + +import org.webrtc.Logging.Severity; + +/** + * Java interface for WebRTC logging. The default implementation uses webrtc.Logging. + * + * When injected, the Loggable will receive logging from both Java and native. + */ +public interface Loggable { + public void onLogMessage(String message, Severity severity, String tag); +} diff --git a/third_party/libwebrtc/rtc_base/java/src/org/webrtc/Logging.java b/third_party/libwebrtc/rtc_base/java/src/org/webrtc/Logging.java new file mode 100644 index 0000000000..e7a9921f4d --- /dev/null +++ b/third_party/libwebrtc/rtc_base/java/src/org/webrtc/Logging.java @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2015 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. + */ + +package org.webrtc; + +import androidx.annotation.Nullable; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.EnumSet; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.webrtc.Loggable; + +/** + * Java wrapper for WebRTC logging. Logging defaults to java.util.logging.Logger, but a custom + * logger implementing the Loggable interface can be injected along with a Severity. All subsequent + * log messages will then be redirected to the injected Loggable, except those with a severity lower + * than the specified severity, which will be discarded. + * + * It is also possible to switch to native logging (rtc::LogMessage) if one of the following static + * functions are called from the app: + * - Logging.enableLogThreads + * - Logging.enableLogTimeStamps + * - Logging.enableLogToDebugOutput + * + * The priority goes: + * 1. Injected loggable + * 2. Native logging + * 3. Fallback logging. + * Only one method will be used at a time. + * + * Injecting a Loggable or using any of the enable... methods requires that the native library is + * loaded, using PeerConnectionFactory.initialize. + */ +public class Logging { + private static final Logger fallbackLogger = createFallbackLogger(); + private static volatile boolean loggingEnabled; + @Nullable private static Loggable loggable; + private static Severity loggableSeverity; + + private static Logger createFallbackLogger() { + final Logger fallbackLogger = Logger.getLogger("org.webrtc.Logging"); + fallbackLogger.setLevel(Level.ALL); + return fallbackLogger; + } + + static void injectLoggable(Loggable injectedLoggable, Severity severity) { + if (injectedLoggable != null) { + loggable = injectedLoggable; + loggableSeverity = severity; + } + } + + static void deleteInjectedLoggable() { + loggable = null; + } + + // TODO(solenberg): Remove once dependent projects updated. + @Deprecated + public enum TraceLevel { + TRACE_NONE(0x0000), + TRACE_STATEINFO(0x0001), + TRACE_WARNING(0x0002), + TRACE_ERROR(0x0004), + TRACE_CRITICAL(0x0008), + TRACE_APICALL(0x0010), + TRACE_DEFAULT(0x00ff), + TRACE_MODULECALL(0x0020), + TRACE_MEMORY(0x0100), + TRACE_TIMER(0x0200), + TRACE_STREAM(0x0400), + TRACE_DEBUG(0x0800), + TRACE_INFO(0x1000), + TRACE_TERSEINFO(0x2000), + TRACE_ALL(0xffff); + + public final int level; + TraceLevel(int level) { + this.level = level; + } + } + + // Keep in sync with webrtc/rtc_base/logging.h:LoggingSeverity. + public enum Severity { LS_VERBOSE, LS_INFO, LS_WARNING, LS_ERROR, LS_NONE } + + public static void enableLogThreads() { + nativeEnableLogThreads(); + } + + public static void enableLogTimeStamps() { + nativeEnableLogTimeStamps(); + } + + // TODO(solenberg): Remove once dependent projects updated. + @Deprecated + public static void enableTracing(String path, EnumSet<TraceLevel> levels) {} + + // Enable diagnostic logging for messages of `severity` to the platform debug + // output. On Android, the output will be directed to Logcat. + // Note: this function starts collecting the output of the RTC_LOG() macros. + // TODO(bugs.webrtc.org/8491): Remove NoSynchronizedMethodCheck suppression. + @SuppressWarnings("NoSynchronizedMethodCheck") + public static synchronized void enableLogToDebugOutput(Severity severity) { + if (loggable != null) { + throw new IllegalStateException( + "Logging to native debug output not supported while Loggable is injected. " + + "Delete the Loggable before calling this method."); + } + nativeEnableLogToDebugOutput(severity.ordinal()); + loggingEnabled = true; + } + + public static void log(Severity severity, String tag, String message) { + if (tag == null || message == null) { + throw new IllegalArgumentException("Logging tag or message may not be null."); + } + if (loggable != null) { + // Filter log messages below loggableSeverity. + if (severity.ordinal() < loggableSeverity.ordinal()) { + return; + } + loggable.onLogMessage(message, severity, tag); + return; + } + + // Try native logging if no loggable is injected. + if (loggingEnabled) { + nativeLog(severity.ordinal(), tag, message); + return; + } + + // Fallback to system log. + Level level; + switch (severity) { + case LS_ERROR: + level = Level.SEVERE; + break; + case LS_WARNING: + level = Level.WARNING; + break; + case LS_INFO: + level = Level.INFO; + break; + default: + level = Level.FINE; + break; + } + fallbackLogger.log(level, tag + ": " + message); + } + + public static void d(String tag, String message) { + log(Severity.LS_INFO, tag, message); + } + + public static void e(String tag, String message) { + log(Severity.LS_ERROR, tag, message); + } + + public static void w(String tag, String message) { + log(Severity.LS_WARNING, tag, message); + } + + public static void e(String tag, String message, Throwable e) { + log(Severity.LS_ERROR, tag, message); + log(Severity.LS_ERROR, tag, e.toString()); + log(Severity.LS_ERROR, tag, getStackTraceString(e)); + } + + public static void w(String tag, String message, Throwable e) { + log(Severity.LS_WARNING, tag, message); + log(Severity.LS_WARNING, tag, e.toString()); + log(Severity.LS_WARNING, tag, getStackTraceString(e)); + } + + public static void v(String tag, String message) { + log(Severity.LS_VERBOSE, tag, message); + } + + private static String getStackTraceString(Throwable e) { + if (e == null) { + return ""; + } + + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + e.printStackTrace(pw); + return sw.toString(); + } + + private static native void nativeEnableLogToDebugOutput(int nativeSeverity); + private static native void nativeEnableLogThreads(); + private static native void nativeEnableLogTimeStamps(); + private static native void nativeLog(int severity, String tag, String message); +} diff --git a/third_party/libwebrtc/rtc_base/java/src/org/webrtc/OWNERS b/third_party/libwebrtc/rtc_base/java/src/org/webrtc/OWNERS new file mode 100644 index 0000000000..109bea2725 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/java/src/org/webrtc/OWNERS @@ -0,0 +1,2 @@ +magjed@webrtc.org +xalep@webrtc.org diff --git a/third_party/libwebrtc/rtc_base/java/src/org/webrtc/Size.java b/third_party/libwebrtc/rtc_base/java/src/org/webrtc/Size.java new file mode 100644 index 0000000000..a711b5d2ca --- /dev/null +++ b/third_party/libwebrtc/rtc_base/java/src/org/webrtc/Size.java @@ -0,0 +1,45 @@ +/* + * Copyright 2016 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. + */ + +package org.webrtc; + +/** + * Class for representing size of an object. Very similar to android.util.Size but available on all + * devices. + */ +public class Size { + public int width; + public int height; + + public Size(int width, int height) { + this.width = width; + this.height = height; + } + + @Override + public String toString() { + return width + "x" + height; + } + + @Override + public boolean equals(Object other) { + if (!(other instanceof Size)) { + return false; + } + final Size otherSize = (Size) other; + return width == otherSize.width && height == otherSize.height; + } + + @Override + public int hashCode() { + // Use prime close to 2^16 to avoid collisions for normal values less than 2^16. + return 1 + 65537 * width + height; + } +} diff --git a/third_party/libwebrtc/rtc_base/java/src/org/webrtc/ThreadUtils.java b/third_party/libwebrtc/rtc_base/java/src/org/webrtc/ThreadUtils.java new file mode 100644 index 0000000000..0c502b1bc3 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/java/src/org/webrtc/ThreadUtils.java @@ -0,0 +1,212 @@ +/* + * Copyright 2015 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. + */ + +package org.webrtc; + +import android.os.Handler; +import android.os.Looper; +import android.os.SystemClock; +import androidx.annotation.Nullable; +import java.util.concurrent.Callable; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +public class ThreadUtils { + /** + * Utility class to be used for checking that a method is called on the correct thread. + */ + public static class ThreadChecker { + @Nullable private Thread thread = Thread.currentThread(); + + public void checkIsOnValidThread() { + if (thread == null) { + thread = Thread.currentThread(); + } + if (Thread.currentThread() != thread) { + throw new IllegalStateException("Wrong thread"); + } + } + + public void detachThread() { + thread = null; + } + } + + /** + * Throws exception if called from other than main thread. + */ + public static void checkIsOnMainThread() { + if (Thread.currentThread() != Looper.getMainLooper().getThread()) { + throw new IllegalStateException("Not on main thread!"); + } + } + + /** + * Utility interface to be used with executeUninterruptibly() to wait for blocking operations + * to complete without getting interrupted.. + */ + public interface BlockingOperation { void run() throws InterruptedException; } + + /** + * Utility method to make sure a blocking operation is executed to completion without getting + * interrupted. This should be used in cases where the operation is waiting for some critical + * work, e.g. cleanup, that must complete before returning. If the thread is interrupted during + * the blocking operation, this function will re-run the operation until completion, and only then + * re-interrupt the thread. + */ + public static void executeUninterruptibly(BlockingOperation operation) { + boolean wasInterrupted = false; + while (true) { + try { + operation.run(); + break; + } catch (InterruptedException e) { + // Someone is asking us to return early at our convenience. We can't cancel this operation, + // but we should preserve the information and pass it along. + wasInterrupted = true; + } + } + // Pass interruption information along. + if (wasInterrupted) { + Thread.currentThread().interrupt(); + } + } + + public static boolean joinUninterruptibly(final Thread thread, long timeoutMs) { + final long startTimeMs = SystemClock.elapsedRealtime(); + long timeRemainingMs = timeoutMs; + boolean wasInterrupted = false; + while (timeRemainingMs > 0) { + try { + thread.join(timeRemainingMs); + break; + } catch (InterruptedException e) { + // Someone is asking us to return early at our convenience. We can't cancel this operation, + // but we should preserve the information and pass it along. + wasInterrupted = true; + final long elapsedTimeMs = SystemClock.elapsedRealtime() - startTimeMs; + timeRemainingMs = timeoutMs - elapsedTimeMs; + } + } + // Pass interruption information along. + if (wasInterrupted) { + Thread.currentThread().interrupt(); + } + return !thread.isAlive(); + } + + public static void joinUninterruptibly(final Thread thread) { + executeUninterruptibly(new BlockingOperation() { + @Override + public void run() throws InterruptedException { + thread.join(); + } + }); + } + + public static void awaitUninterruptibly(final CountDownLatch latch) { + executeUninterruptibly(new BlockingOperation() { + @Override + public void run() throws InterruptedException { + latch.await(); + } + }); + } + + public static boolean awaitUninterruptibly(CountDownLatch barrier, long timeoutMs) { + final long startTimeMs = SystemClock.elapsedRealtime(); + long timeRemainingMs = timeoutMs; + boolean wasInterrupted = false; + boolean result = false; + do { + try { + result = barrier.await(timeRemainingMs, TimeUnit.MILLISECONDS); + break; + } catch (InterruptedException e) { + // Someone is asking us to return early at our convenience. We can't cancel this operation, + // but we should preserve the information and pass it along. + wasInterrupted = true; + final long elapsedTimeMs = SystemClock.elapsedRealtime() - startTimeMs; + timeRemainingMs = timeoutMs - elapsedTimeMs; + } + } while (timeRemainingMs > 0); + // Pass interruption information along. + if (wasInterrupted) { + Thread.currentThread().interrupt(); + } + return result; + } + + /** + * Post `callable` to `handler` and wait for the result. + */ + public static <V> V invokeAtFrontUninterruptibly( + final Handler handler, final Callable<V> callable) { + if (handler.getLooper().getThread() == Thread.currentThread()) { + try { + return callable.call(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + // Place-holder classes that are assignable inside nested class. + class CaughtException { + Exception e; + } + class Result { + public V value; + } + final Result result = new Result(); + final CaughtException caughtException = new CaughtException(); + final CountDownLatch barrier = new CountDownLatch(1); + handler.post(new Runnable() { + @Override + public void run() { + try { + result.value = callable.call(); + } catch (Exception e) { + caughtException.e = e; + } + barrier.countDown(); + } + }); + awaitUninterruptibly(barrier); + // Re-throw any runtime exception caught inside the other thread. Since this is an invoke, add + // stack trace for the waiting thread as well. + if (caughtException.e != null) { + final RuntimeException runtimeException = new RuntimeException(caughtException.e); + runtimeException.setStackTrace( + concatStackTraces(caughtException.e.getStackTrace(), runtimeException.getStackTrace())); + throw runtimeException; + } + return result.value; + } + + /** + * Post `runner` to `handler`, at the front, and wait for completion. + */ + public static void invokeAtFrontUninterruptibly(final Handler handler, final Runnable runner) { + invokeAtFrontUninterruptibly(handler, new Callable<Void>() { + @Override + public Void call() { + runner.run(); + return null; + } + }); + } + + static StackTraceElement[] concatStackTraces( + StackTraceElement[] inner, StackTraceElement[] outer) { + final StackTraceElement[] combined = new StackTraceElement[inner.length + outer.length]; + System.arraycopy(inner, 0, combined, 0, inner.length); + System.arraycopy(outer, 0, combined, inner.length, outer.length); + return combined; + } +} diff --git a/third_party/libwebrtc/rtc_base/log_sinks.cc b/third_party/libwebrtc/rtc_base/log_sinks.cc new file mode 100644 index 0000000000..f511948ed3 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/log_sinks.cc @@ -0,0 +1,86 @@ +/* + * Copyright 2015 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 "rtc_base/log_sinks.h" + +#include <string.h> + +#include <cstdio> +#include <string> + +#include "absl/strings/string_view.h" +#include "rtc_base/checks.h" + +namespace rtc { + +FileRotatingLogSink::FileRotatingLogSink(absl::string_view log_dir_path, + absl::string_view log_prefix, + size_t max_log_size, + size_t num_log_files) + : FileRotatingLogSink(new FileRotatingStream(log_dir_path, + log_prefix, + max_log_size, + num_log_files)) {} + +FileRotatingLogSink::FileRotatingLogSink(FileRotatingStream* stream) + : stream_(stream) { + RTC_DCHECK(stream); +} + +FileRotatingLogSink::~FileRotatingLogSink() {} + +void FileRotatingLogSink::OnLogMessage(const std::string& message) { + OnLogMessage(absl::string_view(message)); +} + +void FileRotatingLogSink::OnLogMessage(absl::string_view message) { + if (!stream_->IsOpen()) { + std::fprintf(stderr, "Init() must be called before adding this sink.\n"); + return; + } + stream_->Write(message.data(), message.size()); +} + +void FileRotatingLogSink::OnLogMessage(const std::string& message, + LoggingSeverity sev, + const char* tag) { + OnLogMessage(absl::string_view(message), sev, tag); +} + +void FileRotatingLogSink::OnLogMessage(absl::string_view message, + LoggingSeverity sev, + const char* tag) { + if (!stream_->IsOpen()) { + std::fprintf(stderr, "Init() must be called before adding this sink.\n"); + return; + } + stream_->Write(tag, strlen(tag)); + stream_->Write(": ", 2); + stream_->Write(message.data(), message.size()); +} + +bool FileRotatingLogSink::Init() { + return stream_->Open(); +} + +bool FileRotatingLogSink::DisableBuffering() { + return stream_->DisableBuffering(); +} + +CallSessionFileRotatingLogSink::CallSessionFileRotatingLogSink( + absl::string_view log_dir_path, + size_t max_total_log_size) + : FileRotatingLogSink( + new CallSessionFileRotatingStream(log_dir_path, max_total_log_size)) { +} + +CallSessionFileRotatingLogSink::~CallSessionFileRotatingLogSink() {} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/log_sinks.h b/third_party/libwebrtc/rtc_base/log_sinks.h new file mode 100644 index 0000000000..62a93b85a8 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/log_sinks.h @@ -0,0 +1,80 @@ +/* + * Copyright 2015 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 RTC_BASE_LOG_SINKS_H_ +#define RTC_BASE_LOG_SINKS_H_ + +#include <stddef.h> + +#include <memory> +#include <string> + +#include "absl/strings/string_view.h" +#include "rtc_base/file_rotating_stream.h" +#include "rtc_base/logging.h" + +namespace rtc { + +// Log sink that uses a FileRotatingStream to write to disk. +// Init() must be called before adding this sink. +class FileRotatingLogSink : public LogSink { + public: + // `num_log_files` must be greater than 1 and `max_log_size` must be greater + // than 0. + FileRotatingLogSink(absl::string_view log_dir_path, + absl::string_view log_prefix, + size_t max_log_size, + size_t num_log_files); + ~FileRotatingLogSink() override; + + FileRotatingLogSink(const FileRotatingLogSink&) = delete; + FileRotatingLogSink& operator=(const FileRotatingLogSink&) = delete; + + // Writes the message to the current file. It will spill over to the next + // file if needed. + void OnLogMessage(const std::string& message) override; + void OnLogMessage(absl::string_view message) override; + void OnLogMessage(const std::string& message, + LoggingSeverity sev, + const char* tag) override; + void OnLogMessage(absl::string_view message, + LoggingSeverity sev, + const char* tag) override; + + // Deletes any existing files in the directory and creates a new log file. + virtual bool Init(); + + // Disables buffering on the underlying stream. + bool DisableBuffering(); + + protected: + explicit FileRotatingLogSink(FileRotatingStream* stream); + + private: + std::unique_ptr<FileRotatingStream> stream_; +}; + +// Log sink that uses a CallSessionFileRotatingStream to write to disk. +// Init() must be called before adding this sink. +class CallSessionFileRotatingLogSink : public FileRotatingLogSink { + public: + CallSessionFileRotatingLogSink(absl::string_view log_dir_path, + size_t max_total_log_size); + ~CallSessionFileRotatingLogSink() override; + + CallSessionFileRotatingLogSink(const CallSessionFileRotatingLogSink&) = + delete; + CallSessionFileRotatingLogSink& operator=( + const CallSessionFileRotatingLogSink&) = delete; +}; + +} // namespace rtc + +#endif // RTC_BASE_LOG_SINKS_H_ diff --git a/third_party/libwebrtc/rtc_base/logging.cc b/third_party/libwebrtc/rtc_base/logging.cc new file mode 100644 index 0000000000..9c2d3b0a39 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/logging.cc @@ -0,0 +1,608 @@ +/* + * 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 "rtc_base/logging.h" + +#include <string.h> + +#if RTC_LOG_ENABLED() + +#if defined(WEBRTC_WIN) +#include <windows.h> +#if _MSC_VER < 1900 +#define snprintf _snprintf +#endif +#undef ERROR // wingdi.h +#endif + +#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) +#include <CoreServices/CoreServices.h> +#elif defined(WEBRTC_ANDROID) +#include <android/log.h> + +// Android has a 1024 limit on log inputs. We use 60 chars as an +// approx for the header/tag portion. +// See android/system/core/liblog/logd_write.c +static const int kMaxLogLineSize = 1024 - 60; +#endif // WEBRTC_MAC && !defined(WEBRTC_IOS) || WEBRTC_ANDROID + +#include <inttypes.h> +#include <stdio.h> +#include <time.h> + +#include <algorithm> +#include <cstdarg> +#include <vector> + +#include "absl/base/attributes.h" +#include "absl/strings/string_view.h" +#include "api/units/timestamp.h" +#include "modules/audio_processing/logging/apm_data_dumper.h" +#include "rtc_base/checks.h" +#include "rtc_base/platform_thread_types.h" +#include "rtc_base/string_encode.h" +#include "rtc_base/string_utils.h" +#include "rtc_base/strings/string_builder.h" +#include "rtc_base/synchronization/mutex.h" +#include "rtc_base/thread_annotations.h" +#include "rtc_base/time_utils.h" + +namespace rtc { + +bool LogMessage::aec_debug_ = false; +std::string LogMessage::aec_filename_base_; + +void LogMessage::set_aec_debug(bool enable) { + aec_debug_ = enable; + webrtc::ApmDataDumper::SetActivated(aec_debug_); +} + +std::string LogMessage::aec_debug_filename() { + return aec_filename_base_; +} + +void LogMessage::set_aec_debug_filename(const char* filename) { + aec_filename_base_ = filename; + webrtc::ApmDataDumper::SetOutputDirectory(aec_filename_base_); +} + +namespace { + +// By default, release builds don't log, debug builds at info level +#if !defined(NDEBUG) +constexpr LoggingSeverity kDefaultLoggingSeverity = LS_INFO; +#else +constexpr LoggingSeverity kDefaultLoggingSeverity = LS_NONE; +#endif + +// Note: `g_min_sev` and `g_dbg_sev` can be changed while running. +LoggingSeverity g_min_sev = kDefaultLoggingSeverity; +LoggingSeverity g_dbg_sev = kDefaultLoggingSeverity; + +// Return the filename portion of the string (that following the last slash). +const char* FilenameFromPath(const char* file) { + const char* end1 = ::strrchr(file, '/'); + const char* end2 = ::strrchr(file, '\\'); + if (!end1 && !end2) + return file; + else + return (end1 > end2) ? end1 + 1 : end2 + 1; +} + +// Global lock for log subsystem, only needed to serialize access to streams_. +webrtc::Mutex& GetLoggingLock() { + static webrtc::Mutex& mutex = *new webrtc::Mutex(); + return mutex; +} + +} // namespace + +std::string LogLineRef::DefaultLogLine() const { + rtc::StringBuilder log_output; + if (timestamp_ != webrtc::Timestamp::MinusInfinity()) { + // TODO(kwiberg): Switch to absl::StrFormat, if binary size is ok. + char timestamp[50]; // Maximum string length of an int64_t is 20. + int len = + snprintf(timestamp, sizeof(timestamp), "[%03" PRId64 ":%03" PRId64 "]", + timestamp_.ms() / 1000, timestamp_.ms() % 1000); + RTC_DCHECK_LT(len, sizeof(timestamp)); + log_output << timestamp; + } + if (thread_id_.has_value()) { + log_output << "[" << *thread_id_ << "] "; + } + if (!filename_.empty()) { +#if defined(WEBRTC_ANDROID) + log_output << "(line " << line_ << "): "; +#else + log_output << "(" << filename_ << ":" << line_ << "): "; +#endif + } + log_output << message_; + return log_output.Release(); +} + +///////////////////////////////////////////////////////////////////////////// +// LogMessage +///////////////////////////////////////////////////////////////////////////// + +bool LogMessage::log_to_stderr_ = false; + +// The list of logging streams currently configured. +// Note: we explicitly do not clean this up, because of the uncertain ordering +// of destructors at program exit. Let the person who sets the stream trigger +// cleanup by setting to null, or let it leak (safe at program exit). +ABSL_CONST_INIT LogSink* LogMessage::streams_ RTC_GUARDED_BY(GetLoggingLock()) = + nullptr; +ABSL_CONST_INIT std::atomic<bool> LogMessage::streams_empty_ = {true}; + +// Boolean options default to false. +ABSL_CONST_INIT bool LogMessage::log_thread_ = false; +ABSL_CONST_INIT bool LogMessage::log_timestamp_ = false; + +LogMessage::LogMessage(const char* file, int line, LoggingSeverity sev) + : LogMessage(file, line, sev, ERRCTX_NONE, 0) {} + +LogMessage::LogMessage(const char* file, + int line, + LoggingSeverity sev, + LogErrorContext err_ctx, + int err) { + log_line_.set_severity(sev); + if (log_timestamp_) { + int64_t log_start_time = LogStartTime(); + // Use SystemTimeMillis so that even if tests use fake clocks, the timestamp + // in log messages represents the real system time. + int64_t time = TimeDiff(SystemTimeMillis(), log_start_time); + // Also ensure WallClockStartTime is initialized, so that it matches + // LogStartTime. + WallClockStartTime(); + log_line_.set_timestamp(webrtc::Timestamp::Millis(time)); + } + + if (log_thread_) { + log_line_.set_thread_id(CurrentThreadId()); + } + + if (file != nullptr) { + log_line_.set_filename(FilenameFromPath(file)); + log_line_.set_line(line); +#if defined(WEBRTC_ANDROID) + log_line_.set_tag(log_line_.filename()); +#endif + } + + if (err_ctx != ERRCTX_NONE) { + char tmp_buf[1024]; + SimpleStringBuilder tmp(tmp_buf); + tmp.AppendFormat("[0x%08X]", err); + switch (err_ctx) { + case ERRCTX_ERRNO: + tmp << " " << strerror(err); + break; +#ifdef WEBRTC_WIN + case ERRCTX_HRESULT: { + char msgbuf[256]; + DWORD flags = + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS; + if (DWORD len = FormatMessageA( + flags, nullptr, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + msgbuf, sizeof(msgbuf) / sizeof(msgbuf[0]), nullptr)) { + while ((len > 0) && + isspace(static_cast<unsigned char>(msgbuf[len - 1]))) { + msgbuf[--len] = 0; + } + tmp << " " << msgbuf; + } + break; + } +#endif // WEBRTC_WIN + default: + break; + } + extra_ = tmp.str(); + } +} + +#if defined(WEBRTC_ANDROID) +LogMessage::LogMessage(const char* file, + int line, + LoggingSeverity sev, + const char* tag) + : LogMessage(file, line, sev, ERRCTX_NONE, /*err=*/0) { + log_line_.set_tag(tag); + print_stream_ << tag << ": "; +} +#endif + +LogMessage::~LogMessage() { + FinishPrintStream(); + + log_line_.set_message(print_stream_.Release()); + + if (log_line_.severity() >= g_dbg_sev) { + OutputToDebug(log_line_); + } + + webrtc::MutexLock lock(&GetLoggingLock()); + for (LogSink* entry = streams_; entry != nullptr; entry = entry->next_) { + if (log_line_.severity() >= entry->min_severity_) { + entry->OnLogMessage(log_line_); + } + } +} + +void LogMessage::AddTag(const char* tag) { +#ifdef WEBRTC_ANDROID + log_line_.set_tag(tag); +#endif +} + +rtc::StringBuilder& LogMessage::stream() { + return print_stream_; +} + +int LogMessage::GetMinLogSeverity() { + return g_min_sev; +} + +LoggingSeverity LogMessage::GetLogToDebug() { + return g_dbg_sev; +} +int64_t LogMessage::LogStartTime() { + static const int64_t g_start = SystemTimeMillis(); + return g_start; +} + +uint32_t LogMessage::WallClockStartTime() { + static const uint32_t g_start_wallclock = time(nullptr); + return g_start_wallclock; +} + +void LogMessage::LogThreads(bool on) { + log_thread_ = on; +} + +void LogMessage::LogTimestamps(bool on) { + log_timestamp_ = on; +} + +void LogMessage::LogToDebug(LoggingSeverity min_sev) { + webrtc::MutexLock lock(&GetLoggingLock()); + g_dbg_sev = min_sev; + UpdateMinLogSeverity(); +} + +void LogMessage::SetLogToStderr(bool log_to_stderr) { + log_to_stderr_ = log_to_stderr; +} + +int LogMessage::GetLogToStream(LogSink* stream) { + webrtc::MutexLock lock(&GetLoggingLock()); + LoggingSeverity sev = LS_NONE; + for (LogSink* entry = streams_; entry != nullptr; entry = entry->next_) { + if (stream == nullptr || stream == entry) { + sev = std::min(sev, entry->min_severity_); + } + } + return sev; +} + +void LogMessage::AddLogToStream(LogSink* stream, LoggingSeverity min_sev) { + webrtc::MutexLock lock(&GetLoggingLock()); + stream->min_severity_ = min_sev; + stream->next_ = streams_; + streams_ = stream; + streams_empty_.store(false, std::memory_order_relaxed); + UpdateMinLogSeverity(); +} + +void LogMessage::RemoveLogToStream(LogSink* stream) { + webrtc::MutexLock lock(&GetLoggingLock()); + for (LogSink** entry = &streams_; *entry != nullptr; + entry = &(*entry)->next_) { + if (*entry == stream) { + *entry = (*entry)->next_; + break; + } + } + streams_empty_.store(streams_ == nullptr, std::memory_order_relaxed); + UpdateMinLogSeverity(); +} + +void LogMessage::ConfigureLogging(absl::string_view params) { + LoggingSeverity current_level = LS_VERBOSE; + LoggingSeverity debug_level = GetLogToDebug(); + + std::vector<std::string> tokens; + tokenize(params, ' ', &tokens); + + for (const std::string& token : tokens) { + if (token.empty()) + continue; + + // Logging features + if (token == "tstamp") { + LogTimestamps(); + } else if (token == "thread") { + LogThreads(); + + // Logging levels + } else if (token == "verbose") { + current_level = LS_VERBOSE; + } else if (token == "info") { + current_level = LS_INFO; + } else if (token == "warning") { + current_level = LS_WARNING; + } else if (token == "error") { + current_level = LS_ERROR; + } else if (token == "none") { + current_level = LS_NONE; + + // Logging targets + } else if (token == "debug") { + debug_level = current_level; + } + } + +#if defined(WEBRTC_WIN) && !defined(WINUWP) + if ((LS_NONE != debug_level) && !::IsDebuggerPresent()) { + // First, attempt to attach to our parent's console... so if you invoke + // from the command line, we'll see the output there. Otherwise, create + // our own console window. + // Note: These methods fail if a console already exists, which is fine. + if (!AttachConsole(ATTACH_PARENT_PROCESS)) + ::AllocConsole(); + } +#endif // defined(WEBRTC_WIN) && !defined(WINUWP) + + LogToDebug(debug_level); +} + +void LogMessage::UpdateMinLogSeverity() + RTC_EXCLUSIVE_LOCKS_REQUIRED(GetLoggingLock()) { + LoggingSeverity min_sev = g_dbg_sev; + for (LogSink* entry = streams_; entry != nullptr; entry = entry->next_) { + min_sev = std::min(min_sev, entry->min_severity_); + } + g_min_sev = min_sev; +} + +void LogMessage::OutputToDebug(const LogLineRef& log_line) { + std::string msg_str = log_line.DefaultLogLine(); + bool log_to_stderr = log_to_stderr_; +#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) && defined(NDEBUG) + // On the Mac, all stderr output goes to the Console log and causes clutter. + // So in opt builds, don't log to stderr unless the user specifically sets + // a preference to do so. + CFStringRef domain = CFBundleGetIdentifier(CFBundleGetMainBundle()); + if (domain != nullptr) { + Boolean exists_and_is_valid; + Boolean should_log = CFPreferencesGetAppBooleanValue( + CFSTR("logToStdErr"), domain, &exists_and_is_valid); + // If the key doesn't exist or is invalid or is false, we will not log to + // stderr. + log_to_stderr = exists_and_is_valid && should_log; + } +#endif // defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) && defined(NDEBUG) + +#if defined(WEBRTC_WIN) + // Always log to the debugger. + // Perhaps stderr should be controlled by a preference, as on Mac? + OutputDebugStringA(msg_str.c_str()); + if (log_to_stderr) { + // This handles dynamically allocated consoles, too. + if (HANDLE error_handle = ::GetStdHandle(STD_ERROR_HANDLE)) { + log_to_stderr = false; + DWORD written = 0; + ::WriteFile(error_handle, msg_str.c_str(), + static_cast<DWORD>(msg_str.size()), &written, 0); + } + } +#endif // WEBRTC_WIN + +#if defined(WEBRTC_ANDROID) + // Android's logging facility uses severity to log messages but we + // need to map libjingle's severity levels to Android ones first. + // Also write to stderr which maybe available to executable started + // from the shell. + int prio; + switch (log_line.severity()) { + case LS_VERBOSE: + prio = ANDROID_LOG_VERBOSE; + break; + case LS_INFO: + prio = ANDROID_LOG_INFO; + break; + case LS_WARNING: + prio = ANDROID_LOG_WARN; + break; + case LS_ERROR: + prio = ANDROID_LOG_ERROR; + break; + default: + prio = ANDROID_LOG_UNKNOWN; + } + + int size = msg_str.size(); + int current_line = 0; + int idx = 0; + const int max_lines = size / kMaxLogLineSize + 1; + if (max_lines == 1) { + __android_log_print(prio, log_line.tag().data(), "%.*s", size, + msg_str.c_str()); + } else { + while (size > 0) { + const int len = std::min(size, kMaxLogLineSize); + // Use the size of the string in the format (msg may have \0 in the + // middle). + __android_log_print(prio, log_line.tag().data(), "[%d/%d] %.*s", + current_line + 1, max_lines, len, + msg_str.c_str() + idx); + idx += len; + size -= len; + ++current_line; + } + } +#endif // WEBRTC_ANDROID + if (log_to_stderr) { + fprintf(stderr, "%s", msg_str.c_str()); + fflush(stderr); + } +} + +// static +bool LogMessage::IsNoop(LoggingSeverity severity) { + // Added MutexLock to fix tsan warnings on accessing g_dbg_sev. (mjf) + // See https://bugs.chromium.org/p/chromium/issues/detail?id=1228729 + webrtc::MutexLock lock(&GetLoggingLock()); + if (severity >= g_dbg_sev || severity >= g_min_sev) + return false; + return streams_empty_.load(std::memory_order_relaxed); +} + +void LogMessage::FinishPrintStream() { + if (!extra_.empty()) + print_stream_ << " : " << extra_; + print_stream_ << "\n"; +} + +namespace webrtc_logging_impl { + +void Log(const LogArgType* fmt, ...) { + va_list args; + va_start(args, fmt); + + LogMetadataErr meta; + const char* tag = nullptr; + switch (*fmt) { + case LogArgType::kLogMetadata: { + meta = {va_arg(args, LogMetadata), ERRCTX_NONE, 0}; + break; + } + case LogArgType::kLogMetadataErr: { + meta = va_arg(args, LogMetadataErr); + break; + } +#ifdef WEBRTC_ANDROID + case LogArgType::kLogMetadataTag: { + const LogMetadataTag tag_meta = va_arg(args, LogMetadataTag); + meta = {{nullptr, 0, tag_meta.severity}, ERRCTX_NONE, 0}; + tag = tag_meta.tag; + break; + } +#endif + default: { + RTC_DCHECK_NOTREACHED(); + va_end(args); + return; + } + } + + LogMessage log_message(meta.meta.File(), meta.meta.Line(), + meta.meta.Severity(), meta.err_ctx, meta.err); + if (tag) { + log_message.AddTag(tag); + } + + for (++fmt; *fmt != LogArgType::kEnd; ++fmt) { + switch (*fmt) { + case LogArgType::kInt: + log_message.stream() << va_arg(args, int); + break; + case LogArgType::kLong: + log_message.stream() << va_arg(args, long); + break; + case LogArgType::kLongLong: + log_message.stream() << va_arg(args, long long); + break; + case LogArgType::kUInt: + log_message.stream() << va_arg(args, unsigned); + break; + case LogArgType::kULong: + log_message.stream() << va_arg(args, unsigned long); + break; + case LogArgType::kULongLong: + log_message.stream() << va_arg(args, unsigned long long); + break; + case LogArgType::kDouble: + log_message.stream() << va_arg(args, double); + break; + case LogArgType::kLongDouble: + log_message.stream() << va_arg(args, long double); + break; + case LogArgType::kCharP: { + const char* s = va_arg(args, const char*); + log_message.stream() << (s ? s : "(null)"); + break; + } + case LogArgType::kStdString: + log_message.stream() << *va_arg(args, const std::string*); + break; + case LogArgType::kStringView: + log_message.stream() << *va_arg(args, const absl::string_view*); + break; + case LogArgType::kVoidP: + log_message.stream() << rtc::ToHex( + reinterpret_cast<uintptr_t>(va_arg(args, const void*))); + break; + default: + RTC_DCHECK_NOTREACHED(); + va_end(args); + return; + } + } + + va_end(args); +} + +} // namespace webrtc_logging_impl +} // namespace rtc +#endif + +namespace rtc { +// Default implementation, override is recomended. +void LogSink::OnLogMessage(const LogLineRef& log_line) { +#if defined(WEBRTC_ANDROID) + OnLogMessage(log_line.DefaultLogLine(), log_line.severity(), + log_line.tag().data()); +#else + OnLogMessage(log_line.DefaultLogLine(), log_line.severity()); +#endif +} + +// Inefficient default implementation, override is recommended. +void LogSink::OnLogMessage(const std::string& msg, + LoggingSeverity severity, + const char* tag) { + OnLogMessage(tag + (": " + msg), severity); +} + +void LogSink::OnLogMessage(const std::string& msg, + LoggingSeverity /* severity */) { + OnLogMessage(msg); +} + +// Inefficient default implementation, override is recommended. +void LogSink::OnLogMessage(absl::string_view msg, + LoggingSeverity severity, + const char* tag) { + OnLogMessage(tag + (": " + std::string(msg)), severity); +} + +void LogSink::OnLogMessage(absl::string_view msg, + LoggingSeverity /* severity */) { + OnLogMessage(msg); +} + +void LogSink::OnLogMessage(absl::string_view msg) { + OnLogMessage(std::string(msg)); +} +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/logging.h b/third_party/libwebrtc/rtc_base/logging.h new file mode 100644 index 0000000000..a3733d7543 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/logging.h @@ -0,0 +1,780 @@ +/* + * 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. + */ + +// RTC_LOG(...) an ostream target that can be used to send formatted +// output to a variety of logging targets, such as debugger console, stderr, +// or any LogSink. +// The severity level passed as the first argument to the logging +// functions is used as a filter, to limit the verbosity of the logging. +// Static members of LogMessage documented below are used to control the +// verbosity and target of the output. +// There are several variations on the RTC_LOG macro which facilitate logging +// of common error conditions, detailed below. + +// RTC_LOG(sev) logs the given stream at severity "sev", which must be a +// compile-time constant of the LoggingSeverity type, without the namespace +// prefix. +// RTC_LOG_IF(sev, condition) logs the given stream at severitye "sev" if +// "condition" is true. +// RTC_LOG_V(sev) Like RTC_LOG(), but sev is a run-time variable of the +// LoggingSeverity type (basically, it just doesn't prepend the namespace). +// RTC_LOG_F(sev) Like RTC_LOG(), but includes the name of the current function. +// RTC_LOG_IF_F(sev, condition), Like RTC_LOG_IF(), but includes the name of +// the current function. +// RTC_LOG_T(sev) Like RTC_LOG(), but includes the this pointer. +// RTC_LOG_T_F(sev) Like RTC_LOG_F(), but includes the this pointer. +// RTC_LOG_GLE(sev [, mod]) attempt to add a string description of the +// HRESULT returned by GetLastError. +// RTC_LOG_ERRNO(sev) attempts to add a string description of an errno-derived +// error. errno and associated facilities exist on both Windows and POSIX, +// but on Windows they only apply to the C/C++ runtime. +// RTC_LOG_ERR(sev) is an alias for the platform's normal error system, i.e. +// _GLE on Windows and _ERRNO on POSIX. +// (The above three also all have _EX versions that let you specify the error +// code, rather than using the last one.) +// RTC_LOG_E(sev, ctx, err, ...) logs a detailed error interpreted using the +// specified context. +// RTC_LOG_CHECK_LEVEL(sev) (and RTC_LOG_CHECK_LEVEL_V(sev)) can be used as a +// test before performing expensive or sensitive operations whose sole +// purpose is to output logging data at the desired level. + +#ifndef RTC_BASE_LOGGING_H_ +#define RTC_BASE_LOGGING_H_ + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wvarargs" + +#if defined(__clang__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wclass-varargs" +#endif + +#include <errno.h> + +#include <atomic> +#include <sstream> // no-presubmit-check TODO(webrtc:8982) +#include <string> +#include <type_traits> +#include <utility> + +#include "absl/base/attributes.h" +#include "absl/meta/type_traits.h" +#include "absl/strings/string_view.h" +#include "absl/types/optional.h" +#include "api/units/timestamp.h" +#include "rtc_base/platform_thread_types.h" +#include "rtc_base/strings/string_builder.h" +#include "rtc_base/system/inline.h" + +#if !defined(NDEBUG) || defined(DLOG_ALWAYS_ON) +#define RTC_DLOG_IS_ON 1 +#else +#define RTC_DLOG_IS_ON 0 +#endif + +#if defined(RTC_DISABLE_LOGGING) +#define RTC_LOG_ENABLED() 0 +#else +#define RTC_LOG_ENABLED() 1 +#endif + +namespace rtc { + +////////////////////////////////////////////////////////////////////// +// The meanings of the levels are: +// LS_VERBOSE: This level is for data which we do not want to appear in the +// normal debug log, but should appear in diagnostic logs. +// LS_INFO: Chatty level used in debugging for all sorts of things, the default +// in debug builds. +// LS_WARNING: Something that may warrant investigation. +// LS_ERROR: Something that should not have occurred. +// LS_NONE: Don't log. +enum LoggingSeverity { + LS_VERBOSE, + LS_INFO, + LS_WARNING, + LS_ERROR, + LS_NONE, +}; + +// LogErrorContext assists in interpreting the meaning of an error value. +enum LogErrorContext { + ERRCTX_NONE, + ERRCTX_ERRNO, // System-local errno + ERRCTX_HRESULT, // Windows HRESULT + + // Abbreviations for LOG_E macro + ERRCTX_EN = ERRCTX_ERRNO, // LOG_E(sev, EN, x) + ERRCTX_HR = ERRCTX_HRESULT, // LOG_E(sev, HR, x) +}; + +class LogMessage; + +// LogLineRef encapsulates all the information required to generate a log line. +// It is used both internally to LogMessage but also as a parameter to +// LogSink::OnLogMessage, allowing custom LogSinks to format the log in +// the most flexible way. +class LogLineRef { + public: + absl::string_view message() const { return message_; } + absl::string_view filename() const { return filename_; } + int line() const { return line_; } + absl::optional<PlatformThreadId> thread_id() const { return thread_id_; } + webrtc::Timestamp timestamp() const { return timestamp_; } + absl::string_view tag() const { return tag_; } + LoggingSeverity severity() const { return severity_; } + +#if RTC_LOG_ENABLED() + std::string DefaultLogLine() const; +#else + std::string DefaultLogLine() const { return ""; } +#endif + + private: + friend class LogMessage; + void set_message(std::string message) { message_ = std::move(message); } + void set_filename(absl::string_view filename) { filename_ = filename; } + void set_line(int line) { line_ = line; } + void set_thread_id(absl::optional<PlatformThreadId> thread_id) { + thread_id_ = thread_id; + } + void set_timestamp(webrtc::Timestamp timestamp) { timestamp_ = timestamp; } + void set_tag(absl::string_view tag) { tag_ = tag; } + void set_severity(LoggingSeverity severity) { severity_ = severity; } + + std::string message_; + absl::string_view filename_; + int line_ = 0; + absl::optional<PlatformThreadId> thread_id_; + webrtc::Timestamp timestamp_ = webrtc::Timestamp::MinusInfinity(); + // The default Android debug output tag. + absl::string_view tag_ = "libjingle"; + // The severity level of this message + LoggingSeverity severity_; +}; + +// Virtual sink interface that can receive log messages. +class LogSink { + public: + LogSink() {} + virtual ~LogSink() {} + virtual void OnLogMessage(const std::string& msg, + LoggingSeverity severity, + const char* tag); + virtual void OnLogMessage(const std::string& message, + LoggingSeverity severity); + virtual void OnLogMessage(const std::string& message) = 0; + + virtual void OnLogMessage(absl::string_view msg, + LoggingSeverity severity, + const char* tag); + virtual void OnLogMessage(absl::string_view message, + LoggingSeverity severity); + virtual void OnLogMessage(absl::string_view message); + virtual void OnLogMessage(const LogLineRef& line); + + private: + friend class ::rtc::LogMessage; +#if RTC_LOG_ENABLED() + // Members for LogMessage class to keep linked list of the registered sinks. + LogSink* next_ = nullptr; + LoggingSeverity min_severity_; +#endif +}; + +namespace webrtc_logging_impl { + +class LogMetadata { + public: + LogMetadata(const char* file, int line, LoggingSeverity severity) + : file_(file), + line_and_sev_(static_cast<uint32_t>(line) << 3 | severity) {} + LogMetadata() = default; + + const char* File() const { return file_; } + int Line() const { return line_and_sev_ >> 3; } + LoggingSeverity Severity() const { + return static_cast<LoggingSeverity>(line_and_sev_ & 0x7); + } + + private: + const char* file_; + + // Line number and severity, the former in the most significant 29 bits, the + // latter in the least significant 3 bits. (This is an optimization; since + // both numbers are usually compile-time constants, this way we can load them + // both with a single instruction.) + uint32_t line_and_sev_; +}; +static_assert(std::is_trivial<LogMetadata>::value, ""); + +struct LogMetadataErr { + LogMetadata meta; + LogErrorContext err_ctx; + int err; +}; + +#ifdef WEBRTC_ANDROID +struct LogMetadataTag { + LoggingSeverity severity; + const char* tag; +}; +#endif + +enum class LogArgType : int8_t { + kEnd = 0, + kInt, + kLong, + kLongLong, + kUInt, + kULong, + kULongLong, + kDouble, + kLongDouble, + kCharP, + kStdString, + kStringView, + kVoidP, + kLogMetadata, + kLogMetadataErr, +#ifdef WEBRTC_ANDROID + kLogMetadataTag, +#endif +}; + +// Wrapper for log arguments. Only ever make values of this type with the +// MakeVal() functions. +template <LogArgType N, typename T> +struct Val { + static constexpr LogArgType Type() { return N; } + T GetVal() const { return val; } + T val; +}; + +// Case for when we need to construct a temp string and then print that. +// (We can't use Val<CheckArgType::kStdString, const std::string*> +// because we need somewhere to store the temp string.) +struct ToStringVal { + static constexpr LogArgType Type() { return LogArgType::kStdString; } + const std::string* GetVal() const { return &val; } + std::string val; +}; + +inline Val<LogArgType::kInt, int> MakeVal(int x) { + return {x}; +} +inline Val<LogArgType::kLong, long> MakeVal(long x) { + return {x}; +} +inline Val<LogArgType::kLongLong, long long> MakeVal(long long x) { + return {x}; +} +inline Val<LogArgType::kUInt, unsigned int> MakeVal(unsigned int x) { + return {x}; +} +inline Val<LogArgType::kULong, unsigned long> MakeVal(unsigned long x) { + return {x}; +} +inline Val<LogArgType::kULongLong, unsigned long long> MakeVal( + unsigned long long x) { + return {x}; +} + +inline Val<LogArgType::kDouble, double> MakeVal(double x) { + return {x}; +} +inline Val<LogArgType::kLongDouble, long double> MakeVal(long double x) { + return {x}; +} + +inline Val<LogArgType::kCharP, const char*> MakeVal(const char* x) { + return {x}; +} +inline Val<LogArgType::kStdString, const std::string*> MakeVal( + const std::string& x) { + return {&x}; +} +inline Val<LogArgType::kStringView, const absl::string_view*> MakeVal( + const absl::string_view& x) { + return {&x}; +} + +inline Val<LogArgType::kVoidP, const void*> MakeVal(const void* x) { + return {x}; +} + +inline Val<LogArgType::kLogMetadata, LogMetadata> MakeVal( + const LogMetadata& x) { + return {x}; +} +inline Val<LogArgType::kLogMetadataErr, LogMetadataErr> MakeVal( + const LogMetadataErr& x) { + return {x}; +} + +// The enum class types are not implicitly convertible to arithmetic types. +template <typename T, + absl::enable_if_t<std::is_enum<T>::value && + !std::is_arithmetic<T>::value>* = nullptr> +inline decltype(MakeVal(std::declval<absl::underlying_type_t<T>>())) MakeVal( + T x) { + return {static_cast<absl::underlying_type_t<T>>(x)}; +} + +#ifdef WEBRTC_ANDROID +inline Val<LogArgType::kLogMetadataTag, LogMetadataTag> MakeVal( + const LogMetadataTag& x) { + return {x}; +} +#endif + +template <typename T, class = void> +struct has_to_log_string : std::false_type {}; +template <typename T> +struct has_to_log_string<T, + absl::enable_if_t<std::is_convertible< + decltype(ToLogString(std::declval<T>())), + std::string>::value>> : std::true_type {}; + +template <typename T, absl::enable_if_t<has_to_log_string<T>::value>* = nullptr> +ToStringVal MakeVal(const T& x) { + return {ToLogString(x)}; +} + +// Handle arbitrary types other than the above by falling back to stringstream. +// TODO(bugs.webrtc.org/9278): Get rid of this overload when callers don't need +// it anymore. No in-tree caller does, but some external callers still do. +template < + typename T, + typename T1 = absl::decay_t<T>, + absl::enable_if_t<std::is_class<T1>::value && + !std::is_same<T1, std::string>::value && + !std::is_same<T1, LogMetadata>::value && + !has_to_log_string<T1>::value && +#ifdef WEBRTC_ANDROID + !std::is_same<T1, LogMetadataTag>::value && +#endif + !std::is_same<T1, LogMetadataErr>::value>* = nullptr> +ToStringVal MakeVal(const T& x) { + std::ostringstream os; // no-presubmit-check TODO(webrtc:8982) + os << x; + return {os.str()}; +} + +#if RTC_LOG_ENABLED() +void Log(const LogArgType* fmt, ...); +#else +inline void Log(const LogArgType* fmt, ...) { + // Do nothing, shouldn't be invoked +} +#endif + +// Ephemeral type that represents the result of the logging << operator. +template <typename... Ts> +class LogStreamer; + +// Base case: Before the first << argument. +template <> +class LogStreamer<> final { + public: + template <typename U, + typename V = decltype(MakeVal(std::declval<U>())), + absl::enable_if_t<std::is_arithmetic<U>::value || + std::is_enum<U>::value>* = nullptr> + RTC_FORCE_INLINE LogStreamer<V> operator<<(U arg) const { + return LogStreamer<V>(MakeVal(arg), this); + } + + template <typename U, + typename V = decltype(MakeVal(std::declval<U>())), + absl::enable_if_t<!std::is_arithmetic<U>::value && + !std::is_enum<U>::value>* = nullptr> + RTC_FORCE_INLINE LogStreamer<V> operator<<(const U& arg) const { + return LogStreamer<V>(MakeVal(arg), this); + } + + template <typename... Us> + RTC_FORCE_INLINE static void Call(const Us&... args) { + static constexpr LogArgType t[] = {Us::Type()..., LogArgType::kEnd}; + Log(t, args.GetVal()...); + } +}; + +// Inductive case: We've already seen at least one << argument. The most recent +// one had type `T`, and the earlier ones had types `Ts`. +template <typename T, typename... Ts> +class LogStreamer<T, Ts...> final { + public: + RTC_FORCE_INLINE LogStreamer(T arg, const LogStreamer<Ts...>* prior) + : arg_(arg), prior_(prior) {} + + template <typename U, + typename V = decltype(MakeVal(std::declval<U>())), + absl::enable_if_t<std::is_arithmetic<U>::value || + std::is_enum<U>::value>* = nullptr> + RTC_FORCE_INLINE LogStreamer<V, T, Ts...> operator<<(U arg) const { + return LogStreamer<V, T, Ts...>(MakeVal(arg), this); + } + + template <typename U, + typename V = decltype(MakeVal(std::declval<U>())), + absl::enable_if_t<!std::is_arithmetic<U>::value && + !std::is_enum<U>::value>* = nullptr> + RTC_FORCE_INLINE LogStreamer<V, T, Ts...> operator<<(const U& arg) const { + return LogStreamer<V, T, Ts...>(MakeVal(arg), this); + } + + template <typename... Us> + RTC_FORCE_INLINE void Call(const Us&... args) const { + prior_->Call(arg_, args...); + } + + private: + // The most recent argument. + T arg_; + + // Earlier arguments. + const LogStreamer<Ts...>* prior_; +}; + +class LogCall final { + public: + // This can be any binary operator with precedence lower than <<. + // We return bool here to be able properly remove logging if + // RTC_DISABLE_LOGGING is defined. + template <typename... Ts> + RTC_FORCE_INLINE bool operator&(const LogStreamer<Ts...>& streamer) { + streamer.Call(); + return true; + } +}; + +// This class is used to explicitly ignore values in the conditional +// logging macros. This avoids compiler warnings like "value computed +// is not used" and "statement has no effect". +class LogMessageVoidify { + public: + LogMessageVoidify() = default; + // This has to be an operator with a precedence lower than << but + // higher than ?: + template <typename... Ts> + void operator&(LogStreamer<Ts...>&& streamer) {} +}; + +} // namespace webrtc_logging_impl + +// Direct use of this class is deprecated; please use the logging macros +// instead. +// TODO(bugs.webrtc.org/9278): Move this class to an unnamed namespace in the +// .cc file. +class LogMessage { + public: + // Same as the above, but using a compile-time constant for the logging + // severity. This saves space at the call site, since passing an empty struct + // is generally the same as not passing an argument at all. + template <LoggingSeverity S> + RTC_NO_INLINE LogMessage(const char* file, + int line, + std::integral_constant<LoggingSeverity, S>) + : LogMessage(file, line, S) {} + +#if RTC_LOG_ENABLED() + LogMessage(const char* file, int line, LoggingSeverity sev); + LogMessage(const char* file, + int line, + LoggingSeverity sev, + LogErrorContext err_ctx, + int err); +#if defined(WEBRTC_ANDROID) + LogMessage(const char* file, int line, LoggingSeverity sev, const char* tag); +#endif + ~LogMessage(); + + LogMessage(const LogMessage&) = delete; + LogMessage& operator=(const LogMessage&) = delete; + + void AddTag(const char* tag); + rtc::StringBuilder& stream(); + // Returns the time at which this function was called for the first time. + // The time will be used as the logging start time. + // If this is not called externally, the LogMessage ctor also calls it, in + // which case the logging start time will be the time of the first LogMessage + // instance is created. + static int64_t LogStartTime(); + // Returns the wall clock equivalent of `LogStartTime`, in seconds from the + // epoch. + static uint32_t WallClockStartTime(); + // LogThreads: Display the thread identifier of the current thread + static void LogThreads(bool on = true); + // LogTimestamps: Display the elapsed time of the program + static void LogTimestamps(bool on = true); + // These are the available logging channels + // Debug: Debug console on Windows, otherwise stderr + static void LogToDebug(LoggingSeverity min_sev); + static LoggingSeverity GetLogToDebug(); + // Sets whether logs will be directed to stderr in debug mode. + static void SetLogToStderr(bool log_to_stderr); + // Stream: Any non-blocking stream interface. + // Installs the `stream` to collect logs with severtiy `min_sev` or higher. + // `stream` must live until deinstalled by RemoveLogToStream. + // If `stream` is the first stream added to the system, we might miss some + // early concurrent log statement happening from another thread happening near + // this instant. + static void AddLogToStream(LogSink* stream, LoggingSeverity min_sev); + // Removes the specified stream, without destroying it. When the method + // has completed, it's guaranteed that `stream` will receive no more logging + // calls. + static void RemoveLogToStream(LogSink* stream); + // Returns the severity for the specified stream, of if none is specified, + // the minimum stream severity. + static int GetLogToStream(LogSink* stream = nullptr); + // Testing against MinLogSeverity allows code to avoid potentially expensive + // logging operations by pre-checking the logging level. + static int GetMinLogSeverity(); + // Parses the provided parameter stream to configure the options above. + // Useful for configuring logging from the command line. + static void ConfigureLogging(absl::string_view params); + // Checks the current global debug severity and if the `streams_` collection + // is empty. If `severity` is smaller than the global severity and if the + // `streams_` collection is empty, the LogMessage will be considered a noop + // LogMessage. + static bool IsNoop(LoggingSeverity severity); + // Version of IsNoop that uses fewer instructions at the call site, since the + // caller doesn't have to pass an argument. + template <LoggingSeverity S> + RTC_NO_INLINE static bool IsNoop() { + return IsNoop(S); + } +#else + // Next methods do nothing; no one will call these functions. + LogMessage(const char* file, int line, LoggingSeverity sev) {} + LogMessage(const char* file, + int line, + LoggingSeverity sev, + LogErrorContext err_ctx, + int err) {} +#if defined(WEBRTC_ANDROID) + LogMessage(const char* file, int line, LoggingSeverity sev, const char* tag) { + } +#endif + ~LogMessage() = default; + + inline void AddTag(const char* tag) {} + inline rtc::StringBuilder& stream() { return print_stream_; } + inline static int64_t LogStartTime() { return 0; } + inline static uint32_t WallClockStartTime() { return 0; } + inline static void LogThreads(bool on = true) {} + inline static void LogTimestamps(bool on = true) {} + inline static void LogToDebug(LoggingSeverity min_sev) {} + inline static LoggingSeverity GetLogToDebug() { + return LoggingSeverity::LS_INFO; + } + inline static void SetLogToStderr(bool log_to_stderr) {} + inline static void AddLogToStream(LogSink* stream, LoggingSeverity min_sev) {} + inline static void RemoveLogToStream(LogSink* stream) {} + inline static int GetLogToStream(LogSink* stream = nullptr) { return 0; } + inline static int GetMinLogSeverity() { return 0; } + inline static void ConfigureLogging(absl::string_view params) {} + static constexpr bool IsNoop(LoggingSeverity severity) { return true; } + template <LoggingSeverity S> + static constexpr bool IsNoop() { + return IsNoop(S); + } +#endif // RTC_LOG_ENABLED() + + // Enable dumping of AEC inputs and outputs. Can be changed in mid-call + static void set_aec_debug(bool enable); + static bool aec_debug() { return aec_debug_; } + static std::string aec_debug_filename(); + static void set_aec_debug_filename(const char* filename); + + private: + friend class LogMessageForTesting; + +#if RTC_LOG_ENABLED() + // Updates min_sev_ appropriately when debug sinks change. + static void UpdateMinLogSeverity(); + + // This writes out the actual log messages. + static void OutputToDebug(const LogLineRef& log_line_ref); + + // Called from the dtor (or from a test) to append optional extra error + // information to the log stream and a newline character. + void FinishPrintStream(); + + LogLineRef log_line_; + + // String data generated in the constructor, that should be appended to + // the message before output. + std::string extra_; + + // The output streams and their associated severities + static LogSink* streams_; + + // Holds true with high probability if `streams_` is empty, false with high + // probability otherwise. Operated on with std::memory_order_relaxed because + // it's ok to lose or log some additional statements near the instant streams + // are added/removed. + static std::atomic<bool> streams_empty_; + + // Flags for formatting options and their potential values. + static bool log_thread_; + static bool log_timestamp_; + + // Determines if logs will be directed to stderr in debug mode. + static bool log_to_stderr_; +#else // RTC_LOG_ENABLED() + // Next methods do nothing; no one will call these functions. + inline static void UpdateMinLogSeverity() {} +#if defined(WEBRTC_ANDROID) + inline static void OutputToDebug(absl::string_view filename, + int line, + absl::string_view msg, + LoggingSeverity severity, + const char* tag) {} +#else + inline static void OutputToDebug(absl::string_view filename, + int line, + absl::string_view msg, + LoggingSeverity severity) {} +#endif // defined(WEBRTC_ANDROID) + inline void FinishPrintStream() {} +#endif // RTC_LOG_ENABLED() + + // The stringbuilder that buffers the formatted message before output + rtc::StringBuilder print_stream_; + + static bool aec_debug_; + static std::string aec_filename_base_; +}; + +////////////////////////////////////////////////////////////////////// +// Logging Helpers +////////////////////////////////////////////////////////////////////// + +#define RTC_LOG_FILE_LINE(sev, file, line) \ + ::rtc::webrtc_logging_impl::LogCall() & \ + ::rtc::webrtc_logging_impl::LogStreamer<>() \ + << ::rtc::webrtc_logging_impl::LogMetadata(file, line, sev) + +#define RTC_LOG(sev) \ + !::rtc::LogMessage::IsNoop<::rtc::sev>() && \ + RTC_LOG_FILE_LINE(::rtc::sev, __FILE__, __LINE__) + +#define RTC_LOG_IF(sev, condition) \ + !::rtc::LogMessage::IsNoop<::rtc::sev>() && (condition) && \ + RTC_LOG_FILE_LINE(::rtc::sev, __FILE__, __LINE__) + +// The _V version is for when a variable is passed in. +#define RTC_LOG_V(sev) \ + !::rtc::LogMessage::IsNoop(sev) && RTC_LOG_FILE_LINE(sev, __FILE__, __LINE__) + +// The _F version prefixes the message with the current function name. +#if (defined(__GNUC__) && !defined(NDEBUG)) || defined(WANT_PRETTY_LOG_F) +#define RTC_LOG_F(sev) RTC_LOG(sev) << __PRETTY_FUNCTION__ << ": " +#define RTC_LOG_IF_F(sev, condition) \ + RTC_LOG_IF(sev, condition) << __PRETTY_FUNCTION__ << ": " +#define RTC_LOG_T_F(sev) \ + RTC_LOG(sev) << this << ": " << __PRETTY_FUNCTION__ << ": " +#else +#define RTC_LOG_F(sev) RTC_LOG(sev) << __FUNCTION__ << ": " +#define RTC_LOG_IF_F(sev, condition) \ + RTC_LOG_IF(sev, condition) << __FUNCTION__ << ": " +#define RTC_LOG_T_F(sev) RTC_LOG(sev) << this << ": " << __FUNCTION__ << ": " +#endif + +#define RTC_LOG_CHECK_LEVEL(sev) ::rtc::LogCheckLevel(::rtc::sev) +#define RTC_LOG_CHECK_LEVEL_V(sev) ::rtc::LogCheckLevel(sev) + +inline bool LogCheckLevel(LoggingSeverity sev) { + return (LogMessage::GetMinLogSeverity() <= sev); +} + +#define RTC_LOG_E(sev, ctx, err) \ + !::rtc::LogMessage::IsNoop<::rtc::sev>() && \ + ::rtc::webrtc_logging_impl::LogCall() & \ + ::rtc::webrtc_logging_impl::LogStreamer<>() \ + << ::rtc::webrtc_logging_impl::LogMetadataErr { \ + {__FILE__, __LINE__, ::rtc::sev}, ::rtc::ERRCTX_##ctx, (err) \ + } + +#define RTC_LOG_T(sev) RTC_LOG(sev) << this << ": " + +#define RTC_LOG_ERRNO_EX(sev, err) RTC_LOG_E(sev, ERRNO, err) +#define RTC_LOG_ERRNO(sev) RTC_LOG_ERRNO_EX(sev, errno) + +#if defined(WEBRTC_WIN) +#define RTC_LOG_GLE_EX(sev, err) RTC_LOG_E(sev, HRESULT, err) +#define RTC_LOG_GLE(sev) RTC_LOG_GLE_EX(sev, static_cast<int>(GetLastError())) +#define RTC_LOG_ERR_EX(sev, err) RTC_LOG_GLE_EX(sev, err) +#define RTC_LOG_ERR(sev) RTC_LOG_GLE(sev) +#elif defined(__native_client__) && __native_client__ +#define RTC_LOG_ERR_EX(sev, err) RTC_LOG(sev) +#define RTC_LOG_ERR(sev) RTC_LOG(sev) +#elif defined(WEBRTC_POSIX) +#define RTC_LOG_ERR_EX(sev, err) RTC_LOG_ERRNO_EX(sev, err) +#define RTC_LOG_ERR(sev) RTC_LOG_ERRNO(sev) +#endif // WEBRTC_WIN + +#ifdef WEBRTC_ANDROID + +namespace webrtc_logging_impl { +// TODO(kwiberg): Replace these with absl::string_view. +inline const char* AdaptString(const char* str) { + return str; +} +inline const char* AdaptString(const std::string& str) { + return str.c_str(); +} +} // namespace webrtc_logging_impl + +#define RTC_LOG_TAG(sev, tag) \ + !::rtc::LogMessage::IsNoop(sev) && \ + ::rtc::webrtc_logging_impl::LogCall() & \ + ::rtc::webrtc_logging_impl::LogStreamer<>() \ + << ::rtc::webrtc_logging_impl::LogMetadataTag { \ + sev, ::rtc::webrtc_logging_impl::AdaptString(tag) \ + } + +#else + +// DEPRECATED. This macro is only intended for Android. +#define RTC_LOG_TAG(sev, tag) RTC_LOG_V(sev) + +#endif + +// The RTC_DLOG macros are equivalent to their RTC_LOG counterparts except that +// they only generate code in debug builds. +#if RTC_DLOG_IS_ON +#define RTC_DLOG(sev) RTC_LOG(sev) +#define RTC_DLOG_IF(sev, condition) RTC_LOG_IF(sev, condition) +#define RTC_DLOG_V(sev) RTC_LOG_V(sev) +#define RTC_DLOG_F(sev) RTC_LOG_F(sev) +#define RTC_DLOG_IF_F(sev, condition) RTC_LOG_IF_F(sev, condition) +#else +#define RTC_DLOG_EAT_STREAM_PARAMS() \ + while (false) \ + ::rtc::webrtc_logging_impl::LogMessageVoidify() & \ + (::rtc::webrtc_logging_impl::LogStreamer<>()) +#define RTC_DLOG(sev) RTC_DLOG_EAT_STREAM_PARAMS() +#define RTC_DLOG_IF(sev, condition) RTC_DLOG_EAT_STREAM_PARAMS() +#define RTC_DLOG_V(sev) RTC_DLOG_EAT_STREAM_PARAMS() +#define RTC_DLOG_F(sev) RTC_DLOG_EAT_STREAM_PARAMS() +#define RTC_DLOG_IF_F(sev, condition) RTC_DLOG_EAT_STREAM_PARAMS() +#endif + +} // namespace rtc + +#pragma GCC diagnostic pop +#if defined(__clang__) +# pragma clang diagnostic pop +#endif + +#endif // RTC_BASE_LOGGING_H_ diff --git a/third_party/libwebrtc/rtc_base/logging_gn/moz.build b/third_party/libwebrtc/rtc_base/logging_gn/moz.build new file mode 100644 index 0000000000..02f74cddfa --- /dev/null +++ b/third_party/libwebrtc/rtc_base/logging_gn/moz.build @@ -0,0 +1,233 @@ +# 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_APM_DEBUG_DUMP"] = "1" +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/rtc_base/logging.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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("logging_gn") diff --git a/third_party/libwebrtc/rtc_base/logging_unittest.cc b/third_party/libwebrtc/rtc_base/logging_unittest.cc new file mode 100644 index 0000000000..b05907e74a --- /dev/null +++ b/third_party/libwebrtc/rtc_base/logging_unittest.cc @@ -0,0 +1,386 @@ +/* + * 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 "rtc_base/logging.h" + +#if RTC_LOG_ENABLED() + +#include <string.h> + +#include <algorithm> + +#include "absl/strings/string_view.h" +#include "rtc_base/arraysize.h" +#include "rtc_base/checks.h" +#include "rtc_base/event.h" +#include "rtc_base/platform_thread.h" +#include "rtc_base/time_utils.h" +#include "test/gmock.h" +#include "test/gtest.h" + +namespace rtc { + +namespace { + +#if defined(WEBRTC_WIN) +constexpr char kFakeFilePath[] = "some\\path\\myfile.cc"; +#else +constexpr char kFakeFilePath[] = "some/path/myfile.cc"; +#endif + +} // namespace + +class LogSinkImpl : public LogSink { + public: + explicit LogSinkImpl(std::string* log_data) : log_data_(log_data) {} + + template <typename P> + explicit LogSinkImpl(P* p) {} + + private: + void OnLogMessage(const std::string& message) override { + OnLogMessage(absl::string_view(message)); + } + void OnLogMessage(absl::string_view message) override { + log_data_->append(message.begin(), message.end()); + } + std::string* const log_data_; +}; + +class LogMessageForTesting : public LogMessage { + public: + LogMessageForTesting(const char* file, + int line, + LoggingSeverity sev, + LogErrorContext err_ctx = ERRCTX_NONE, + int err = 0) + : LogMessage(file, line, sev, err_ctx, err) {} + + const std::string& get_extra() const { return extra_; } +#if defined(WEBRTC_ANDROID) + const char* get_tag() const { return log_line_.tag().data(); } +#endif + + // Returns the contents of the internal log stream. + // Note that parts of the stream won't (as is) be available until *after* the + // dtor of the parent class has run. So, as is, this only represents a + // partially built stream. + std::string GetPrintStream() { + RTC_DCHECK(!is_finished_); + is_finished_ = true; + FinishPrintStream(); + return print_stream_.Release(); + } + + private: + bool is_finished_ = false; +}; + +// Test basic logging operation. We should get the INFO log but not the VERBOSE. +// We should restore the correct global state at the end. +TEST(LogTest, SingleStream) { + int sev = LogMessage::GetLogToStream(nullptr); + + std::string str; + LogSinkImpl stream(&str); + LogMessage::AddLogToStream(&stream, LS_INFO); + EXPECT_EQ(LS_INFO, LogMessage::GetLogToStream(&stream)); + + RTC_LOG(LS_INFO) << "INFO"; + RTC_LOG(LS_VERBOSE) << "VERBOSE"; + EXPECT_NE(std::string::npos, str.find("INFO")); + EXPECT_EQ(std::string::npos, str.find("VERBOSE")); + + int i = 1; + long l = 2l; + long long ll = 3ll; + + unsigned int u = 4u; + unsigned long ul = 5ul; + unsigned long long ull = 6ull; + + std::string s1 = "char*"; + std::string s2 = "std::string"; + std::string s3 = "absl::stringview"; + const char* null_string = nullptr; + void* p = reinterpret_cast<void*>(0xabcd); + + // Log all suported types(except doubles/floats) as a sanity-check. + RTC_LOG(LS_INFO) << "|" << i << "|" << l << "|" << ll << "|" << u << "|" << ul + << "|" << ull << "|" << s1.c_str() << "|" << s2 << "|" + << absl::string_view(s3) << "|" << p << "|" << null_string + << "|"; + + // Signed integers + EXPECT_NE(std::string::npos, str.find("|1|")); + EXPECT_NE(std::string::npos, str.find("|2|")); + EXPECT_NE(std::string::npos, str.find("|3|")); + + // Unsigned integers + EXPECT_NE(std::string::npos, str.find("|4|")); + EXPECT_NE(std::string::npos, str.find("|5|")); + EXPECT_NE(std::string::npos, str.find("|6|")); + + // Strings + EXPECT_NE(std::string::npos, str.find("|char*|")); + EXPECT_NE(std::string::npos, str.find("|std::string|")); + EXPECT_NE(std::string::npos, str.find("|absl::stringview|")); + + // void* + EXPECT_NE(std::string::npos, str.find("|abcd|")); + + // null char* + EXPECT_NE(std::string::npos, str.find("|(null)|")); + + LogMessage::RemoveLogToStream(&stream); + EXPECT_EQ(LS_NONE, LogMessage::GetLogToStream(&stream)); + EXPECT_EQ(sev, LogMessage::GetLogToStream(nullptr)); +} + +TEST(LogTest, LogIfLogIfConditionIsTrue) { + std::string str; + LogSinkImpl stream(&str); + LogMessage::AddLogToStream(&stream, LS_INFO); + + RTC_LOG_IF(LS_INFO, true) << "Hello"; + EXPECT_NE(std::string::npos, str.find("Hello")); + + LogMessage::RemoveLogToStream(&stream); +} + +TEST(LogTest, LogIfDontLogIfConditionIsFalse) { + std::string str; + LogSinkImpl stream(&str); + LogMessage::AddLogToStream(&stream, LS_INFO); + + RTC_LOG_IF(LS_INFO, false) << "Hello"; + EXPECT_EQ(std::string::npos, str.find("Hello")); + + LogMessage::RemoveLogToStream(&stream); +} + +TEST(LogTest, LogIfFLogIfConditionIsTrue) { + std::string str; + LogSinkImpl stream(&str); + LogMessage::AddLogToStream(&stream, LS_INFO); + + RTC_LOG_IF_F(LS_INFO, true) << "Hello"; + EXPECT_NE(std::string::npos, str.find(__FUNCTION__)); + EXPECT_NE(std::string::npos, str.find("Hello")); + + LogMessage::RemoveLogToStream(&stream); +} + +TEST(LogTest, LogIfFDontLogIfConditionIsFalse) { + std::string str; + LogSinkImpl stream(&str); + LogMessage::AddLogToStream(&stream, LS_INFO); + + RTC_LOG_IF_F(LS_INFO, false) << "Not"; + EXPECT_EQ(std::string::npos, str.find(__FUNCTION__)); + EXPECT_EQ(std::string::npos, str.find("Not")); + + LogMessage::RemoveLogToStream(&stream); +} + +// Test using multiple log streams. The INFO stream should get the INFO message, +// the VERBOSE stream should get the INFO and the VERBOSE. +// We should restore the correct global state at the end. +TEST(LogTest, MultipleStreams) { + int sev = LogMessage::GetLogToStream(nullptr); + + std::string str1, str2; + LogSinkImpl stream1(&str1), stream2(&str2); + LogMessage::AddLogToStream(&stream1, LS_INFO); + LogMessage::AddLogToStream(&stream2, LS_VERBOSE); + EXPECT_EQ(LS_INFO, LogMessage::GetLogToStream(&stream1)); + EXPECT_EQ(LS_VERBOSE, LogMessage::GetLogToStream(&stream2)); + + RTC_LOG(LS_INFO) << "INFO"; + RTC_LOG(LS_VERBOSE) << "VERBOSE"; + + EXPECT_NE(std::string::npos, str1.find("INFO")); + EXPECT_EQ(std::string::npos, str1.find("VERBOSE")); + EXPECT_NE(std::string::npos, str2.find("INFO")); + EXPECT_NE(std::string::npos, str2.find("VERBOSE")); + + LogMessage::RemoveLogToStream(&stream2); + LogMessage::RemoveLogToStream(&stream1); + EXPECT_EQ(LS_NONE, LogMessage::GetLogToStream(&stream2)); + EXPECT_EQ(LS_NONE, LogMessage::GetLogToStream(&stream1)); + + EXPECT_EQ(sev, LogMessage::GetLogToStream(nullptr)); +} + +class LogThread { + public: + void Start() { + thread_ = PlatformThread::SpawnJoinable( + [] { RTC_LOG(LS_VERBOSE) << "RTC_LOG"; }, "LogThread"); + } + + private: + PlatformThread thread_; +}; + +// Ensure we don't crash when adding/removing streams while threads are going. +// We should restore the correct global state at the end. +TEST(LogTest, MultipleThreads) { + int sev = LogMessage::GetLogToStream(nullptr); + + LogThread thread1, thread2, thread3; + thread1.Start(); + thread2.Start(); + thread3.Start(); + + std::string s1, s2, s3; + LogSinkImpl stream1(&s1), stream2(&s2), stream3(&s3); + for (int i = 0; i < 1000; ++i) { + LogMessage::AddLogToStream(&stream1, LS_WARNING); + LogMessage::AddLogToStream(&stream2, LS_INFO); + LogMessage::AddLogToStream(&stream3, LS_VERBOSE); + LogMessage::RemoveLogToStream(&stream1); + LogMessage::RemoveLogToStream(&stream2); + LogMessage::RemoveLogToStream(&stream3); + } + + EXPECT_EQ(sev, LogMessage::GetLogToStream(nullptr)); +} + +TEST(LogTest, WallClockStartTime) { + uint32_t time = LogMessage::WallClockStartTime(); + // Expect the time to be in a sensible range, e.g. > 2012-01-01. + EXPECT_GT(time, 1325376000u); +} + +TEST(LogTest, CheckExtraErrorField) { + LogMessageForTesting log_msg(kFakeFilePath, 100, LS_WARNING, ERRCTX_ERRNO, + 0xD); + log_msg.stream() << "This gets added at dtor time"; + + const std::string& extra = log_msg.get_extra(); + const size_t length_to_check = arraysize("[0x12345678]") - 1; + ASSERT_GE(extra.length(), length_to_check); + EXPECT_EQ(std::string("[0x0000000D]"), extra.substr(0, length_to_check)); +} + +TEST(LogTest, CheckFilePathParsed) { + std::string str; + LogSinkImpl stream(&str); + LogMessage::AddLogToStream(&stream, LS_INFO); + EXPECT_EQ(LS_INFO, LogMessage::GetLogToStream(&stream)); +#if defined(WEBRTC_ANDROID) + const char* tag = nullptr; +#endif + { + LogMessageForTesting log_msg(kFakeFilePath, 100, LS_INFO); + log_msg.stream() << "<- Does this look right?"; +#if defined(WEBRTC_ANDROID) + tag = log_msg.get_tag(); +#endif + } + +#if defined(WEBRTC_ANDROID) + EXPECT_NE(nullptr, strstr(tag, "myfile.cc")); + EXPECT_NE(std::string::npos, str.find("100")); +#else + EXPECT_NE(std::string::npos, str.find("(myfile.cc:100)")); +#endif + LogMessage::RemoveLogToStream(&stream); +} + +#if defined(WEBRTC_ANDROID) +TEST(LogTest, CheckTagAddedToStringInDefaultOnLogMessageAndroid) { + std::string str; + LogSinkImpl stream(&str); + LogMessage::AddLogToStream(&stream, LS_INFO); + EXPECT_EQ(LS_INFO, LogMessage::GetLogToStream(&stream)); + + RTC_LOG_TAG(LS_INFO, "my_tag") << "INFO"; + EXPECT_NE(std::string::npos, str.find("INFO")); + EXPECT_NE(std::string::npos, str.find("my_tag")); +} +#endif + +// Test the time required to write 1000 80-character logs to a string. +TEST(LogTest, Perf) { + std::string str; + LogSinkImpl stream(&str); + LogMessage::AddLogToStream(&stream, LS_VERBOSE); + + const std::string message(80, 'X'); + { LogMessageForTesting sanity_check_msg(__FILE__, __LINE__, LS_VERBOSE); } + + // We now know how many bytes the logging framework will tag onto every msg. + const size_t logging_overhead = str.size(); + // Reset the stream to 0 size. + str.clear(); + str.reserve(120000); + static const int kRepetitions = 1000; + + int64_t start = TimeMillis(), finish; + for (int i = 0; i < kRepetitions; ++i) { + LogMessageForTesting(__FILE__, __LINE__, LS_VERBOSE).stream() << message; + } + finish = TimeMillis(); + + LogMessage::RemoveLogToStream(&stream); + + EXPECT_EQ(str.size(), (message.size() + logging_overhead) * kRepetitions); + RTC_LOG(LS_INFO) << "Total log time: " << TimeDiff(finish, start) + << " ms " + " total bytes logged: " + << str.size(); +} + +TEST(LogTest, EnumsAreSupported) { + enum class TestEnum { kValue0 = 0, kValue1 = 1 }; + std::string str; + LogSinkImpl stream(&str); + LogMessage::AddLogToStream(&stream, LS_INFO); + RTC_LOG(LS_INFO) << "[" << TestEnum::kValue0 << "]"; + EXPECT_NE(std::string::npos, str.find("[0]")); + EXPECT_EQ(std::string::npos, str.find("[1]")); + RTC_LOG(LS_INFO) << "[" << TestEnum::kValue1 << "]"; + EXPECT_NE(std::string::npos, str.find("[1]")); + LogMessage::RemoveLogToStream(&stream); +} + +TEST(LogTest, NoopSeverityDoesNotRunStringFormatting) { + if (!LogMessage::IsNoop(LS_VERBOSE)) { + RTC_LOG(LS_WARNING) << "Skipping test since verbose logging is turned on."; + return; + } + bool was_called = false; + auto cb = [&was_called]() { + was_called = true; + return "This could be an expensive callback."; + }; + RTC_LOG(LS_VERBOSE) << "This should not be logged: " << cb(); + EXPECT_FALSE(was_called); +} + +struct TestStruct {}; +std::string ToLogString(TestStruct foo) { + return "bar"; +} + +TEST(LogTest, ToLogStringUsedForUnknownTypes) { + std::string str; + LogSinkImpl stream(&str); + LogMessage::AddLogToStream(&stream, LS_INFO); + TestStruct t; + RTC_LOG(LS_INFO) << t; + EXPECT_THAT(str, ::testing::HasSubstr("bar")); + LogMessage::RemoveLogToStream(&stream); +} + +} // namespace rtc +#endif // RTC_LOG_ENABLED() diff --git a/third_party/libwebrtc/rtc_base/mac_ifaddrs_converter.cc b/third_party/libwebrtc/rtc_base/mac_ifaddrs_converter.cc new file mode 100644 index 0000000000..eb82cf2024 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/mac_ifaddrs_converter.cc @@ -0,0 +1,282 @@ +/* + * Copyright 2015 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 <net/if.h> +#include <sys/ioctl.h> +#include <unistd.h> + +#include <memory> + +#include "rtc_base/checks.h" +#include "rtc_base/ifaddrs_converter.h" +#include "rtc_base/logging.h" + +#if !defined(WEBRTC_IOS) +#include <net/if_media.h> +#include <netinet/in_var.h> +#else // WEBRTC_IOS +#define SCOPE6_ID_MAX 16 + +struct in6_addrlifetime { + time_t ia6t_expire; /* valid lifetime expiration time */ + time_t ia6t_preferred; /* preferred lifetime expiration time */ + u_int32_t ia6t_vltime; /* valid lifetime */ + u_int32_t ia6t_pltime; /* prefix lifetime */ +}; + +struct in6_ifstat { + u_quad_t ifs6_in_receive; /* # of total input datagram */ + u_quad_t ifs6_in_hdrerr; /* # of datagrams with invalid hdr */ + u_quad_t ifs6_in_toobig; /* # of datagrams exceeded MTU */ + u_quad_t ifs6_in_noroute; /* # of datagrams with no route */ + u_quad_t ifs6_in_addrerr; /* # of datagrams with invalid dst */ + u_quad_t ifs6_in_protounknown; /* # of datagrams with unknown proto */ + /* NOTE: increment on final dst if */ + u_quad_t ifs6_in_truncated; /* # of truncated datagrams */ + u_quad_t ifs6_in_discard; /* # of discarded datagrams */ + /* NOTE: fragment timeout is not here */ + u_quad_t ifs6_in_deliver; /* # of datagrams delivered to ULP */ + /* NOTE: increment on final dst if */ + u_quad_t ifs6_out_forward; /* # of datagrams forwarded */ + /* NOTE: increment on outgoing if */ + u_quad_t ifs6_out_request; /* # of outgoing datagrams from ULP */ + /* NOTE: does not include forwrads */ + u_quad_t ifs6_out_discard; /* # of discarded datagrams */ + u_quad_t ifs6_out_fragok; /* # of datagrams fragmented */ + u_quad_t ifs6_out_fragfail; /* # of datagrams failed on fragment */ + u_quad_t ifs6_out_fragcreat; /* # of fragment datagrams */ + /* NOTE: this is # after fragment */ + u_quad_t ifs6_reass_reqd; /* # of incoming fragmented packets */ + /* NOTE: increment on final dst if */ + u_quad_t ifs6_reass_ok; /* # of reassembled packets */ + /* NOTE: this is # after reass */ + /* NOTE: increment on final dst if */ + u_quad_t ifs6_reass_fail; /* # of reass failures */ + /* NOTE: may not be packet count */ + /* NOTE: increment on final dst if */ + u_quad_t ifs6_in_mcast; /* # of inbound multicast datagrams */ + u_quad_t ifs6_out_mcast; /* # of outbound multicast datagrams */ +}; +struct icmp6_ifstat { + /* + * Input statistics + */ + /* ipv6IfIcmpInMsgs, total # of input messages */ + u_quad_t ifs6_in_msg; + /* ipv6IfIcmpInErrors, # of input error messages */ + u_quad_t ifs6_in_error; + /* ipv6IfIcmpInDestUnreachs, # of input dest unreach errors */ + u_quad_t ifs6_in_dstunreach; + /* ipv6IfIcmpInAdminProhibs, # of input admin. prohibited errs */ + u_quad_t ifs6_in_adminprohib; + /* ipv6IfIcmpInTimeExcds, # of input time exceeded errors */ + u_quad_t ifs6_in_timeexceed; + /* ipv6IfIcmpInParmProblems, # of input parameter problem errors */ + u_quad_t ifs6_in_paramprob; + /* ipv6IfIcmpInPktTooBigs, # of input packet too big errors */ + u_quad_t ifs6_in_pkttoobig; + /* ipv6IfIcmpInEchos, # of input echo requests */ + u_quad_t ifs6_in_echo; + /* ipv6IfIcmpInEchoReplies, # of input echo replies */ + u_quad_t ifs6_in_echoreply; + /* ipv6IfIcmpInRouterSolicits, # of input router solicitations */ + u_quad_t ifs6_in_routersolicit; + /* ipv6IfIcmpInRouterAdvertisements, # of input router advertisements */ + u_quad_t ifs6_in_routeradvert; + /* ipv6IfIcmpInNeighborSolicits, # of input neighbor solicitations */ + u_quad_t ifs6_in_neighborsolicit; + /* ipv6IfIcmpInNeighborAdvertisements, # of input neighbor advs. */ + u_quad_t ifs6_in_neighboradvert; + /* ipv6IfIcmpInRedirects, # of input redirects */ + u_quad_t ifs6_in_redirect; + /* ipv6IfIcmpInGroupMembQueries, # of input MLD queries */ + u_quad_t ifs6_in_mldquery; + /* ipv6IfIcmpInGroupMembResponses, # of input MLD reports */ + u_quad_t ifs6_in_mldreport; + /* ipv6IfIcmpInGroupMembReductions, # of input MLD done */ + u_quad_t ifs6_in_mlddone; + + /* + * Output statistics. We should solve unresolved routing problem... + */ + /* ipv6IfIcmpOutMsgs, total # of output messages */ + u_quad_t ifs6_out_msg; + /* ipv6IfIcmpOutErrors, # of output error messages */ + u_quad_t ifs6_out_error; + /* ipv6IfIcmpOutDestUnreachs, # of output dest unreach errors */ + u_quad_t ifs6_out_dstunreach; + /* ipv6IfIcmpOutAdminProhibs, # of output admin. prohibited errs */ + u_quad_t ifs6_out_adminprohib; + /* ipv6IfIcmpOutTimeExcds, # of output time exceeded errors */ + u_quad_t ifs6_out_timeexceed; + /* ipv6IfIcmpOutParmProblems, # of output parameter problem errors */ + u_quad_t ifs6_out_paramprob; + /* ipv6IfIcmpOutPktTooBigs, # of output packet too big errors */ + u_quad_t ifs6_out_pkttoobig; + /* ipv6IfIcmpOutEchos, # of output echo requests */ + u_quad_t ifs6_out_echo; + /* ipv6IfIcmpOutEchoReplies, # of output echo replies */ + u_quad_t ifs6_out_echoreply; + /* ipv6IfIcmpOutRouterSolicits, # of output router solicitations */ + u_quad_t ifs6_out_routersolicit; + /* ipv6IfIcmpOutRouterAdvertisements, # of output router advs. */ + u_quad_t ifs6_out_routeradvert; + /* ipv6IfIcmpOutNeighborSolicits, # of output neighbor solicitations */ + u_quad_t ifs6_out_neighborsolicit; + /* ipv6IfIcmpOutNeighborAdvertisements, # of output neighbor advs. */ + u_quad_t ifs6_out_neighboradvert; + /* ipv6IfIcmpOutRedirects, # of output redirects */ + u_quad_t ifs6_out_redirect; + /* ipv6IfIcmpOutGroupMembQueries, # of output MLD queries */ + u_quad_t ifs6_out_mldquery; + /* ipv6IfIcmpOutGroupMembResponses, # of output MLD reports */ + u_quad_t ifs6_out_mldreport; + /* ipv6IfIcmpOutGroupMembReductions, # of output MLD done */ + u_quad_t ifs6_out_mlddone; +}; + +struct in6_ifreq { + char ifr_name[IFNAMSIZ]; + union { + struct sockaddr_in6 ifru_addr; + struct sockaddr_in6 ifru_dstaddr; + int ifru_flags; + int ifru_flags6; + int ifru_metric; + int ifru_intval; + caddr_t ifru_data; + struct in6_addrlifetime ifru_lifetime; + struct in6_ifstat ifru_stat; + struct icmp6_ifstat ifru_icmp6stat; + u_int32_t ifru_scope_id[SCOPE6_ID_MAX]; + } ifr_ifru; +}; + +#define SIOCGIFAFLAG_IN6 _IOWR('i', 73, struct in6_ifreq) + +#define IN6_IFF_ANYCAST 0x0001 /* anycast address */ +#define IN6_IFF_TENTATIVE 0x0002 /* tentative address */ +#define IN6_IFF_DUPLICATED 0x0004 /* DAD detected duplicate */ +#define IN6_IFF_DETACHED 0x0008 /* may be detached from the link */ +#define IN6_IFF_DEPRECATED 0x0010 /* deprecated address */ +#define IN6_IFF_TEMPORARY 0x0080 /* temporary (anonymous) address. */ + +#endif // WEBRTC_IOS + +namespace rtc { + +namespace { + +class IPv6AttributesGetter { + public: + IPv6AttributesGetter(); + virtual ~IPv6AttributesGetter(); + bool IsInitialized() const; + bool GetIPAttributes(const char* ifname, + const sockaddr* sock_addr, + int* native_attributes); + + private: + // on MAC or IOS, we have to use ioctl with a socket to query an IPv6 + // interface's attribute. + int ioctl_socket_; +}; + +IPv6AttributesGetter::IPv6AttributesGetter() + : ioctl_socket_( + socket(AF_INET6, SOCK_DGRAM, 0 /* unspecified protocol */)) { + RTC_DCHECK_GE(ioctl_socket_, 0); +} + +bool IPv6AttributesGetter::IsInitialized() const { + return ioctl_socket_ >= 0; +} + +IPv6AttributesGetter::~IPv6AttributesGetter() { + if (!IsInitialized()) { + return; + } + close(ioctl_socket_); +} + +bool IPv6AttributesGetter::GetIPAttributes(const char* ifname, + const sockaddr* sock_addr, + int* native_attributes) { + if (!IsInitialized()) { + return false; + } + + struct in6_ifreq ifr = {}; + strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name) - 1); + memcpy(&ifr.ifr_ifru.ifru_addr, sock_addr, sock_addr->sa_len); + int rv = ioctl(ioctl_socket_, SIOCGIFAFLAG_IN6, &ifr); + if (rv >= 0) { + *native_attributes = ifr.ifr_ifru.ifru_flags; + } else { + RTC_LOG(LS_ERROR) << "ioctl returns " << errno; + } + return (rv >= 0); +} + +// Converts native IPv6 address attributes to net IPv6 address attributes. If +// it returns false, the IP address isn't suitable for one-to-one communications +// applications and should be ignored. +bool ConvertNativeToIPAttributes(int native_attributes, int* net_attributes) { + // For MacOSX, we disallow addresses with attributes IN6_IFF_ANYCASE, + // IN6_IFF_DUPLICATED, IN6_IFF_TENTATIVE, and IN6_IFF_DETACHED as these are + // still progressing through duplicated address detection (DAD) or are not + // suitable for one-to-one communication applications. + if (native_attributes & (IN6_IFF_ANYCAST | IN6_IFF_DUPLICATED | + IN6_IFF_TENTATIVE | IN6_IFF_DETACHED)) { + return false; + } + + if (native_attributes & IN6_IFF_TEMPORARY) { + *net_attributes |= IPV6_ADDRESS_FLAG_TEMPORARY; + } + + if (native_attributes & IN6_IFF_DEPRECATED) { + *net_attributes |= IPV6_ADDRESS_FLAG_DEPRECATED; + } + + return true; +} + +class MacIfAddrsConverter : public IfAddrsConverter { + public: + MacIfAddrsConverter() : ip_attribute_getter_(new IPv6AttributesGetter()) {} + ~MacIfAddrsConverter() override {} + + bool ConvertNativeAttributesToIPAttributes(const struct ifaddrs* interface, + int* ip_attributes) override { + int native_attributes; + if (!ip_attribute_getter_->GetIPAttributes( + interface->ifa_name, interface->ifa_addr, &native_attributes)) { + return false; + } + + if (!ConvertNativeToIPAttributes(native_attributes, ip_attributes)) { + return false; + } + + return true; + } + + private: + std::unique_ptr<IPv6AttributesGetter> ip_attribute_getter_; +}; + +} // namespace + +IfAddrsConverter* CreateIfAddrsConverter() { + return new MacIfAddrsConverter(); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/macromagic_gn/moz.build b/third_party/libwebrtc/rtc_base/macromagic_gn/moz.build new file mode 100644 index 0000000000..b44dfa38f5 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/macromagic_gn/moz.build @@ -0,0 +1,205 @@ +# 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("macromagic_gn") diff --git a/third_party/libwebrtc/rtc_base/mdns_responder_interface.h b/third_party/libwebrtc/rtc_base/mdns_responder_interface.h new file mode 100644 index 0000000000..14ef9a202d --- /dev/null +++ b/third_party/libwebrtc/rtc_base/mdns_responder_interface.h @@ -0,0 +1,51 @@ +/* + * 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 RTC_BASE_MDNS_RESPONDER_INTERFACE_H_ +#define RTC_BASE_MDNS_RESPONDER_INTERFACE_H_ + +#include <functional> +#include <string> + +#include "absl/strings/string_view.h" +#include "rtc_base/ip_address.h" + +namespace webrtc { + +// Defines an mDNS responder that can be used in ICE candidate gathering, where +// the local IP addresses of host candidates are replaced by mDNS hostnames. +class MdnsResponderInterface { + public: + using NameCreatedCallback = + std::function<void(const rtc::IPAddress&, absl::string_view)>; + using NameRemovedCallback = std::function<void(bool)>; + + MdnsResponderInterface() = default; + virtual ~MdnsResponderInterface() = default; + + // Asynchronously creates and returns a new name via `callback` for `addr` if + // there is no name mapped to it by this responder, and initializes the + // reference count of this name to one. Otherwise the existing name mapped to + // `addr` is returned and its reference count is incremented by one. + virtual void CreateNameForAddress(const rtc::IPAddress& addr, + NameCreatedCallback callback) = 0; + // Decrements the reference count of the mapped name of `addr`, if + // there is a map created previously via CreateNameForAddress; asynchronously + // removes the association between `addr` and its mapped name, and returns + // true via `callback` if the decremented reference count reaches zero. + // Otherwise no operation is done and false is returned via `callback` + // asynchronously. + virtual void RemoveNameForAddress(const rtc::IPAddress& addr, + NameRemovedCallback callback) = 0; +}; + +} // namespace webrtc + +#endif // RTC_BASE_MDNS_RESPONDER_INTERFACE_H_ diff --git a/third_party/libwebrtc/rtc_base/memory/BUILD.gn b/third_party/libwebrtc/rtc_base/memory/BUILD.gn new file mode 100644 index 0000000000..ee3baa40fb --- /dev/null +++ b/third_party/libwebrtc/rtc_base/memory/BUILD.gn @@ -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. + +import("../../webrtc.gni") +if (is_android) { + import("//build/config/android/config.gni") + import("//build/config/android/rules.gni") +} + +rtc_library("aligned_malloc") { + sources = [ + "aligned_malloc.cc", + "aligned_malloc.h", + ] + deps = [ "..:checks" ] +} + +# Test only utility. +rtc_library("fifo_buffer") { + testonly = true + visibility = [ + ":unittests", + "..:rtc_base_tests_utils", + "..:rtc_base_unittests", + ] + sources = [ + "fifo_buffer.cc", + "fifo_buffer.h", + ] + deps = [ + "..:stream", + "..:threading", + "../../api/task_queue:pending_task_safety_flag", + "../synchronization:mutex", + ] +} + +rtc_library("unittests") { + testonly = true + sources = [ + "aligned_malloc_unittest.cc", + "always_valid_pointer_unittest.cc", + "fifo_buffer_unittest.cc", + ] + deps = [ + ":aligned_malloc", + ":always_valid_pointer", + ":fifo_buffer", + "../../test:test_support", + ] +} + +rtc_source_set("always_valid_pointer") { + sources = [ "always_valid_pointer.h" ] + deps = [ "..:checks" ] +} diff --git a/third_party/libwebrtc/rtc_base/memory/aligned_malloc.cc b/third_party/libwebrtc/rtc_base/memory/aligned_malloc.cc new file mode 100644 index 0000000000..7add079398 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/memory/aligned_malloc.cc @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2011 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 "rtc_base/memory/aligned_malloc.h" + +#include <stdlib.h> // for free, malloc +#include <string.h> // for memcpy + +#include "rtc_base/checks.h" + +#ifdef _WIN32 +#include <windows.h> +#else +#include <stdint.h> +#endif + +// Reference on memory alignment: +// http://stackoverflow.com/questions/227897/solve-the-memory-alignment-in-c-interview-question-that-stumped-me +namespace webrtc { + +uintptr_t GetRightAlign(uintptr_t start_pos, size_t alignment) { + // The pointer should be aligned with `alignment` bytes. The - 1 guarantees + // that it is aligned towards the closest higher (right) address. + return (start_pos + alignment - 1) & ~(alignment - 1); +} + +// Alignment must be an integer power of two. +bool ValidAlignment(size_t alignment) { + if (!alignment) { + return false; + } + return (alignment & (alignment - 1)) == 0; +} + +void* GetRightAlign(const void* pointer, size_t alignment) { + if (!pointer) { + return NULL; + } + if (!ValidAlignment(alignment)) { + return NULL; + } + uintptr_t start_pos = reinterpret_cast<uintptr_t>(pointer); + return reinterpret_cast<void*>(GetRightAlign(start_pos, alignment)); +} + +void* AlignedMalloc(size_t size, size_t alignment) { + if (size == 0) { + return NULL; + } + if (!ValidAlignment(alignment)) { + return NULL; + } + + // The memory is aligned towards the lowest address that so only + // alignment - 1 bytes needs to be allocated. + // A pointer to the start of the memory must be stored so that it can be + // retreived for deletion, ergo the sizeof(uintptr_t). + void* memory_pointer = malloc(size + sizeof(uintptr_t) + alignment - 1); + RTC_CHECK(memory_pointer) << "Couldn't allocate memory in AlignedMalloc"; + + // Aligning after the sizeof(uintptr_t) bytes will leave room for the header + // in the same memory block. + uintptr_t align_start_pos = reinterpret_cast<uintptr_t>(memory_pointer); + align_start_pos += sizeof(uintptr_t); + uintptr_t aligned_pos = GetRightAlign(align_start_pos, alignment); + void* aligned_pointer = reinterpret_cast<void*>(aligned_pos); + + // Store the address to the beginning of the memory just before the aligned + // memory. + uintptr_t header_pos = aligned_pos - sizeof(uintptr_t); + void* header_pointer = reinterpret_cast<void*>(header_pos); + uintptr_t memory_start = reinterpret_cast<uintptr_t>(memory_pointer); + memcpy(header_pointer, &memory_start, sizeof(uintptr_t)); + + return aligned_pointer; +} + +void AlignedFree(void* mem_block) { + if (mem_block == NULL) { + return; + } + uintptr_t aligned_pos = reinterpret_cast<uintptr_t>(mem_block); + uintptr_t header_pos = aligned_pos - sizeof(uintptr_t); + + // Read out the address of the AlignedMemory struct from the header. + uintptr_t memory_start_pos = *reinterpret_cast<uintptr_t*>(header_pos); + void* memory_start = reinterpret_cast<void*>(memory_start_pos); + free(memory_start); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/memory/aligned_malloc.h b/third_party/libwebrtc/rtc_base/memory/aligned_malloc.h new file mode 100644 index 0000000000..1c7d303885 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/memory/aligned_malloc.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2011 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 RTC_BASE_MEMORY_ALIGNED_MALLOC_H_ +#define RTC_BASE_MEMORY_ALIGNED_MALLOC_H_ + +// The functions declared here +// 1) Allocates block of aligned memory. +// 2) Re-calculates a pointer such that it is aligned to a higher or equal +// address. +// Note: alignment must be a power of two. The alignment is in bytes. + +#include <stddef.h> + +namespace webrtc { + +// Returns a pointer to the first boundry of `alignment` bytes following the +// address of `ptr`. +// Note that there is no guarantee that the memory in question is available. +// `ptr` has no requirements other than it can't be NULL. +void* GetRightAlign(const void* ptr, size_t alignment); + +// Allocates memory of `size` bytes aligned on an `alignment` boundry. +// The return value is a pointer to the memory. Note that the memory must +// be de-allocated using AlignedFree. +void* AlignedMalloc(size_t size, size_t alignment); +// De-allocates memory created using the AlignedMalloc() API. +void AlignedFree(void* mem_block); + +// Templated versions to facilitate usage of aligned malloc without casting +// to and from void*. +template <typename T> +T* GetRightAlign(const T* ptr, size_t alignment) { + return reinterpret_cast<T*>( + GetRightAlign(reinterpret_cast<const void*>(ptr), alignment)); +} +template <typename T> +T* AlignedMalloc(size_t size, size_t alignment) { + return reinterpret_cast<T*>(AlignedMalloc(size, alignment)); +} + +// Deleter for use with unique_ptr. E.g., use as +// std::unique_ptr<Foo, AlignedFreeDeleter> foo; +struct AlignedFreeDeleter { + inline void operator()(void* ptr) const { AlignedFree(ptr); } +}; + +} // namespace webrtc + +#endif // RTC_BASE_MEMORY_ALIGNED_MALLOC_H_ diff --git a/third_party/libwebrtc/rtc_base/memory/aligned_malloc_gn/moz.build b/third_party/libwebrtc/rtc_base/memory/aligned_malloc_gn/moz.build new file mode 100644 index 0000000000..f5720480dd --- /dev/null +++ b/third_party/libwebrtc/rtc_base/memory/aligned_malloc_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/rtc_base/memory/aligned_malloc.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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("aligned_malloc_gn") diff --git a/third_party/libwebrtc/rtc_base/memory/aligned_malloc_unittest.cc b/third_party/libwebrtc/rtc_base/memory/aligned_malloc_unittest.cc new file mode 100644 index 0000000000..8e750035f0 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/memory/aligned_malloc_unittest.cc @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2012 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 "rtc_base/memory/aligned_malloc.h" + +#include <memory> + +#ifdef _WIN32 +#include <windows.h> +#else +#include <stdint.h> +#endif + +#include "test/gtest.h" + +namespace webrtc { + +// Returns true if `size` and `alignment` are valid combinations. +bool CorrectUsage(size_t size, size_t alignment) { + std::unique_ptr<char, AlignedFreeDeleter> scoped( + static_cast<char*>(AlignedMalloc(size, alignment))); + if (scoped.get() == NULL) { + return false; + } + const uintptr_t scoped_address = reinterpret_cast<uintptr_t>(scoped.get()); + return 0u == scoped_address % alignment; +} + +TEST(AlignedMalloc, GetRightAlign) { + const size_t size = 100; + const size_t alignment = 32; + const size_t left_misalignment = 1; + std::unique_ptr<char, AlignedFreeDeleter> scoped( + static_cast<char*>(AlignedMalloc(size, alignment))); + EXPECT_TRUE(scoped.get() != NULL); + const uintptr_t aligned_address = reinterpret_cast<uintptr_t>(scoped.get()); + const uintptr_t misaligned_address = aligned_address - left_misalignment; + const char* misaligned_ptr = + reinterpret_cast<const char*>(misaligned_address); + const char* realigned_ptr = GetRightAlign(misaligned_ptr, alignment); + EXPECT_EQ(scoped.get(), realigned_ptr); +} + +TEST(AlignedMalloc, IncorrectSize) { + const size_t incorrect_size = 0; + const size_t alignment = 64; + EXPECT_FALSE(CorrectUsage(incorrect_size, alignment)); +} + +TEST(AlignedMalloc, IncorrectAlignment) { + const size_t size = 100; + const size_t incorrect_alignment = 63; + EXPECT_FALSE(CorrectUsage(size, incorrect_alignment)); +} + +TEST(AlignedMalloc, AlignTo2Bytes) { + size_t size = 100; + size_t alignment = 2; + EXPECT_TRUE(CorrectUsage(size, alignment)); +} + +TEST(AlignedMalloc, AlignTo32Bytes) { + size_t size = 100; + size_t alignment = 32; + EXPECT_TRUE(CorrectUsage(size, alignment)); +} + +TEST(AlignedMalloc, AlignTo128Bytes) { + size_t size = 100; + size_t alignment = 128; + EXPECT_TRUE(CorrectUsage(size, alignment)); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/memory/always_valid_pointer.h b/third_party/libwebrtc/rtc_base/memory/always_valid_pointer.h new file mode 100644 index 0000000000..4e68104b55 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/memory/always_valid_pointer.h @@ -0,0 +1,248 @@ +/* + * Copyright 2022 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 RTC_BASE_MEMORY_ALWAYS_VALID_POINTER_H_ +#define RTC_BASE_MEMORY_ALWAYS_VALID_POINTER_H_ + +#include <memory> +#include <utility> + +#include "rtc_base/checks.h" + +namespace webrtc { + +// This template allows the instantiation of a pointer to Interface in such a +// way that if it is passed a null pointer, an object of class Default will be +// created, which will be deallocated when the pointer is deleted. +template <typename Interface, typename Default = Interface> +class AlwaysValidPointer { + public: + explicit AlwaysValidPointer(Interface* pointer) + : owned_instance_(pointer ? nullptr : std::make_unique<Default>()), + pointer_(pointer ? pointer : owned_instance_.get()) { + RTC_DCHECK(pointer_); + } + + template <typename Arg, + typename std::enable_if<!(std::is_invocable<Arg>::value), + bool>::type = true> + AlwaysValidPointer(Interface* pointer, Arg arg) + : owned_instance_(pointer ? nullptr + : std::make_unique<Default>(std::move(arg))), + pointer_(pointer ? pointer : owned_instance_.get()) { + RTC_DCHECK(pointer_); + } + + // Multiple arguments + template <typename Arg1, typename... Args> + AlwaysValidPointer(Interface* pointer, Arg1 arg1, Args... args) + : owned_instance_(pointer + ? nullptr + : std::make_unique<Default>(std::move(arg1), + std::move(args...))), + pointer_(pointer ? pointer : owned_instance_.get()) { + RTC_DCHECK(pointer_); + } + + // Create a pointer by + // a) using |pointer|, without taking ownership + // b) calling |function| and taking ownership of the result + template <typename Func, + typename std::enable_if<std::is_invocable<Func>::value, + bool>::type = true> + AlwaysValidPointer(Interface* pointer, Func function) + : owned_instance_(pointer ? nullptr : function()), + pointer_(owned_instance_ ? owned_instance_.get() : pointer) { + RTC_DCHECK(pointer_); + } + + // Create a pointer by + // a) taking over ownership of |instance| + // b) or fallback to |pointer|, without taking ownership. + // c) or Default. + AlwaysValidPointer(std::unique_ptr<Interface>&& instance, Interface* pointer) + : owned_instance_( + instance + ? std::move(instance) + : (pointer == nullptr ? std::make_unique<Default>() : nullptr)), + pointer_(owned_instance_ ? owned_instance_.get() : pointer) { + RTC_DCHECK(pointer_); + } + + // Create a pointer by + // a) taking over ownership of |instance| + // b) or fallback to |pointer|, without taking ownership. + // c) or Default (with forwarded args). + template <typename... Args> + AlwaysValidPointer(std::unique_ptr<Interface>&& instance, + Interface* pointer, + Args... args) + : owned_instance_( + instance ? std::move(instance) + : (pointer == nullptr + ? std::make_unique<Default>(std::move(args...)) + : nullptr)), + pointer_(owned_instance_ ? owned_instance_.get() : pointer) { + RTC_DCHECK(pointer_); + } + + Interface* get() { return pointer_; } + Interface* operator->() { return pointer_; } + Interface& operator*() { return *pointer_; } + + Interface* get() const { return pointer_; } + Interface* operator->() const { return pointer_; } + Interface& operator*() const { return *pointer_; } + + private: + const std::unique_ptr<Interface> owned_instance_; + Interface* const pointer_; +}; + +// This class is similar to AlwaysValidPointer, but it does not create +// a default object and crashes if none of the input pointers are non-null. +template <typename Interface> +class AlwaysValidPointerNoDefault { + public: + explicit AlwaysValidPointerNoDefault(Interface* pointer) : pointer_(pointer) { + RTC_CHECK(pointer_); + } + + // Create a pointer by + // a) taking over ownership of |instance| + // b) or fallback to |pointer|, without taking ownership. + // At least one of the arguments must be non-null. + explicit AlwaysValidPointerNoDefault(std::unique_ptr<Interface> instance, + Interface* pointer = nullptr) + : owned_instance_(std::move(instance)), + pointer_(owned_instance_ ? owned_instance_.get() : pointer) { + RTC_CHECK(pointer_); + } + + Interface* get() { return pointer_; } + Interface* operator->() { return pointer_; } + Interface& operator*() { return *pointer_; } + + Interface* get() const { return pointer_; } + Interface* operator->() const { return pointer_; } + Interface& operator*() const { return *pointer_; } + + private: + const std::unique_ptr<Interface> owned_instance_; + Interface* const pointer_; +}; + +template <typename T, typename U, typename V, typename W> +bool operator==(const AlwaysValidPointer<T, U>& a, + const AlwaysValidPointer<V, W>& b) { + return a.get() == b.get(); +} + +template <typename T, typename U, typename V, typename W> +bool operator!=(const AlwaysValidPointer<T, U>& a, + const AlwaysValidPointer<V, W>& b) { + return !(a == b); +} + +template <typename T, typename U> +bool operator==(const AlwaysValidPointer<T, U>& a, std::nullptr_t) { + return a.get() == nullptr; +} + +template <typename T, typename U> +bool operator!=(const AlwaysValidPointer<T, U>& a, std::nullptr_t) { + return !(a == nullptr); +} + +template <typename T, typename U> +bool operator==(std::nullptr_t, const AlwaysValidPointer<T, U>& a) { + return a.get() == nullptr; +} + +template <typename T, typename U> +bool operator!=(std::nullptr_t, const AlwaysValidPointer<T, U>& a) { + return !(a == nullptr); +} + +template <typename T, typename U> +bool operator==(const AlwaysValidPointerNoDefault<T>& a, + const AlwaysValidPointerNoDefault<U>& b) { + return a.get() == b.get(); +} + +template <typename T, typename U> +bool operator!=(const AlwaysValidPointerNoDefault<T>& a, + const AlwaysValidPointerNoDefault<U>& b) { + return !(a == b); +} + +template <typename T> +bool operator==(const AlwaysValidPointerNoDefault<T>& a, std::nullptr_t) { + return a.get() == nullptr; +} + +template <typename T> +bool operator!=(const AlwaysValidPointerNoDefault<T>& a, std::nullptr_t) { + return !(a == nullptr); +} + +template <typename T> +bool operator==(std::nullptr_t, const AlwaysValidPointerNoDefault<T>& a) { + return a.get() == nullptr; +} + +template <typename T> +bool operator!=(std::nullptr_t, const AlwaysValidPointerNoDefault<T>& a) { + return !(a == nullptr); +} + +// Comparison with raw pointer. +template <typename T, typename U, typename V> +bool operator==(const AlwaysValidPointer<T, U>& a, const V* b) { + return a.get() == b; +} + +template <typename T, typename U, typename V> +bool operator!=(const AlwaysValidPointer<T, U>& a, const V* b) { + return !(a == b); +} + +template <typename T, typename U, typename V> +bool operator==(const T* a, const AlwaysValidPointer<U, V>& b) { + return a == b.get(); +} + +template <typename T, typename U, typename V> +bool operator!=(const T* a, const AlwaysValidPointer<U, V>& b) { + return !(a == b); +} + +template <typename T, typename U> +bool operator==(const AlwaysValidPointerNoDefault<T>& a, const U* b) { + return a.get() == b; +} + +template <typename T, typename U> +bool operator!=(const AlwaysValidPointerNoDefault<T>& a, const U* b) { + return !(a == b); +} + +template <typename T, typename U> +bool operator==(const T* a, const AlwaysValidPointerNoDefault<U>& b) { + return a == b.get(); +} + +template <typename T, typename U> +bool operator!=(const T* a, const AlwaysValidPointerNoDefault<U>& b) { + return !(a == b); +} + +} // namespace webrtc + +#endif // RTC_BASE_MEMORY_ALWAYS_VALID_POINTER_H_ diff --git a/third_party/libwebrtc/rtc_base/memory/always_valid_pointer_unittest.cc b/third_party/libwebrtc/rtc_base/memory/always_valid_pointer_unittest.cc new file mode 100644 index 0000000000..a228c102d0 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/memory/always_valid_pointer_unittest.cc @@ -0,0 +1,129 @@ +/* + * 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 "rtc_base/memory/always_valid_pointer.h" + +#include <string> + +#include "test/gtest.h" + +namespace webrtc { + +TEST(AlwaysValidPointerTest, DefaultToEmptyValue) { + AlwaysValidPointer<std::string> ptr(nullptr); + EXPECT_EQ(*ptr, ""); +} +TEST(AlwaysValidPointerTest, DefaultWithForwardedArgument) { + AlwaysValidPointer<std::string> ptr(nullptr, "test"); + EXPECT_EQ(*ptr, "test"); +} +TEST(AlwaysValidPointerTest, DefaultToSubclass) { + struct A { + virtual ~A() {} + virtual int f() = 0; + }; + struct B : public A { + int b = 0; + explicit B(int val) : b(val) {} + virtual ~B() {} + int f() override { return b; } + }; + AlwaysValidPointer<A, B> ptr(nullptr, 3); + EXPECT_EQ(ptr->f(), 3); + EXPECT_EQ((*ptr).f(), 3); + EXPECT_EQ(ptr.get()->f(), 3); +} +TEST(AlwaysValidPointerTest, NonDefaultValue) { + std::string str("keso"); + AlwaysValidPointer<std::string> ptr(&str, "test"); + EXPECT_EQ(*ptr, "keso"); +} + +TEST(AlwaysValidPointerTest, TakeOverOwnershipOfInstance) { + std::string str("keso"); + std::unique_ptr<std::string> str2 = std::make_unique<std::string>("kent"); + AlwaysValidPointer<std::string> ptr(std::move(str2), &str); + EXPECT_EQ(*ptr, "kent"); + EXPECT_EQ(str2, nullptr); +} + +TEST(AlwaysValidPointerTest, TakeOverOwnershipFallbackOnPointer) { + std::string str("keso"); + std::unique_ptr<std::string> str2; + AlwaysValidPointer<std::string> ptr(std::move(str2), &str); + EXPECT_EQ(*ptr, "keso"); +} + +TEST(AlwaysValidPointerTest, TakeOverOwnershipFallbackOnDefault) { + std::unique_ptr<std::string> str; + std::string* str_ptr = nullptr; + AlwaysValidPointer<std::string> ptr(std::move(str), str_ptr); + EXPECT_EQ(*ptr, ""); +} + +TEST(AlwaysValidPointerTest, + TakeOverOwnershipFallbackOnDefaultWithForwardedArgument) { + std::unique_ptr<std::string> str2; + AlwaysValidPointer<std::string> ptr(std::move(str2), nullptr, "keso"); + EXPECT_EQ(*ptr, "keso"); +} + +TEST(AlwaysValidPointerTest, TakeOverOwnershipDoesNotForwardDefaultArguments) { + std::unique_ptr<std::string> str = std::make_unique<std::string>("kalle"); + std::unique_ptr<std::string> str2 = std::make_unique<std::string>("anka"); + AlwaysValidPointer<std::string> ptr(std::move(str), nullptr, *str2); + EXPECT_EQ(*ptr, "kalle"); + EXPECT_TRUE(!str); + EXPECT_EQ(*str2, "anka"); +} + +TEST(AlwaysValidPointerTest, DefaultToLambda) { + AlwaysValidPointer<std::string> ptr( + nullptr, []() { return std::make_unique<std::string>("onkel skrue"); }); + EXPECT_EQ(*ptr, "onkel skrue"); +} + +TEST(AlwaysValidPointerTest, NoDefaultObjectPassValidPointer) { + std::string str("foo"); + AlwaysValidPointerNoDefault<std::string> ptr(&str); + EXPECT_EQ(*ptr, "foo"); + EXPECT_EQ(ptr, &str); +} + +TEST(AlwaysValidPointerTest, NoDefaultObjectWithTakeOverOwnership) { + std::unique_ptr<std::string> str = std::make_unique<std::string>("yum"); + AlwaysValidPointerNoDefault<std::string> ptr(std::move(str)); + EXPECT_EQ(*ptr, "yum"); + std::unique_ptr<std::string> str2 = std::make_unique<std::string>("fun"); + AlwaysValidPointerNoDefault<std::string> ptr2(std::move(str), str2.get()); + EXPECT_EQ(*ptr2, "fun"); + EXPECT_EQ(ptr2, str2.get()); +} + +#if GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID) + +TEST(AlwaysValidPointerTest, NoDefaultObjectPassNullPointer) { + auto pass_null = []() { + AlwaysValidPointerNoDefault<std::string> ptr(nullptr); + }; + EXPECT_DEATH(pass_null(), ""); +} + +TEST(AlwaysValidPointerTest, NoDefaultObjectPassNullUniquePointer) { + auto pass_null = []() { + std::unique_ptr<std::string> str; + AlwaysValidPointerNoDefault<std::string> ptr(std::move(str)); + }; + EXPECT_DEATH(pass_null(), ""); +} + +#endif + +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/memory/fifo_buffer.cc b/third_party/libwebrtc/rtc_base/memory/fifo_buffer.cc new file mode 100644 index 0000000000..c159bc979f --- /dev/null +++ b/third_party/libwebrtc/rtc_base/memory/fifo_buffer.cc @@ -0,0 +1,197 @@ +/* + * 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 "rtc_base/memory/fifo_buffer.h" + +#include <algorithm> + +#include "rtc_base/thread.h" + +namespace rtc { + +FifoBuffer::FifoBuffer(size_t size) + : state_(SS_OPEN), + buffer_(new char[size]), + buffer_length_(size), + data_length_(0), + read_position_(0), + owner_(Thread::Current()) { + // all events are done on the owner_ thread +} + +FifoBuffer::FifoBuffer(size_t size, Thread* owner) + : state_(SS_OPEN), + buffer_(new char[size]), + buffer_length_(size), + data_length_(0), + read_position_(0), + owner_(owner) { + // all events are done on the owner_ thread +} + +FifoBuffer::~FifoBuffer() {} + +bool FifoBuffer::GetBuffered(size_t* size) const { + webrtc::MutexLock lock(&mutex_); + *size = data_length_; + return true; +} + +StreamState FifoBuffer::GetState() const { + webrtc::MutexLock lock(&mutex_); + return state_; +} + +StreamResult FifoBuffer::Read(rtc::ArrayView<uint8_t> buffer, + size_t& bytes_read, + int& error) { + webrtc::MutexLock lock(&mutex_); + const bool was_writable = data_length_ < buffer_length_; + size_t copy = 0; + StreamResult result = ReadLocked(buffer.data(), buffer.size(), ©); + + if (result == SR_SUCCESS) { + // If read was successful then adjust the read position and number of + // bytes buffered. + read_position_ = (read_position_ + copy) % buffer_length_; + data_length_ -= copy; + bytes_read = copy; + + // if we were full before, and now we're not, post an event + if (!was_writable && copy > 0) { + PostEvent(SE_WRITE, 0); + } + } + return result; +} + +StreamResult FifoBuffer::Write(rtc::ArrayView<const uint8_t> buffer, + size_t& bytes_written, + int& error) { + webrtc::MutexLock lock(&mutex_); + + const bool was_readable = (data_length_ > 0); + size_t copy = 0; + StreamResult result = WriteLocked(buffer.data(), buffer.size(), ©); + + if (result == SR_SUCCESS) { + // If write was successful then adjust the number of readable bytes. + data_length_ += copy; + bytes_written = copy; + // if we didn't have any data to read before, and now we do, post an event + if (!was_readable && copy > 0) { + PostEvent(SE_READ, 0); + } + } + return result; +} + +void FifoBuffer::Close() { + webrtc::MutexLock lock(&mutex_); + state_ = SS_CLOSED; +} + +const void* FifoBuffer::GetReadData(size_t* size) { + webrtc::MutexLock lock(&mutex_); + *size = (read_position_ + data_length_ <= buffer_length_) + ? data_length_ + : buffer_length_ - read_position_; + return &buffer_[read_position_]; +} + +void FifoBuffer::ConsumeReadData(size_t size) { + webrtc::MutexLock lock(&mutex_); + RTC_DCHECK(size <= data_length_); + const bool was_writable = data_length_ < buffer_length_; + read_position_ = (read_position_ + size) % buffer_length_; + data_length_ -= size; + if (!was_writable && size > 0) { + PostEvent(SE_WRITE, 0); + } +} + +void* FifoBuffer::GetWriteBuffer(size_t* size) { + webrtc::MutexLock lock(&mutex_); + if (state_ == SS_CLOSED) { + return nullptr; + } + + // if empty, reset the write position to the beginning, so we can get + // the biggest possible block + if (data_length_ == 0) { + read_position_ = 0; + } + + const size_t write_position = + (read_position_ + data_length_) % buffer_length_; + *size = (write_position > read_position_ || data_length_ == 0) + ? buffer_length_ - write_position + : read_position_ - write_position; + return &buffer_[write_position]; +} + +void FifoBuffer::ConsumeWriteBuffer(size_t size) { + webrtc::MutexLock lock(&mutex_); + RTC_DCHECK(size <= buffer_length_ - data_length_); + const bool was_readable = (data_length_ > 0); + data_length_ += size; + if (!was_readable && size > 0) { + PostEvent(SE_READ, 0); + } +} + +StreamResult FifoBuffer::ReadLocked(void* buffer, + size_t bytes, + size_t* bytes_read) { + if (data_length_ == 0) { + return (state_ != SS_CLOSED) ? SR_BLOCK : SR_EOS; + } + + const size_t available = data_length_; + const size_t read_position = read_position_ % buffer_length_; + const size_t copy = std::min(bytes, available); + const size_t tail_copy = std::min(copy, buffer_length_ - read_position); + char* const p = static_cast<char*>(buffer); + memcpy(p, &buffer_[read_position], tail_copy); + memcpy(p + tail_copy, &buffer_[0], copy - tail_copy); + + if (bytes_read) { + *bytes_read = copy; + } + return SR_SUCCESS; +} + +StreamResult FifoBuffer::WriteLocked(const void* buffer, + size_t bytes, + size_t* bytes_written) { + if (state_ == SS_CLOSED) { + return SR_EOS; + } + + if (data_length_ >= buffer_length_) { + return SR_BLOCK; + } + + const size_t available = buffer_length_ - data_length_; + const size_t write_position = + (read_position_ + data_length_) % buffer_length_; + const size_t copy = std::min(bytes, available); + const size_t tail_copy = std::min(copy, buffer_length_ - write_position); + const char* const p = static_cast<const char*>(buffer); + memcpy(&buffer_[write_position], p, tail_copy); + memcpy(&buffer_[0], p + tail_copy, copy - tail_copy); + + if (bytes_written) { + *bytes_written = copy; + } + return SR_SUCCESS; +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/memory/fifo_buffer.h b/third_party/libwebrtc/rtc_base/memory/fifo_buffer.h new file mode 100644 index 0000000000..a225c688ac --- /dev/null +++ b/third_party/libwebrtc/rtc_base/memory/fifo_buffer.h @@ -0,0 +1,118 @@ +/* + * 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 RTC_BASE_MEMORY_FIFO_BUFFER_H_ +#define RTC_BASE_MEMORY_FIFO_BUFFER_H_ + +#include <memory> + +#include "api/task_queue/pending_task_safety_flag.h" +#include "rtc_base/stream.h" +#include "rtc_base/synchronization/mutex.h" + +namespace rtc { + +// FifoBuffer allows for efficient, thread-safe buffering of data between +// writer and reader. +class FifoBuffer final : public StreamInterface { + public: + // Creates a FIFO buffer with the specified capacity. + explicit FifoBuffer(size_t length); + // Creates a FIFO buffer with the specified capacity and owner + FifoBuffer(size_t length, Thread* owner); + ~FifoBuffer() override; + + FifoBuffer(const FifoBuffer&) = delete; + FifoBuffer& operator=(const FifoBuffer&) = delete; + + // Gets the amount of data currently readable from the buffer. + bool GetBuffered(size_t* data_len) const; + + // StreamInterface methods + StreamState GetState() const override; + StreamResult Read(rtc::ArrayView<uint8_t> buffer, + size_t& bytes_read, + int& error) override; + StreamResult Write(rtc::ArrayView<const uint8_t> buffer, + size_t& bytes_written, + int& error) override; + void Close() override; + + // Seek to a byte offset from the beginning of the stream. Returns false if + // the stream does not support seeking, or cannot seek to the specified + // position. + bool SetPosition(size_t position); + + // Get the byte offset of the current position from the start of the stream. + // Returns false if the position is not known. + bool GetPosition(size_t* position) const; + + // Seek to the start of the stream. + bool Rewind() { return SetPosition(0); } + + // GetReadData returns a pointer to a buffer which is owned by the stream. + // The buffer contains data_len bytes. null is returned if no data is + // available, or if the method fails. If the caller processes the data, it + // must call ConsumeReadData with the number of processed bytes. GetReadData + // does not require a matching call to ConsumeReadData if the data is not + // processed. Read and ConsumeReadData invalidate the buffer returned by + // GetReadData. + const void* GetReadData(size_t* data_len); + void ConsumeReadData(size_t used); + // GetWriteBuffer returns a pointer to a buffer which is owned by the stream. + // The buffer has a capacity of buf_len bytes. null is returned if there is + // no buffer available, or if the method fails. The call may write data to + // the buffer, and then call ConsumeWriteBuffer with the number of bytes + // written. GetWriteBuffer does not require a matching call to + // ConsumeWriteData if no data is written. Write and + // ConsumeWriteData invalidate the buffer returned by GetWriteBuffer. + void* GetWriteBuffer(size_t* buf_len); + void ConsumeWriteBuffer(size_t used); + + private: + void PostEvent(int events, int err) { + owner_->PostTask(webrtc::SafeTask( + task_safety_.flag(), + [this, events, err]() { SignalEvent(this, events, err); })); + } + + // Helper method that implements Read. Caller must acquire a lock + // when calling this method. + StreamResult ReadLocked(void* buffer, size_t bytes, size_t* bytes_read) + RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + // Helper method that implements Write. Caller must acquire a lock + // when calling this method. + StreamResult WriteLocked(const void* buffer, + size_t bytes, + size_t* bytes_written) + RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + webrtc::ScopedTaskSafety task_safety_; + + // keeps the opened/closed state of the stream + StreamState state_ RTC_GUARDED_BY(mutex_); + // the allocated buffer + std::unique_ptr<char[]> buffer_ RTC_GUARDED_BY(mutex_); + // size of the allocated buffer + const size_t buffer_length_; + // amount of readable data in the buffer + size_t data_length_ RTC_GUARDED_BY(mutex_); + // offset to the readable data + size_t read_position_ RTC_GUARDED_BY(mutex_); + // stream callbacks are dispatched on this thread + Thread* const owner_; + // object lock + mutable webrtc::Mutex mutex_; +}; + +} // namespace rtc + +#endif // RTC_BASE_MEMORY_FIFO_BUFFER_H_ diff --git a/third_party/libwebrtc/rtc_base/memory/fifo_buffer_unittest.cc b/third_party/libwebrtc/rtc_base/memory/fifo_buffer_unittest.cc new file mode 100644 index 0000000000..27eb8d8b45 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/memory/fifo_buffer_unittest.cc @@ -0,0 +1,249 @@ +/* + * 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 "rtc_base/memory/fifo_buffer.h" + +#include <string.h> + +#include "test/gtest.h" + +namespace rtc { + +TEST(FifoBufferTest, TestAll) { + rtc::AutoThread main_thread; + const size_t kSize = 16; + const uint8_t in[kSize * 2 + 1] = "0123456789ABCDEFGHIJKLMNOPQRSTUV"; + uint8_t out[kSize * 2]; + void* p; + const void* q; + size_t bytes; + FifoBuffer buf(kSize); + + // Test assumptions about base state + EXPECT_EQ(SS_OPEN, buf.GetState()); + int error; + EXPECT_EQ(SR_BLOCK, buf.Read(rtc::MakeArrayView(out, kSize), bytes, error)); + EXPECT_TRUE(nullptr != buf.GetWriteBuffer(&bytes)); + EXPECT_EQ(kSize, bytes); + buf.ConsumeWriteBuffer(0); + + // Try a full write + EXPECT_EQ(SR_SUCCESS, buf.Write(rtc::MakeArrayView(in, kSize), bytes, error)); + EXPECT_EQ(kSize, bytes); + + // Try a write that should block + EXPECT_EQ(SR_BLOCK, buf.Write(rtc::MakeArrayView(in, kSize), bytes, error)); + + // Try a full read + EXPECT_EQ(SR_SUCCESS, buf.Read(rtc::MakeArrayView(out, kSize), bytes, error)); + EXPECT_EQ(kSize, bytes); + EXPECT_EQ(0, memcmp(in, out, kSize)); + + // Try a read that should block + EXPECT_EQ(SR_BLOCK, buf.Read(rtc::MakeArrayView(out, kSize), bytes, error)); + + // Try a too-big write + EXPECT_EQ(SR_SUCCESS, + buf.Write(rtc::MakeArrayView(in, kSize * 2), bytes, error)); + EXPECT_EQ(bytes, kSize); + + // Try a too-big read + EXPECT_EQ(SR_SUCCESS, + buf.Read(rtc::MakeArrayView(out, kSize * 2), bytes, error)); + EXPECT_EQ(kSize, bytes); + EXPECT_EQ(0, memcmp(in, out, kSize)); + + // Try some small writes and reads + EXPECT_EQ(SR_SUCCESS, + buf.Write(rtc::MakeArrayView(in, kSize / 2), bytes, error)); + EXPECT_EQ(kSize / 2, bytes); + EXPECT_EQ(SR_SUCCESS, + buf.Read(rtc::MakeArrayView(out, kSize / 2), bytes, error)); + EXPECT_EQ(kSize / 2, bytes); + EXPECT_EQ(0, memcmp(in, out, kSize / 2)); + EXPECT_EQ(SR_SUCCESS, + buf.Write(rtc::MakeArrayView(in, kSize / 2), bytes, error)); + EXPECT_EQ(kSize / 2, bytes); + EXPECT_EQ(SR_SUCCESS, + buf.Write(rtc::MakeArrayView(in, kSize / 2), bytes, error)); + EXPECT_EQ(kSize / 2, bytes); + EXPECT_EQ(SR_SUCCESS, + buf.Read(rtc::MakeArrayView(out, kSize / 2), bytes, error)); + EXPECT_EQ(kSize / 2, bytes); + EXPECT_EQ(0, memcmp(in, out, kSize / 2)); + EXPECT_EQ(SR_SUCCESS, + buf.Read(rtc::MakeArrayView(out, kSize / 2), bytes, error)); + EXPECT_EQ(kSize / 2, bytes); + EXPECT_EQ(0, memcmp(in, out, kSize / 2)); + + // Try wraparound reads and writes in the following pattern + // WWWWWWWWWWWW.... 0123456789AB.... + // RRRRRRRRXXXX.... ........89AB.... + // WWWW....XXXXWWWW 4567....89AB0123 + // XXXX....RRRRXXXX 4567........0123 + // XXXXWWWWWWWWXXXX 4567012345670123 + // RRRRXXXXXXXXRRRR ....01234567.... + // ....RRRRRRRR.... ................ + EXPECT_EQ(SR_SUCCESS, + buf.Write(rtc::MakeArrayView(in, kSize * 3 / 4), bytes, error)); + EXPECT_EQ(kSize * 3 / 4, bytes); + EXPECT_EQ(SR_SUCCESS, + buf.Read(rtc::MakeArrayView(out, kSize / 2), bytes, error)); + EXPECT_EQ(kSize / 2, bytes); + EXPECT_EQ(0, memcmp(in, out, kSize / 2)); + EXPECT_EQ(SR_SUCCESS, + buf.Write(rtc::MakeArrayView(in, kSize / 2), bytes, error)); + EXPECT_EQ(kSize / 2, bytes); + EXPECT_EQ(SR_SUCCESS, + buf.Read(rtc::MakeArrayView(out, kSize / 4), bytes, error)); + EXPECT_EQ(kSize / 4, bytes); + EXPECT_EQ(0, memcmp(in + kSize / 2, out, kSize / 4)); + EXPECT_EQ(SR_SUCCESS, + buf.Write(rtc::MakeArrayView(in, kSize / 2), bytes, error)); + EXPECT_EQ(kSize / 2, bytes); + EXPECT_EQ(SR_SUCCESS, + buf.Read(rtc::MakeArrayView(out, kSize / 2), bytes, error)); + EXPECT_EQ(kSize / 2, bytes); + EXPECT_EQ(0, memcmp(in, out, kSize / 2)); + EXPECT_EQ(SR_SUCCESS, + buf.Read(rtc::MakeArrayView(out, kSize / 2), bytes, error)); + EXPECT_EQ(kSize / 2, bytes); + EXPECT_EQ(0, memcmp(in, out, kSize / 2)); + + // Use GetWriteBuffer to reset the read_position for the next tests + buf.GetWriteBuffer(&bytes); + buf.ConsumeWriteBuffer(0); + + // Try using GetReadData to do a full read + EXPECT_EQ(SR_SUCCESS, buf.Write(rtc::MakeArrayView(in, kSize), bytes, error)); + q = buf.GetReadData(&bytes); + EXPECT_TRUE(nullptr != q); + EXPECT_EQ(kSize, bytes); + EXPECT_EQ(0, memcmp(q, in, kSize)); + buf.ConsumeReadData(kSize); + EXPECT_EQ(SR_BLOCK, buf.Read(rtc::MakeArrayView(out, kSize), bytes, error)); + + // Try using GetReadData to do some small reads + EXPECT_EQ(SR_SUCCESS, buf.Write(rtc::MakeArrayView(in, kSize), bytes, error)); + q = buf.GetReadData(&bytes); + EXPECT_TRUE(nullptr != q); + EXPECT_EQ(kSize, bytes); + EXPECT_EQ(0, memcmp(q, in, kSize / 2)); + buf.ConsumeReadData(kSize / 2); + q = buf.GetReadData(&bytes); + EXPECT_TRUE(nullptr != q); + EXPECT_EQ(kSize / 2, bytes); + EXPECT_EQ(0, memcmp(q, in + kSize / 2, kSize / 2)); + buf.ConsumeReadData(kSize / 2); + EXPECT_EQ(SR_BLOCK, buf.Read(rtc::MakeArrayView(out, kSize), bytes, error)); + + // Try using GetReadData in a wraparound case + // WWWWWWWWWWWWWWWW 0123456789ABCDEF + // RRRRRRRRRRRRXXXX ............CDEF + // WWWWWWWW....XXXX 01234567....CDEF + // ............RRRR 01234567........ + // RRRRRRRR........ ................ + EXPECT_EQ(SR_SUCCESS, buf.Write(rtc::MakeArrayView(in, kSize), bytes, error)); + EXPECT_EQ(SR_SUCCESS, + buf.Read(rtc::MakeArrayView(out, kSize * 3 / 4), bytes, error)); + EXPECT_EQ(SR_SUCCESS, + buf.Write(rtc::MakeArrayView(in, kSize / 2), bytes, error)); + q = buf.GetReadData(&bytes); + EXPECT_TRUE(nullptr != q); + EXPECT_EQ(kSize / 4, bytes); + EXPECT_EQ(0, memcmp(q, in + kSize * 3 / 4, kSize / 4)); + buf.ConsumeReadData(kSize / 4); + q = buf.GetReadData(&bytes); + EXPECT_TRUE(nullptr != q); + EXPECT_EQ(kSize / 2, bytes); + EXPECT_EQ(0, memcmp(q, in, kSize / 2)); + buf.ConsumeReadData(kSize / 2); + + // Use GetWriteBuffer to reset the read_position for the next tests + buf.GetWriteBuffer(&bytes); + buf.ConsumeWriteBuffer(0); + + // Try using GetWriteBuffer to do a full write + p = buf.GetWriteBuffer(&bytes); + EXPECT_TRUE(nullptr != p); + EXPECT_EQ(kSize, bytes); + memcpy(p, in, kSize); + buf.ConsumeWriteBuffer(kSize); + EXPECT_EQ(SR_SUCCESS, buf.Read(rtc::MakeArrayView(out, kSize), bytes, error)); + EXPECT_EQ(kSize, bytes); + EXPECT_EQ(0, memcmp(in, out, kSize)); + + // Try using GetWriteBuffer to do some small writes + p = buf.GetWriteBuffer(&bytes); + EXPECT_TRUE(nullptr != p); + EXPECT_EQ(kSize, bytes); + memcpy(p, in, kSize / 2); + buf.ConsumeWriteBuffer(kSize / 2); + p = buf.GetWriteBuffer(&bytes); + EXPECT_TRUE(nullptr != p); + EXPECT_EQ(kSize / 2, bytes); + memcpy(p, in + kSize / 2, kSize / 2); + buf.ConsumeWriteBuffer(kSize / 2); + EXPECT_EQ(SR_SUCCESS, buf.Read(rtc::MakeArrayView(out, kSize), bytes, error)); + EXPECT_EQ(kSize, bytes); + EXPECT_EQ(0, memcmp(in, out, kSize)); + + // Try using GetWriteBuffer in a wraparound case + // WWWWWWWWWWWW.... 0123456789AB.... + // RRRRRRRRXXXX.... ........89AB.... + // ........XXXXWWWW ........89AB0123 + // WWWW....XXXXXXXX 4567....89AB0123 + // RRRR....RRRRRRRR ................ + EXPECT_EQ(SR_SUCCESS, + buf.Write(rtc::MakeArrayView(in, kSize * 3 / 4), bytes, error)); + EXPECT_EQ(SR_SUCCESS, + buf.Read(rtc::MakeArrayView(out, kSize / 2), bytes, error)); + p = buf.GetWriteBuffer(&bytes); + EXPECT_TRUE(nullptr != p); + EXPECT_EQ(kSize / 4, bytes); + memcpy(p, in, kSize / 4); + buf.ConsumeWriteBuffer(kSize / 4); + p = buf.GetWriteBuffer(&bytes); + EXPECT_TRUE(nullptr != p); + EXPECT_EQ(kSize / 2, bytes); + memcpy(p, in + kSize / 4, kSize / 4); + buf.ConsumeWriteBuffer(kSize / 4); + EXPECT_EQ(SR_SUCCESS, + buf.Read(rtc::MakeArrayView(out, kSize * 3 / 4), bytes, error)); + EXPECT_EQ(kSize * 3 / 4, bytes); + EXPECT_EQ(0, memcmp(in + kSize / 2, out, kSize / 4)); + EXPECT_EQ(0, memcmp(in, out + kSize / 4, kSize / 4)); + + // Check that the stream is now empty + EXPECT_EQ(SR_BLOCK, buf.Read(rtc::MakeArrayView(out, kSize), bytes, error)); + + // Write to the stream, close it, read the remaining bytes + EXPECT_EQ(SR_SUCCESS, + buf.Write(rtc::MakeArrayView(in, kSize / 2), bytes, error)); + buf.Close(); + EXPECT_EQ(SS_CLOSED, buf.GetState()); + EXPECT_EQ(SR_EOS, buf.Write(rtc::MakeArrayView(in, kSize / 2), bytes, error)); + EXPECT_EQ(SR_SUCCESS, + buf.Read(rtc::MakeArrayView(out, kSize / 2), bytes, error)); + EXPECT_EQ(0, memcmp(in, out, kSize / 2)); + EXPECT_EQ(SR_EOS, buf.Read(rtc::MakeArrayView(out, kSize / 2), bytes, error)); +} + +TEST(FifoBufferTest, FullBufferCheck) { + rtc::AutoThread main_thread; + FifoBuffer buff(10); + buff.ConsumeWriteBuffer(10); + + size_t free; + EXPECT_TRUE(buff.GetWriteBuffer(&free) != nullptr); + EXPECT_EQ(0U, free); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/memory_stream.cc b/third_party/libwebrtc/rtc_base/memory_stream.cc new file mode 100644 index 0000000000..8ceab7aa9b --- /dev/null +++ b/third_party/libwebrtc/rtc_base/memory_stream.cc @@ -0,0 +1,144 @@ +/* + * 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. + */ + +#include "rtc_base/memory_stream.h" + +#include <errno.h> +#include <string.h> + +#include <algorithm> + +#include "rtc_base/checks.h" + +namespace rtc { + +StreamState MemoryStream::GetState() const { + return SS_OPEN; +} + +StreamResult MemoryStream::Read(rtc::ArrayView<uint8_t> buffer, + size_t& bytes_read, + int& error) { + if (seek_position_ >= data_length_) { + return SR_EOS; + } + size_t available = data_length_ - seek_position_; + size_t bytes; + if (buffer.size() > available) { + // Read partial buffer + bytes = available; + } else { + bytes = buffer.size(); + } + memcpy(buffer.data(), &buffer_[seek_position_], bytes); + seek_position_ += bytes; + bytes_read = bytes; + return SR_SUCCESS; +} + +StreamResult MemoryStream::Write(rtc::ArrayView<const uint8_t> buffer, + size_t& bytes_written, + int& error) { + size_t available = buffer_length_ - seek_position_; + if (0 == available) { + // Increase buffer size to the larger of: + // a) new position rounded up to next 256 bytes + // b) double the previous length + size_t new_buffer_length = std::max( + ((seek_position_ + buffer.size()) | 0xFF) + 1, buffer_length_ * 2); + StreamResult result = DoReserve(new_buffer_length, &error); + if (SR_SUCCESS != result) { + return result; + } + RTC_DCHECK(buffer_length_ >= new_buffer_length); + available = buffer_length_ - seek_position_; + } + + size_t bytes = buffer.size(); + if (bytes > available) { + bytes = available; + } + memcpy(&buffer_[seek_position_], buffer.data(), bytes); + seek_position_ += bytes; + if (data_length_ < seek_position_) { + data_length_ = seek_position_; + } + bytes_written = bytes; + return SR_SUCCESS; +} + +void MemoryStream::Close() { + // nothing to do +} + +bool MemoryStream::SetPosition(size_t position) { + if (position > data_length_) + return false; + seek_position_ = position; + return true; +} + +bool MemoryStream::GetPosition(size_t* position) const { + if (position) + *position = seek_position_; + return true; +} + +void MemoryStream::Rewind() { + seek_position_ = 0; +} + +bool MemoryStream::GetSize(size_t* size) const { + if (size) + *size = data_length_; + return true; +} + +bool MemoryStream::ReserveSize(size_t size) { + return (SR_SUCCESS == DoReserve(size, nullptr)); +} + +/////////////////////////////////////////////////////////////////////////////// + +MemoryStream::MemoryStream() {} + +MemoryStream::~MemoryStream() { + delete[] buffer_; +} + +void MemoryStream::SetData(const void* data, size_t length) { + data_length_ = buffer_length_ = length; + delete[] buffer_; + buffer_ = new char[buffer_length_]; + memcpy(buffer_, data, data_length_); + seek_position_ = 0; +} + +StreamResult MemoryStream::DoReserve(size_t size, int* error) { + if (buffer_length_ >= size) + return SR_SUCCESS; + + if (char* new_buffer = new char[size]) { + if (buffer_ != nullptr && data_length_ > 0) { + memcpy(new_buffer, buffer_, data_length_); + } + delete[] buffer_; + buffer_ = new_buffer; + buffer_length_ = size; + return SR_SUCCESS; + } + + if (error) { + *error = ENOMEM; + } + return SR_ERROR; +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/memory_stream.h b/third_party/libwebrtc/rtc_base/memory_stream.h new file mode 100644 index 0000000000..07e07f0694 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/memory_stream.h @@ -0,0 +1,59 @@ +/* + * 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 RTC_BASE_MEMORY_STREAM_H_ +#define RTC_BASE_MEMORY_STREAM_H_ + +#include <stddef.h> + +#include "rtc_base/stream.h" + +namespace rtc { + +// MemoryStream dynamically resizes to accomodate written data. + +class MemoryStream final : public StreamInterface { + public: + MemoryStream(); + ~MemoryStream() override; + + StreamState GetState() const override; + StreamResult Read(rtc::ArrayView<uint8_t> buffer, + size_t& bytes_read, + int& error) override; + StreamResult Write(rtc::ArrayView<const uint8_t> buffer, + size_t& bytes_written, + int& error) override; + void Close() override; + bool GetSize(size_t* size) const; + bool ReserveSize(size_t size); + + bool SetPosition(size_t position); + bool GetPosition(size_t* position) const; + void Rewind(); + + char* GetBuffer() { return buffer_; } + const char* GetBuffer() const { return buffer_; } + + void SetData(const void* data, size_t length); + + private: + StreamResult DoReserve(size_t size, int* error); + + // Invariant: 0 <= seek_position <= data_length_ <= buffer_length_ + char* buffer_ = nullptr; + size_t buffer_length_ = 0; + size_t data_length_ = 0; + size_t seek_position_ = 0; +}; + +} // namespace rtc + +#endif // RTC_BASE_MEMORY_STREAM_H_ diff --git a/third_party/libwebrtc/rtc_base/memory_usage.cc b/third_party/libwebrtc/rtc_base/memory_usage.cc new file mode 100644 index 0000000000..2d33d98eed --- /dev/null +++ b/third_party/libwebrtc/rtc_base/memory_usage.cc @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2017 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 "rtc_base/memory_usage.h" + +#if defined(WEBRTC_LINUX) +#include <unistd.h> + +#include <cstdio> +#elif defined(WEBRTC_MAC) +#include <mach/mach.h> +#elif defined(WEBRTC_WIN) +// clang-format off +// clang formating would change include order. +#include <windows.h> +#include <psapi.h> // must come after windows.h +// clang-format on +#elif defined(WEBRTC_FUCHSIA) +#include <lib/zx/process.h> +#include <zircon/status.h> +#endif + +#include "rtc_base/logging.h" + +namespace rtc { + +int64_t GetProcessResidentSizeBytes() { +#if defined(WEBRTC_LINUX) + FILE* file = fopen("/proc/self/statm", "r"); + if (file == nullptr) { + RTC_LOG(LS_ERROR) << "Failed to open /proc/self/statm"; + return -1; + } + int result = -1; + if (fscanf(file, "%*s%d", &result) != 1) { + fclose(file); + RTC_LOG(LS_ERROR) << "Failed to parse /proc/self/statm"; + return -1; + } + fclose(file); + return static_cast<int64_t>(result) * sysconf(_SC_PAGESIZE); +#elif defined(WEBRTC_MAC) + task_basic_info_64 info; + mach_msg_type_number_t info_count = TASK_BASIC_INFO_64_COUNT; + if (task_info(mach_task_self(), TASK_BASIC_INFO_64, + reinterpret_cast<task_info_t>(&info), + &info_count) != KERN_SUCCESS) { + RTC_LOG_ERR(LS_ERROR) << "task_info() failed"; + return -1; + } + return info.resident_size; +#elif defined(WEBRTC_WIN) + PROCESS_MEMORY_COUNTERS pmc; + if (GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc)) == 0) { + RTC_LOG_ERR(LS_ERROR) << "GetProcessMemoryInfo() failed"; + return -1; + } + return pmc.WorkingSetSize; +#elif defined(WEBRTC_FUCHSIA) + zx_info_task_stats_t task_stats; + zx_status_t status = zx::process::self()->get_info( + ZX_INFO_TASK_STATS, &task_stats, sizeof(task_stats), nullptr, nullptr); + if (status == ZX_OK) { + return task_stats.mem_mapped_bytes; + } else { + RTC_LOG_ERR(LS_ERROR) << "get_info() failed: " + << zx_status_get_string(status); + return -1; + } +#else + // Not implemented yet. + static_assert(false, + "GetProcessVirtualMemoryUsageBytes() platform support not yet " + "implemented."); +#endif +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/memory_usage.h b/third_party/libwebrtc/rtc_base/memory_usage.h new file mode 100644 index 0000000000..c49323c825 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/memory_usage.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2017 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 RTC_BASE_MEMORY_USAGE_H_ +#define RTC_BASE_MEMORY_USAGE_H_ + +#include <stdint.h> + +namespace rtc { + +// Returns current memory used by the process in bytes (working set size on +// Windows and resident set size on other platforms). +// Returns -1 on failure. +int64_t GetProcessResidentSizeBytes(); + +} // namespace rtc + +#endif // RTC_BASE_MEMORY_USAGE_H_ diff --git a/third_party/libwebrtc/rtc_base/memory_usage_unittest.cc b/third_party/libwebrtc/rtc_base/memory_usage_unittest.cc new file mode 100644 index 0000000000..a928efbb61 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/memory_usage_unittest.cc @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2017 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 "rtc_base/memory_usage.h" + +#include "test/gtest.h" + +namespace rtc { + +TEST(GetMemoryUsage, SimpleTest) { + int64_t used_bytes = GetProcessResidentSizeBytes(); + EXPECT_GE(used_bytes, 0); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/message_digest.cc b/third_party/libwebrtc/rtc_base/message_digest.cc new file mode 100644 index 0000000000..56abcd2c7b --- /dev/null +++ b/third_party/libwebrtc/rtc_base/message_digest.cc @@ -0,0 +1,183 @@ +/* + * Copyright 2011 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 "rtc_base/message_digest.h" + +#include <string.h> + +#include <cstdint> +#include <memory> + +#include "absl/strings/string_view.h" +#include "rtc_base/openssl_digest.h" +#include "rtc_base/string_encode.h" + +namespace rtc { + +// From RFC 4572. +const char DIGEST_MD5[] = "md5"; +const char DIGEST_SHA_1[] = "sha-1"; +const char DIGEST_SHA_224[] = "sha-224"; +const char DIGEST_SHA_256[] = "sha-256"; +const char DIGEST_SHA_384[] = "sha-384"; +const char DIGEST_SHA_512[] = "sha-512"; + +static const size_t kBlockSize = 64; // valid for SHA-256 and down + +MessageDigest* MessageDigestFactory::Create(absl::string_view alg) { + MessageDigest* digest = new OpenSSLDigest(alg); + if (digest->Size() == 0) { // invalid algorithm + delete digest; + digest = nullptr; + } + return digest; +} + +bool IsFips180DigestAlgorithm(absl::string_view alg) { + // These are the FIPS 180 algorithms. According to RFC 4572 Section 5, + // "Self-signed certificates (for which legacy certificates are not a + // consideration) MUST use one of the FIPS 180 algorithms (SHA-1, + // SHA-224, SHA-256, SHA-384, or SHA-512) as their signature algorithm, + // and thus also MUST use it to calculate certificate fingerprints." + return alg == DIGEST_SHA_1 || alg == DIGEST_SHA_224 || + alg == DIGEST_SHA_256 || alg == DIGEST_SHA_384 || + alg == DIGEST_SHA_512; +} + +size_t ComputeDigest(MessageDigest* digest, + const void* input, + size_t in_len, + void* output, + size_t out_len) { + digest->Update(input, in_len); + return digest->Finish(output, out_len); +} + +size_t ComputeDigest(absl::string_view alg, + const void* input, + size_t in_len, + void* output, + size_t out_len) { + std::unique_ptr<MessageDigest> digest(MessageDigestFactory::Create(alg)); + return (digest) ? ComputeDigest(digest.get(), input, in_len, output, out_len) + : 0; +} + +std::string ComputeDigest(MessageDigest* digest, absl::string_view input) { + std::unique_ptr<char[]> output(new char[digest->Size()]); + ComputeDigest(digest, input.data(), input.size(), output.get(), + digest->Size()); + return hex_encode(absl::string_view(output.get(), digest->Size())); +} + +bool ComputeDigest(absl::string_view alg, + absl::string_view input, + std::string* output) { + std::unique_ptr<MessageDigest> digest(MessageDigestFactory::Create(alg)); + if (!digest) { + return false; + } + *output = ComputeDigest(digest.get(), input); + return true; +} + +std::string ComputeDigest(absl::string_view alg, absl::string_view input) { + std::string output; + ComputeDigest(alg, input, &output); + return output; +} + +// Compute a RFC 2104 HMAC: H(K XOR opad, H(K XOR ipad, text)) +size_t ComputeHmac(MessageDigest* digest, + const void* key, + size_t key_len, + const void* input, + size_t in_len, + void* output, + size_t out_len) { + // We only handle algorithms with a 64-byte blocksize. + // TODO: Add BlockSize() method to MessageDigest. + size_t block_len = kBlockSize; + if (digest->Size() > 32) { + return 0; + } + // Copy the key to a block-sized buffer to simplify padding. + // If the key is longer than a block, hash it and use the result instead. + std::unique_ptr<uint8_t[]> new_key(new uint8_t[block_len]); + if (key_len > block_len) { + ComputeDigest(digest, key, key_len, new_key.get(), block_len); + memset(new_key.get() + digest->Size(), 0, block_len - digest->Size()); + } else { + memcpy(new_key.get(), key, key_len); + memset(new_key.get() + key_len, 0, block_len - key_len); + } + // Set up the padding from the key, salting appropriately for each padding. + std::unique_ptr<uint8_t[]> o_pad(new uint8_t[block_len]); + std::unique_ptr<uint8_t[]> i_pad(new uint8_t[block_len]); + for (size_t i = 0; i < block_len; ++i) { + o_pad[i] = 0x5c ^ new_key[i]; + i_pad[i] = 0x36 ^ new_key[i]; + } + // Inner hash; hash the inner padding, and then the input buffer. + std::unique_ptr<uint8_t[]> inner(new uint8_t[digest->Size()]); + digest->Update(i_pad.get(), block_len); + digest->Update(input, in_len); + digest->Finish(inner.get(), digest->Size()); + // Outer hash; hash the outer padding, and then the result of the inner hash. + digest->Update(o_pad.get(), block_len); + digest->Update(inner.get(), digest->Size()); + return digest->Finish(output, out_len); +} + +size_t ComputeHmac(absl::string_view alg, + const void* key, + size_t key_len, + const void* input, + size_t in_len, + void* output, + size_t out_len) { + std::unique_ptr<MessageDigest> digest(MessageDigestFactory::Create(alg)); + if (!digest) { + return 0; + } + return ComputeHmac(digest.get(), key, key_len, input, in_len, output, + out_len); +} + +std::string ComputeHmac(MessageDigest* digest, + absl::string_view key, + absl::string_view input) { + std::unique_ptr<char[]> output(new char[digest->Size()]); + ComputeHmac(digest, key.data(), key.size(), input.data(), input.size(), + output.get(), digest->Size()); + return hex_encode(absl::string_view(output.get(), digest->Size())); +} + +bool ComputeHmac(absl::string_view alg, + absl::string_view key, + absl::string_view input, + std::string* output) { + std::unique_ptr<MessageDigest> digest(MessageDigestFactory::Create(alg)); + if (!digest) { + return false; + } + *output = ComputeHmac(digest.get(), key, input); + return true; +} + +std::string ComputeHmac(absl::string_view alg, + absl::string_view key, + absl::string_view input) { + std::string output; + ComputeHmac(alg, key, input, &output); + return output; +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/message_digest.h b/third_party/libwebrtc/rtc_base/message_digest.h new file mode 100644 index 0000000000..632b9af075 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/message_digest.h @@ -0,0 +1,133 @@ +/* + * 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 RTC_BASE_MESSAGE_DIGEST_H_ +#define RTC_BASE_MESSAGE_DIGEST_H_ + +#include <stddef.h> + +#include <string> + +#include "absl/strings/string_view.h" + +namespace rtc { + +// Definitions for the digest algorithms. +extern const char DIGEST_MD5[]; +extern const char DIGEST_SHA_1[]; +extern const char DIGEST_SHA_224[]; +extern const char DIGEST_SHA_256[]; +extern const char DIGEST_SHA_384[]; +extern const char DIGEST_SHA_512[]; + +// A general class for computing hashes. +class MessageDigest { + public: + enum { kMaxSize = 64 }; // Maximum known size (SHA-512) + virtual ~MessageDigest() {} + // Returns the digest output size (e.g. 16 bytes for MD5). + virtual size_t Size() const = 0; + // Updates the digest with `len` bytes from `buf`. + virtual void Update(const void* buf, size_t len) = 0; + // Outputs the digest value to `buf` with length `len`. + // Returns the number of bytes written, i.e., Size(). + virtual size_t Finish(void* buf, size_t len) = 0; +}; + +// A factory class for creating digest objects. +class MessageDigestFactory { + public: + static MessageDigest* Create(absl::string_view alg); +}; + +// A check that an algorithm is in a list of approved digest algorithms +// from RFC 4572 (FIPS 180). +bool IsFips180DigestAlgorithm(absl::string_view alg); + +// Functions to create hashes. + +// Computes the hash of `in_len` bytes of `input`, using the `digest` hash +// implementation, and outputs the hash to the buffer `output`, which is +// `out_len` bytes long. Returns the number of bytes written to `output` if +// successful, or 0 if `out_len` was too small. +size_t ComputeDigest(MessageDigest* digest, + const void* input, + size_t in_len, + void* output, + size_t out_len); +// Like the previous function, but creates a digest implementation based on +// the desired digest name `alg`, e.g. DIGEST_SHA_1. Returns 0 if there is no +// digest with the given name. +size_t ComputeDigest(absl::string_view alg, + const void* input, + size_t in_len, + void* output, + size_t out_len); +// Computes the hash of `input` using the `digest` hash implementation, and +// returns it as a hex-encoded string. +std::string ComputeDigest(MessageDigest* digest, absl::string_view input); +// Like the previous function, but creates a digest implementation based on +// the desired digest name `alg`, e.g. DIGEST_SHA_1. Returns empty string if +// there is no digest with the given name. +std::string ComputeDigest(absl::string_view alg, absl::string_view input); +// Like the previous function, but returns an explicit result code. +bool ComputeDigest(absl::string_view alg, + absl::string_view input, + std::string* output); + +// Shorthand way to compute a hex-encoded hash using MD5. +inline std::string MD5(absl::string_view input) { + return ComputeDigest(DIGEST_MD5, input); +} + +// Functions to compute RFC 2104 HMACs. + +// Computes the HMAC of `in_len` bytes of `input`, using the `digest` hash +// implementation and `key_len` bytes of `key` to key the HMAC, and outputs +// the HMAC to the buffer `output`, which is `out_len` bytes long. Returns the +// number of bytes written to `output` if successful, or 0 if `out_len` was too +// small. +size_t ComputeHmac(MessageDigest* digest, + const void* key, + size_t key_len, + const void* input, + size_t in_len, + void* output, + size_t out_len); +// Like the previous function, but creates a digest implementation based on +// the desired digest name `alg`, e.g. DIGEST_SHA_1. Returns 0 if there is no +// digest with the given name. +size_t ComputeHmac(absl::string_view alg, + const void* key, + size_t key_len, + const void* input, + size_t in_len, + void* output, + size_t out_len); +// Computes the HMAC of `input` using the `digest` hash implementation and `key` +// to key the HMAC, and returns it as a hex-encoded string. +std::string ComputeHmac(MessageDigest* digest, + absl::string_view key, + absl::string_view input); +// Like the previous function, but creates a digest implementation based on +// the desired digest name `alg`, e.g. DIGEST_SHA_1. Returns empty string if +// there is no digest with the given name. +std::string ComputeHmac(absl::string_view alg, + absl::string_view key, + absl::string_view input); +// Like the previous function, but returns an explicit result code. +bool ComputeHmac(absl::string_view alg, + absl::string_view key, + absl::string_view input, + std::string* output); + +} // namespace rtc + +#endif // RTC_BASE_MESSAGE_DIGEST_H_ diff --git a/third_party/libwebrtc/rtc_base/message_digest_unittest.cc b/third_party/libwebrtc/rtc_base/message_digest_unittest.cc new file mode 100644 index 0000000000..b296783d4e --- /dev/null +++ b/third_party/libwebrtc/rtc_base/message_digest_unittest.cc @@ -0,0 +1,156 @@ +/* + * Copyright 2012 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 "rtc_base/message_digest.h" + +#include "absl/strings/string_view.h" +#include "rtc_base/string_encode.h" +#include "test/gtest.h" + +namespace rtc { + +// Test vectors from RFC 1321. +TEST(MessageDigestTest, TestMd5Digest) { + // Test the string versions of the APIs. + EXPECT_EQ("d41d8cd98f00b204e9800998ecf8427e", ComputeDigest(DIGEST_MD5, "")); + EXPECT_EQ("900150983cd24fb0d6963f7d28e17f72", + ComputeDigest(DIGEST_MD5, "abc")); + EXPECT_EQ("c3fcd3d76192e4007dfb496cca67e13b", + ComputeDigest(DIGEST_MD5, "abcdefghijklmnopqrstuvwxyz")); + + // Test the raw buffer versions of the APIs; also check output buffer size. + char output[16]; + EXPECT_EQ(sizeof(output), + ComputeDigest(DIGEST_MD5, "abc", 3, output, sizeof(output))); + EXPECT_EQ("900150983cd24fb0d6963f7d28e17f72", + hex_encode(absl::string_view(output, sizeof(output)))); + EXPECT_EQ(0U, + ComputeDigest(DIGEST_MD5, "abc", 3, output, sizeof(output) - 1)); +} + +// Test vectors from RFC 3174. +TEST(MessageDigestTest, TestSha1Digest) { + // Test the string versions of the APIs. + EXPECT_EQ("da39a3ee5e6b4b0d3255bfef95601890afd80709", + ComputeDigest(DIGEST_SHA_1, "")); + EXPECT_EQ("a9993e364706816aba3e25717850c26c9cd0d89d", + ComputeDigest(DIGEST_SHA_1, "abc")); + EXPECT_EQ("84983e441c3bd26ebaae4aa1f95129e5e54670f1", + ComputeDigest( + DIGEST_SHA_1, + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq")); + + // Test the raw buffer versions of the APIs; also check output buffer size. + char output[20]; + EXPECT_EQ(sizeof(output), + ComputeDigest(DIGEST_SHA_1, "abc", 3, output, sizeof(output))); + EXPECT_EQ("a9993e364706816aba3e25717850c26c9cd0d89d", + hex_encode(absl::string_view(output, sizeof(output)))); + EXPECT_EQ(0U, + ComputeDigest(DIGEST_SHA_1, "abc", 3, output, sizeof(output) - 1)); +} + +// Test that we fail properly if a bad digest algorithm is specified. +TEST(MessageDigestTest, TestBadDigest) { + std::string output; + EXPECT_FALSE(ComputeDigest("sha-9000", "abc", &output)); + EXPECT_EQ("", ComputeDigest("sha-9000", "abc")); +} + +// Test vectors from RFC 2202. +TEST(MessageDigestTest, TestMd5Hmac) { + // Test the string versions of the APIs. + EXPECT_EQ("9294727a3638bb1c13f48ef8158bfc9d", + ComputeHmac(DIGEST_MD5, std::string(16, '\x0b'), "Hi There")); + EXPECT_EQ("750c783e6ab0b503eaa86e310a5db738", + ComputeHmac(DIGEST_MD5, "Jefe", "what do ya want for nothing?")); + EXPECT_EQ("56be34521d144c88dbb8c733f0e8b3f6", + ComputeHmac(DIGEST_MD5, std::string(16, '\xaa'), + std::string(50, '\xdd'))); + EXPECT_EQ( + "697eaf0aca3a3aea3a75164746ffaa79", + ComputeHmac(DIGEST_MD5, + "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" + "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19", + std::string(50, '\xcd'))); + EXPECT_EQ( + "56461ef2342edc00f9bab995690efd4c", + ComputeHmac(DIGEST_MD5, std::string(16, '\x0c'), "Test With Truncation")); + EXPECT_EQ( + "6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd", + ComputeHmac(DIGEST_MD5, std::string(80, '\xaa'), + "Test Using Larger Than Block-Size Key - Hash Key First")); + EXPECT_EQ("6f630fad67cda0ee1fb1f562db3aa53e", + ComputeHmac(DIGEST_MD5, std::string(80, '\xaa'), + "Test Using Larger Than Block-Size Key and Larger " + "Than One Block-Size Data")); + + // Test the raw buffer versions of the APIs; also check output buffer size. + std::string key(16, '\x0b'); + std::string input("Hi There"); + char output[16]; + EXPECT_EQ(sizeof(output), + ComputeHmac(DIGEST_MD5, key.c_str(), key.size(), input.c_str(), + input.size(), output, sizeof(output))); + EXPECT_EQ("9294727a3638bb1c13f48ef8158bfc9d", + hex_encode(absl::string_view(output, sizeof(output)))); + EXPECT_EQ(0U, ComputeHmac(DIGEST_MD5, key.c_str(), key.size(), input.c_str(), + input.size(), output, sizeof(output) - 1)); +} + +// Test vectors from RFC 2202. +TEST(MessageDigestTest, TestSha1Hmac) { + // Test the string versions of the APIs. + EXPECT_EQ("b617318655057264e28bc0b6fb378c8ef146be00", + ComputeHmac(DIGEST_SHA_1, std::string(20, '\x0b'), "Hi There")); + EXPECT_EQ("effcdf6ae5eb2fa2d27416d5f184df9c259a7c79", + ComputeHmac(DIGEST_SHA_1, "Jefe", "what do ya want for nothing?")); + EXPECT_EQ("125d7342b9ac11cd91a39af48aa17b4f63f175d3", + ComputeHmac(DIGEST_SHA_1, std::string(20, '\xaa'), + std::string(50, '\xdd'))); + EXPECT_EQ( + "4c9007f4026250c6bc8414f9bf50c86c2d7235da", + ComputeHmac(DIGEST_SHA_1, + "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" + "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19", + std::string(50, '\xcd'))); + EXPECT_EQ("4c1a03424b55e07fe7f27be1d58bb9324a9a5a04", + ComputeHmac(DIGEST_SHA_1, std::string(20, '\x0c'), + "Test With Truncation")); + EXPECT_EQ( + "aa4ae5e15272d00e95705637ce8a3b55ed402112", + ComputeHmac(DIGEST_SHA_1, std::string(80, '\xaa'), + "Test Using Larger Than Block-Size Key - Hash Key First")); + EXPECT_EQ("e8e99d0f45237d786d6bbaa7965c7808bbff1a91", + ComputeHmac(DIGEST_SHA_1, std::string(80, '\xaa'), + "Test Using Larger Than Block-Size Key and Larger " + "Than One Block-Size Data")); + + // Test the raw buffer versions of the APIs; also check output buffer size. + std::string key(20, '\x0b'); + std::string input("Hi There"); + char output[20]; + EXPECT_EQ(sizeof(output), + ComputeHmac(DIGEST_SHA_1, key.c_str(), key.size(), input.c_str(), + input.size(), output, sizeof(output))); + EXPECT_EQ("b617318655057264e28bc0b6fb378c8ef146be00", + hex_encode(absl::string_view(output, sizeof(output)))); + EXPECT_EQ(0U, + ComputeHmac(DIGEST_SHA_1, key.c_str(), key.size(), input.c_str(), + input.size(), output, sizeof(output) - 1)); +} + +TEST(MessageDigestTest, TestBadHmac) { + std::string output; + EXPECT_FALSE(ComputeHmac("sha-9000", "key", "abc", &output)); + EXPECT_EQ("", ComputeHmac("sha-9000", "key", "abc")); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/mod_ops_gn/moz.build b/third_party/libwebrtc/rtc_base/mod_ops_gn/moz.build new file mode 100644 index 0000000000..84e775fe74 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/mod_ops_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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("mod_ops_gn") diff --git a/third_party/libwebrtc/rtc_base/moving_max_counter_gn/moz.build b/third_party/libwebrtc/rtc_base/moving_max_counter_gn/moz.build new file mode 100644 index 0000000000..5cd827786e --- /dev/null +++ b/third_party/libwebrtc/rtc_base/moving_max_counter_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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("moving_max_counter_gn") diff --git a/third_party/libwebrtc/rtc_base/nat_server.cc b/third_party/libwebrtc/rtc_base/nat_server.cc new file mode 100644 index 0000000000..b818685efb --- /dev/null +++ b/third_party/libwebrtc/rtc_base/nat_server.cc @@ -0,0 +1,255 @@ +/* + * 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 "rtc_base/nat_server.h" + +#include <memory> + +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" +#include "rtc_base/nat_socket_factory.h" +#include "rtc_base/socket_adapters.h" + +namespace rtc { + +RouteCmp::RouteCmp(NAT* nat) : symmetric(nat->IsSymmetric()) {} + +size_t RouteCmp::operator()(const SocketAddressPair& r) const { + size_t h = r.source().Hash(); + if (symmetric) + h ^= r.destination().Hash(); + return h; +} + +bool RouteCmp::operator()(const SocketAddressPair& r1, + const SocketAddressPair& r2) const { + if (r1.source() < r2.source()) + return true; + if (r2.source() < r1.source()) + return false; + if (symmetric && (r1.destination() < r2.destination())) + return true; + if (symmetric && (r2.destination() < r1.destination())) + return false; + return false; +} + +AddrCmp::AddrCmp(NAT* nat) + : use_ip(nat->FiltersIP()), use_port(nat->FiltersPort()) {} + +size_t AddrCmp::operator()(const SocketAddress& a) const { + size_t h = 0; + if (use_ip) + h ^= HashIP(a.ipaddr()); + if (use_port) + h ^= a.port() | (a.port() << 16); + return h; +} + +bool AddrCmp::operator()(const SocketAddress& a1, + const SocketAddress& a2) const { + if (use_ip && (a1.ipaddr() < a2.ipaddr())) + return true; + if (use_ip && (a2.ipaddr() < a1.ipaddr())) + return false; + if (use_port && (a1.port() < a2.port())) + return true; + if (use_port && (a2.port() < a1.port())) + return false; + return false; +} + +// Proxy socket that will capture the external destination address intended for +// a TCP connection to the NAT server. +class NATProxyServerSocket : public AsyncProxyServerSocket { + public: + NATProxyServerSocket(Socket* socket) + : AsyncProxyServerSocket(socket, kNATEncodedIPv6AddressSize) { + BufferInput(true); + } + + void SendConnectResult(int err, const SocketAddress& addr) override { + char code = err ? 1 : 0; + BufferedReadAdapter::DirectSend(&code, sizeof(char)); + } + + protected: + void ProcessInput(char* data, size_t* len) override { + if (*len < 2) { + return; + } + + int family = data[1]; + RTC_DCHECK(family == AF_INET || family == AF_INET6); + if ((family == AF_INET && *len < kNATEncodedIPv4AddressSize) || + (family == AF_INET6 && *len < kNATEncodedIPv6AddressSize)) { + return; + } + + SocketAddress dest_addr; + size_t address_length = UnpackAddressFromNAT(data, *len, &dest_addr); + + *len -= address_length; + if (*len > 0) { + memmove(data, data + address_length, *len); + } + + bool remainder = (*len > 0); + BufferInput(false); + SignalConnectRequest(this, dest_addr); + if (remainder) { + SignalReadEvent(this); + } + } +}; + +class NATProxyServer : public ProxyServer { + public: + NATProxyServer(SocketFactory* int_factory, + const SocketAddress& int_addr, + SocketFactory* ext_factory, + const SocketAddress& ext_ip) + : ProxyServer(int_factory, int_addr, ext_factory, ext_ip) {} + + protected: + AsyncProxyServerSocket* WrapSocket(Socket* socket) override { + return new NATProxyServerSocket(socket); + } +}; + +NATServer::NATServer(NATType type, + SocketFactory* internal, + const SocketAddress& internal_udp_addr, + const SocketAddress& internal_tcp_addr, + SocketFactory* external, + const SocketAddress& external_ip) + : external_(external), external_ip_(external_ip.ipaddr(), 0) { + nat_ = NAT::Create(type); + + udp_server_socket_ = AsyncUDPSocket::Create(internal, internal_udp_addr); + udp_server_socket_->SignalReadPacket.connect(this, + &NATServer::OnInternalUDPPacket); + tcp_proxy_server_ = + new NATProxyServer(internal, internal_tcp_addr, external, external_ip); + + int_map_ = new InternalMap(RouteCmp(nat_)); + ext_map_ = new ExternalMap(); +} + +NATServer::~NATServer() { + for (InternalMap::iterator iter = int_map_->begin(); iter != int_map_->end(); + iter++) + delete iter->second; + + delete nat_; + delete udp_server_socket_; + delete tcp_proxy_server_; + delete int_map_; + delete ext_map_; +} + +void NATServer::OnInternalUDPPacket(AsyncPacketSocket* socket, + const char* buf, + size_t size, + const SocketAddress& addr, + const int64_t& /* packet_time_us */) { + // Read the intended destination from the wire. + SocketAddress dest_addr; + size_t length = UnpackAddressFromNAT(buf, size, &dest_addr); + + // Find the translation for these addresses (allocating one if necessary). + SocketAddressPair route(addr, dest_addr); + InternalMap::iterator iter = int_map_->find(route); + if (iter == int_map_->end()) { + Translate(route); + iter = int_map_->find(route); + } + RTC_DCHECK(iter != int_map_->end()); + + // Allow the destination to send packets back to the source. + iter->second->AllowlistInsert(dest_addr); + + // Send the packet to its intended destination. + rtc::PacketOptions options; + iter->second->socket->SendTo(buf + length, size - length, dest_addr, options); +} + +void NATServer::OnExternalUDPPacket(AsyncPacketSocket* socket, + const char* buf, + size_t size, + const SocketAddress& remote_addr, + const int64_t& /* packet_time_us */) { + SocketAddress local_addr = socket->GetLocalAddress(); + + // Find the translation for this addresses. + ExternalMap::iterator iter = ext_map_->find(local_addr); + RTC_DCHECK(iter != ext_map_->end()); + + // Allow the NAT to reject this packet. + if (ShouldFilterOut(iter->second, remote_addr)) { + RTC_LOG(LS_INFO) << "Packet from " << remote_addr.ToSensitiveString() + << " was filtered out by the NAT."; + return; + } + + // Forward this packet to the internal address. + // First prepend the address in a quasi-STUN format. + std::unique_ptr<char[]> real_buf(new char[size + kNATEncodedIPv6AddressSize]); + size_t addrlength = PackAddressForNAT( + real_buf.get(), size + kNATEncodedIPv6AddressSize, remote_addr); + // Copy the data part after the address. + rtc::PacketOptions options; + memcpy(real_buf.get() + addrlength, buf, size); + udp_server_socket_->SendTo(real_buf.get(), size + addrlength, + iter->second->route.source(), options); +} + +void NATServer::Translate(const SocketAddressPair& route) { + AsyncUDPSocket* socket = AsyncUDPSocket::Create(external_, external_ip_); + + if (!socket) { + RTC_LOG(LS_ERROR) << "Couldn't find a free port!"; + return; + } + + TransEntry* entry = new TransEntry(route, socket, nat_); + (*int_map_)[route] = entry; + (*ext_map_)[socket->GetLocalAddress()] = entry; + socket->SignalReadPacket.connect(this, &NATServer::OnExternalUDPPacket); +} + +bool NATServer::ShouldFilterOut(TransEntry* entry, + const SocketAddress& ext_addr) { + return entry->AllowlistContains(ext_addr); +} + +NATServer::TransEntry::TransEntry(const SocketAddressPair& r, + AsyncUDPSocket* s, + NAT* nat) + : route(r), socket(s) { + allowlist = new AddressSet(AddrCmp(nat)); +} + +NATServer::TransEntry::~TransEntry() { + delete allowlist; + delete socket; +} + +void NATServer::TransEntry::AllowlistInsert(const SocketAddress& addr) { + webrtc::MutexLock lock(&mutex_); + allowlist->insert(addr); +} + +bool NATServer::TransEntry::AllowlistContains(const SocketAddress& ext_addr) { + webrtc::MutexLock lock(&mutex_); + return allowlist->find(ext_addr) == allowlist->end(); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/nat_server.h b/third_party/libwebrtc/rtc_base/nat_server.h new file mode 100644 index 0000000000..acbd62a092 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/nat_server.h @@ -0,0 +1,131 @@ +/* + * 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 RTC_BASE_NAT_SERVER_H_ +#define RTC_BASE_NAT_SERVER_H_ + +#include <map> +#include <set> + +#include "rtc_base/async_udp_socket.h" +#include "rtc_base/nat_types.h" +#include "rtc_base/proxy_server.h" +#include "rtc_base/socket_address_pair.h" +#include "rtc_base/socket_factory.h" +#include "rtc_base/synchronization/mutex.h" +#include "rtc_base/thread.h" + +namespace rtc { + +// Change how routes (socketaddress pairs) are compared based on the type of +// NAT. The NAT server maintains a hashtable of the routes that it knows +// about. So these affect which routes are treated the same. +struct RouteCmp { + explicit RouteCmp(NAT* nat); + size_t operator()(const SocketAddressPair& r) const; + bool operator()(const SocketAddressPair& r1, + const SocketAddressPair& r2) const; + + bool symmetric; +}; + +// Changes how addresses are compared based on the filtering rules of the NAT. +struct AddrCmp { + explicit AddrCmp(NAT* nat); + size_t operator()(const SocketAddress& r) const; + bool operator()(const SocketAddress& r1, const SocketAddress& r2) const; + + bool use_ip; + bool use_port; +}; + +// Implements the NAT device. It listens for packets on the internal network, +// translates them, and sends them out over the external network. +// +// TCP connections initiated from the internal side of the NAT server are +// also supported, by making a connection to the NAT server's TCP address and +// then sending the remote address in quasi-STUN format. The connection status +// will be indicated back to the client as a 1 byte status code, where '0' +// indicates success. + +const int NAT_SERVER_UDP_PORT = 4237; +const int NAT_SERVER_TCP_PORT = 4238; + +class NATServer : public sigslot::has_slots<> { + public: + NATServer(NATType type, + SocketFactory* internal, + const SocketAddress& internal_udp_addr, + const SocketAddress& internal_tcp_addr, + SocketFactory* external, + const SocketAddress& external_ip); + ~NATServer() override; + + NATServer(const NATServer&) = delete; + NATServer& operator=(const NATServer&) = delete; + + SocketAddress internal_udp_address() const { + return udp_server_socket_->GetLocalAddress(); + } + + SocketAddress internal_tcp_address() const { + return tcp_proxy_server_->GetServerAddress(); + } + + // Packets received on one of the networks. + void OnInternalUDPPacket(AsyncPacketSocket* socket, + const char* buf, + size_t size, + const SocketAddress& addr, + const int64_t& packet_time_us); + void OnExternalUDPPacket(AsyncPacketSocket* socket, + const char* buf, + size_t size, + const SocketAddress& remote_addr, + const int64_t& packet_time_us); + + private: + typedef std::set<SocketAddress, AddrCmp> AddressSet; + + /* Records a translation and the associated external socket. */ + struct TransEntry { + TransEntry(const SocketAddressPair& r, AsyncUDPSocket* s, NAT* nat); + ~TransEntry(); + + void AllowlistInsert(const SocketAddress& addr); + bool AllowlistContains(const SocketAddress& ext_addr); + + SocketAddressPair route; + AsyncUDPSocket* socket; + AddressSet* allowlist; + webrtc::Mutex mutex_; + }; + + typedef std::map<SocketAddressPair, TransEntry*, RouteCmp> InternalMap; + typedef std::map<SocketAddress, TransEntry*> ExternalMap; + + /* Creates a new entry that translates the given route. */ + void Translate(const SocketAddressPair& route); + + /* Determines whether the NAT would filter out a packet from this address. */ + bool ShouldFilterOut(TransEntry* entry, const SocketAddress& ext_addr); + + NAT* nat_; + SocketFactory* external_; + SocketAddress external_ip_; + AsyncUDPSocket* udp_server_socket_; + ProxyServer* tcp_proxy_server_; + InternalMap* int_map_; + ExternalMap* ext_map_; +}; + +} // namespace rtc + +#endif // RTC_BASE_NAT_SERVER_H_ diff --git a/third_party/libwebrtc/rtc_base/nat_socket_factory.cc b/third_party/libwebrtc/rtc_base/nat_socket_factory.cc new file mode 100644 index 0000000000..fe021b95ff --- /dev/null +++ b/third_party/libwebrtc/rtc_base/nat_socket_factory.cc @@ -0,0 +1,515 @@ +/* + * 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 "rtc_base/nat_socket_factory.h" + +#include "rtc_base/arraysize.h" +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" +#include "rtc_base/nat_server.h" +#include "rtc_base/virtual_socket_server.h" + +namespace rtc { + +// Packs the given socketaddress into the buffer in buf, in the quasi-STUN +// format that the natserver uses. +// Returns 0 if an invalid address is passed. +size_t PackAddressForNAT(char* buf, + size_t buf_size, + const SocketAddress& remote_addr) { + const IPAddress& ip = remote_addr.ipaddr(); + int family = ip.family(); + buf[0] = 0; + buf[1] = family; + // Writes the port. + *(reinterpret_cast<uint16_t*>(&buf[2])) = HostToNetwork16(remote_addr.port()); + if (family == AF_INET) { + RTC_DCHECK(buf_size >= kNATEncodedIPv4AddressSize); + in_addr v4addr = ip.ipv4_address(); + memcpy(&buf[4], &v4addr, kNATEncodedIPv4AddressSize - 4); + return kNATEncodedIPv4AddressSize; + } else if (family == AF_INET6) { + RTC_DCHECK(buf_size >= kNATEncodedIPv6AddressSize); + in6_addr v6addr = ip.ipv6_address(); + memcpy(&buf[4], &v6addr, kNATEncodedIPv6AddressSize - 4); + return kNATEncodedIPv6AddressSize; + } + return 0U; +} + +// Decodes the remote address from a packet that has been encoded with the nat's +// quasi-STUN format. Returns the length of the address (i.e., the offset into +// data where the original packet starts). +size_t UnpackAddressFromNAT(const char* buf, + size_t buf_size, + SocketAddress* remote_addr) { + RTC_DCHECK(buf_size >= 8); + RTC_DCHECK(buf[0] == 0); + int family = buf[1]; + uint16_t port = + NetworkToHost16(*(reinterpret_cast<const uint16_t*>(&buf[2]))); + if (family == AF_INET) { + const in_addr* v4addr = reinterpret_cast<const in_addr*>(&buf[4]); + *remote_addr = SocketAddress(IPAddress(*v4addr), port); + return kNATEncodedIPv4AddressSize; + } else if (family == AF_INET6) { + RTC_DCHECK(buf_size >= 20); + const in6_addr* v6addr = reinterpret_cast<const in6_addr*>(&buf[4]); + *remote_addr = SocketAddress(IPAddress(*v6addr), port); + return kNATEncodedIPv6AddressSize; + } + return 0U; +} + +// NATSocket +class NATSocket : public Socket, public sigslot::has_slots<> { + public: + explicit NATSocket(NATInternalSocketFactory* sf, int family, int type) + : sf_(sf), + family_(family), + type_(type), + connected_(false), + socket_(nullptr), + buf_(nullptr), + size_(0) {} + + ~NATSocket() override { + delete socket_; + delete[] buf_; + } + + SocketAddress GetLocalAddress() const override { + return (socket_) ? socket_->GetLocalAddress() : SocketAddress(); + } + + SocketAddress GetRemoteAddress() const override { + return remote_addr_; // will be NIL if not connected + } + + int Bind(const SocketAddress& addr) override { + if (socket_) { // already bound, bubble up error + return -1; + } + + return BindInternal(addr); + } + + int Connect(const SocketAddress& addr) override { + int result = 0; + // If we're not already bound (meaning `socket_` is null), bind to ANY + // address. + if (!socket_) { + result = BindInternal(SocketAddress(GetAnyIP(family_), 0)); + if (result < 0) { + return result; + } + } + + if (type_ == SOCK_STREAM) { + result = socket_->Connect(server_addr_.IsNil() ? addr : server_addr_); + } else { + connected_ = true; + } + + if (result >= 0) { + remote_addr_ = addr; + } + + return result; + } + + int Send(const void* data, size_t size) override { + RTC_DCHECK(connected_); + return SendTo(data, size, remote_addr_); + } + + int SendTo(const void* data, + size_t size, + const SocketAddress& addr) override { + RTC_DCHECK(!connected_ || addr == remote_addr_); + if (server_addr_.IsNil() || type_ == SOCK_STREAM) { + return socket_->SendTo(data, size, addr); + } + // This array will be too large for IPv4 packets, but only by 12 bytes. + std::unique_ptr<char[]> buf(new char[size + kNATEncodedIPv6AddressSize]); + size_t addrlength = + PackAddressForNAT(buf.get(), size + kNATEncodedIPv6AddressSize, addr); + size_t encoded_size = size + addrlength; + memcpy(buf.get() + addrlength, data, size); + int result = socket_->SendTo(buf.get(), encoded_size, server_addr_); + if (result >= 0) { + RTC_DCHECK(result == static_cast<int>(encoded_size)); + result = result - static_cast<int>(addrlength); + } + return result; + } + + int Recv(void* data, size_t size, int64_t* timestamp) override { + SocketAddress addr; + return RecvFrom(data, size, &addr, timestamp); + } + + int RecvFrom(void* data, + size_t size, + SocketAddress* out_addr, + int64_t* timestamp) override { + if (server_addr_.IsNil() || type_ == SOCK_STREAM) { + return socket_->RecvFrom(data, size, out_addr, timestamp); + } + // Make sure we have enough room to read the requested amount plus the + // largest possible header address. + SocketAddress remote_addr; + Grow(size + kNATEncodedIPv6AddressSize); + + // Read the packet from the socket. + int result = socket_->RecvFrom(buf_, size_, &remote_addr, timestamp); + if (result >= 0) { + RTC_DCHECK(remote_addr == server_addr_); + + // TODO: we need better framing so we know how many bytes we can + // return before we need to read the next address. For UDP, this will be + // fine as long as the reader always reads everything in the packet. + RTC_DCHECK((size_t)result < size_); + + // Decode the wire packet into the actual results. + SocketAddress real_remote_addr; + size_t addrlength = UnpackAddressFromNAT(buf_, result, &real_remote_addr); + memcpy(data, buf_ + addrlength, result - addrlength); + + // Make sure this packet should be delivered before returning it. + if (!connected_ || (real_remote_addr == remote_addr_)) { + if (out_addr) + *out_addr = real_remote_addr; + result = result - static_cast<int>(addrlength); + } else { + RTC_LOG(LS_ERROR) << "Dropping packet from unknown remote address: " + << real_remote_addr.ToString(); + result = 0; // Tell the caller we didn't read anything + } + } + + return result; + } + + int Close() override { + int result = 0; + if (socket_) { + result = socket_->Close(); + if (result >= 0) { + connected_ = false; + remote_addr_ = SocketAddress(); + delete socket_; + socket_ = nullptr; + } + } + return result; + } + + int Listen(int backlog) override { return socket_->Listen(backlog); } + Socket* Accept(SocketAddress* paddr) override { + return socket_->Accept(paddr); + } + int GetError() const override { + return socket_ ? socket_->GetError() : error_; + } + void SetError(int error) override { + if (socket_) { + socket_->SetError(error); + } else { + error_ = error; + } + } + ConnState GetState() const override { + return connected_ ? CS_CONNECTED : CS_CLOSED; + } + int GetOption(Option opt, int* value) override { + return socket_ ? socket_->GetOption(opt, value) : -1; + } + int SetOption(Option opt, int value) override { + return socket_ ? socket_->SetOption(opt, value) : -1; + } + + void OnConnectEvent(Socket* socket) { + // If we're NATed, we need to send a message with the real addr to use. + RTC_DCHECK(socket == socket_); + if (server_addr_.IsNil()) { + connected_ = true; + SignalConnectEvent(this); + } else { + SendConnectRequest(); + } + } + void OnReadEvent(Socket* socket) { + // If we're NATed, we need to process the connect reply. + RTC_DCHECK(socket == socket_); + if (type_ == SOCK_STREAM && !server_addr_.IsNil() && !connected_) { + HandleConnectReply(); + } else { + SignalReadEvent(this); + } + } + void OnWriteEvent(Socket* socket) { + RTC_DCHECK(socket == socket_); + SignalWriteEvent(this); + } + void OnCloseEvent(Socket* socket, int error) { + RTC_DCHECK(socket == socket_); + SignalCloseEvent(this, error); + } + + private: + int BindInternal(const SocketAddress& addr) { + RTC_DCHECK(!socket_); + + int result; + socket_ = sf_->CreateInternalSocket(family_, type_, addr, &server_addr_); + result = (socket_) ? socket_->Bind(addr) : -1; + if (result >= 0) { + socket_->SignalConnectEvent.connect(this, &NATSocket::OnConnectEvent); + socket_->SignalReadEvent.connect(this, &NATSocket::OnReadEvent); + socket_->SignalWriteEvent.connect(this, &NATSocket::OnWriteEvent); + socket_->SignalCloseEvent.connect(this, &NATSocket::OnCloseEvent); + } else { + server_addr_.Clear(); + delete socket_; + socket_ = nullptr; + } + + return result; + } + + // Makes sure the buffer is at least the given size. + void Grow(size_t new_size) { + if (size_ < new_size) { + delete[] buf_; + size_ = new_size; + buf_ = new char[size_]; + } + } + + // Sends the destination address to the server to tell it to connect. + void SendConnectRequest() { + char buf[kNATEncodedIPv6AddressSize]; + size_t length = PackAddressForNAT(buf, arraysize(buf), remote_addr_); + socket_->Send(buf, length); + } + + // Handles the byte sent back from the server and fires the appropriate event. + void HandleConnectReply() { + char code; + socket_->Recv(&code, sizeof(code), nullptr); + if (code == 0) { + connected_ = true; + SignalConnectEvent(this); + } else { + Close(); + SignalCloseEvent(this, code); + } + } + + NATInternalSocketFactory* sf_; + int family_; + int type_; + bool connected_; + SocketAddress remote_addr_; + SocketAddress server_addr_; // address of the NAT server + Socket* socket_; + // Need to hold error in case it occurs before the socket is created. + int error_ = 0; + char* buf_; + size_t size_; +}; + +// NATSocketFactory +NATSocketFactory::NATSocketFactory(SocketFactory* factory, + const SocketAddress& nat_udp_addr, + const SocketAddress& nat_tcp_addr) + : factory_(factory), + nat_udp_addr_(nat_udp_addr), + nat_tcp_addr_(nat_tcp_addr) {} + +Socket* NATSocketFactory::CreateSocket(int family, int type) { + return new NATSocket(this, family, type); +} + +Socket* NATSocketFactory::CreateInternalSocket(int family, + int type, + const SocketAddress& local_addr, + SocketAddress* nat_addr) { + if (type == SOCK_STREAM) { + *nat_addr = nat_tcp_addr_; + } else { + *nat_addr = nat_udp_addr_; + } + return factory_->CreateSocket(family, type); +} + +// NATSocketServer +NATSocketServer::NATSocketServer(SocketServer* server) + : server_(server), msg_queue_(nullptr) {} + +NATSocketServer::Translator* NATSocketServer::GetTranslator( + const SocketAddress& ext_ip) { + return nats_.Get(ext_ip); +} + +NATSocketServer::Translator* NATSocketServer::AddTranslator( + const SocketAddress& ext_ip, + const SocketAddress& int_ip, + NATType type) { + // Fail if a translator already exists with this extternal address. + if (nats_.Get(ext_ip)) + return nullptr; + + return nats_.Add(ext_ip, new Translator(this, type, int_ip, server_, ext_ip)); +} + +void NATSocketServer::RemoveTranslator(const SocketAddress& ext_ip) { + nats_.Remove(ext_ip); +} + +Socket* NATSocketServer::CreateSocket(int family, int type) { + return new NATSocket(this, family, type); +} + +void NATSocketServer::SetMessageQueue(Thread* queue) { + msg_queue_ = queue; + server_->SetMessageQueue(queue); +} + +bool NATSocketServer::Wait(webrtc::TimeDelta max_wait_duration, + bool process_io) { + return server_->Wait(max_wait_duration, process_io); +} + +void NATSocketServer::WakeUp() { + server_->WakeUp(); +} + +Socket* NATSocketServer::CreateInternalSocket(int family, + int type, + const SocketAddress& local_addr, + SocketAddress* nat_addr) { + Socket* socket = nullptr; + Translator* nat = nats_.FindClient(local_addr); + if (nat) { + socket = nat->internal_factory()->CreateSocket(family, type); + *nat_addr = (type == SOCK_STREAM) ? nat->internal_tcp_address() + : nat->internal_udp_address(); + } else { + socket = server_->CreateSocket(family, type); + } + return socket; +} + +// NATSocketServer::Translator +NATSocketServer::Translator::Translator(NATSocketServer* server, + NATType type, + const SocketAddress& int_ip, + SocketFactory* ext_factory, + const SocketAddress& ext_ip) + : server_(server) { + // Create a new private network, and a NATServer running on the private + // network that bridges to the external network. Also tell the private + // network to use the same message queue as us. + internal_server_ = std::make_unique<VirtualSocketServer>(); + internal_server_->SetMessageQueue(server_->queue()); + nat_server_ = std::make_unique<NATServer>( + type, internal_server_.get(), int_ip, int_ip, ext_factory, ext_ip); +} + +NATSocketServer::Translator::~Translator() { + internal_server_->SetMessageQueue(nullptr); +} + +NATSocketServer::Translator* NATSocketServer::Translator::GetTranslator( + const SocketAddress& ext_ip) { + return nats_.Get(ext_ip); +} + +NATSocketServer::Translator* NATSocketServer::Translator::AddTranslator( + const SocketAddress& ext_ip, + const SocketAddress& int_ip, + NATType type) { + // Fail if a translator already exists with this extternal address. + if (nats_.Get(ext_ip)) + return nullptr; + + AddClient(ext_ip); + return nats_.Add(ext_ip, + new Translator(server_, type, int_ip, server_, ext_ip)); +} +void NATSocketServer::Translator::RemoveTranslator( + const SocketAddress& ext_ip) { + nats_.Remove(ext_ip); + RemoveClient(ext_ip); +} + +bool NATSocketServer::Translator::AddClient(const SocketAddress& int_ip) { + // Fail if a client already exists with this internal address. + if (clients_.find(int_ip) != clients_.end()) + return false; + + clients_.insert(int_ip); + return true; +} + +void NATSocketServer::Translator::RemoveClient(const SocketAddress& int_ip) { + std::set<SocketAddress>::iterator it = clients_.find(int_ip); + if (it != clients_.end()) { + clients_.erase(it); + } +} + +NATSocketServer::Translator* NATSocketServer::Translator::FindClient( + const SocketAddress& int_ip) { + // See if we have the requested IP, or any of our children do. + return (clients_.find(int_ip) != clients_.end()) ? this + : nats_.FindClient(int_ip); +} + +// NATSocketServer::TranslatorMap +NATSocketServer::TranslatorMap::~TranslatorMap() { + for (TranslatorMap::iterator it = begin(); it != end(); ++it) { + delete it->second; + } +} + +NATSocketServer::Translator* NATSocketServer::TranslatorMap::Get( + const SocketAddress& ext_ip) { + TranslatorMap::iterator it = find(ext_ip); + return (it != end()) ? it->second : nullptr; +} + +NATSocketServer::Translator* NATSocketServer::TranslatorMap::Add( + const SocketAddress& ext_ip, + Translator* nat) { + (*this)[ext_ip] = nat; + return nat; +} + +void NATSocketServer::TranslatorMap::Remove(const SocketAddress& ext_ip) { + TranslatorMap::iterator it = find(ext_ip); + if (it != end()) { + delete it->second; + erase(it); + } +} + +NATSocketServer::Translator* NATSocketServer::TranslatorMap::FindClient( + const SocketAddress& int_ip) { + Translator* nat = nullptr; + for (TranslatorMap::iterator it = begin(); it != end() && !nat; ++it) { + nat = it->second->FindClient(int_ip); + } + return nat; +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/nat_socket_factory.h b/third_party/libwebrtc/rtc_base/nat_socket_factory.h new file mode 100644 index 0000000000..0b301b5844 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/nat_socket_factory.h @@ -0,0 +1,179 @@ +/* + * 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 RTC_BASE_NAT_SOCKET_FACTORY_H_ +#define RTC_BASE_NAT_SOCKET_FACTORY_H_ + +#include <stddef.h> + +#include <map> +#include <memory> +#include <set> + +#include "rtc_base/nat_server.h" +#include "rtc_base/nat_types.h" +#include "rtc_base/socket.h" +#include "rtc_base/socket_address.h" +#include "rtc_base/socket_factory.h" +#include "rtc_base/socket_server.h" +#include "rtc_base/thread.h" + +namespace rtc { + +const size_t kNATEncodedIPv4AddressSize = 8U; +const size_t kNATEncodedIPv6AddressSize = 20U; + +// Used by the NAT socket implementation. +class NATInternalSocketFactory { + public: + virtual ~NATInternalSocketFactory() {} + virtual Socket* CreateInternalSocket(int family, + int type, + const SocketAddress& local_addr, + SocketAddress* nat_addr) = 0; +}; + +// Creates sockets that will send all traffic through a NAT, using an existing +// NATServer instance running at nat_addr. The actual data is sent using sockets +// from a socket factory, given to the constructor. +class NATSocketFactory : public SocketFactory, public NATInternalSocketFactory { + public: + NATSocketFactory(SocketFactory* factory, + const SocketAddress& nat_udp_addr, + const SocketAddress& nat_tcp_addr); + + NATSocketFactory(const NATSocketFactory&) = delete; + NATSocketFactory& operator=(const NATSocketFactory&) = delete; + + // SocketFactory implementation + Socket* CreateSocket(int family, int type) override; + + // NATInternalSocketFactory implementation + Socket* CreateInternalSocket(int family, + int type, + const SocketAddress& local_addr, + SocketAddress* nat_addr) override; + + private: + SocketFactory* factory_; + SocketAddress nat_udp_addr_; + SocketAddress nat_tcp_addr_; +}; + +// Creates sockets that will send traffic through a NAT depending on what +// address they bind to. This can be used to simulate a client on a NAT sending +// to a client that is not behind a NAT. +// Note that the internal addresses of clients must be unique. This is because +// there is only one socketserver per thread, and the Bind() address is used to +// figure out which NAT (if any) the socket should talk to. +// +// Example with 3 NATs (2 cascaded), and 3 clients. +// ss->AddTranslator("1.2.3.4", "192.168.0.1", NAT_ADDR_RESTRICTED); +// ss->AddTranslator("99.99.99.99", "10.0.0.1", NAT_SYMMETRIC)-> +// AddTranslator("10.0.0.2", "192.168.1.1", NAT_OPEN_CONE); +// ss->GetTranslator("1.2.3.4")->AddClient("1.2.3.4", "192.168.0.2"); +// ss->GetTranslator("99.99.99.99")->AddClient("10.0.0.3"); +// ss->GetTranslator("99.99.99.99")->GetTranslator("10.0.0.2")-> +// AddClient("192.168.1.2"); +class NATSocketServer : public SocketServer, public NATInternalSocketFactory { + public: + class Translator; + + // holds a list of NATs + class TranslatorMap : private std::map<SocketAddress, Translator*> { + public: + ~TranslatorMap(); + Translator* Get(const SocketAddress& ext_ip); + Translator* Add(const SocketAddress& ext_ip, Translator*); + void Remove(const SocketAddress& ext_ip); + Translator* FindClient(const SocketAddress& int_ip); + }; + + // a specific NAT + class Translator { + public: + Translator(NATSocketServer* server, + NATType type, + const SocketAddress& int_addr, + SocketFactory* ext_factory, + const SocketAddress& ext_addr); + ~Translator(); + + SocketFactory* internal_factory() { return internal_server_.get(); } + SocketAddress internal_udp_address() const { + return nat_server_->internal_udp_address(); + } + SocketAddress internal_tcp_address() const { + return SocketAddress(); // nat_server_->internal_tcp_address(); + } + + Translator* GetTranslator(const SocketAddress& ext_ip); + Translator* AddTranslator(const SocketAddress& ext_ip, + const SocketAddress& int_ip, + NATType type); + void RemoveTranslator(const SocketAddress& ext_ip); + + bool AddClient(const SocketAddress& int_ip); + void RemoveClient(const SocketAddress& int_ip); + + // Looks for the specified client in this or a child NAT. + Translator* FindClient(const SocketAddress& int_ip); + + private: + NATSocketServer* server_; + std::unique_ptr<SocketServer> internal_server_; + std::unique_ptr<NATServer> nat_server_; + TranslatorMap nats_; + std::set<SocketAddress> clients_; + }; + + explicit NATSocketServer(SocketServer* ss); + + NATSocketServer(const NATSocketServer&) = delete; + NATSocketServer& operator=(const NATSocketServer&) = delete; + + SocketServer* socketserver() { return server_; } + Thread* queue() { return msg_queue_; } + + Translator* GetTranslator(const SocketAddress& ext_ip); + Translator* AddTranslator(const SocketAddress& ext_ip, + const SocketAddress& int_ip, + NATType type); + void RemoveTranslator(const SocketAddress& ext_ip); + + // SocketServer implementation + Socket* CreateSocket(int family, int type) override; + + void SetMessageQueue(Thread* queue) override; + bool Wait(webrtc::TimeDelta max_wait_duration, bool process_io) override; + void WakeUp() override; + + // NATInternalSocketFactory implementation + Socket* CreateInternalSocket(int family, + int type, + const SocketAddress& local_addr, + SocketAddress* nat_addr) override; + + private: + SocketServer* server_; + Thread* msg_queue_; + TranslatorMap nats_; +}; + +// Free-standing NAT helper functions. +size_t PackAddressForNAT(char* buf, + size_t buf_size, + const SocketAddress& remote_addr); +size_t UnpackAddressFromNAT(const char* buf, + size_t buf_size, + SocketAddress* remote_addr); +} // namespace rtc + +#endif // RTC_BASE_NAT_SOCKET_FACTORY_H_ diff --git a/third_party/libwebrtc/rtc_base/nat_types.cc b/third_party/libwebrtc/rtc_base/nat_types.cc new file mode 100644 index 0000000000..9ca03608e8 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/nat_types.cc @@ -0,0 +1,61 @@ +/* + * 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 "rtc_base/nat_types.h" + +#include "rtc_base/checks.h" + +namespace rtc { + +class SymmetricNAT : public NAT { + public: + bool IsSymmetric() override { return true; } + bool FiltersIP() override { return true; } + bool FiltersPort() override { return true; } +}; + +class OpenConeNAT : public NAT { + public: + bool IsSymmetric() override { return false; } + bool FiltersIP() override { return false; } + bool FiltersPort() override { return false; } +}; + +class AddressRestrictedNAT : public NAT { + public: + bool IsSymmetric() override { return false; } + bool FiltersIP() override { return true; } + bool FiltersPort() override { return false; } +}; + +class PortRestrictedNAT : public NAT { + public: + bool IsSymmetric() override { return false; } + bool FiltersIP() override { return true; } + bool FiltersPort() override { return true; } +}; + +NAT* NAT::Create(NATType type) { + switch (type) { + case NAT_OPEN_CONE: + return new OpenConeNAT(); + case NAT_ADDR_RESTRICTED: + return new AddressRestrictedNAT(); + case NAT_PORT_RESTRICTED: + return new PortRestrictedNAT(); + case NAT_SYMMETRIC: + return new SymmetricNAT(); + default: + RTC_DCHECK_NOTREACHED(); + return 0; + } +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/nat_types.h b/third_party/libwebrtc/rtc_base/nat_types.h new file mode 100644 index 0000000000..60e7fbd4b4 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/nat_types.h @@ -0,0 +1,47 @@ +/* + * 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 RTC_BASE_NAT_TYPES_H_ +#define RTC_BASE_NAT_TYPES_H_ + +namespace rtc { + +/* Identifies each type of NAT that can be simulated. */ +enum NATType { + NAT_OPEN_CONE, + NAT_ADDR_RESTRICTED, + NAT_PORT_RESTRICTED, + NAT_SYMMETRIC +}; + +// Implements the rules for each specific type of NAT. +class NAT { + public: + virtual ~NAT() {} + + // Determines whether this NAT uses both source and destination address when + // checking whether a mapping already exists. + virtual bool IsSymmetric() = 0; + + // Determines whether this NAT drops packets received from a different IP + // the one last sent to. + virtual bool FiltersIP() = 0; + + // Determines whether this NAT drops packets received from a different port + // the one last sent to. + virtual bool FiltersPort() = 0; + + // Returns an implementation of the given type of NAT. + static NAT* Create(NATType type); +}; + +} // namespace rtc + +#endif // RTC_BASE_NAT_TYPES_H_ diff --git a/third_party/libwebrtc/rtc_base/nat_unittest.cc b/third_party/libwebrtc/rtc_base/nat_unittest.cc new file mode 100644 index 0000000000..19e53543ba --- /dev/null +++ b/third_party/libwebrtc/rtc_base/nat_unittest.cc @@ -0,0 +1,408 @@ +/* + * 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 <string.h> + +#include <algorithm> +#include <memory> +#include <string> +#include <vector> + +#include "absl/memory/memory.h" +#include "rtc_base/async_packet_socket.h" +#include "rtc_base/async_tcp_socket.h" +#include "rtc_base/async_udp_socket.h" +#include "rtc_base/gunit.h" +#include "rtc_base/ip_address.h" +#include "rtc_base/logging.h" +#include "rtc_base/nat_server.h" +#include "rtc_base/nat_socket_factory.h" +#include "rtc_base/nat_types.h" +#include "rtc_base/net_helpers.h" +#include "rtc_base/net_test_helpers.h" +#include "rtc_base/network.h" +#include "rtc_base/physical_socket_server.h" +#include "rtc_base/socket.h" +#include "rtc_base/socket_address.h" +#include "rtc_base/socket_factory.h" +#include "rtc_base/socket_server.h" +#include "rtc_base/test_client.h" +#include "rtc_base/third_party/sigslot/sigslot.h" +#include "rtc_base/thread.h" +#include "rtc_base/virtual_socket_server.h" +#include "test/gtest.h" +#include "test/scoped_key_value_config.h" + +namespace rtc { +namespace { + +bool CheckReceive(TestClient* client, + bool should_receive, + const char* buf, + size_t size) { + return (should_receive) ? client->CheckNextPacket(buf, size, 0) + : client->CheckNoPacket(); +} + +TestClient* CreateTestClient(SocketFactory* factory, + const SocketAddress& local_addr) { + return new TestClient( + absl::WrapUnique(AsyncUDPSocket::Create(factory, local_addr))); +} + +TestClient* CreateTCPTestClient(Socket* socket) { + return new TestClient(std::make_unique<AsyncTCPSocket>(socket)); +} + +// Tests that when sending from internal_addr to external_addrs through the +// NAT type specified by nat_type, all external addrs receive the sent packet +// and, if exp_same is true, all use the same mapped-address on the NAT. +void TestSend(SocketServer* internal, + const SocketAddress& internal_addr, + SocketServer* external, + const SocketAddress external_addrs[4], + NATType nat_type, + bool exp_same) { + Thread th_int(internal); + Thread th_ext(external); + + SocketAddress server_addr = internal_addr; + server_addr.SetPort(0); // Auto-select a port + NATServer* nat = new NATServer(nat_type, internal, server_addr, server_addr, + external, external_addrs[0]); + NATSocketFactory* natsf = new NATSocketFactory( + internal, nat->internal_udp_address(), nat->internal_tcp_address()); + + TestClient* in = CreateTestClient(natsf, internal_addr); + TestClient* out[4]; + for (int i = 0; i < 4; i++) + out[i] = CreateTestClient(external, external_addrs[i]); + + th_int.Start(); + th_ext.Start(); + + const char* buf = "filter_test"; + size_t len = strlen(buf); + + in->SendTo(buf, len, out[0]->address()); + SocketAddress trans_addr; + EXPECT_TRUE(out[0]->CheckNextPacket(buf, len, &trans_addr)); + + for (int i = 1; i < 4; i++) { + in->SendTo(buf, len, out[i]->address()); + SocketAddress trans_addr2; + EXPECT_TRUE(out[i]->CheckNextPacket(buf, len, &trans_addr2)); + bool are_same = (trans_addr == trans_addr2); + ASSERT_EQ(are_same, exp_same) << "same translated address"; + ASSERT_NE(AF_UNSPEC, trans_addr.family()); + ASSERT_NE(AF_UNSPEC, trans_addr2.family()); + } + + th_int.Stop(); + th_ext.Stop(); + + delete nat; + delete natsf; + delete in; + for (int i = 0; i < 4; i++) + delete out[i]; +} + +// Tests that when sending from external_addrs to internal_addr, the packet +// is delivered according to the specified filter_ip and filter_port rules. +void TestRecv(SocketServer* internal, + const SocketAddress& internal_addr, + SocketServer* external, + const SocketAddress external_addrs[4], + NATType nat_type, + bool filter_ip, + bool filter_port) { + Thread th_int(internal); + Thread th_ext(external); + + SocketAddress server_addr = internal_addr; + server_addr.SetPort(0); // Auto-select a port + NATServer* nat = new NATServer(nat_type, internal, server_addr, server_addr, + external, external_addrs[0]); + NATSocketFactory* natsf = new NATSocketFactory( + internal, nat->internal_udp_address(), nat->internal_tcp_address()); + + TestClient* in = CreateTestClient(natsf, internal_addr); + TestClient* out[4]; + for (int i = 0; i < 4; i++) + out[i] = CreateTestClient(external, external_addrs[i]); + + th_int.Start(); + th_ext.Start(); + + const char* buf = "filter_test"; + size_t len = strlen(buf); + + in->SendTo(buf, len, out[0]->address()); + SocketAddress trans_addr; + EXPECT_TRUE(out[0]->CheckNextPacket(buf, len, &trans_addr)); + + out[1]->SendTo(buf, len, trans_addr); + EXPECT_TRUE(CheckReceive(in, !filter_ip, buf, len)); + + out[2]->SendTo(buf, len, trans_addr); + EXPECT_TRUE(CheckReceive(in, !filter_port, buf, len)); + + out[3]->SendTo(buf, len, trans_addr); + EXPECT_TRUE(CheckReceive(in, !filter_ip && !filter_port, buf, len)); + + th_int.Stop(); + th_ext.Stop(); + + delete nat; + delete natsf; + delete in; + for (int i = 0; i < 4; i++) + delete out[i]; +} + +// Tests that NATServer allocates bindings properly. +void TestBindings(SocketServer* internal, + const SocketAddress& internal_addr, + SocketServer* external, + const SocketAddress external_addrs[4]) { + TestSend(internal, internal_addr, external, external_addrs, NAT_OPEN_CONE, + true); + TestSend(internal, internal_addr, external, external_addrs, + NAT_ADDR_RESTRICTED, true); + TestSend(internal, internal_addr, external, external_addrs, + NAT_PORT_RESTRICTED, true); + TestSend(internal, internal_addr, external, external_addrs, NAT_SYMMETRIC, + false); +} + +// Tests that NATServer filters packets properly. +void TestFilters(SocketServer* internal, + const SocketAddress& internal_addr, + SocketServer* external, + const SocketAddress external_addrs[4]) { + TestRecv(internal, internal_addr, external, external_addrs, NAT_OPEN_CONE, + false, false); + TestRecv(internal, internal_addr, external, external_addrs, + NAT_ADDR_RESTRICTED, true, false); + TestRecv(internal, internal_addr, external, external_addrs, + NAT_PORT_RESTRICTED, true, true); + TestRecv(internal, internal_addr, external, external_addrs, NAT_SYMMETRIC, + true, true); +} + +bool TestConnectivity(const SocketAddress& src, const IPAddress& dst) { + // The physical NAT tests require connectivity to the selected ip from the + // internal address used for the NAT. Things like firewalls can break that, so + // check to see if it's worth even trying with this ip. + std::unique_ptr<PhysicalSocketServer> pss(new PhysicalSocketServer()); + std::unique_ptr<Socket> client(pss->CreateSocket(src.family(), SOCK_DGRAM)); + std::unique_ptr<Socket> server(pss->CreateSocket(src.family(), SOCK_DGRAM)); + if (client->Bind(SocketAddress(src.ipaddr(), 0)) != 0 || + server->Bind(SocketAddress(dst, 0)) != 0) { + return false; + } + const char* buf = "hello other socket"; + size_t len = strlen(buf); + int sent = client->SendTo(buf, len, server->GetLocalAddress()); + SocketAddress addr; + const size_t kRecvBufSize = 64; + char recvbuf[kRecvBufSize]; + Thread::Current()->SleepMs(100); + int received = server->RecvFrom(recvbuf, kRecvBufSize, &addr, nullptr); + return received == sent && ::memcmp(buf, recvbuf, len) == 0; +} + +void TestPhysicalInternal(const SocketAddress& int_addr) { + webrtc::test::ScopedKeyValueConfig field_trials; + rtc::AutoThread main_thread; + PhysicalSocketServer socket_server; + BasicNetworkManager network_manager(nullptr, &socket_server, &field_trials); + network_manager.StartUpdating(); + // Process pending messages so the network list is updated. + Thread::Current()->ProcessMessages(0); + + std::vector<const Network*> networks = network_manager.GetNetworks(); + networks.erase(std::remove_if(networks.begin(), networks.end(), + [](const rtc::Network* network) { + return rtc::kDefaultNetworkIgnoreMask & + network->type(); + }), + networks.end()); + if (networks.empty()) { + RTC_LOG(LS_WARNING) << "Not enough network adapters for test."; + return; + } + + SocketAddress ext_addr1(int_addr); + SocketAddress ext_addr2; + // Find an available IP with matching family. The test breaks if int_addr + // can't talk to ip, so check for connectivity as well. + for (const Network* const network : networks) { + const IPAddress& ip = network->GetBestIP(); + if (ip.family() == int_addr.family() && TestConnectivity(int_addr, ip)) { + ext_addr2.SetIP(ip); + break; + } + } + if (ext_addr2.IsNil()) { + RTC_LOG(LS_WARNING) << "No available IP of same family as " + << int_addr.ToString(); + return; + } + + RTC_LOG(LS_INFO) << "selected ip " << ext_addr2.ipaddr().ToString(); + + SocketAddress ext_addrs[4] = { + SocketAddress(ext_addr1), SocketAddress(ext_addr2), + SocketAddress(ext_addr1), SocketAddress(ext_addr2)}; + + std::unique_ptr<PhysicalSocketServer> int_pss(new PhysicalSocketServer()); + std::unique_ptr<PhysicalSocketServer> ext_pss(new PhysicalSocketServer()); + + TestBindings(int_pss.get(), int_addr, ext_pss.get(), ext_addrs); + TestFilters(int_pss.get(), int_addr, ext_pss.get(), ext_addrs); +} + +TEST(NatTest, TestPhysicalIPv4) { + TestPhysicalInternal(SocketAddress("127.0.0.1", 0)); +} + +TEST(NatTest, TestPhysicalIPv6) { + if (HasIPv6Enabled()) { + TestPhysicalInternal(SocketAddress("::1", 0)); + } else { + RTC_LOG(LS_WARNING) << "No IPv6, skipping"; + } +} + +namespace { + +class TestVirtualSocketServer : public VirtualSocketServer { + public: + // Expose this publicly + IPAddress GetNextIP(int af) { return VirtualSocketServer::GetNextIP(af); } +}; + +} // namespace + +void TestVirtualInternal(int family) { + rtc::AutoThread main_thread; + std::unique_ptr<TestVirtualSocketServer> int_vss( + new TestVirtualSocketServer()); + std::unique_ptr<TestVirtualSocketServer> ext_vss( + new TestVirtualSocketServer()); + + SocketAddress int_addr; + SocketAddress ext_addrs[4]; + int_addr.SetIP(int_vss->GetNextIP(family)); + ext_addrs[0].SetIP(ext_vss->GetNextIP(int_addr.family())); + ext_addrs[1].SetIP(ext_vss->GetNextIP(int_addr.family())); + ext_addrs[2].SetIP(ext_addrs[0].ipaddr()); + ext_addrs[3].SetIP(ext_addrs[1].ipaddr()); + + TestBindings(int_vss.get(), int_addr, ext_vss.get(), ext_addrs); + TestFilters(int_vss.get(), int_addr, ext_vss.get(), ext_addrs); +} + +TEST(NatTest, TestVirtualIPv4) { + TestVirtualInternal(AF_INET); +} + +TEST(NatTest, TestVirtualIPv6) { + if (HasIPv6Enabled()) { + TestVirtualInternal(AF_INET6); + } else { + RTC_LOG(LS_WARNING) << "No IPv6, skipping"; + } +} + +class NatTcpTest : public ::testing::Test, public sigslot::has_slots<> { + public: + NatTcpTest() + : int_addr_("192.168.0.1", 0), + ext_addr_("10.0.0.1", 0), + connected_(false), + int_vss_(new TestVirtualSocketServer()), + ext_vss_(new TestVirtualSocketServer()), + int_thread_(new Thread(int_vss_.get())), + ext_thread_(new Thread(ext_vss_.get())), + nat_(new NATServer(NAT_OPEN_CONE, + int_vss_.get(), + int_addr_, + int_addr_, + ext_vss_.get(), + ext_addr_)), + natsf_(new NATSocketFactory(int_vss_.get(), + nat_->internal_udp_address(), + nat_->internal_tcp_address())) { + int_thread_->Start(); + ext_thread_->Start(); + } + + void OnConnectEvent(Socket* socket) { connected_ = true; } + + void OnAcceptEvent(Socket* socket) { + accepted_.reset(server_->Accept(nullptr)); + } + + void OnCloseEvent(Socket* socket, int error) {} + + void ConnectEvents() { + server_->SignalReadEvent.connect(this, &NatTcpTest::OnAcceptEvent); + client_->SignalConnectEvent.connect(this, &NatTcpTest::OnConnectEvent); + } + + SocketAddress int_addr_; + SocketAddress ext_addr_; + bool connected_; + std::unique_ptr<TestVirtualSocketServer> int_vss_; + std::unique_ptr<TestVirtualSocketServer> ext_vss_; + std::unique_ptr<Thread> int_thread_; + std::unique_ptr<Thread> ext_thread_; + std::unique_ptr<NATServer> nat_; + std::unique_ptr<NATSocketFactory> natsf_; + std::unique_ptr<Socket> client_; + std::unique_ptr<Socket> server_; + std::unique_ptr<Socket> accepted_; +}; + +TEST_F(NatTcpTest, DISABLED_TestConnectOut) { + server_.reset(ext_vss_->CreateSocket(AF_INET, SOCK_STREAM)); + server_->Bind(ext_addr_); + server_->Listen(5); + + client_.reset(natsf_->CreateSocket(AF_INET, SOCK_STREAM)); + EXPECT_GE(0, client_->Bind(int_addr_)); + EXPECT_GE(0, client_->Connect(server_->GetLocalAddress())); + + ConnectEvents(); + + EXPECT_TRUE_WAIT(connected_, 1000); + EXPECT_EQ(client_->GetRemoteAddress(), server_->GetLocalAddress()); + EXPECT_EQ(accepted_->GetRemoteAddress().ipaddr(), ext_addr_.ipaddr()); + + std::unique_ptr<rtc::TestClient> in(CreateTCPTestClient(client_.release())); + std::unique_ptr<rtc::TestClient> out( + CreateTCPTestClient(accepted_.release())); + + const char* buf = "test_packet"; + size_t len = strlen(buf); + + in->Send(buf, len); + SocketAddress trans_addr; + EXPECT_TRUE(out->CheckNextPacket(buf, len, &trans_addr)); + + out->Send(buf, len); + EXPECT_TRUE(in->CheckNextPacket(buf, len, &trans_addr)); +} + +} // namespace +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/net_helper.cc b/third_party/libwebrtc/rtc_base/net_helper.cc new file mode 100644 index 0000000000..4afee7bfb0 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/net_helper.cc @@ -0,0 +1,33 @@ +/* + * Copyright 2017 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 "rtc_base/net_helper.h" + +#include "absl/strings/string_view.h" + +namespace cricket { + +const char UDP_PROTOCOL_NAME[] = "udp"; +const char TCP_PROTOCOL_NAME[] = "tcp"; +const char SSLTCP_PROTOCOL_NAME[] = "ssltcp"; +const char TLS_PROTOCOL_NAME[] = "tls"; + +int GetProtocolOverhead(absl::string_view protocol) { + if (protocol == TCP_PROTOCOL_NAME || protocol == SSLTCP_PROTOCOL_NAME) { + return kTcpHeaderSize; + } else if (protocol == UDP_PROTOCOL_NAME) { + return kUdpHeaderSize; + } else { + // TODO(srte): We should crash on unexpected input and handle TLS correctly. + return 8; + } +} + +} // namespace cricket diff --git a/third_party/libwebrtc/rtc_base/net_helper.h b/third_party/libwebrtc/rtc_base/net_helper.h new file mode 100644 index 0000000000..2dce91196c --- /dev/null +++ b/third_party/libwebrtc/rtc_base/net_helper.h @@ -0,0 +1,35 @@ +/* + * Copyright 2017 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 RTC_BASE_NET_HELPER_H_ +#define RTC_BASE_NET_HELPER_H_ + +#include <string> + +#include "absl/strings/string_view.h" +#include "rtc_base/system/rtc_export.h" + +// This header contains helper functions and constants used by different types +// of transports. +namespace cricket { + +RTC_EXPORT extern const char UDP_PROTOCOL_NAME[]; +RTC_EXPORT extern const char TCP_PROTOCOL_NAME[]; +extern const char SSLTCP_PROTOCOL_NAME[]; +extern const char TLS_PROTOCOL_NAME[]; + +constexpr int kTcpHeaderSize = 20; +constexpr int kUdpHeaderSize = 8; + +// Get the transport layer overhead per packet based on the protocol. +int GetProtocolOverhead(absl::string_view protocol); + +} // namespace cricket + +#endif // RTC_BASE_NET_HELPER_H_ diff --git a/third_party/libwebrtc/rtc_base/net_helpers.cc b/third_party/libwebrtc/rtc_base/net_helpers.cc new file mode 100644 index 0000000000..00cd434a58 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/net_helpers.cc @@ -0,0 +1,45 @@ +/* + * Copyright 2008 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 "rtc_base/net_helpers.h" + +#include <memory> +#include <string> + +#include "absl/strings/string_view.h" + +#if defined(WEBRTC_WIN) +#include <ws2spi.h> +#include <ws2tcpip.h> + +#endif +#if defined(WEBRTC_POSIX) && !defined(__native_client__) +#include <arpa/inet.h> +#endif // defined(WEBRTC_POSIX) && !defined(__native_client__) + +namespace rtc { + +const char* inet_ntop(int af, const void* src, char* dst, socklen_t size) { +#if defined(WEBRTC_WIN) + return win32_inet_ntop(af, src, dst, size); +#else + return ::inet_ntop(af, src, dst, size); +#endif +} + +int inet_pton(int af, absl::string_view src, void* dst) { + std::string src_str(src); +#if defined(WEBRTC_WIN) + return win32_inet_pton(af, src_str.c_str(), dst); +#else + return ::inet_pton(af, src_str.c_str(), dst); +#endif +} +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/net_helpers.h b/third_party/libwebrtc/rtc_base/net_helpers.h new file mode 100644 index 0000000000..a529f4f03f --- /dev/null +++ b/third_party/libwebrtc/rtc_base/net_helpers.h @@ -0,0 +1,34 @@ +/* + * Copyright 2008 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 RTC_BASE_NET_HELPERS_H_ +#define RTC_BASE_NET_HELPERS_H_ + +#if defined(WEBRTC_POSIX) +#include <sys/socket.h> +#elif WEBRTC_WIN +#include <winsock2.h> // NOLINT + +#include "rtc_base/win32.h" +#endif + +#include "absl/strings/string_view.h" +#include "rtc_base/system/rtc_export.h" + +namespace rtc { + +// rtc namespaced wrappers for inet_ntop and inet_pton so we can avoid +// the windows-native versions of these. +const char* inet_ntop(int af, const void* src, char* dst, socklen_t size); +int inet_pton(int af, absl::string_view src, void* dst); + +} // namespace rtc + +#endif // RTC_BASE_NET_HELPERS_H_ diff --git a/third_party/libwebrtc/rtc_base/net_helpers_gn/moz.build b/third_party/libwebrtc/rtc_base/net_helpers_gn/moz.build new file mode 100644 index 0000000000..c036110d1a --- /dev/null +++ b/third_party/libwebrtc/rtc_base/net_helpers_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/rtc_base/net_helpers.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_ENABLE_LIBEVENT"] = 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 += [ + "GLESv2", + "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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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" + ] + +if CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("net_helpers_gn") diff --git a/third_party/libwebrtc/rtc_base/net_test_helpers.cc b/third_party/libwebrtc/rtc_base/net_test_helpers.cc new file mode 100644 index 0000000000..806d7dee60 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/net_test_helpers.cc @@ -0,0 +1,111 @@ +/* + * Copyright 2023 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 "rtc_base/net_test_helpers.h" + +#include <memory> +#include <string> + +#if defined(WEBRTC_WIN) +#include <ws2spi.h> +#include <ws2tcpip.h> + +#include "rtc_base/win/windows_version.h" +#endif +#if defined(WEBRTC_POSIX) && !defined(__native_client__) +#include <arpa/inet.h> +#if defined(WEBRTC_ANDROID) +#include "rtc_base/ifaddrs_android.h" +#else +#include <ifaddrs.h> +#endif +#endif // defined(WEBRTC_POSIX) && !defined(__native_client__) + +namespace rtc { + +bool HasIPv4Enabled() { +#if defined(WEBRTC_POSIX) && !defined(__native_client__) + bool has_ipv4 = false; + struct ifaddrs* ifa; + if (getifaddrs(&ifa) < 0) { + return false; + } + for (struct ifaddrs* cur = ifa; cur != nullptr; cur = cur->ifa_next) { + if (cur->ifa_addr != nullptr && cur->ifa_addr->sa_family == AF_INET) { + has_ipv4 = true; + break; + } + } + freeifaddrs(ifa); + return has_ipv4; +#else + return true; +#endif +} + +bool HasIPv6Enabled() { +#if defined(WINUWP) + // WinUWP always has IPv6 capability. + return true; +#elif defined(WEBRTC_WIN) + if (rtc::rtc_win::GetVersion() >= rtc::rtc_win::Version::VERSION_VISTA) { + return true; + } + if (rtc::rtc_win::GetVersion() < rtc::rtc_win::Version::VERSION_XP) { + return false; + } + DWORD protbuff_size = 4096; + std::unique_ptr<char[]> protocols; + LPWSAPROTOCOL_INFOW protocol_infos = nullptr; + int requested_protocols[2] = {AF_INET6, 0}; + + int err = 0; + int ret = 0; + // Check for protocols in a do-while loop until we provide a buffer large + // enough. (WSCEnumProtocols sets protbuff_size to its desired value). + // It is extremely unlikely that this will loop more than once. + do { + protocols.reset(new char[protbuff_size]); + protocol_infos = reinterpret_cast<LPWSAPROTOCOL_INFOW>(protocols.get()); + ret = WSCEnumProtocols(requested_protocols, protocol_infos, &protbuff_size, + &err); + } while (ret == SOCKET_ERROR && err == WSAENOBUFS); + + if (ret == SOCKET_ERROR) { + return false; + } + + // Even if ret is positive, check specifically for IPv6. + // Non-IPv6 enabled WinXP will still return a RAW protocol. + for (int i = 0; i < ret; ++i) { + if (protocol_infos[i].iAddressFamily == AF_INET6) { + return true; + } + } + return false; +#elif defined(WEBRTC_POSIX) && !defined(__native_client__) + bool has_ipv6 = false; + struct ifaddrs* ifa; + if (getifaddrs(&ifa) < 0) { + return false; + } + for (struct ifaddrs* cur = ifa; cur != nullptr; cur = cur->ifa_next) { + if (cur->ifa_addr != nullptr && cur->ifa_addr->sa_family == AF_INET6) { + has_ipv6 = true; + break; + } + } + freeifaddrs(ifa); + return has_ipv6; +#else + return true; +#endif +} +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/net_test_helpers.h b/third_party/libwebrtc/rtc_base/net_test_helpers.h new file mode 100644 index 0000000000..2e8320c4d8 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/net_test_helpers.h @@ -0,0 +1,23 @@ +/* + * Copyright 2023 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 RTC_BASE_NET_TEST_HELPERS_H_ +#define RTC_BASE_NET_TEST_HELPERS_H_ + +#include "rtc_base/system/rtc_export.h" + +namespace rtc { + +RTC_EXPORT bool HasIPv4Enabled(); +RTC_EXPORT bool HasIPv6Enabled(); + +} // namespace rtc + +#endif // RTC_BASE_NET_TEST_HELPERS_H_ diff --git a/third_party/libwebrtc/rtc_base/network.cc b/third_party/libwebrtc/rtc_base/network.cc new file mode 100644 index 0000000000..4be6eed759 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/network.cc @@ -0,0 +1,1306 @@ +/* + * 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 "rtc_base/network.h" + +#include "absl/strings/string_view.h" +#include "rtc_base/experiments/field_trial_parser.h" + +#if defined(WEBRTC_POSIX) +#include <net/if.h> +#endif // WEBRTC_POSIX + +#if defined(WEBRTC_WIN) +#include <iphlpapi.h> + +#include "rtc_base/win32.h" +#elif !defined(__native_client__) +#include "rtc_base/ifaddrs_converter.h" +#endif + +#include <memory> + +#include "absl/algorithm/container.h" +#include "absl/memory/memory.h" +#include "absl/strings/match.h" +#include "absl/strings/string_view.h" +#include "api/task_queue/pending_task_safety_flag.h" +#include "api/transport/field_trial_based_config.h" +#include "api/units/time_delta.h" +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" +#include "rtc_base/memory/always_valid_pointer.h" +#include "rtc_base/network_monitor.h" +#include "rtc_base/socket.h" // includes something that makes windows happy +#include "rtc_base/string_encode.h" +#include "rtc_base/string_utils.h" +#include "rtc_base/strings/string_builder.h" +#include "rtc_base/thread.h" + +namespace rtc { +namespace { +using ::webrtc::SafeTask; +using ::webrtc::TimeDelta; + +// List of MAC addresses of known VPN (for windows). +constexpr uint8_t kVpns[3][6] = { + // Cisco AnyConnect SSL VPN Client. + {0x0, 0x5, 0x9A, 0x3C, 0x7A, 0x0}, + // Cisco AnyConnect IPSEC VPN Client. + {0x0, 0x5, 0x9A, 0x3C, 0x78, 0x0}, + // GlobalProtect Virtual Ethernet. + {0x2, 0x50, 0x41, 0x0, 0x0, 0x1}, +}; + +// Fetch list of networks every two seconds. +const int kNetworksUpdateIntervalMs = 2000; + +const int kHighestNetworkPreference = 127; + +struct AddressList { + std::unique_ptr<Network> net; + std::vector<InterfaceAddress> ips; +}; + +bool SortNetworks(const Network* a, const Network* b) { + // Network types will be preferred above everything else while sorting + // Networks. + + // Networks are sorted first by type. + if (a->type() != b->type()) { + return a->type() < b->type(); + } + + IPAddress ip_a = a->GetBestIP(); + IPAddress ip_b = b->GetBestIP(); + + // After type, networks are sorted by IP address precedence values + // from RFC 3484-bis + if (IPAddressPrecedence(ip_a) != IPAddressPrecedence(ip_b)) { + return IPAddressPrecedence(ip_a) > IPAddressPrecedence(ip_b); + } + + // TODO(mallinath) - Add VPN and Link speed conditions while sorting. + + // Networks are sorted last by key. + return a->key() < b->key(); +} + +uint16_t ComputeNetworkCostByType(int type, + bool is_vpn, + bool use_differentiated_cellular_costs, + bool add_network_cost_to_vpn) { + // TODO(jonaso) : Rollout support for cellular network cost using A/B + // experiment to make sure it does not introduce regressions. + int vpnCost = (is_vpn && add_network_cost_to_vpn) ? kNetworkCostVpn : 0; + switch (type) { + case rtc::ADAPTER_TYPE_ETHERNET: + case rtc::ADAPTER_TYPE_LOOPBACK: + return kNetworkCostMin + vpnCost; + case rtc::ADAPTER_TYPE_WIFI: + return kNetworkCostLow + vpnCost; + case rtc::ADAPTER_TYPE_CELLULAR: + return kNetworkCostCellular + vpnCost; + case rtc::ADAPTER_TYPE_CELLULAR_2G: + return (use_differentiated_cellular_costs ? kNetworkCostCellular2G + : kNetworkCostCellular) + + vpnCost; + case rtc::ADAPTER_TYPE_CELLULAR_3G: + return (use_differentiated_cellular_costs ? kNetworkCostCellular3G + : kNetworkCostCellular) + + vpnCost; + case rtc::ADAPTER_TYPE_CELLULAR_4G: + return (use_differentiated_cellular_costs ? kNetworkCostCellular4G + : kNetworkCostCellular) + + vpnCost; + case rtc::ADAPTER_TYPE_CELLULAR_5G: + return (use_differentiated_cellular_costs ? kNetworkCostCellular5G + : kNetworkCostCellular) + + vpnCost; + case rtc::ADAPTER_TYPE_ANY: + // Candidates gathered from the any-address/wildcard ports, as backups, + // are given the maximum cost so that if there are other candidates with + // known interface types, we would not select candidate pairs using these + // backup candidates if other selection criteria with higher precedence + // (network conditions over the route) are the same. Note that setting the + // cost to kNetworkCostUnknown would be problematic since + // ADAPTER_TYPE_CELLULAR would then have a higher cost. See + // P2PTransportChannel::SortConnectionsAndUpdateState for how we rank and + // select candidate pairs, where the network cost is among the criteria. + return kNetworkCostMax + vpnCost; + case rtc::ADAPTER_TYPE_VPN: + // The cost of a VPN should be computed using its underlying network type. + RTC_DCHECK_NOTREACHED(); + return kNetworkCostUnknown; + default: + return kNetworkCostUnknown + vpnCost; + } +} + +#if !defined(__native_client__) +bool IsIgnoredIPv6(bool allow_mac_based_ipv6, const InterfaceAddress& ip) { + if (ip.family() != AF_INET6) { + return false; + } + + // Link-local addresses require scope id to be bound successfully. + // However, our IPAddress structure doesn't carry that so the + // information is lost and causes binding failure. + if (IPIsLinkLocal(ip)) { + RTC_LOG(LS_VERBOSE) << "Ignore link local IP:" << ip.ToSensitiveString(); + return true; + } + + // Any MAC based IPv6 should be avoided to prevent the MAC tracking. + if (IPIsMacBased(ip) && !allow_mac_based_ipv6) { + RTC_LOG(LS_INFO) << "Ignore Mac based IP:" << ip.ToSensitiveString(); + return true; + } + + // Ignore deprecated IPv6. + if (ip.ipv6_flags() & IPV6_ADDRESS_FLAG_DEPRECATED) { + RTC_LOG(LS_INFO) << "Ignore deprecated IP:" << ip.ToSensitiveString(); + return true; + } + + return false; +} +#endif // !defined(__native_client__) + +// Note: consider changing to const Network* as arguments +// if/when considering other changes that should not trigger +// OnNetworksChanged. +bool ShouldAdapterChangeTriggerNetworkChange(rtc::AdapterType old_type, + rtc::AdapterType new_type) { + // skip triggering OnNetworksChanged if + // changing from one cellular to another. + if (Network::IsCellular(old_type) && Network::IsCellular(new_type)) + return false; + return true; +} + +#if defined(WEBRTC_WIN) +bool IpAddressAttributesEnabled(const webrtc::FieldTrialsView* field_trials) { + // Field trial key reserved in bugs.webrtc.org/14334 + if (field_trials && + field_trials->IsEnabled("WebRTC-IPv6NetworkResolutionFixes")) { + webrtc::FieldTrialParameter<bool> ip_address_attributes_enabled( + "IpAddressAttributesEnabled", false); + webrtc::ParseFieldTrial( + {&ip_address_attributes_enabled}, + field_trials->Lookup("WebRTC-IPv6NetworkResolutionFixes")); + return ip_address_attributes_enabled; + } + return false; +} +#endif // WEBRTC_WIN + +} // namespace + +// These addresses are used as the targets to find out the default local address +// on a multi-homed endpoint. They are actually DNS servers. +const char kPublicIPv4Host[] = "8.8.8.8"; +const char kPublicIPv6Host[] = "2001:4860:4860::8888"; +const int kPublicPort = 53; // DNS port. + +namespace webrtc_network_internal { +bool CompareNetworks(const std::unique_ptr<Network>& a, + const std::unique_ptr<Network>& b) { + if (a->prefix_length() != b->prefix_length()) { + return a->prefix_length() < b->prefix_length(); + } + if (a->name() != b->name()) { + return a->name() < b->name(); + } + return a->prefix() < b->prefix(); +} +} // namespace webrtc_network_internal + +std::string MakeNetworkKey(absl::string_view name, + const IPAddress& prefix, + int prefix_length) { + rtc::StringBuilder ost; + ost << name << "%" << prefix.ToString() << "/" << prefix_length; + return ost.Release(); +} +// Test if the network name matches the type<number> pattern, e.g. eth0. The +// matching is case-sensitive. +bool MatchTypeNameWithIndexPattern(absl::string_view network_name, + absl::string_view type_name) { + if (!absl::StartsWith(network_name, type_name)) { + return false; + } + return absl::c_none_of(network_name.substr(type_name.size()), + [](char c) { return !isdigit(c); }); +} + +// A cautious note that this method may not provide an accurate adapter type +// based on the string matching. Incorrect type of adapters can affect the +// result of the downstream network filtering, see e.g. +// BasicPortAllocatorSession::GetNetworks when +// PORTALLOCATOR_DISABLE_COSTLY_NETWORKS is turned on. +AdapterType GetAdapterTypeFromName(absl::string_view network_name) { + if (MatchTypeNameWithIndexPattern(network_name, "lo")) { + // Note that we have a more robust way to determine if a network interface + // is a loopback interface by checking the flag IFF_LOOPBACK in ifa_flags of + // an ifaddr struct. See ConvertIfAddrs in this file. + return ADAPTER_TYPE_LOOPBACK; + } + + if (MatchTypeNameWithIndexPattern(network_name, "eth")) { + return ADAPTER_TYPE_ETHERNET; + } + + if (MatchTypeNameWithIndexPattern(network_name, "wlan") || + MatchTypeNameWithIndexPattern(network_name, "v4-wlan")) { + return ADAPTER_TYPE_WIFI; + } + + if (MatchTypeNameWithIndexPattern(network_name, "ipsec") || + MatchTypeNameWithIndexPattern(network_name, "tun") || + MatchTypeNameWithIndexPattern(network_name, "utun") || + MatchTypeNameWithIndexPattern(network_name, "tap")) { + return ADAPTER_TYPE_VPN; + } +#if defined(WEBRTC_IOS) + // Cell networks are pdp_ipN on iOS. + if (MatchTypeNameWithIndexPattern(network_name, "pdp_ip")) { + return ADAPTER_TYPE_CELLULAR; + } + if (MatchTypeNameWithIndexPattern(network_name, "en")) { + // This may not be most accurate because sometimes Ethernet interface + // name also starts with "en" but it is better than showing it as + // "unknown" type. + // TODO(honghaiz): Write a proper IOS network manager. + return ADAPTER_TYPE_WIFI; + } +#elif defined(WEBRTC_ANDROID) + if (MatchTypeNameWithIndexPattern(network_name, "rmnet") || + MatchTypeNameWithIndexPattern(network_name, "rmnet_data") || + MatchTypeNameWithIndexPattern(network_name, "v4-rmnet") || + MatchTypeNameWithIndexPattern(network_name, "v4-rmnet_data") || + MatchTypeNameWithIndexPattern(network_name, "clat") || + MatchTypeNameWithIndexPattern(network_name, "ccmni")) { + return ADAPTER_TYPE_CELLULAR; + } +#endif + + return ADAPTER_TYPE_UNKNOWN; +} + +NetworkManager::EnumerationPermission NetworkManager::enumeration_permission() + const { + return ENUMERATION_ALLOWED; +} + +bool NetworkManager::GetDefaultLocalAddress(int family, IPAddress* addr) const { + return false; +} + +webrtc::MdnsResponderInterface* NetworkManager::GetMdnsResponder() const { + return nullptr; +} + +NetworkManagerBase::NetworkManagerBase( + const webrtc::FieldTrialsView* field_trials) + : field_trials_(field_trials), + enumeration_permission_(NetworkManager::ENUMERATION_ALLOWED), + signal_network_preference_change_( + field_trials + ? field_trials->IsEnabled("WebRTC-SignalNetworkPreferenceChange") + : false) {} + +NetworkManager::EnumerationPermission +NetworkManagerBase::enumeration_permission() const { + return enumeration_permission_; +} + +std::unique_ptr<Network> NetworkManagerBase::CreateNetwork( + absl::string_view name, + absl::string_view description, + const IPAddress& prefix, + int prefix_length, + AdapterType type) const { + return std::make_unique<Network>(name, description, prefix, prefix_length, + type); +} + +std::vector<const Network*> NetworkManagerBase::GetAnyAddressNetworks() { + std::vector<const Network*> networks; + if (!ipv4_any_address_network_) { + const rtc::IPAddress ipv4_any_address(INADDR_ANY); + ipv4_any_address_network_ = + CreateNetwork("any", "any", ipv4_any_address, 0, ADAPTER_TYPE_ANY); + ipv4_any_address_network_->set_default_local_address_provider(this); + ipv4_any_address_network_->set_mdns_responder_provider(this); + ipv4_any_address_network_->AddIP(ipv4_any_address); + } + networks.push_back(ipv4_any_address_network_.get()); + + if (!ipv6_any_address_network_) { + const rtc::IPAddress ipv6_any_address(in6addr_any); + ipv6_any_address_network_ = + CreateNetwork("any", "any", ipv6_any_address, 0, ADAPTER_TYPE_ANY); + ipv6_any_address_network_->set_default_local_address_provider(this); + ipv6_any_address_network_->set_mdns_responder_provider(this); + ipv6_any_address_network_->AddIP(ipv6_any_address); + } + networks.push_back(ipv6_any_address_network_.get()); + return networks; +} + +std::vector<const Network*> NetworkManagerBase::GetNetworks() const { + std::vector<const Network*> result; + result.insert(result.begin(), networks_.begin(), networks_.end()); + return result; +} + +void NetworkManagerBase::MergeNetworkList( + std::vector<std::unique_ptr<Network>> new_networks, + bool* changed) { + NetworkManager::Stats stats; + MergeNetworkList(std::move(new_networks), changed, &stats); +} + +void NetworkManagerBase::MergeNetworkList( + std::vector<std::unique_ptr<Network>> new_networks, + bool* changed, + NetworkManager::Stats* stats) { + *changed = false; + // AddressList in this map will track IP addresses for all Networks + // with the same key. + std::map<std::string, AddressList> consolidated_address_list; + absl::c_sort(new_networks, rtc::webrtc_network_internal::CompareNetworks); + // First, build a set of network-keys to the ipaddresses. + for (auto& network : new_networks) { + bool might_add_to_merged_list = false; + std::string key = MakeNetworkKey(network->name(), network->prefix(), + network->prefix_length()); + const std::vector<InterfaceAddress>& addresses = network->GetIPs(); + if (consolidated_address_list.find(key) == + consolidated_address_list.end()) { + AddressList addrlist; + addrlist.net = std::move(network); + consolidated_address_list[key] = std::move(addrlist); + might_add_to_merged_list = true; + } + AddressList& current_list = consolidated_address_list[key]; + for (const InterfaceAddress& address : addresses) { + current_list.ips.push_back(address); + } + if (might_add_to_merged_list) { + if (current_list.ips[0].family() == AF_INET) { + stats->ipv4_network_count++; + } else { + RTC_DCHECK(current_list.ips[0].family() == AF_INET6); + stats->ipv6_network_count++; + } + } + } + + // Next, look for existing network objects to re-use. + // Result of Network merge. Element in this list should have unique key. + std::vector<Network*> merged_list; + for (auto& kv : consolidated_address_list) { + const std::string& key = kv.first; + std::unique_ptr<Network> net = std::move(kv.second.net); + auto existing = networks_map_.find(key); + if (existing == networks_map_.end()) { + // This network is new. + net->set_id(next_available_network_id_++); + // We might have accumulated IPAddresses from the first + // step, set it here. + net->SetIPs(kv.second.ips, true); + // Place it in the network map. + merged_list.push_back(net.get()); + networks_map_[key] = std::move(net); + *changed = true; + } else { + // This network exists in the map already. Reset its IP addresses. + Network* existing_net = existing->second.get(); + *changed = existing_net->SetIPs(kv.second.ips, *changed); + merged_list.push_back(existing_net); + if (net->type() != ADAPTER_TYPE_UNKNOWN && + net->type() != existing_net->type()) { + if (ShouldAdapterChangeTriggerNetworkChange(existing_net->type(), + net->type())) { + *changed = true; + } + existing_net->set_type(net->type()); + } + // If the existing network was not active, networks have changed. + if (!existing_net->active()) { + *changed = true; + } + if (net->network_preference() != existing_net->network_preference()) { + existing_net->set_network_preference(net->network_preference()); + if (signal_network_preference_change_) { + *changed = true; + } + } + RTC_DCHECK(net->active()); + } + networks_map_[key]->set_mdns_responder_provider(this); + } + // It may still happen that the merged list is a subset of `networks_`. + // To detect this change, we compare their sizes. + if (merged_list.size() != networks_.size()) { + *changed = true; + } + + // If the network list changes, we re-assign `networks_` to the merged list + // and re-sort it. + if (*changed) { + networks_ = merged_list; + // Reset the active states of all networks. + for (const auto& kv : networks_map_) { + const std::unique_ptr<Network>& network = kv.second; + // If `network` is in the newly generated `networks_`, it is active. + bool found = absl::c_linear_search(networks_, network.get()); + network->set_active(found); + } + absl::c_sort(networks_, SortNetworks); + // Now network interfaces are sorted, we should set the preference value + // for each of the interfaces we are planning to use. + // Preference order of network interfaces might have changed from previous + // sorting due to addition of higher preference network interface. + // Since we have already sorted the network interfaces based on our + // requirements, we will just assign a preference value starting with 127, + // in decreasing order. + int pref = kHighestNetworkPreference; + for (Network* network : networks_) { + network->set_preference(pref); + if (pref > 0) { + --pref; + } else { + RTC_LOG(LS_ERROR) << "Too many network interfaces to handle!"; + break; + } + } + } +} + +void NetworkManagerBase::set_default_local_addresses(const IPAddress& ipv4, + const IPAddress& ipv6) { + if (ipv4.family() == AF_INET) { + default_local_ipv4_address_ = ipv4; + } + if (ipv6.family() == AF_INET6) { + default_local_ipv6_address_ = ipv6; + } +} + +bool NetworkManagerBase::GetDefaultLocalAddress(int family, + IPAddress* ipaddr) const { + if (family == AF_INET && !default_local_ipv4_address_.IsNil()) { + *ipaddr = default_local_ipv4_address_; + return true; + } else if (family == AF_INET6 && !default_local_ipv6_address_.IsNil()) { + Network* ipv6_network = GetNetworkFromAddress(default_local_ipv6_address_); + if (ipv6_network) { + // If the default ipv6 network's BestIP is different than + // default_local_ipv6_address_, use it instead. + // This is to prevent potential IP address leakage. See WebRTC bug 5376. + *ipaddr = ipv6_network->GetBestIP(); + } else { + *ipaddr = default_local_ipv6_address_; + } + return true; + } + return false; +} + +Network* NetworkManagerBase::GetNetworkFromAddress( + const rtc::IPAddress& ip) const { + for (Network* network : networks_) { + const auto& ips = network->GetIPs(); + if (absl::c_any_of(ips, [&](const InterfaceAddress& existing_ip) { + return ip == static_cast<rtc::IPAddress>(existing_ip); + })) { + return network; + } + } + return nullptr; +} + +bool NetworkManagerBase::IsVpnMacAddress( + rtc::ArrayView<const uint8_t> address) { + if (address.data() == nullptr && address.size() == 0) { + return false; + } + for (const auto& vpn : kVpns) { + if (sizeof(vpn) == address.size() && + memcmp(vpn, address.data(), address.size()) == 0) { + return true; + } + } + return false; +} + +BasicNetworkManager::BasicNetworkManager( + NetworkMonitorFactory* network_monitor_factory, + SocketFactory* socket_factory, + const webrtc::FieldTrialsView* field_trials_view) + : NetworkManagerBase(field_trials_view), + field_trials_(field_trials_view), + network_monitor_factory_(network_monitor_factory), + socket_factory_(socket_factory), + allow_mac_based_ipv6_( + field_trials()->IsEnabled("WebRTC-AllowMACBasedIPv6")), + bind_using_ifname_( + !field_trials()->IsDisabled("WebRTC-BindUsingInterfaceName")) { + RTC_DCHECK(socket_factory_); +} + +BasicNetworkManager::~BasicNetworkManager() { + if (task_safety_flag_) { + task_safety_flag_->SetNotAlive(); + } +} + +void BasicNetworkManager::OnNetworksChanged() { + RTC_DCHECK_RUN_ON(thread_); + RTC_LOG(LS_INFO) << "Network change was observed"; + UpdateNetworksOnce(); +} + +#if defined(__native_client__) + +bool BasicNetworkManager::CreateNetworks( + bool include_ignored, + std::vector<std::unique_ptr<Network>>* networks) const { + RTC_DCHECK_NOTREACHED(); + RTC_LOG(LS_WARNING) << "BasicNetworkManager doesn't work on NaCl yet"; + return false; +} + +#elif defined(WEBRTC_POSIX) +NetworkMonitorInterface::InterfaceInfo BasicNetworkManager::GetInterfaceInfo( + struct ifaddrs* cursor) const { + if (cursor->ifa_flags & IFF_LOOPBACK) { + return { + .adapter_type = ADAPTER_TYPE_LOOPBACK, + .underlying_type_for_vpn = ADAPTER_TYPE_UNKNOWN, + .network_preference = NetworkPreference::NEUTRAL, + .available = true, + }; + } else if (network_monitor_) { + return network_monitor_->GetInterfaceInfo(cursor->ifa_name); + } else { + return {.adapter_type = GetAdapterTypeFromName(cursor->ifa_name), + .underlying_type_for_vpn = ADAPTER_TYPE_UNKNOWN, + .network_preference = NetworkPreference::NEUTRAL, + .available = true}; + } +} + +void BasicNetworkManager::ConvertIfAddrs( + struct ifaddrs* interfaces, + IfAddrsConverter* ifaddrs_converter, + bool include_ignored, + std::vector<std::unique_ptr<Network>>* networks) const { + std::map<std::string, Network*> current_networks; + + for (struct ifaddrs* cursor = interfaces; cursor != nullptr; + cursor = cursor->ifa_next) { + IPAddress prefix; + IPAddress mask; + InterfaceAddress ip; + int scope_id = 0; + + // Some interfaces may not have address assigned. + if (!cursor->ifa_addr || !cursor->ifa_netmask) { + continue; + } + // Skip unknown family. + if (cursor->ifa_addr->sa_family != AF_INET && + cursor->ifa_addr->sa_family != AF_INET6) { + continue; + } + // Convert to InterfaceAddress. + // TODO(webrtc:13114): Convert ConvertIfAddrs to use rtc::Netmask. + if (!ifaddrs_converter->ConvertIfAddrsToIPAddress(cursor, &ip, &mask)) { + continue; + } + // Skip ones which are down. + if (!(cursor->ifa_flags & IFF_RUNNING)) { + RTC_LOG(LS_INFO) << "Skip interface because of not IFF_RUNNING: " + << ip.ToSensitiveString(); + continue; + } + + // Special case for IPv6 address. + if (cursor->ifa_addr->sa_family == AF_INET6) { + if (IsIgnoredIPv6(allow_mac_based_ipv6_, ip)) { + continue; + } + scope_id = + reinterpret_cast<sockaddr_in6*>(cursor->ifa_addr)->sin6_scope_id; + } + + int prefix_length = CountIPMaskBits(mask); + prefix = TruncateIP(ip, prefix_length); + std::string key = + MakeNetworkKey(std::string(cursor->ifa_name), prefix, prefix_length); + + auto iter = current_networks.find(key); + if (iter != current_networks.end()) { + // We have already added this network, simply add extra IP. + iter->second->AddIP(ip); +#if RTC_DCHECK_IS_ON + // Validate that different IP of same network has same properties + auto existing_network = iter->second; + + NetworkMonitorInterface::InterfaceInfo if_info = GetInterfaceInfo(cursor); + if (if_info.adapter_type != ADAPTER_TYPE_VPN && + IsConfiguredVpn(prefix, prefix_length)) { + if_info.underlying_type_for_vpn = if_info.adapter_type; + if_info.adapter_type = ADAPTER_TYPE_VPN; + } + + RTC_DCHECK(existing_network->type() == if_info.adapter_type); + RTC_DCHECK(existing_network->underlying_type_for_vpn() == + if_info.underlying_type_for_vpn); + RTC_DCHECK(existing_network->network_preference() == + if_info.network_preference); + if (!if_info.available) { + RTC_DCHECK(existing_network->ignored()); + } +#endif // RTC_DCHECK_IS_ON + continue; + } + + // Create a new network. + NetworkMonitorInterface::InterfaceInfo if_info = GetInterfaceInfo(cursor); + + // Check manually configured VPN override. + if (if_info.adapter_type != ADAPTER_TYPE_VPN && + IsConfiguredVpn(prefix, prefix_length)) { + if_info.underlying_type_for_vpn = if_info.adapter_type; + if_info.adapter_type = ADAPTER_TYPE_VPN; + } + + auto network = CreateNetwork(cursor->ifa_name, cursor->ifa_name, prefix, + prefix_length, if_info.adapter_type); + network->set_default_local_address_provider(this); + network->set_scope_id(scope_id); + network->AddIP(ip); + if (!if_info.available) { + network->set_ignored(true); + } else { + network->set_ignored(IsIgnoredNetwork(*network)); + } + network->set_underlying_type_for_vpn(if_info.underlying_type_for_vpn); + network->set_network_preference(if_info.network_preference); + if (include_ignored || !network->ignored()) { + current_networks[key] = network.get(); + networks->push_back(std::move(network)); + } + } +} + +bool BasicNetworkManager::CreateNetworks( + bool include_ignored, + std::vector<std::unique_ptr<Network>>* networks) const { + struct ifaddrs* interfaces; + int error = getifaddrs(&interfaces); + if (error != 0) { + RTC_LOG_ERR(LS_ERROR) << "getifaddrs failed to gather interface data: " + << error; + return false; + } + + std::unique_ptr<IfAddrsConverter> ifaddrs_converter(CreateIfAddrsConverter()); + ConvertIfAddrs(interfaces, ifaddrs_converter.get(), include_ignored, + networks); + + freeifaddrs(interfaces); + return true; +} + +#elif defined(WEBRTC_WIN) + +unsigned int GetPrefix(PIP_ADAPTER_PREFIX prefixlist, + const IPAddress& ip, + IPAddress* prefix) { + IPAddress current_prefix; + IPAddress best_prefix; + unsigned int best_length = 0; + while (prefixlist) { + // Look for the longest matching prefix in the prefixlist. + if (prefixlist->Address.lpSockaddr == nullptr || + prefixlist->Address.lpSockaddr->sa_family != ip.family()) { + prefixlist = prefixlist->Next; + continue; + } + switch (prefixlist->Address.lpSockaddr->sa_family) { + case AF_INET: { + sockaddr_in* v4_addr = + reinterpret_cast<sockaddr_in*>(prefixlist->Address.lpSockaddr); + current_prefix = IPAddress(v4_addr->sin_addr); + break; + } + case AF_INET6: { + sockaddr_in6* v6_addr = + reinterpret_cast<sockaddr_in6*>(prefixlist->Address.lpSockaddr); + current_prefix = IPAddress(v6_addr->sin6_addr); + break; + } + default: { + prefixlist = prefixlist->Next; + continue; + } + } + if (TruncateIP(ip, prefixlist->PrefixLength) == current_prefix && + prefixlist->PrefixLength > best_length) { + best_prefix = current_prefix; + best_length = prefixlist->PrefixLength; + } + prefixlist = prefixlist->Next; + } + *prefix = best_prefix; + return best_length; +} + +bool BasicNetworkManager::CreateNetworks( + bool include_ignored, + std::vector<std::unique_ptr<Network>>* networks) const { + std::map<std::string, Network*> current_networks; + // MSDN recommends a 15KB buffer for the first try at GetAdaptersAddresses. + size_t buffer_size = 16384; + std::unique_ptr<char[]> adapter_info(new char[buffer_size]); + PIP_ADAPTER_ADDRESSES adapter_addrs = + reinterpret_cast<PIP_ADAPTER_ADDRESSES>(adapter_info.get()); + int adapter_flags = (GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_ANYCAST | + GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_INCLUDE_PREFIX); + int ret = 0; + do { + adapter_info.reset(new char[buffer_size]); + adapter_addrs = reinterpret_cast<PIP_ADAPTER_ADDRESSES>(adapter_info.get()); + ret = GetAdaptersAddresses(AF_UNSPEC, adapter_flags, 0, adapter_addrs, + reinterpret_cast<PULONG>(&buffer_size)); + } while (ret == ERROR_BUFFER_OVERFLOW); + if (ret != ERROR_SUCCESS) { + return false; + } + int count = 0; + while (adapter_addrs) { + if (adapter_addrs->OperStatus == IfOperStatusUp) { + PIP_ADAPTER_UNICAST_ADDRESS address = adapter_addrs->FirstUnicastAddress; + PIP_ADAPTER_PREFIX prefixlist = adapter_addrs->FirstPrefix; + std::string description = ToUtf8(adapter_addrs->Description, + wcslen(adapter_addrs->Description)); + + for (; address; address = address->Next) { + std::string name = rtc::ToString(count); +#if !defined(NDEBUG) + name = ToUtf8(adapter_addrs->FriendlyName, + wcslen(adapter_addrs->FriendlyName)); +#endif + + IPAddress ip; + int scope_id = 0; + std::unique_ptr<Network> network; + switch (address->Address.lpSockaddr->sa_family) { + case AF_INET: { + sockaddr_in* v4_addr = + reinterpret_cast<sockaddr_in*>(address->Address.lpSockaddr); + ip = IPAddress(v4_addr->sin_addr); + break; + } + case AF_INET6: { + sockaddr_in6* v6_addr = + reinterpret_cast<sockaddr_in6*>(address->Address.lpSockaddr); + scope_id = v6_addr->sin6_scope_id; + + // From http://technet.microsoft.com/en-us/ff568768(v=vs.60).aspx, + // the way to identify a temporary IPv6 Address is to check if + // PrefixOrigin is equal to IpPrefixOriginRouterAdvertisement and + // SuffixOrigin equal to IpSuffixOriginRandom. + int ip_address_attributes = IPV6_ADDRESS_FLAG_NONE; + if (IpAddressAttributesEnabled(field_trials_.get())) { + if (address->PrefixOrigin == IpPrefixOriginRouterAdvertisement && + address->SuffixOrigin == IpSuffixOriginRandom) { + ip_address_attributes |= IPV6_ADDRESS_FLAG_TEMPORARY; + } + if (address->PreferredLifetime == 0) { + ip_address_attributes |= IPV6_ADDRESS_FLAG_DEPRECATED; + } + } + if (IsIgnoredIPv6(allow_mac_based_ipv6_, + InterfaceAddress(v6_addr->sin6_addr, + ip_address_attributes))) { + continue; + } + ip = InterfaceAddress(v6_addr->sin6_addr, ip_address_attributes); + break; + } + default: { + continue; + } + } + + IPAddress prefix; + int prefix_length = GetPrefix(prefixlist, ip, &prefix); + std::string key = MakeNetworkKey(name, prefix, prefix_length); + auto existing_network = current_networks.find(key); + if (existing_network == current_networks.end()) { + AdapterType adapter_type = ADAPTER_TYPE_UNKNOWN; + switch (adapter_addrs->IfType) { + case IF_TYPE_SOFTWARE_LOOPBACK: + adapter_type = ADAPTER_TYPE_LOOPBACK; + break; + case IF_TYPE_ETHERNET_CSMACD: + case IF_TYPE_ETHERNET_3MBIT: + case IF_TYPE_IEEE80212: + case IF_TYPE_FASTETHER: + case IF_TYPE_FASTETHER_FX: + case IF_TYPE_GIGABITETHERNET: + adapter_type = ADAPTER_TYPE_ETHERNET; + break; + case IF_TYPE_IEEE80211: + adapter_type = ADAPTER_TYPE_WIFI; + break; + case IF_TYPE_WWANPP: + case IF_TYPE_WWANPP2: + adapter_type = ADAPTER_TYPE_CELLULAR; + break; + default: + // TODO(phoglund): Need to recognize other types as well. + adapter_type = ADAPTER_TYPE_UNKNOWN; + break; + } + auto underlying_type_for_vpn = ADAPTER_TYPE_UNKNOWN; + if (adapter_type != ADAPTER_TYPE_VPN && + IsConfiguredVpn(prefix, prefix_length)) { + underlying_type_for_vpn = adapter_type; + adapter_type = ADAPTER_TYPE_VPN; + } + if (adapter_type != ADAPTER_TYPE_VPN && + IsVpnMacAddress(rtc::ArrayView<const uint8_t>( + reinterpret_cast<const uint8_t*>( + adapter_addrs->PhysicalAddress), + adapter_addrs->PhysicalAddressLength))) { + // With MAC-based detection we do not know the + // underlying adapter type. + underlying_type_for_vpn = ADAPTER_TYPE_UNKNOWN; + adapter_type = ADAPTER_TYPE_VPN; + } + + auto network = CreateNetwork(name, description, prefix, prefix_length, + adapter_type); + network->set_underlying_type_for_vpn(underlying_type_for_vpn); + network->set_default_local_address_provider(this); + network->set_mdns_responder_provider(this); + network->set_scope_id(scope_id); + network->AddIP(ip); + bool ignored = IsIgnoredNetwork(*network); + network->set_ignored(ignored); + if (include_ignored || !network->ignored()) { + current_networks[key] = network.get(); + networks->push_back(std::move(network)); + } + } else { + (*existing_network).second->AddIP(ip); + } + } + // Count is per-adapter - all 'Networks' created from the same + // adapter need to have the same name. + ++count; + } + adapter_addrs = adapter_addrs->Next; + } + return true; +} +#endif // WEBRTC_WIN + +bool BasicNetworkManager::IsIgnoredNetwork(const Network& network) const { + // Ignore networks on the explicit ignore list. + for (const std::string& ignored_name : network_ignore_list_) { + if (network.name() == ignored_name) { + return true; + } + } + +#if defined(WEBRTC_POSIX) + // Filter out VMware/VirtualBox interfaces, typically named vmnet1, + // vmnet8, or vboxnet0. + if (strncmp(network.name().c_str(), "vmnet", 5) == 0 || + strncmp(network.name().c_str(), "vnic", 4) == 0 || + strncmp(network.name().c_str(), "vboxnet", 7) == 0) { + return true; + } +#elif defined(WEBRTC_WIN) + // Ignore any HOST side vmware adapters with a description like: + // VMware Virtual Ethernet Adapter for VMnet1 + // but don't ignore any GUEST side adapters with a description like: + // VMware Accelerated AMD PCNet Adapter #2 + if (strstr(network.description().c_str(), "VMnet") != nullptr) { + return true; + } +#endif + + // Ignore any networks with a 0.x.y.z IP + if (network.prefix().family() == AF_INET) { + return (network.prefix().v4AddressAsHostOrderInteger() < 0x01000000); + } + + return false; +} + +void BasicNetworkManager::StartUpdating() { + thread_ = Thread::Current(); + // Redundant but necessary for thread annotations. + RTC_DCHECK_RUN_ON(thread_); + if (start_count_) { + // If network interfaces are already discovered and signal is sent, + // we should trigger network signal immediately for the new clients + // to start allocating ports. + if (sent_first_update_) + thread_->PostTask(SafeTask(task_safety_flag_, [this] { + RTC_DCHECK_RUN_ON(thread_); + SignalNetworksChanged(); + })); + } else { + RTC_DCHECK(task_safety_flag_ == nullptr); + task_safety_flag_ = webrtc::PendingTaskSafetyFlag::Create(); + thread_->PostTask(SafeTask(task_safety_flag_, [this] { + RTC_DCHECK_RUN_ON(thread_); + UpdateNetworksContinually(); + })); + StartNetworkMonitor(); + } + ++start_count_; +} + +void BasicNetworkManager::StopUpdating() { + RTC_DCHECK_RUN_ON(thread_); + if (!start_count_) + return; + + --start_count_; + if (!start_count_) { + task_safety_flag_->SetNotAlive(); + task_safety_flag_ = nullptr; + sent_first_update_ = false; + StopNetworkMonitor(); + } +} + +void BasicNetworkManager::StartNetworkMonitor() { + if (network_monitor_factory_ == nullptr) { + return; + } + if (!network_monitor_) { + network_monitor_.reset( + network_monitor_factory_->CreateNetworkMonitor(*field_trials())); + if (!network_monitor_) { + return; + } + network_monitor_->SetNetworksChangedCallback( + [this]() { OnNetworksChanged(); }); + } + + if (network_monitor_->SupportsBindSocketToNetwork()) { + // Set NetworkBinder on SocketServer so that + // PhysicalSocket::Bind will call + // BasicNetworkManager::BindSocketToNetwork(), (that will lookup interface + // name and then call network_monitor_->BindSocketToNetwork()). + thread_->socketserver()->set_network_binder(this); + } + + network_monitor_->Start(); +} + +void BasicNetworkManager::StopNetworkMonitor() { + if (!network_monitor_) { + return; + } + network_monitor_->Stop(); + + if (network_monitor_->SupportsBindSocketToNetwork()) { + // Reset NetworkBinder on SocketServer. + if (thread_->socketserver()->network_binder() == this) { + thread_->socketserver()->set_network_binder(nullptr); + } + } +} + +IPAddress BasicNetworkManager::QueryDefaultLocalAddress(int family) const { + RTC_DCHECK(family == AF_INET || family == AF_INET6); + + std::unique_ptr<Socket> socket( + socket_factory_->CreateSocket(family, SOCK_DGRAM)); + if (!socket) { + RTC_LOG_ERR(LS_ERROR) << "Socket creation failed"; + return IPAddress(); + } + + if (socket->Connect(SocketAddress( + family == AF_INET ? kPublicIPv4Host : kPublicIPv6Host, kPublicPort)) < + 0) { + if (socket->GetError() != ENETUNREACH && + socket->GetError() != EHOSTUNREACH) { + // Ignore the expected case of "host/net unreachable" - which happens if + // the network is V4- or V6-only. + RTC_LOG(LS_INFO) << "Connect failed with " << socket->GetError(); + } + return IPAddress(); + } + return socket->GetLocalAddress().ipaddr(); +} + +void BasicNetworkManager::UpdateNetworksOnce() { + if (!start_count_) + return; + + std::vector<std::unique_ptr<Network>> list; + if (!CreateNetworks(false, &list)) { + SignalError(); + } else { + bool changed; + NetworkManager::Stats stats; + MergeNetworkList(std::move(list), &changed, &stats); + set_default_local_addresses(QueryDefaultLocalAddress(AF_INET), + QueryDefaultLocalAddress(AF_INET6)); + if (changed || !sent_first_update_) { + SignalNetworksChanged(); + sent_first_update_ = true; + } + } +} + +void BasicNetworkManager::UpdateNetworksContinually() { + UpdateNetworksOnce(); + thread_->PostDelayedTask(SafeTask(task_safety_flag_, + [this] { + RTC_DCHECK_RUN_ON(thread_); + UpdateNetworksContinually(); + }), + TimeDelta::Millis(kNetworksUpdateIntervalMs)); +} + +void BasicNetworkManager::DumpNetworks() { + RTC_DCHECK_RUN_ON(thread_); + std::vector<const Network*> list = GetNetworks(); + RTC_LOG(LS_INFO) << "NetworkManager detected " << list.size() << " networks:"; + for (const Network* network : list) { + RTC_LOG(LS_INFO) << network->ToString() << ": " << network->description() + << ", active ? " << network->active() + << ((network->ignored()) ? ", Ignored" : ""); + } +} + +NetworkBindingResult BasicNetworkManager::BindSocketToNetwork( + int socket_fd, + const IPAddress& address) { + RTC_DCHECK_RUN_ON(thread_); + std::string if_name; + if (bind_using_ifname_) { + Network* net = GetNetworkFromAddress(address); + if (net != nullptr) { + if_name = net->name(); + } + } + return network_monitor_->BindSocketToNetwork(socket_fd, address, if_name); +} + +Network::Network(absl::string_view name, + absl::string_view desc, + const IPAddress& prefix, + int prefix_length, + AdapterType type) + : name_(name), + description_(desc), + prefix_(prefix), + prefix_length_(prefix_length), + key_(MakeNetworkKey(name, prefix, prefix_length)), + scope_id_(0), + ignored_(false), + type_(type), + preference_(0) {} + +Network::Network(const Network&) = default; + +Network::~Network() = default; + +// Sets the addresses of this network. Returns true if the address set changed. +// Change detection is short circuited if the changed argument is true. +bool Network::SetIPs(const std::vector<InterfaceAddress>& ips, bool changed) { + // Detect changes with a nested loop; n-squared but we expect on the order + // of 2-3 addresses per network. + changed = changed || ips.size() != ips_.size(); + if (!changed) { + for (const InterfaceAddress& ip : ips) { + if (!absl::c_linear_search(ips_, ip)) { + changed = true; + break; + } + } + } + + ips_ = ips; + return changed; +} + +// Select the best IP address to use from this Network. +IPAddress Network::GetBestIP() const { + if (ips_.size() == 0) { + return IPAddress(); + } + + if (prefix_.family() == AF_INET) { + return static_cast<IPAddress>(ips_.at(0)); + } + + InterfaceAddress selected_ip, link_local_ip, ula_ip; + + for (const InterfaceAddress& ip : ips_) { + // Ignore any address which has been deprecated already. + if (ip.ipv6_flags() & IPV6_ADDRESS_FLAG_DEPRECATED) + continue; + + if (IPIsLinkLocal(ip)) { + link_local_ip = ip; + continue; + } + + // ULA address should only be returned when we have no other + // global IP. + if (IPIsULA(static_cast<const IPAddress&>(ip))) { + ula_ip = ip; + continue; + } + selected_ip = ip; + + // Search could stop once a temporary non-deprecated one is found. + if (ip.ipv6_flags() & IPV6_ADDRESS_FLAG_TEMPORARY) + break; + } + + if (IPIsUnspec(selected_ip)) { + if (!IPIsUnspec(link_local_ip)) { + // No proper global IPv6 address found, use link local address instead. + selected_ip = link_local_ip; + } else if (!IPIsUnspec(ula_ip)) { + // No proper global and link local address found, use ULA instead. + selected_ip = ula_ip; + } + } + + return static_cast<IPAddress>(selected_ip); +} + +webrtc::MdnsResponderInterface* Network::GetMdnsResponder() const { + if (mdns_responder_provider_ == nullptr) { + return nullptr; + } + return mdns_responder_provider_->GetMdnsResponder(); +} + +uint16_t Network::GetCost(const webrtc::FieldTrialsView* field_trials) const { + return GetCost( + *webrtc::AlwaysValidPointer<const webrtc::FieldTrialsView, + webrtc::FieldTrialBasedConfig>(field_trials)); +} + +uint16_t Network::GetCost(const webrtc::FieldTrialsView& field_trials) const { + AdapterType type = IsVpn() ? underlying_type_for_vpn_ : type_; + const bool use_differentiated_cellular_costs = + field_trials.IsEnabled("WebRTC-UseDifferentiatedCellularCosts"); + const bool add_network_cost_to_vpn = + field_trials.IsEnabled("WebRTC-AddNetworkCostToVpn"); + return ComputeNetworkCostByType(type, IsVpn(), + use_differentiated_cellular_costs, + add_network_cost_to_vpn); +} + +// This is the inverse of ComputeNetworkCostByType(). +std::pair<rtc::AdapterType, bool /* vpn */> +Network::GuessAdapterFromNetworkCost(int network_cost) { + switch (network_cost) { + case kNetworkCostMin: + return {rtc::ADAPTER_TYPE_ETHERNET, false}; + case kNetworkCostMin + kNetworkCostVpn: + return {rtc::ADAPTER_TYPE_ETHERNET, true}; + case kNetworkCostLow: + return {rtc::ADAPTER_TYPE_WIFI, false}; + case kNetworkCostLow + kNetworkCostVpn: + return {rtc::ADAPTER_TYPE_WIFI, true}; + case kNetworkCostCellular: + return {rtc::ADAPTER_TYPE_CELLULAR, false}; + case kNetworkCostCellular + kNetworkCostVpn: + return {rtc::ADAPTER_TYPE_CELLULAR, true}; + case kNetworkCostCellular2G: + return {rtc::ADAPTER_TYPE_CELLULAR_2G, false}; + case kNetworkCostCellular2G + kNetworkCostVpn: + return {rtc::ADAPTER_TYPE_CELLULAR_2G, true}; + case kNetworkCostCellular3G: + return {rtc::ADAPTER_TYPE_CELLULAR_3G, false}; + case kNetworkCostCellular3G + kNetworkCostVpn: + return {rtc::ADAPTER_TYPE_CELLULAR_3G, true}; + case kNetworkCostCellular4G: + return {rtc::ADAPTER_TYPE_CELLULAR_4G, false}; + case kNetworkCostCellular4G + kNetworkCostVpn: + return {rtc::ADAPTER_TYPE_CELLULAR_4G, true}; + case kNetworkCostCellular5G: + return {rtc::ADAPTER_TYPE_CELLULAR_5G, false}; + case kNetworkCostCellular5G + kNetworkCostVpn: + return {rtc::ADAPTER_TYPE_CELLULAR_5G, true}; + case kNetworkCostUnknown: + return {rtc::ADAPTER_TYPE_UNKNOWN, false}; + case kNetworkCostUnknown + kNetworkCostVpn: + return {rtc::ADAPTER_TYPE_UNKNOWN, true}; + case kNetworkCostMax: + return {rtc::ADAPTER_TYPE_ANY, false}; + case kNetworkCostMax + kNetworkCostVpn: + return {rtc::ADAPTER_TYPE_ANY, true}; + } + RTC_LOG(LS_VERBOSE) << "Unknown network cost: " << network_cost; + return {rtc::ADAPTER_TYPE_UNKNOWN, false}; +} + +std::string Network::ToString() const { + rtc::StringBuilder ss; + // Print out the first space-terminated token of the network desc, plus + // the IP address. + ss << "Net[" << description_.substr(0, description_.find(' ')) << ":" + << prefix_.ToSensitiveString() << "/" << prefix_length_ << ":" + << AdapterTypeToString(type_); + if (IsVpn()) { + ss << "/" << AdapterTypeToString(underlying_type_for_vpn_); + } + ss << ":id=" << id_ << "]"; + return ss.Release(); +} + +void BasicNetworkManager::set_vpn_list(const std::vector<NetworkMask>& vpn) { + if (thread_ == nullptr) { + vpn_ = vpn; + } else { + thread_->BlockingCall([this, vpn] { vpn_ = vpn; }); + } +} + +bool BasicNetworkManager::IsConfiguredVpn(IPAddress prefix, + int prefix_length) const { + RTC_DCHECK_RUN_ON(thread_); + for (const auto& vpn : vpn_) { + if (prefix_length >= vpn.prefix_length()) { + auto copy = TruncateIP(prefix, vpn.prefix_length()); + if (copy == vpn.address()) { + return true; + } + } + } + return false; +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/network.h b/third_party/libwebrtc/rtc_base/network.h new file mode 100644 index 0000000000..4a97a45d4d --- /dev/null +++ b/third_party/libwebrtc/rtc_base/network.h @@ -0,0 +1,601 @@ +/* + * 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 RTC_BASE_NETWORK_H_ +#define RTC_BASE_NETWORK_H_ + +#include <stdint.h> + +#include <deque> +#include <map> +#include <memory> +#include <string> +#include <vector> + +#include "absl/base/attributes.h" +#include "absl/strings/string_view.h" +#include "api/array_view.h" +#include "api/field_trials_view.h" +#include "api/sequence_checker.h" +#include "api/task_queue/pending_task_safety_flag.h" +#include "api/transport/field_trial_based_config.h" +#include "rtc_base/ip_address.h" +#include "rtc_base/mdns_responder_interface.h" +#include "rtc_base/memory/always_valid_pointer.h" +#include "rtc_base/network_monitor.h" +#include "rtc_base/network_monitor_factory.h" +#include "rtc_base/socket_factory.h" +#include "rtc_base/system/rtc_export.h" +#include "rtc_base/third_party/sigslot/sigslot.h" +#include "rtc_base/thread_annotations.h" + +#if defined(WEBRTC_POSIX) +struct ifaddrs; +#endif // defined(WEBRTC_POSIX) + +namespace rtc { + +extern const char kPublicIPv4Host[]; +extern const char kPublicIPv6Host[]; + +class IfAddrsConverter; +class Network; +class NetworkMonitorInterface; +class Thread; + +// By default, ignore loopback interfaces on the host. +const int kDefaultNetworkIgnoreMask = ADAPTER_TYPE_LOOPBACK; + +namespace webrtc_network_internal { +bool CompareNetworks(const std::unique_ptr<Network>& a, + const std::unique_ptr<Network>& b); +} // namespace webrtc_network_internal + +// Makes a string key for this network. Used in the network manager's maps. +// Network objects are keyed on interface name, network prefix and the +// length of that prefix. +std::string MakeNetworkKey(absl::string_view name, + const IPAddress& prefix, + int prefix_length); + +// Utility function that attempts to determine an adapter type by an interface +// name (e.g., "wlan0"). Can be used by NetworkManager subclasses when other +// mechanisms fail to determine the type. +RTC_EXPORT AdapterType GetAdapterTypeFromName(absl::string_view network_name); + +class DefaultLocalAddressProvider { + public: + virtual ~DefaultLocalAddressProvider() = default; + + // The default local address is the local address used in multi-homed endpoint + // when the any address (0.0.0.0 or ::) is used as the local address. It's + // important to check the return value as a IP family may not be enabled. + virtual bool GetDefaultLocalAddress(int family, IPAddress* ipaddr) const = 0; +}; + +class MdnsResponderProvider { + public: + virtual ~MdnsResponderProvider() = default; + + // Returns the mDNS responder that can be used to obfuscate the local IP + // addresses of ICE host candidates by mDNS hostnames. + // + // The provider MUST outlive the mDNS responder. + virtual webrtc::MdnsResponderInterface* GetMdnsResponder() const = 0; +}; + +// Network/mask in CIDR representation. +class NetworkMask { + public: + NetworkMask(const IPAddress& addr, int prefix_length) + : address_(addr), prefix_length_(prefix_length) {} + + const IPAddress& address() const { return address_; } + int prefix_length() const { return prefix_length_; } + + bool operator==(const NetworkMask& o) const { + return address_ == o.address_ && prefix_length_ == o.prefix_length_; + } + + private: + IPAddress address_; + // Length of valid bits in address_ (for ipv4 valid range is 0-32) + int prefix_length_; +}; + +// Generic network manager interface. It provides list of local +// networks. +// +// Every method of NetworkManager (including the destructor) must be called on +// the same thread, except for the constructor which may be called on any +// thread. +// +// This allows constructing a NetworkManager subclass on one thread and +// passing it into an object that uses it on a different thread. +class RTC_EXPORT NetworkManager : public DefaultLocalAddressProvider, + public MdnsResponderProvider { + public: + // This enum indicates whether adapter enumeration is allowed. + enum EnumerationPermission { + ENUMERATION_ALLOWED, // Adapter enumeration is allowed. Getting 0 network + // from GetNetworks means that there is no network + // available. + ENUMERATION_BLOCKED, // Adapter enumeration is disabled. + // GetAnyAddressNetworks() should be used instead. + }; + + // Called when network list is updated. + sigslot::signal0<> SignalNetworksChanged; + + // Indicates a failure when getting list of network interfaces. + sigslot::signal0<> SignalError; + + // This should be called on the NetworkManager's thread before the + // NetworkManager is used. Subclasses may override this if necessary. + virtual void Initialize() {} + + // Start/Stop monitoring of network interfaces + // list. SignalNetworksChanged or SignalError is emitted immediately + // after StartUpdating() is called. After that SignalNetworksChanged + // is emitted whenever list of networks changes. + virtual void StartUpdating() = 0; + virtual void StopUpdating() = 0; + + // Returns the current list of networks available on this machine. + // StartUpdating() must be called before this method is called. + // It makes sure that repeated calls return the same object for a + // given network, so that quality is tracked appropriately. Does not + // include ignored networks. + // The returned vector of Network* is valid as long as the NetworkManager is + // alive. + virtual std::vector<const Network*> GetNetworks() const = 0; + + // Returns the current permission state of GetNetworks(). + virtual EnumerationPermission enumeration_permission() const; + + // "AnyAddressNetwork" is a network which only contains single "any address" + // IP address. (i.e. INADDR_ANY for IPv4 or in6addr_any for IPv6). This is + // useful as binding to such interfaces allow default routing behavior like + // http traffic. + // + // This method appends the "any address" networks to the list, such that this + // can optionally be called after GetNetworks. + virtual std::vector<const Network*> GetAnyAddressNetworks() = 0; + + // Dumps the current list of networks in the network manager. + virtual void DumpNetworks() {} + bool GetDefaultLocalAddress(int family, IPAddress* ipaddr) const override; + + struct Stats { + int ipv4_network_count; + int ipv6_network_count; + Stats() { + ipv4_network_count = 0; + ipv6_network_count = 0; + } + }; + + // MdnsResponderProvider interface. + webrtc::MdnsResponderInterface* GetMdnsResponder() const override; + + virtual void set_vpn_list(const std::vector<NetworkMask>& vpn) {} +}; + +// Base class for NetworkManager implementations. +class RTC_EXPORT NetworkManagerBase : public NetworkManager { + public: + NetworkManagerBase(const webrtc::FieldTrialsView* field_trials = nullptr); + + std::vector<const Network*> GetNetworks() const override; + std::vector<const Network*> GetAnyAddressNetworks() override; + + EnumerationPermission enumeration_permission() const override; + + bool GetDefaultLocalAddress(int family, IPAddress* ipaddr) const override; + + // Check if MAC address in |bytes| is one of the pre-defined + // MAC addresses for know VPNs. + static bool IsVpnMacAddress(rtc::ArrayView<const uint8_t> address); + + protected: + // Updates `networks_` with the networks listed in `list`. If + // `networks_map_` already has a Network object for a network listed + // in the `list` then it is reused. Accept ownership of the Network + // objects in the `list`. `changed` will be set to true if there is + // any change in the network list. + void MergeNetworkList(std::vector<std::unique_ptr<Network>> list, + bool* changed); + + // `stats` will be populated even if |*changed| is false. + void MergeNetworkList(std::vector<std::unique_ptr<Network>> list, + bool* changed, + NetworkManager::Stats* stats); + + void set_enumeration_permission(EnumerationPermission state) { + enumeration_permission_ = state; + } + + void set_default_local_addresses(const IPAddress& ipv4, + const IPAddress& ipv6); + + Network* GetNetworkFromAddress(const rtc::IPAddress& ip) const; + + // To enable subclasses to get the networks list, without interfering with + // refactoring of the interface GetNetworks method. + const std::vector<Network*>& GetNetworksInternal() const { return networks_; } + + std::unique_ptr<Network> CreateNetwork(absl::string_view name, + absl::string_view description, + const IPAddress& prefix, + int prefix_length, + AdapterType type) const; + + const webrtc::FieldTrialsView* field_trials() const { + return field_trials_.get(); + } + + private: + friend class NetworkTest; + webrtc::AlwaysValidPointer<const webrtc::FieldTrialsView, + webrtc::FieldTrialBasedConfig> + field_trials_; + EnumerationPermission enumeration_permission_; + + std::vector<Network*> networks_; + + std::map<std::string, std::unique_ptr<Network>> networks_map_; + + std::unique_ptr<rtc::Network> ipv4_any_address_network_; + std::unique_ptr<rtc::Network> ipv6_any_address_network_; + + IPAddress default_local_ipv4_address_; + IPAddress default_local_ipv6_address_; + // We use 16 bits to save the bandwidth consumption when sending the network + // id over the Internet. It is OK that the 16-bit integer overflows to get a + // network id 0 because we only compare the network ids in the old and the new + // best connections in the transport channel. + uint16_t next_available_network_id_ = 1; + + // True if calling network_preference() with a changed value + // should result in firing the SignalNetworkChanged signal. + bool signal_network_preference_change_ = false; +}; + +// Basic implementation of the NetworkManager interface that gets list +// of networks using OS APIs. +class RTC_EXPORT BasicNetworkManager : public NetworkManagerBase, + public NetworkBinderInterface, + public sigslot::has_slots<> { + public: + // This is used by lots of downstream code. + BasicNetworkManager(SocketFactory* socket_factory, + const webrtc::FieldTrialsView* field_trials = nullptr) + : BasicNetworkManager(/* network_monitor_factory= */ nullptr, + socket_factory, + field_trials) {} + + BasicNetworkManager(NetworkMonitorFactory* network_monitor_factory, + SocketFactory* socket_factory, + const webrtc::FieldTrialsView* field_trials = nullptr); + ~BasicNetworkManager() override; + + void StartUpdating() override; + void StopUpdating() override; + + void DumpNetworks() override; + + bool started() { return start_count_ > 0; } + + // Sets the network ignore list, which is empty by default. Any network on the + // ignore list will be filtered from network enumeration results. + // Should be called only before initialization. + void set_network_ignore_list(const std::vector<std::string>& list) { + RTC_DCHECK(thread_ == nullptr); + network_ignore_list_ = list; + } + + // Set a list of manually configured VPN's. + void set_vpn_list(const std::vector<NetworkMask>& vpn) override; + + // Check if |prefix| is configured as VPN. + bool IsConfiguredVpn(IPAddress prefix, int prefix_length) const; + + // Bind a socket to interface that ip address belong to. + // Implementation look up interface name and calls + // BindSocketToNetwork on NetworkMonitor. + // The interface name is needed as e.g ipv4 over ipv6 addresses + // are not exposed using Android functions, but it is possible + // bind an ipv4 address to the interface. + NetworkBindingResult BindSocketToNetwork(int socket_fd, + const IPAddress& address) override; + + protected: +#if defined(WEBRTC_POSIX) + // Separated from CreateNetworks for tests. + void ConvertIfAddrs(ifaddrs* interfaces, + IfAddrsConverter* converter, + bool include_ignored, + std::vector<std::unique_ptr<Network>>* networks) const + RTC_RUN_ON(thread_); + NetworkMonitorInterface::InterfaceInfo GetInterfaceInfo( + struct ifaddrs* cursor) const RTC_RUN_ON(thread_); +#endif // defined(WEBRTC_POSIX) + + // Creates a network object for each network available on the machine. + bool CreateNetworks(bool include_ignored, + std::vector<std::unique_ptr<Network>>* networks) const + RTC_RUN_ON(thread_); + + // Determines if a network should be ignored. This should only be determined + // based on the network's property instead of any individual IP. + bool IsIgnoredNetwork(const Network& network) const RTC_RUN_ON(thread_); + + // This function connects a UDP socket to a public address and returns the + // local address associated it. Since it binds to the "any" address + // internally, it returns the default local address on a multi-homed endpoint. + IPAddress QueryDefaultLocalAddress(int family) const RTC_RUN_ON(thread_); + + private: + friend class NetworkTest; + + // Creates a network monitor and listens for network updates. + void StartNetworkMonitor() RTC_RUN_ON(thread_); + // Stops and removes the network monitor. + void StopNetworkMonitor() RTC_RUN_ON(thread_); + // Called when it receives updates from the network monitor. + void OnNetworksChanged(); + + // Updates the networks and reschedules the next update. + void UpdateNetworksContinually() RTC_RUN_ON(thread_); + // Only updates the networks; does not reschedule the next update. + void UpdateNetworksOnce() RTC_RUN_ON(thread_); + + Thread* thread_ = nullptr; + bool sent_first_update_ = true; + int start_count_ = 0; + + webrtc::AlwaysValidPointer<const webrtc::FieldTrialsView, + webrtc::FieldTrialBasedConfig> + field_trials_; + std::vector<std::string> network_ignore_list_; + NetworkMonitorFactory* const network_monitor_factory_; + SocketFactory* const socket_factory_; + std::unique_ptr<NetworkMonitorInterface> network_monitor_ + RTC_GUARDED_BY(thread_); + bool allow_mac_based_ipv6_ RTC_GUARDED_BY(thread_) = false; + bool bind_using_ifname_ RTC_GUARDED_BY(thread_) = false; + + std::vector<NetworkMask> vpn_; + rtc::scoped_refptr<webrtc::PendingTaskSafetyFlag> task_safety_flag_; +}; + +// Represents a Unix-type network interface, with a name and single address. +class RTC_EXPORT Network { + public: + Network(absl::string_view name, + absl::string_view description, + const IPAddress& prefix, + int prefix_length) + : Network(name, + description, + prefix, + prefix_length, + rtc::ADAPTER_TYPE_UNKNOWN) {} + + Network(absl::string_view name, + absl::string_view description, + const IPAddress& prefix, + int prefix_length, + AdapterType type); + + Network(const Network&); + ~Network(); + + // This signal is fired whenever type() or underlying_type_for_vpn() changes. + // Mutable, to support connecting on the const Network passed to cricket::Port + // constructor. + mutable sigslot::signal1<const Network*> SignalTypeChanged; + + // This signal is fired whenever network preference changes. + sigslot::signal1<const Network*> SignalNetworkPreferenceChanged; + + const DefaultLocalAddressProvider* default_local_address_provider() const { + return default_local_address_provider_; + } + void set_default_local_address_provider( + const DefaultLocalAddressProvider* provider) { + default_local_address_provider_ = provider; + } + + void set_mdns_responder_provider(const MdnsResponderProvider* provider) { + mdns_responder_provider_ = provider; + } + + // Returns the name of the interface this network is associated with. + const std::string& name() const { return name_; } + + // Returns the OS-assigned name for this network. This is useful for + // debugging but should not be sent over the wire (for privacy reasons). + const std::string& description() const { return description_; } + + // Returns the prefix for this network. + const IPAddress& prefix() const { return prefix_; } + // Returns the length, in bits, of this network's prefix. + int prefix_length() const { return prefix_length_; } + + // Returns the family for the network prefix. + int family() const { return prefix_.family(); } + + // `key_` has unique value per network interface. Used in sorting network + // interfaces. Key is derived from interface name and it's prefix. + std::string key() const { return key_; } + + // Returns the Network's current idea of the 'best' IP it has. + // Or return an unset IP if this network has no active addresses. + // Here is the rule on how we mark the IPv6 address as ignorable for WebRTC. + // 1) return all global temporary dynamic and non-deprecated ones. + // 2) if #1 not available, return global ones. + // 3) if #2 not available, return local link ones. + // 4) if #3 not available, use ULA ipv6 as last resort. (ULA stands for + // unique local address, which is not route-able in open internet but might + // be useful for a close WebRTC deployment. + + // TODO(guoweis): rule #3 actually won't happen at current + // implementation. The reason being that ULA address starting with + // 0xfc 0r 0xfd will be grouped into its own Network. The result of + // that is WebRTC will have one extra Network to generate candidates + // but the lack of rule #3 shouldn't prevent turning on IPv6 since + // ULA should only be tried in a close deployment anyway. + + // Note that when not specifying any flag, it's treated as case global + // IPv6 address + IPAddress GetBestIP() const; + + // Adds an active IP address to this network. Does not check for duplicates. + void AddIP(const InterfaceAddress& ip) { ips_.push_back(ip); } + void AddIP(const IPAddress& ip) { ips_.push_back(rtc::InterfaceAddress(ip)); } + + // Sets the network's IP address list. Returns true if new IP addresses were + // detected. Passing true to already_changed skips this check. + bool SetIPs(const std::vector<InterfaceAddress>& ips, bool already_changed); + // Get the list of IP Addresses associated with this network. + const std::vector<InterfaceAddress>& GetIPs() const { return ips_; } + // Clear the network's list of addresses. + void ClearIPs() { ips_.clear(); } + // Returns the mDNS responder that can be used to obfuscate the local IP + // addresses of host candidates by mDNS names in ICE gathering. After a + // name-address mapping is created by the mDNS responder, queries for the + // created name will be resolved by the responder. + webrtc::MdnsResponderInterface* GetMdnsResponder() const; + + // Returns the scope-id of the network's address. + // Should only be relevant for link-local IPv6 addresses. + int scope_id() const { return scope_id_; } + void set_scope_id(int id) { scope_id_ = id; } + + // Indicates whether this network should be ignored, perhaps because + // the IP is 0, or the interface is one we know is invalid. + bool ignored() const { return ignored_; } + void set_ignored(bool ignored) { ignored_ = ignored; } + + AdapterType type() const { return type_; } + // When type() is ADAPTER_TYPE_VPN, this returns the type of the underlying + // network interface used by the VPN, typically the preferred network type + // (see for example, the method setUnderlyingNetworks(android.net.Network[]) + // on https://developer.android.com/reference/android/net/VpnService.html). + // When this information is unavailable from the OS, ADAPTER_TYPE_UNKNOWN is + // returned. + AdapterType underlying_type_for_vpn() const { + return underlying_type_for_vpn_; + } + void set_type(AdapterType type) { + if (type_ == type) { + return; + } + type_ = type; + if (type != ADAPTER_TYPE_VPN) { + underlying_type_for_vpn_ = ADAPTER_TYPE_UNKNOWN; + } + SignalTypeChanged(this); + } + + void set_underlying_type_for_vpn(AdapterType type) { + if (underlying_type_for_vpn_ == type) { + return; + } + underlying_type_for_vpn_ = type; + SignalTypeChanged(this); + } + + bool IsVpn() const { return type_ == ADAPTER_TYPE_VPN; } + + bool IsCellular() const { return IsCellular(type_); } + + static bool IsCellular(AdapterType type) { + switch (type) { + case ADAPTER_TYPE_CELLULAR: + case ADAPTER_TYPE_CELLULAR_2G: + case ADAPTER_TYPE_CELLULAR_3G: + case ADAPTER_TYPE_CELLULAR_4G: + case ADAPTER_TYPE_CELLULAR_5G: + return true; + default: + return false; + } + } + + // Note: This function is called "rarely". + // Twice per Network in BasicPortAllocator if + // PORTALLOCATOR_DISABLE_COSTLY_NETWORKS. Once in Port::Construct() (and when + // Port::OnNetworkTypeChanged is called). + ABSL_DEPRECATED( + "Use the version with field trials, see bugs.webrtc.org/webrtc:10335") + uint16_t GetCost(const webrtc::FieldTrialsView* field_trials = nullptr) const; + uint16_t GetCost(const webrtc::FieldTrialsView& field_trials) const; + + // A unique id assigned by the network manager, which may be signaled + // to the remote side in the candidate. + uint16_t id() const { return id_; } + void set_id(uint16_t id) { id_ = id; } + + int preference() const { return preference_; } + void set_preference(int preference) { preference_ = preference; } + + // When we enumerate networks and find a previously-seen network is missing, + // we do not remove it (because it may be used elsewhere). Instead, we mark + // it inactive, so that we can detect network changes properly. + bool active() const { return active_; } + void set_active(bool active) { + if (active_ != active) { + active_ = active; + } + } + + // Property set by operating system/firmware that has information + // about connection strength to e.g WIFI router or CELL base towers. + NetworkPreference network_preference() const { return network_preference_; } + void set_network_preference(NetworkPreference val) { + if (network_preference_ == val) { + return; + } + network_preference_ = val; + SignalNetworkPreferenceChanged(this); + } + + static std::pair<rtc::AdapterType, bool /* vpn */> + GuessAdapterFromNetworkCost(int network_cost); + + // Debugging description of this network + std::string ToString() const; + + private: + const DefaultLocalAddressProvider* default_local_address_provider_ = nullptr; + const MdnsResponderProvider* mdns_responder_provider_ = nullptr; + std::string name_; + std::string description_; + IPAddress prefix_; + int prefix_length_; + std::string key_; + std::vector<InterfaceAddress> ips_; + int scope_id_; + bool ignored_; + AdapterType type_; + AdapterType underlying_type_for_vpn_ = ADAPTER_TYPE_UNKNOWN; + int preference_; + bool active_ = true; + uint16_t id_ = 0; + NetworkPreference network_preference_ = NetworkPreference::NEUTRAL; + + friend class NetworkManager; +}; + +} // namespace rtc + +#endif // RTC_BASE_NETWORK_H_ diff --git a/third_party/libwebrtc/rtc_base/network/BUILD.gn b/third_party/libwebrtc/rtc_base/network/BUILD.gn new file mode 100644 index 0000000000..a42745a4c0 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/network/BUILD.gn @@ -0,0 +1,33 @@ +# 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("sent_packet") { + sources = [ + "sent_packet.cc", + "sent_packet.h", + ] + deps = [ "../system:rtc_export" ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] +} + +rtc_library("received_packet") { + sources = [ + "received_packet.cc", + "received_packet.h", + ] + deps = [ + "../../api:array_view", + "../../api/units:timestamp", + ] + absl_deps = [ + "//third_party/abseil-cpp/absl/functional:any_invocable", + "//third_party/abseil-cpp/absl/types:optional", + ] +} diff --git a/third_party/libwebrtc/rtc_base/network/received_packet.cc b/third_party/libwebrtc/rtc_base/network/received_packet.cc new file mode 100644 index 0000000000..9612c3dab4 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/network/received_packet.cc @@ -0,0 +1,23 @@ +/* + * Copyright 2023 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 "rtc_base/network/received_packet.h" + +#include <utility> + +#include "absl/types/optional.h" + +namespace rtc { + +ReceivedPacket::ReceivedPacket(rtc::ArrayView<const uint8_t> payload, + absl::optional<webrtc::Timestamp> arrival_time) + : payload_(payload), arrival_time_(std::move(arrival_time)) {} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/network/received_packet.h b/third_party/libwebrtc/rtc_base/network/received_packet.h new file mode 100644 index 0000000000..7f8b2f934c --- /dev/null +++ b/third_party/libwebrtc/rtc_base/network/received_packet.h @@ -0,0 +1,47 @@ +/* + * Copyright 2023 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 RTC_BASE_NETWORK_RECEIVED_PACKET_H_ +#define RTC_BASE_NETWORK_RECEIVED_PACKET_H_ + +#include <cstdint> + +#include "absl/types/optional.h" +#include "api/array_view.h" +#include "api/units/timestamp.h" + +namespace rtc { + +// ReceivedPacket repressent a received IP packet. +// It contains a payload and metadata. +// ReceivedPacket itself does not put constraints on what payload contains. For +// example it may contains STUN, SCTP, SRTP, RTP, RTCP.... etc. +class ReceivedPacket { + public: + // Caller must keep memory pointed to by payload valid for the lifetime of + // this ReceivedPacket. + ReceivedPacket( + rtc::ArrayView<const uint8_t> payload, + absl::optional<webrtc::Timestamp> arrival_time = absl::nullopt); + + rtc::ArrayView<const uint8_t> payload() const { return payload_; } + + // Timestamp when this packet was received. Not available on all socket + // implementations. + absl::optional<webrtc::Timestamp> arrival_time() const { + return arrival_time_; + } + + private: + rtc::ArrayView<const uint8_t> payload_; + absl::optional<webrtc::Timestamp> arrival_time_; +}; + +} // namespace rtc +#endif // RTC_BASE_NETWORK_RECEIVED_PACKET_H_ diff --git a/third_party/libwebrtc/rtc_base/network/sent_packet.cc b/third_party/libwebrtc/rtc_base/network/sent_packet.cc new file mode 100644 index 0000000000..8cc49737ef --- /dev/null +++ b/third_party/libwebrtc/rtc_base/network/sent_packet.cc @@ -0,0 +1,27 @@ +/* + * 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. + */ + +#include "rtc_base/network/sent_packet.h" + +namespace rtc { + +PacketInfo::PacketInfo() = default; +PacketInfo::PacketInfo(const PacketInfo& info) = default; +PacketInfo::~PacketInfo() = default; + +SentPacket::SentPacket() = default; +SentPacket::SentPacket(int64_t packet_id, int64_t send_time_ms) + : packet_id(packet_id), send_time_ms(send_time_ms) {} +SentPacket::SentPacket(int64_t packet_id, + int64_t send_time_ms, + const rtc::PacketInfo& info) + : packet_id(packet_id), send_time_ms(send_time_ms), info(info) {} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/network/sent_packet.h b/third_party/libwebrtc/rtc_base/network/sent_packet.h new file mode 100644 index 0000000000..457fb969cf --- /dev/null +++ b/third_party/libwebrtc/rtc_base/network/sent_packet.h @@ -0,0 +1,69 @@ +/* + * 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 RTC_BASE_NETWORK_SENT_PACKET_H_ +#define RTC_BASE_NETWORK_SENT_PACKET_H_ + +#include <stddef.h> +#include <stdint.h> + +#include "absl/types/optional.h" +#include "rtc_base/system/rtc_export.h" + +namespace rtc { + +enum class PacketType { + kUnknown, + kData, + kIceConnectivityCheck, + kIceConnectivityCheckResponse, + kStunMessage, + kTurnMessage, +}; + +enum class PacketInfoProtocolType { + kUnknown, + kUdp, + kTcp, + kSsltcp, + kTls, +}; + +struct RTC_EXPORT PacketInfo { + PacketInfo(); + PacketInfo(const PacketInfo& info); + ~PacketInfo(); + + bool included_in_feedback = false; + bool included_in_allocation = false; + PacketType packet_type = PacketType::kUnknown; + PacketInfoProtocolType protocol = PacketInfoProtocolType::kUnknown; + // A unique id assigned by the network manager, and absl::nullopt if not set. + absl::optional<uint16_t> network_id; + size_t packet_size_bytes = 0; + size_t turn_overhead_bytes = 0; + size_t ip_overhead_bytes = 0; +}; + +struct RTC_EXPORT SentPacket { + SentPacket(); + SentPacket(int64_t packet_id, int64_t send_time_ms); + SentPacket(int64_t packet_id, + int64_t send_time_ms, + const rtc::PacketInfo& info); + + int64_t packet_id = -1; + int64_t send_time_ms = -1; + rtc::PacketInfo info; +}; + +} // namespace rtc + +#endif // RTC_BASE_NETWORK_SENT_PACKET_H_ diff --git a/third_party/libwebrtc/rtc_base/network/sent_packet_gn/moz.build b/third_party/libwebrtc/rtc_base/network/sent_packet_gn/moz.build new file mode 100644 index 0000000000..a1276d9a7a --- /dev/null +++ b/third_party/libwebrtc/rtc_base/network/sent_packet_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/rtc_base/network/sent_packet.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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("sent_packet_gn") diff --git a/third_party/libwebrtc/rtc_base/network_constants.cc b/third_party/libwebrtc/rtc_base/network_constants.cc new file mode 100644 index 0000000000..9e6ab520e5 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/network_constants.cc @@ -0,0 +1,47 @@ +/* + * 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. + */ + +#include "rtc_base/network_constants.h" + +#include "rtc_base/checks.h" + +namespace rtc { + +std::string AdapterTypeToString(AdapterType type) { + switch (type) { + case ADAPTER_TYPE_ANY: + return "Wildcard"; + case ADAPTER_TYPE_UNKNOWN: + return "Unknown"; + case ADAPTER_TYPE_ETHERNET: + return "Ethernet"; + case ADAPTER_TYPE_WIFI: + return "Wifi"; + case ADAPTER_TYPE_CELLULAR: + return "Cellular"; + case ADAPTER_TYPE_CELLULAR_2G: + return "Cellular2G"; + case ADAPTER_TYPE_CELLULAR_3G: + return "Cellular3G"; + case ADAPTER_TYPE_CELLULAR_4G: + return "Cellular4G"; + case ADAPTER_TYPE_CELLULAR_5G: + return "Cellular5G"; + case ADAPTER_TYPE_VPN: + return "VPN"; + case ADAPTER_TYPE_LOOPBACK: + return "Loopback"; + default: + RTC_DCHECK_NOTREACHED() << "Invalid type " << type; + return std::string(); + } +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/network_constants.h b/third_party/libwebrtc/rtc_base/network_constants.h new file mode 100644 index 0000000000..578b9710d0 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/network_constants.h @@ -0,0 +1,72 @@ +/* + * 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 RTC_BASE_NETWORK_CONSTANTS_H_ +#define RTC_BASE_NETWORK_CONSTANTS_H_ + +#include <stdint.h> + +#include <string> + +namespace rtc { + +constexpr uint16_t kNetworkCostMax = 999; +constexpr uint16_t kNetworkCostCellular2G = 980; +constexpr uint16_t kNetworkCostCellular3G = 910; +constexpr uint16_t kNetworkCostCellular = 900; +constexpr uint16_t kNetworkCostCellular4G = 500; +constexpr uint16_t kNetworkCostCellular5G = 250; +constexpr uint16_t kNetworkCostUnknown = 50; +constexpr uint16_t kNetworkCostLow = 10; +constexpr uint16_t kNetworkCostMin = 0; + +// Add 1 to network cost of underlying network type +// so that e.g a "plain" WIFI is prefered over a VPN over WIFI +// everything else being equal. +constexpr uint16_t kNetworkCostVpn = 1; + +// alias +constexpr uint16_t kNetworkCostHigh = kNetworkCostCellular; + +enum AdapterType { + // This enum resembles the one in Chromium net::ConnectionType. + ADAPTER_TYPE_UNKNOWN = 0, + ADAPTER_TYPE_ETHERNET = 1 << 0, + ADAPTER_TYPE_WIFI = 1 << 1, + ADAPTER_TYPE_CELLULAR = 1 << 2, // This is CELLULAR of unknown type. + ADAPTER_TYPE_VPN = 1 << 3, + ADAPTER_TYPE_LOOPBACK = 1 << 4, + // ADAPTER_TYPE_ANY is used for a network, which only contains a single "any + // address" IP address (INADDR_ANY for IPv4 or in6addr_any for IPv6), and can + // use any/all network interfaces. Whereas ADAPTER_TYPE_UNKNOWN is used + // when the network uses a specific interface/IP, but its interface type can + // not be determined or not fit in this enum. + ADAPTER_TYPE_ANY = 1 << 5, + ADAPTER_TYPE_CELLULAR_2G = 1 << 6, + ADAPTER_TYPE_CELLULAR_3G = 1 << 7, + ADAPTER_TYPE_CELLULAR_4G = 1 << 8, + ADAPTER_TYPE_CELLULAR_5G = 1 << 9 +}; + +std::string AdapterTypeToString(AdapterType type); + +// Useful for testing! +constexpr AdapterType kAllAdapterTypes[] = { + ADAPTER_TYPE_UNKNOWN, ADAPTER_TYPE_ETHERNET, + ADAPTER_TYPE_WIFI, ADAPTER_TYPE_CELLULAR, + ADAPTER_TYPE_VPN, ADAPTER_TYPE_LOOPBACK, + ADAPTER_TYPE_ANY, ADAPTER_TYPE_CELLULAR_2G, + ADAPTER_TYPE_CELLULAR_3G, ADAPTER_TYPE_CELLULAR_4G, + ADAPTER_TYPE_CELLULAR_5G, +}; + +} // namespace rtc + +#endif // RTC_BASE_NETWORK_CONSTANTS_H_ diff --git a/third_party/libwebrtc/rtc_base/network_constants_gn/moz.build b/third_party/libwebrtc/rtc_base/network_constants_gn/moz.build new file mode 100644 index 0000000000..083e18ac8e --- /dev/null +++ b/third_party/libwebrtc/rtc_base/network_constants_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/rtc_base/network_constants.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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("network_constants_gn") diff --git a/third_party/libwebrtc/rtc_base/network_monitor.cc b/third_party/libwebrtc/rtc_base/network_monitor.cc new file mode 100644 index 0000000000..70c2ad5020 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/network_monitor.cc @@ -0,0 +1,30 @@ +/* + * Copyright 2015 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 "rtc_base/network_monitor.h" + +#include "rtc_base/checks.h" + +namespace rtc { + +const char* NetworkPreferenceToString(NetworkPreference preference) { + switch (preference) { + case NetworkPreference::NEUTRAL: + return "NEUTRAL"; + case NetworkPreference::NOT_PREFERRED: + return "NOT_PREFERRED"; + } + RTC_CHECK_NOTREACHED(); +} + +NetworkMonitorInterface::NetworkMonitorInterface() {} +NetworkMonitorInterface::~NetworkMonitorInterface() {} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/network_monitor.h b/third_party/libwebrtc/rtc_base/network_monitor.h new file mode 100644 index 0000000000..605854f6ea --- /dev/null +++ b/third_party/libwebrtc/rtc_base/network_monitor.h @@ -0,0 +1,139 @@ +/* + * Copyright 2015 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 RTC_BASE_NETWORK_MONITOR_H_ +#define RTC_BASE_NETWORK_MONITOR_H_ + +#include <functional> +#include <utility> + +#include "absl/strings/string_view.h" +#include "rtc_base/network_constants.h" + +namespace rtc { + +class IPAddress; + +enum class NetworkBindingResult { + SUCCESS = 0, // No error + FAILURE = -1, // Generic error + NOT_IMPLEMENTED = -2, + ADDRESS_NOT_FOUND = -3, + NETWORK_CHANGED = -4 +}; + +// NetworkPreference property set by operating system/firmware that has +// information about connection strength to e.g WIFI router or CELL base towers. +// GENERATED_JAVA_ENUM_PACKAGE: org.webrtc +enum class NetworkPreference { + NEUTRAL = 0, + NOT_PREFERRED = -1, +}; + +const char* NetworkPreferenceToString(NetworkPreference preference); + +// This interface is set onto a socket server, +// where only the ip address is known at the time of binding. +class NetworkBinderInterface { + public: + // Binds a socket to the network that is attached to `address` so that all + // packets on the socket `socket_fd` will be sent via that network. + // This is needed because some operating systems (like Android) require a + // special bind call to put packets on a non-default network interface. + virtual NetworkBindingResult BindSocketToNetwork( + int socket_fd, + const IPAddress& address) = 0; + virtual ~NetworkBinderInterface() {} +}; + +/* + * Receives network-change events via `OnNetworksChanged` and signals the + * networks changed event. + * + * Threading consideration: + * It is expected that all upstream operations (from native to Java) are + * performed from the worker thread. This includes creating, starting and + * stopping the monitor. This avoids the potential race condition when creating + * the singleton Java NetworkMonitor class. Downstream operations can be from + * any thread, but this class will forward all the downstream operations onto + * the worker thread. + * + * Memory consideration: + * NetworkMonitor is owned by the caller (NetworkManager). The global network + * monitor factory is owned by the PeerConnectionFactory. + */ +// Generic network monitor interface. It starts and stops monitoring network +// changes, and fires the SignalNetworksChanged event when networks change. +class NetworkMonitorInterface { + public: + struct InterfaceInfo { + // The type of adapter if known. + AdapterType adapter_type; + + // Is ADAPTER_TYPE_UNKNOWN unless adapter_type == ADAPTER_TYPE_VPN. + AdapterType underlying_type_for_vpn = ADAPTER_TYPE_UNKNOWN; + + // The OS/firmware specific preference of this interface. + NetworkPreference network_preference = NetworkPreference::NEUTRAL; + + // Is this interface available to use? WebRTC shouldn't attempt to use it if + // this returns false. + // + // It's possible for this status to change, in which case + // SignalNetworksChanged will be fired. + // + // The specific use case this was added for was a phone with two SIM + // cards, where attempting to use all interfaces returned from getifaddrs + // caused the connection to be dropped. + bool available = true; + }; + + NetworkMonitorInterface(); + virtual ~NetworkMonitorInterface(); + + virtual void Start() = 0; + virtual void Stop() = 0; + + // Get information about an interface. + // If the interface is not known, the return struct will have set + // `adapter_type` to ADAPTER_TYPE_UNKNOWN and `available` to false. + virtual InterfaceInfo GetInterfaceInfo(absl::string_view interface_name) = 0; + + // Does `this` NetworkMonitorInterface implement BindSocketToNetwork? + // Only Android returns true. + virtual bool SupportsBindSocketToNetwork() const { return false; } + + // Bind a socket to an interface specified by ip address and/or interface + // name. Only implemented on Android. + virtual NetworkBindingResult BindSocketToNetwork( + int socket_fd, + const IPAddress& address, + absl::string_view interface_name) { + return NetworkBindingResult::NOT_IMPLEMENTED; + } + + void SetNetworksChangedCallback(std::function<void()> callback) { + networks_changed_callback_ = std::move(callback); + } + + protected: + void InvokeNetworksChangedCallback() { + if (networks_changed_callback_) { + networks_changed_callback_(); + } + } + + private: + std::function<void()> networks_changed_callback_; +}; + +} // namespace rtc + +#endif // RTC_BASE_NETWORK_MONITOR_H_ diff --git a/third_party/libwebrtc/rtc_base/network_monitor_factory.cc b/third_party/libwebrtc/rtc_base/network_monitor_factory.cc new file mode 100644 index 0000000000..9fac4d95a0 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/network_monitor_factory.cc @@ -0,0 +1,18 @@ +/* + * 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. + */ + +#include "rtc_base/network_monitor_factory.h" + +namespace rtc { + +NetworkMonitorFactory::NetworkMonitorFactory() {} +NetworkMonitorFactory::~NetworkMonitorFactory() {} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/network_monitor_factory.h b/third_party/libwebrtc/rtc_base/network_monitor_factory.h new file mode 100644 index 0000000000..c76ed97d8c --- /dev/null +++ b/third_party/libwebrtc/rtc_base/network_monitor_factory.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 RTC_BASE_NETWORK_MONITOR_FACTORY_H_ +#define RTC_BASE_NETWORK_MONITOR_FACTORY_H_ + +namespace webrtc { +class FieldTrialsView; +} // namespace webrtc + +namespace rtc { + +// Forward declaring this so it's not part of the API surface; it's only +// expected to be used by Android/iOS SDK code. +class NetworkMonitorInterface; + +/* + * NetworkMonitorFactory creates NetworkMonitors. + * Note that CreateNetworkMonitor is expected to be called on the network + * thread with the returned object only being used on that thread thereafter. + */ +class NetworkMonitorFactory { + public: + virtual NetworkMonitorInterface* CreateNetworkMonitor( + const webrtc::FieldTrialsView& field_trials) = 0; + + virtual ~NetworkMonitorFactory(); + + protected: + NetworkMonitorFactory(); +}; + +} // namespace rtc + +#endif // RTC_BASE_NETWORK_MONITOR_FACTORY_H_ diff --git a/third_party/libwebrtc/rtc_base/network_route.cc b/third_party/libwebrtc/rtc_base/network_route.cc new file mode 100644 index 0000000000..9762dc2eb7 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/network_route.cc @@ -0,0 +1,27 @@ +/* + * 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. + */ + +#include "rtc_base/network_route.h" + +namespace rtc { + +bool RouteEndpoint::operator==(const RouteEndpoint& other) const { + return adapter_type_ == other.adapter_type_ && + adapter_id_ == other.adapter_id_ && network_id_ == other.network_id_ && + uses_turn_ == other.uses_turn_; +} + +bool NetworkRoute::operator==(const NetworkRoute& other) const { + return connected == other.connected && local == other.local && + remote == other.remote && packet_overhead == other.packet_overhead && + last_sent_packet_id == other.last_sent_packet_id; +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/network_route.h b/third_party/libwebrtc/rtc_base/network_route.h new file mode 100644 index 0000000000..17b43e5b69 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/network_route.h @@ -0,0 +1,95 @@ +/* + * Copyright 2016 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 RTC_BASE_NETWORK_ROUTE_H_ +#define RTC_BASE_NETWORK_ROUTE_H_ + +#include <stdint.h> + +#include <string> + +#include "rtc_base/network_constants.h" +#include "rtc_base/strings/string_builder.h" +#include "rtc_base/system/inline.h" + +// TODO(honghaiz): Make a directory that describes the interfaces and structs +// the media code can rely on and the network code can implement, and both can +// depend on that, but not depend on each other. Then, move this file to that +// directory. +namespace rtc { + +class RouteEndpoint { + public: + RouteEndpoint() {} // Used by tests. + RouteEndpoint(AdapterType adapter_type, + uint16_t adapter_id, + uint16_t network_id, + bool uses_turn) + : adapter_type_(adapter_type), + adapter_id_(adapter_id), + network_id_(network_id), + uses_turn_(uses_turn) {} + + RouteEndpoint(const RouteEndpoint&) = default; + RouteEndpoint& operator=(const RouteEndpoint&) = default; + + // Used by tests. + static RouteEndpoint CreateWithNetworkId(uint16_t network_id) { + return RouteEndpoint(ADAPTER_TYPE_UNKNOWN, + /* adapter_id = */ 0, network_id, + /* uses_turn = */ false); + } + RouteEndpoint CreateWithTurn(bool uses_turn) const { + return RouteEndpoint(adapter_type_, adapter_id_, network_id_, uses_turn); + } + + AdapterType adapter_type() const { return adapter_type_; } + uint16_t adapter_id() const { return adapter_id_; } + uint16_t network_id() const { return network_id_; } + bool uses_turn() const { return uses_turn_; } + + bool operator==(const RouteEndpoint& other) const; + + private: + AdapterType adapter_type_ = ADAPTER_TYPE_UNKNOWN; + uint16_t adapter_id_ = 0; + uint16_t network_id_ = 0; + bool uses_turn_ = false; +}; + +struct NetworkRoute { + bool connected = false; + RouteEndpoint local; + RouteEndpoint remote; + // Last packet id sent on the PREVIOUS route. + int last_sent_packet_id = -1; + // The overhead in bytes from IP layer and above. + // This is the maximum of any part of the route. + int packet_overhead = 0; + + RTC_NO_INLINE inline std::string DebugString() const { + rtc::StringBuilder oss; + oss << "[ connected: " << connected << " local: [ " << local.adapter_id() + << "/" << local.network_id() << " " + << AdapterTypeToString(local.adapter_type()) + << " turn: " << local.uses_turn() << " ] remote: [ " + << remote.adapter_id() << "/" << remote.network_id() << " " + << AdapterTypeToString(remote.adapter_type()) + << " turn: " << remote.uses_turn() + << " ] packet_overhead_bytes: " << packet_overhead << " ]"; + return oss.Release(); + } + + bool operator==(const NetworkRoute& other) const; +}; + +} // namespace rtc + +#endif // RTC_BASE_NETWORK_ROUTE_H_ diff --git a/third_party/libwebrtc/rtc_base/network_route_gn/moz.build b/third_party/libwebrtc/rtc_base/network_route_gn/moz.build new file mode 100644 index 0000000000..c35c498d44 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/network_route_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/rtc_base/network_route.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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("network_route_gn") diff --git a/third_party/libwebrtc/rtc_base/network_route_unittest.cc b/third_party/libwebrtc/rtc_base/network_route_unittest.cc new file mode 100644 index 0000000000..485683b71f --- /dev/null +++ b/third_party/libwebrtc/rtc_base/network_route_unittest.cc @@ -0,0 +1,24 @@ +/* + * 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 "rtc_base/network_route.h" + +#include "rtc_base/gunit.h" +#include "test/gmock.h" + +namespace rtc { + +TEST(NetworkRoute, Equals) { + NetworkRoute r1; + NetworkRoute r2 = r1; + EXPECT_TRUE(r1 == r2); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/network_unittest.cc b/third_party/libwebrtc/rtc_base/network_unittest.cc new file mode 100644 index 0000000000..d1999f349c --- /dev/null +++ b/third_party/libwebrtc/rtc_base/network_unittest.cc @@ -0,0 +1,1704 @@ +/* + * 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 "rtc_base/network.h" + +#include <stdlib.h> + +#include <algorithm> +#include <memory> +#include <vector> + +#include "absl/algorithm/container.h" +#include "absl/strings/match.h" +#include "absl/strings/string_view.h" +#include "rtc_base/checks.h" +#include "rtc_base/net_helpers.h" +#include "rtc_base/net_test_helpers.h" +#include "rtc_base/network_monitor.h" +#include "rtc_base/network_monitor_factory.h" +#include "rtc_base/physical_socket_server.h" +#if defined(WEBRTC_POSIX) +#include <net/if.h> +#include <sys/types.h> + +#include "rtc_base/ifaddrs_converter.h" +#endif // defined(WEBRTC_POSIX) +#include "rtc_base/gunit.h" +#include "test/gmock.h" +#if defined(WEBRTC_WIN) +#include "rtc_base/logging.h" // For RTC_LOG_GLE +#endif +#include "test/field_trial.h" +#include "test/scoped_key_value_config.h" + +using ::testing::Contains; +using ::testing::Not; +using ::testing::UnorderedElementsAre; +using ::testing::UnorderedElementsAreArray; + +namespace rtc { + +#define MAYBE_SKIP_IPV4 \ + if (!HasIPv4Enabled()) { \ + RTC_LOG(LS_INFO) << "No IPv4... skipping"; \ + return; \ + } + +namespace { + +IPAddress IPFromString(absl::string_view str) { + IPAddress ip; + RTC_CHECK(IPFromString(str, &ip)); + return ip; +} + +class FakeNetworkMonitor : public NetworkMonitorInterface { + public: + void Start() override { started_ = true; } + void Stop() override { started_ = false; } + bool started() { return started_; } + InterfaceInfo GetInterfaceInfo(absl::string_view if_name) override { + InterfaceInfo if_info = { + .adapter_type = ADAPTER_TYPE_UNKNOWN, + .available = absl::c_count(unavailable_adapters_, if_name) == 0, + }; + if (absl::StartsWith(if_name, "wifi")) { + if_info.adapter_type = ADAPTER_TYPE_WIFI; + } else if (absl::StartsWith(if_name, "cellular")) { + if_info.adapter_type = ADAPTER_TYPE_CELLULAR; + } + return if_info; + } + + // Used to test IsAdapterAvailable. + void set_unavailable_adapters(std::vector<std::string> unavailable_adapters) { + unavailable_adapters_ = unavailable_adapters; + } + + bool SupportsBindSocketToNetwork() const override { return true; } + + NetworkBindingResult BindSocketToNetwork(int socket_fd, + const IPAddress& address, + absl::string_view if_name) override { + if (absl::c_count(addresses_, address) > 0) { + return NetworkBindingResult::SUCCESS; + } + + for (auto const& iter : adapters_) { + if (if_name.find(iter) != absl::string_view::npos) { + return NetworkBindingResult::SUCCESS; + } + } + return NetworkBindingResult::ADDRESS_NOT_FOUND; + } + + void set_ip_addresses(std::vector<IPAddress> addresses) { + addresses_ = addresses; + } + + void set_adapters(std::vector<std::string> adapters) { adapters_ = adapters; } + + void InovkeNetworksChangedCallbackForTesting() { + InvokeNetworksChangedCallback(); + } + + private: + bool started_ = false; + std::vector<std::string> adapters_; + std::vector<std::string> unavailable_adapters_; + std::vector<IPAddress> addresses_; +}; + +class FakeNetworkMonitorFactory : public NetworkMonitorFactory { + public: + FakeNetworkMonitorFactory() {} + NetworkMonitorInterface* CreateNetworkMonitor( + const webrtc::FieldTrialsView& field_trials) override { + return new FakeNetworkMonitor(); + } +}; + +bool SameNameAndPrefix(const rtc::Network& a, const rtc::Network& b) { + if (a.name() != b.name()) { + RTC_LOG(LS_INFO) << "Different interface names."; + return false; + } + if (a.prefix_length() != b.prefix_length() || a.prefix() != b.prefix()) { + RTC_LOG(LS_INFO) << "Different IP prefixes."; + return false; + } + return true; +} + +std::vector<const Network*> CopyNetworkPointers( + const std::vector<std::unique_ptr<Network>>& owning_list) { + std::vector<const Network*> ptr_list; + ptr_list.reserve(owning_list.size()); + for (const auto& network : owning_list) { + ptr_list.push_back(network.get()); + } + return ptr_list; +} + +} // namespace + +class NetworkTest : public ::testing::Test, public sigslot::has_slots<> { + public: + NetworkTest() : callback_called_(false) {} + + void OnNetworksChanged() { callback_called_ = true; } + + NetworkManager::Stats MergeNetworkList( + BasicNetworkManager& network_manager, + std::vector<std::unique_ptr<Network>> list, + bool* changed) { + NetworkManager::Stats stats; + network_manager.MergeNetworkList(std::move(list), changed, &stats); + return stats; + } + + bool IsIgnoredNetwork(BasicNetworkManager& network_manager, + const Network& network) { + RTC_DCHECK_RUN_ON(network_manager.thread_); + return network_manager.IsIgnoredNetwork(network); + } + + IPAddress QueryDefaultLocalAddress(BasicNetworkManager& network_manager, + int family) { + RTC_DCHECK_RUN_ON(network_manager.thread_); + return network_manager.QueryDefaultLocalAddress(family); + } + + std::vector<std::unique_ptr<Network>> GetNetworks( + const BasicNetworkManager& network_manager, + bool include_ignored) { + RTC_DCHECK_RUN_ON(network_manager.thread_); + std::vector<std::unique_ptr<Network>> list; + network_manager.CreateNetworks(include_ignored, &list); + return list; + } + + FakeNetworkMonitor* GetNetworkMonitor(BasicNetworkManager& network_manager) { + RTC_DCHECK_RUN_ON(network_manager.thread_); + return static_cast<FakeNetworkMonitor*>( + network_manager.network_monitor_.get()); + } + void ClearNetworks(BasicNetworkManager& network_manager) { + network_manager.networks_.clear(); + network_manager.networks_map_.clear(); + } + + AdapterType GetAdapterType(BasicNetworkManager& network_manager) { + std::vector<const Network*> list = network_manager.GetNetworks(); + RTC_CHECK_EQ(1, list.size()); + return list[0]->type(); + } + +#if defined(WEBRTC_POSIX) + // Separated from CreateNetworks for tests. + static void CallConvertIfAddrs( + const BasicNetworkManager& network_manager, + struct ifaddrs* interfaces, + bool include_ignored, + std::vector<std::unique_ptr<Network>>* networks) { + RTC_DCHECK_RUN_ON(network_manager.thread_); + // Use the base IfAddrsConverter for test cases. + std::unique_ptr<IfAddrsConverter> ifaddrs_converter(new IfAddrsConverter()); + network_manager.ConvertIfAddrs(interfaces, ifaddrs_converter.get(), + include_ignored, networks); + } + + struct sockaddr_in6* CreateIpv6Addr(absl::string_view ip_string, + uint32_t scope_id) { + struct sockaddr_in6* ipv6_addr = + static_cast<struct sockaddr_in6*>(malloc(sizeof(struct sockaddr_in6))); + memset(ipv6_addr, 0, sizeof(struct sockaddr_in6)); + ipv6_addr->sin6_family = AF_INET6; + ipv6_addr->sin6_scope_id = scope_id; + IPAddress ip; + IPFromString(ip_string, &ip); + ipv6_addr->sin6_addr = ip.ipv6_address(); + return ipv6_addr; + } + + // Pointers created here need to be released via ReleaseIfAddrs. + struct ifaddrs* AddIpv6Address(struct ifaddrs* list, + char* if_name, + absl::string_view ipv6_address, + absl::string_view ipv6_netmask, + uint32_t scope_id) { + struct ifaddrs* if_addr = new struct ifaddrs; + memset(if_addr, 0, sizeof(struct ifaddrs)); + if_addr->ifa_name = if_name; + if_addr->ifa_addr = reinterpret_cast<struct sockaddr*>( + CreateIpv6Addr(ipv6_address, scope_id)); + if_addr->ifa_netmask = + reinterpret_cast<struct sockaddr*>(CreateIpv6Addr(ipv6_netmask, 0)); + if_addr->ifa_next = list; + if_addr->ifa_flags = IFF_RUNNING; + return if_addr; + } + + struct ifaddrs* InstallIpv6Network(char* if_name, + absl::string_view ipv6_address, + absl::string_view ipv6_mask, + BasicNetworkManager& network_manager) { + ifaddrs* addr_list = nullptr; + addr_list = AddIpv6Address(addr_list, if_name, ipv6_address, ipv6_mask, 0); + std::vector<std::unique_ptr<Network>> result; + bool changed; + NetworkManager::Stats stats; + CallConvertIfAddrs(network_manager, addr_list, true, &result); + network_manager.MergeNetworkList(std::move(result), &changed, &stats); + return addr_list; + } + + struct sockaddr_in* CreateIpv4Addr(absl::string_view ip_string) { + struct sockaddr_in* ipv4_addr = + static_cast<struct sockaddr_in*>(malloc(sizeof(struct sockaddr_in))); + memset(ipv4_addr, 0, sizeof(struct sockaddr_in)); + ipv4_addr->sin_family = AF_INET; + IPAddress ip; + IPFromString(ip_string, &ip); + ipv4_addr->sin_addr = ip.ipv4_address(); + return ipv4_addr; + } + + // Pointers created here need to be released via ReleaseIfAddrs. + struct ifaddrs* AddIpv4Address(struct ifaddrs* list, + char* if_name, + absl::string_view ipv4_address, + absl::string_view ipv4_netmask) { + struct ifaddrs* if_addr = new struct ifaddrs; + memset(if_addr, 0, sizeof(struct ifaddrs)); + if_addr->ifa_name = if_name; + if_addr->ifa_addr = + reinterpret_cast<struct sockaddr*>(CreateIpv4Addr(ipv4_address)); + if_addr->ifa_netmask = + reinterpret_cast<struct sockaddr*>(CreateIpv4Addr(ipv4_netmask)); + if_addr->ifa_next = list; + if_addr->ifa_flags = IFF_RUNNING; + return if_addr; + } + + struct ifaddrs* InstallIpv4Network(char* if_name, + absl::string_view ipv4_address, + absl::string_view ipv4_mask, + BasicNetworkManager& network_manager) { + ifaddrs* addr_list = nullptr; + addr_list = AddIpv4Address(addr_list, if_name, ipv4_address, ipv4_mask); + std::vector<std::unique_ptr<Network>> result; + bool changed; + NetworkManager::Stats stats; + CallConvertIfAddrs(network_manager, addr_list, true, &result); + network_manager.MergeNetworkList(std::move(result), &changed, &stats); + return addr_list; + } + + void ReleaseIfAddrs(struct ifaddrs* list) { + struct ifaddrs* if_addr = list; + while (if_addr != nullptr) { + struct ifaddrs* next_addr = if_addr->ifa_next; + free(if_addr->ifa_addr); + free(if_addr->ifa_netmask); + delete if_addr; + if_addr = next_addr; + } + } +#endif // defined(WEBRTC_POSIX) + + protected: + webrtc::test::ScopedKeyValueConfig field_trials_; + rtc::AutoThread main_thread_; + bool callback_called_; +}; + +class TestBasicNetworkManager : public BasicNetworkManager { + public: + TestBasicNetworkManager(NetworkMonitorFactory* network_monitor_factory, + SocketFactory* socket_factory, + const webrtc::FieldTrialsView& field_trials) + : BasicNetworkManager(network_monitor_factory, + socket_factory, + &field_trials) {} + using BasicNetworkManager::QueryDefaultLocalAddress; + using BasicNetworkManager::set_default_local_addresses; +}; + +// Test that the Network ctor works properly. +TEST_F(NetworkTest, TestNetworkConstruct) { + Network ipv4_network1("test_eth0", "Test Network Adapter 1", + IPAddress(0x12345600U), 24); + EXPECT_EQ("test_eth0", ipv4_network1.name()); + EXPECT_EQ("Test Network Adapter 1", ipv4_network1.description()); + EXPECT_EQ(IPAddress(0x12345600U), ipv4_network1.prefix()); + EXPECT_EQ(24, ipv4_network1.prefix_length()); + EXPECT_EQ(AF_INET, ipv4_network1.family()); + EXPECT_FALSE(ipv4_network1.ignored()); +} + +TEST_F(NetworkTest, TestIsIgnoredNetworkIgnoresIPsStartingWith0) { + Network ipv4_network1("test_eth0", "Test Network Adapter 1", + IPAddress(0x12345600U), 24, ADAPTER_TYPE_ETHERNET); + Network ipv4_network2("test_eth1", "Test Network Adapter 2", + IPAddress(0x010000U), 24, ADAPTER_TYPE_ETHERNET); + PhysicalSocketServer socket_server; + BasicNetworkManager network_manager(&socket_server); + network_manager.StartUpdating(); + EXPECT_FALSE(IsIgnoredNetwork(network_manager, ipv4_network1)); + EXPECT_TRUE(IsIgnoredNetwork(network_manager, ipv4_network2)); +} + +// TODO(phoglund): Remove when ignore list goes away. +TEST_F(NetworkTest, TestIgnoreList) { + Network ignore_me("ignore_me", "Ignore me please!", IPAddress(0x12345600U), + 24); + Network include_me("include_me", "Include me please!", IPAddress(0x12345600U), + 24); + PhysicalSocketServer socket_server; + BasicNetworkManager default_network_manager(&socket_server); + default_network_manager.StartUpdating(); + EXPECT_FALSE(IsIgnoredNetwork(default_network_manager, ignore_me)); + EXPECT_FALSE(IsIgnoredNetwork(default_network_manager, include_me)); + + BasicNetworkManager ignoring_network_manager(&socket_server); + std::vector<std::string> ignore_list; + ignore_list.push_back("ignore_me"); + ignoring_network_manager.set_network_ignore_list(ignore_list); + ignoring_network_manager.StartUpdating(); + EXPECT_TRUE(IsIgnoredNetwork(ignoring_network_manager, ignore_me)); + EXPECT_FALSE(IsIgnoredNetwork(ignoring_network_manager, include_me)); +} + +// Test is failing on Windows opt: b/11288214 +TEST_F(NetworkTest, DISABLED_TestCreateNetworks) { + PhysicalSocketServer socket_server; + BasicNetworkManager manager(&socket_server); + std::vector<std::unique_ptr<Network>> result = GetNetworks(manager, true); + // We should be able to bind to any addresses we find. + for (auto it = result.begin(); it != result.end(); ++it) { + sockaddr_storage storage; + memset(&storage, 0, sizeof(storage)); + IPAddress ip = (*it)->GetBestIP(); + SocketAddress bindaddress(ip, 0); + bindaddress.SetScopeID((*it)->scope_id()); + // TODO(thaloun): Use rtc::Socket once it supports IPv6. + int fd = static_cast<int>(socket(ip.family(), SOCK_STREAM, IPPROTO_TCP)); + if (fd > 0) { + size_t ipsize = bindaddress.ToSockAddrStorage(&storage); + EXPECT_GE(ipsize, 0U); + int success = ::bind(fd, reinterpret_cast<sockaddr*>(&storage), + static_cast<int>(ipsize)); +#if defined(WEBRTC_WIN) + if (success) + RTC_LOG_GLE(LS_ERROR) << "Socket bind failed."; +#endif + EXPECT_EQ(0, success); +#if defined(WEBRTC_WIN) + closesocket(fd); +#else + close(fd); +#endif + } + } +} + +// Test StartUpdating() and StopUpdating(). network_permission_state starts with +// ALLOWED. +TEST_F(NetworkTest, TestUpdateNetworks) { + PhysicalSocketServer socket_server; + BasicNetworkManager manager(nullptr, &socket_server, &field_trials_); + manager.SignalNetworksChanged.connect(static_cast<NetworkTest*>(this), + &NetworkTest::OnNetworksChanged); + EXPECT_EQ(NetworkManager::ENUMERATION_ALLOWED, + manager.enumeration_permission()); + manager.StartUpdating(); + Thread::Current()->ProcessMessages(0); + EXPECT_TRUE(callback_called_); + callback_called_ = false; + // Callback should be triggered immediately when StartUpdating + // is called, after network update signal is already sent. + manager.StartUpdating(); + EXPECT_TRUE(manager.started()); + Thread::Current()->ProcessMessages(0); + EXPECT_TRUE(callback_called_); + manager.StopUpdating(); + EXPECT_TRUE(manager.started()); + manager.StopUpdating(); + EXPECT_EQ(NetworkManager::ENUMERATION_ALLOWED, + manager.enumeration_permission()); + EXPECT_FALSE(manager.started()); + manager.StopUpdating(); + EXPECT_FALSE(manager.started()); + callback_called_ = false; + // Callback should be triggered immediately after StartUpdating is called + // when start_count_ is reset to 0. + manager.StartUpdating(); + Thread::Current()->ProcessMessages(0); + EXPECT_TRUE(callback_called_); +} + +// Verify that MergeNetworkList() merges network lists properly. +TEST_F(NetworkTest, TestBasicMergeNetworkList) { + Network ipv4_network1("test_eth0", "Test Network Adapter 1", + IPAddress(0x12345600U), 24); + Network ipv4_network2("test_eth1", "Test Network Adapter 2", + IPAddress(0x00010000U), 16); + ipv4_network1.AddIP(IPAddress(0x12345678)); + ipv4_network2.AddIP(IPAddress(0x00010004)); + PhysicalSocketServer socket_server; + BasicNetworkManager manager(&socket_server); + + // Add ipv4_network1 to the list of networks. + std::vector<std::unique_ptr<Network>> list; + list.push_back(std::make_unique<Network>(ipv4_network1)); + bool changed; + NetworkManager::Stats stats = + MergeNetworkList(manager, std::move(list), &changed); + EXPECT_TRUE(changed); + EXPECT_EQ(stats.ipv6_network_count, 0); + EXPECT_EQ(stats.ipv4_network_count, 1); + list.clear(); // It is fine to call .clear() on a moved-from vector. + + std::vector<const rtc::Network*> current = manager.GetNetworks(); + EXPECT_EQ(1U, current.size()); + EXPECT_TRUE(SameNameAndPrefix(ipv4_network1, *current[0])); + const Network* net1 = current[0]; + uint16_t net_id1 = net1->id(); + EXPECT_EQ(1, net_id1); + + // Replace ipv4_network1 with ipv4_network2. + list.push_back(std::make_unique<Network>(ipv4_network2)); + stats = MergeNetworkList(manager, std::move(list), &changed); + EXPECT_TRUE(changed); + EXPECT_EQ(stats.ipv6_network_count, 0); + EXPECT_EQ(stats.ipv4_network_count, 1); + list.clear(); + + current = manager.GetNetworks(); + EXPECT_EQ(1U, current.size()); + EXPECT_TRUE(SameNameAndPrefix(ipv4_network2, *current[0])); + const Network* net2 = current[0]; + uint16_t net_id2 = net2->id(); + // Network id will increase. + EXPECT_LT(net_id1, net_id2); + + // Add Network2 back. + list.push_back(std::make_unique<Network>(ipv4_network1)); + list.push_back(std::make_unique<Network>(ipv4_network2)); + stats = MergeNetworkList(manager, std::move(list), &changed); + EXPECT_TRUE(changed); + EXPECT_EQ(stats.ipv6_network_count, 0); + EXPECT_EQ(stats.ipv4_network_count, 2); + list.clear(); + + // Verify that we get previous instances of Network objects. + current = manager.GetNetworks(); + EXPECT_EQ(2U, current.size()); + EXPECT_TRUE((net1 == current[0] && net2 == current[1]) || + (net1 == current[1] && net2 == current[0])); + EXPECT_TRUE((net_id1 == current[0]->id() && net_id2 == current[1]->id()) || + (net_id1 == current[1]->id() && net_id2 == current[0]->id())); + + // Call MergeNetworkList() again and verify that we don't get update + // notification. + list.push_back(std::make_unique<Network>(ipv4_network2)); + list.push_back(std::make_unique<Network>(ipv4_network1)); + stats = MergeNetworkList(manager, std::move(list), &changed); + EXPECT_FALSE(changed); + EXPECT_EQ(stats.ipv6_network_count, 0); + EXPECT_EQ(stats.ipv4_network_count, 2); + list.clear(); + + // Verify that we get previous instances of Network objects. + current = manager.GetNetworks(); + EXPECT_EQ(2U, current.size()); + EXPECT_TRUE((net1 == current[0] && net2 == current[1]) || + (net1 == current[1] && net2 == current[0])); + EXPECT_TRUE((net_id1 == current[0]->id() && net_id2 == current[1]->id()) || + (net_id1 == current[1]->id() && net_id2 == current[0]->id())); +} + +// Sets up some test IPv6 networks and appends them to list. +// Four networks are added - public and link local, for two interfaces. +void SetupNetworks(std::vector<std::unique_ptr<Network>>* list) { + IPAddress ip; + IPAddress prefix; + EXPECT_TRUE(IPFromString("abcd::1234:5678:abcd:ef12", &ip)); + EXPECT_TRUE(IPFromString("abcd::", &prefix)); + // First, fake link-locals. + Network ipv6_eth0_linklocalnetwork("test_eth0", "Test NetworkAdapter 1", + prefix, 64); + ipv6_eth0_linklocalnetwork.AddIP(ip); + EXPECT_TRUE(IPFromString("abcd::5678:abcd:ef12:3456", &ip)); + Network ipv6_eth1_linklocalnetwork("test_eth1", "Test NetworkAdapter 2", + prefix, 64); + ipv6_eth1_linklocalnetwork.AddIP(ip); + // Public networks: + EXPECT_TRUE(IPFromString("2401:fa00:4:1000:be30:5bff:fee5:c3", &ip)); + prefix = TruncateIP(ip, 64); + Network ipv6_eth0_publicnetwork1_ip1("test_eth0", "Test NetworkAdapter 1", + prefix, 64); + ipv6_eth0_publicnetwork1_ip1.AddIP(ip); + EXPECT_TRUE(IPFromString("2400:4030:1:2c00:be30:abcd:efab:cdef", &ip)); + prefix = TruncateIP(ip, 64); + Network ipv6_eth1_publicnetwork1_ip1("test_eth1", "Test NetworkAdapter 1", + prefix, 64); + ipv6_eth1_publicnetwork1_ip1.AddIP(ip); + list->push_back(std::make_unique<Network>(ipv6_eth0_linklocalnetwork)); + list->push_back(std::make_unique<Network>(ipv6_eth1_linklocalnetwork)); + list->push_back(std::make_unique<Network>(ipv6_eth0_publicnetwork1_ip1)); + list->push_back(std::make_unique<Network>(ipv6_eth1_publicnetwork1_ip1)); +} + +// Test that the basic network merging case works. +TEST_F(NetworkTest, TestIPv6MergeNetworkList) { + PhysicalSocketServer socket_server; + BasicNetworkManager manager(&socket_server); + manager.SignalNetworksChanged.connect(static_cast<NetworkTest*>(this), + &NetworkTest::OnNetworksChanged); + std::vector<std::unique_ptr<Network>> networks; + SetupNetworks(&networks); + std::vector<const Network*> original_list = CopyNetworkPointers(networks); + bool changed = false; + NetworkManager::Stats stats = + MergeNetworkList(manager, std::move(networks), &changed); + EXPECT_TRUE(changed); + EXPECT_EQ(stats.ipv6_network_count, 4); + EXPECT_EQ(stats.ipv4_network_count, 0); + std::vector<const Network*> list = manager.GetNetworks(); + // Verify that the original members are in the merged list. + EXPECT_THAT(list, UnorderedElementsAreArray(original_list)); +} + +// Tests that when two network lists that describe the same set of networks are +// merged, that the changed callback is not called, and that the original +// objects remain in the result list. +TEST_F(NetworkTest, TestNoChangeMerge) { + PhysicalSocketServer socket_server; + BasicNetworkManager manager(&socket_server); + manager.SignalNetworksChanged.connect(static_cast<NetworkTest*>(this), + &NetworkTest::OnNetworksChanged); + std::vector<std::unique_ptr<Network>> networks; + SetupNetworks(&networks); + std::vector<const Network*> original_list = CopyNetworkPointers(networks); + bool changed = false; + MergeNetworkList(manager, std::move(networks), &changed); + EXPECT_TRUE(changed); + // Second list that describes the same networks but with new objects. + std::vector<std::unique_ptr<Network>> second_networks; + SetupNetworks(&second_networks); + std::vector<const Network*> second_list = + CopyNetworkPointers(second_networks); + changed = false; + MergeNetworkList(manager, std::move(second_networks), &changed); + EXPECT_FALSE(changed); + std::vector<const Network*> resulting_list = manager.GetNetworks(); + // Verify that the original members are in the merged list. + EXPECT_THAT(resulting_list, UnorderedElementsAreArray(original_list)); + // Doublecheck that the new networks aren't in the list. + for (const Network* network : second_list) { + EXPECT_THAT(resulting_list, Not(Contains(network))); + } +} + +// Test that we can merge a network that is the same as another network but with +// a different IP. The original network should remain in the list, but have its +// IP changed. +TEST_F(NetworkTest, MergeWithChangedIP) { + PhysicalSocketServer socket_server; + BasicNetworkManager manager(&socket_server); + manager.SignalNetworksChanged.connect(static_cast<NetworkTest*>(this), + &NetworkTest::OnNetworksChanged); + std::vector<std::unique_ptr<Network>> original_list; + SetupNetworks(&original_list); + // Make a network that we're going to change. + IPAddress ip; + EXPECT_TRUE(IPFromString("2401:fa01:4:1000:be30:faa:fee:faa", &ip)); + IPAddress prefix = TruncateIP(ip, 64); + std::unique_ptr<Network> network_to_change = std::make_unique<Network>( + "test_eth0", "Test Network Adapter 1", prefix, 64); + std::unique_ptr<Network> changed_network = + std::make_unique<Network>(*network_to_change); + network_to_change->AddIP(ip); + IPAddress changed_ip; + EXPECT_TRUE(IPFromString("2401:fa01:4:1000:be30:f00:f00:f00", &changed_ip)); + changed_network->AddIP(changed_ip); + const Network* const network_to_change_ptr = network_to_change.get(); + original_list.push_back(std::move(network_to_change)); + const size_t original_size = original_list.size(); + bool changed = false; + MergeNetworkList(manager, std::move(original_list), &changed); + std::vector<std::unique_ptr<Network>> second_list; + SetupNetworks(&second_list); + second_list.push_back(std::move(changed_network)); + changed = false; + MergeNetworkList(manager, std::move(second_list), &changed); + EXPECT_TRUE(changed); + std::vector<const Network*> list = manager.GetNetworks(); + EXPECT_EQ(original_size, list.size()); + // Make sure the original network is still in the merged list. + EXPECT_THAT(list, Contains(network_to_change_ptr)); + EXPECT_EQ(changed_ip, network_to_change_ptr->GetIPs().at(0)); +} + +TEST_F(NetworkTest, TestMultipleIPMergeNetworkList) { + PhysicalSocketServer socket_server; + BasicNetworkManager manager(&socket_server); + manager.SignalNetworksChanged.connect(static_cast<NetworkTest*>(this), + &NetworkTest::OnNetworksChanged); + std::vector<std::unique_ptr<Network>> original_list; + SetupNetworks(&original_list); + const Network* const network_ptr = original_list[2].get(); + bool changed = false; + MergeNetworkList(manager, std::move(original_list), &changed); + EXPECT_TRUE(changed); + IPAddress ip; + IPAddress check_ip; + IPAddress prefix; + // Add a second IP to the public network on eth0 (2401:fa00:4:1000/64). + EXPECT_TRUE(IPFromString("2401:fa00:4:1000:be30:5bff:fee5:c6", &ip)); + prefix = TruncateIP(ip, 64); + Network ipv6_eth0_publicnetwork1_ip2("test_eth0", "Test NetworkAdapter 1", + prefix, 64); + // This is the IP that already existed in the public network on eth0. + EXPECT_TRUE(IPFromString("2401:fa00:4:1000:be30:5bff:fee5:c3", &check_ip)); + ipv6_eth0_publicnetwork1_ip2.AddIP(ip); + + std::vector<std::unique_ptr<Network>> second_list; + SetupNetworks(&second_list); + second_list.push_back( + std::make_unique<Network>(ipv6_eth0_publicnetwork1_ip2)); + changed = false; + const auto network_copy = std::make_unique<Network>(*second_list[2]); + MergeNetworkList(manager, std::move(second_list), &changed); + EXPECT_TRUE(changed); + // There should still be four networks. + std::vector<const Network*> list = manager.GetNetworks(); + EXPECT_EQ(4U, list.size()); + // Check the gathered IPs. + int matchcount = 0; + for (const Network* network : list) { + if (SameNameAndPrefix(*network, *network_copy)) { + ++matchcount; + EXPECT_EQ(1, matchcount); + // This should be the same network object as before. + EXPECT_EQ(network, network_ptr); + // But with two addresses now. + EXPECT_THAT(network->GetIPs(), + UnorderedElementsAre(InterfaceAddress(check_ip), + InterfaceAddress(ip))); + } else { + // Check the IP didn't get added anywhere it wasn't supposed to. + EXPECT_THAT(network->GetIPs(), Not(Contains(InterfaceAddress(ip)))); + } + } +} + +// Test that merge correctly distinguishes multiple networks on an interface. +TEST_F(NetworkTest, TestMultiplePublicNetworksOnOneInterfaceMerge) { + PhysicalSocketServer socket_server; + BasicNetworkManager manager(&socket_server); + manager.SignalNetworksChanged.connect(static_cast<NetworkTest*>(this), + &NetworkTest::OnNetworksChanged); + std::vector<std::unique_ptr<Network>> original_list; + SetupNetworks(&original_list); + bool changed = false; + MergeNetworkList(manager, std::move(original_list), &changed); + EXPECT_TRUE(changed); + IPAddress ip; + IPAddress prefix; + // A second network for eth0. + EXPECT_TRUE(IPFromString("2400:4030:1:2c00:be30:5bff:fee5:c3", &ip)); + prefix = TruncateIP(ip, 64); + Network ipv6_eth0_publicnetwork2_ip1("test_eth0", "Test NetworkAdapter 1", + prefix, 64); + ipv6_eth0_publicnetwork2_ip1.AddIP(ip); + std::vector<std::unique_ptr<Network>> second_list; + SetupNetworks(&second_list); + second_list.push_back( + std::make_unique<Network>(ipv6_eth0_publicnetwork2_ip1)); + changed = false; + MergeNetworkList(manager, std::move(second_list), &changed); + EXPECT_TRUE(changed); + // There should be five networks now. + std::vector<const Network*> list = manager.GetNetworks(); + EXPECT_EQ(5U, list.size()); + // Check the resulting addresses. + for (const Network* network : list) { + if (network->prefix() == ipv6_eth0_publicnetwork2_ip1.prefix() && + network->name() == ipv6_eth0_publicnetwork2_ip1.name()) { + // Check the new network has 1 IP and that it's the correct one. + EXPECT_EQ(1U, network->GetIPs().size()); + EXPECT_EQ(ip, network->GetIPs().at(0)); + } else { + // Check the IP didn't get added anywhere it wasn't supposed to. + EXPECT_THAT(network->GetIPs(), Not(Contains(InterfaceAddress(ip)))); + } + } +} + +// Test that DumpNetworks does not crash. +TEST_F(NetworkTest, TestCreateAndDumpNetworks) { + PhysicalSocketServer socket_server; + BasicNetworkManager manager(&socket_server); + manager.StartUpdating(); + std::vector<std::unique_ptr<Network>> list = GetNetworks(manager, true); + bool changed; + MergeNetworkList(manager, std::move(list), &changed); + manager.DumpNetworks(); +} + +TEST_F(NetworkTest, TestIPv6Toggle) { + PhysicalSocketServer socket_server; + BasicNetworkManager manager(&socket_server); + manager.StartUpdating(); + bool ipv6_found = false; + for (const auto& network : GetNetworks(manager, true)) { + if (network->prefix().family() == AF_INET6) { + ipv6_found = true; + break; + } + } + EXPECT_TRUE(ipv6_found); +} + +// Test that when network interfaces are sorted and given preference values, +// IPv6 comes first. +TEST_F(NetworkTest, IPv6NetworksPreferredOverIPv4) { + PhysicalSocketServer socket_server; + BasicNetworkManager manager(&socket_server); + Network ipv4_network1("test_eth0", "Test Network Adapter 1", + IPAddress(0x12345600U), 24); + ipv4_network1.AddIP(IPAddress(0x12345600U)); + + IPAddress ip; + IPAddress prefix; + EXPECT_TRUE(IPFromString("2400:4030:1:2c00:be30:abcd:efab:cdef", &ip)); + prefix = TruncateIP(ip, 64); + Network ipv6_eth1_publicnetwork1_ip1("test_eth1", "Test NetworkAdapter 2", + prefix, 64); + ipv6_eth1_publicnetwork1_ip1.AddIP(ip); + + std::vector<std::unique_ptr<Network>> list; + list.push_back(std::make_unique<Network>(ipv4_network1)); + list.push_back(std::make_unique<Network>(ipv6_eth1_publicnetwork1_ip1)); + const Network* net1 = list[0].get(); + const Network* net2 = list[1].get(); + + bool changed = false; + MergeNetworkList(manager, std::move(list), &changed); + ASSERT_TRUE(changed); + // After sorting IPv6 network should be higher order than IPv4 networks. + EXPECT_TRUE(net1->preference() < net2->preference()); +} + +// When two interfaces are equivalent in everything but name, they're expected +// to be preference-ordered by name. For example, "eth0" before "eth1". +TEST_F(NetworkTest, NetworksSortedByInterfaceName) { + PhysicalSocketServer socket_server; + BasicNetworkManager manager(&socket_server, &field_trials_); + auto eth0 = std::make_unique<Network>("test_eth0", "Test Network Adapter 1", + IPAddress(0x65432100U), 24); + eth0->AddIP(IPAddress(0x65432100U)); + auto eth1 = std::make_unique<Network>("test_eth1", "Test Network Adapter 2", + IPAddress(0x12345600U), 24); + eth1->AddIP(IPAddress(0x12345600U)); + std::vector<std::unique_ptr<Network>> list; + const Network* eth0_ptr = eth0.get(); + const Network* eth1_ptr = eth1.get(); + // Add them to the list in the opposite of the expected sorted order, to + // ensure sorting actually occurs. + list.push_back(std::move(eth1)); + list.push_back(std::move(eth0)); + + bool changed = false; + MergeNetworkList(manager, std::move(list), &changed); + ASSERT_TRUE(changed); + // "test_eth0" should be preferred over "test_eth1". + EXPECT_TRUE(eth0_ptr->preference() > eth1_ptr->preference()); +} + +TEST_F(NetworkTest, TestNetworkAdapterTypes) { + Network wifi("wlan0", "Wireless Adapter", IPAddress(0x12345600U), 24, + ADAPTER_TYPE_WIFI); + EXPECT_EQ(ADAPTER_TYPE_WIFI, wifi.type()); + Network ethernet("eth0", "Ethernet", IPAddress(0x12345600U), 24, + ADAPTER_TYPE_ETHERNET); + EXPECT_EQ(ADAPTER_TYPE_ETHERNET, ethernet.type()); + Network cellular("test_cell", "Cellular Adapter", IPAddress(0x12345600U), 24, + ADAPTER_TYPE_CELLULAR); + EXPECT_EQ(ADAPTER_TYPE_CELLULAR, cellular.type()); + Network vpn("bridge_test", "VPN Adapter", IPAddress(0x12345600U), 24, + ADAPTER_TYPE_VPN); + EXPECT_EQ(ADAPTER_TYPE_VPN, vpn.type()); + Network unknown("test", "Test Adapter", IPAddress(0x12345600U), 24, + ADAPTER_TYPE_UNKNOWN); + EXPECT_EQ(ADAPTER_TYPE_UNKNOWN, unknown.type()); +} + +#if defined(WEBRTC_POSIX) +// Verify that we correctly handle interfaces with no address. +TEST_F(NetworkTest, TestConvertIfAddrsNoAddress) { + ifaddrs list; + memset(&list, 0, sizeof(list)); + list.ifa_name = const_cast<char*>("test_iface"); + + std::vector<std::unique_ptr<Network>> result; + PhysicalSocketServer socket_server; + BasicNetworkManager manager(&socket_server); + manager.StartUpdating(); + CallConvertIfAddrs(manager, &list, true, &result); + EXPECT_TRUE(result.empty()); +} + +// Verify that if there are two addresses on one interface, only one network +// is generated. +TEST_F(NetworkTest, TestConvertIfAddrsMultiAddressesOnOneInterface) { + char if_name[20] = "rmnet0"; + ifaddrs* list = nullptr; + list = AddIpv6Address(list, if_name, "1000:2000:3000:4000:0:0:0:1", + "FFFF:FFFF:FFFF:FFFF::", 0); + list = AddIpv6Address(list, if_name, "1000:2000:3000:4000:0:0:0:2", + "FFFF:FFFF:FFFF:FFFF::", 0); + std::vector<std::unique_ptr<Network>> result; + PhysicalSocketServer socket_server; + BasicNetworkManager manager(&socket_server); + manager.StartUpdating(); + CallConvertIfAddrs(manager, list, true, &result); + EXPECT_EQ(1U, result.size()); + bool changed; + // This ensures we release the objects created in CallConvertIfAddrs. + MergeNetworkList(manager, std::move(result), &changed); + ReleaseIfAddrs(list); +} + +TEST_F(NetworkTest, TestConvertIfAddrsNotRunning) { + ifaddrs list; + memset(&list, 0, sizeof(list)); + list.ifa_name = const_cast<char*>("test_iface"); + sockaddr ifa_addr; + ifa_addr.sa_family = AF_UNSPEC; + sockaddr ifa_netmask; + list.ifa_addr = &ifa_addr; + list.ifa_netmask = &ifa_netmask; + + std::vector<std::unique_ptr<Network>> result; + PhysicalSocketServer socket_server; + BasicNetworkManager manager(&socket_server); + manager.StartUpdating(); + CallConvertIfAddrs(manager, &list, true, &result); + EXPECT_TRUE(result.empty()); +} + +TEST_F(NetworkTest, TestConvertIfAddrsGetsNullAddr) { + ifaddrs list; + memset(&list, 0, sizeof(list)); + list.ifa_name = const_cast<char*>("test_iface"); + list.ifa_addr = nullptr; + list.ifa_netmask = nullptr; + + std::vector<std::unique_ptr<Network>> result; + PhysicalSocketServer socket_server; + BasicNetworkManager manager(&socket_server); + manager.StartUpdating(); + CallConvertIfAddrs(manager, &list, true, &result); + EXPECT_TRUE(result.empty()); +} + +// Tests that the network type can be determined from the network monitor when +// it would otherwise be unknown. +TEST_F(NetworkTest, TestGetAdapterTypeFromNetworkMonitor) { + char if_name[20] = "wifi0"; + std::string ipv6_address = "1000:2000:3000:4000:0:0:0:1"; + std::string ipv6_mask = "FFFF:FFFF:FFFF:FFFF::"; + PhysicalSocketServer socket_server; + BasicNetworkManager manager_without_monitor(nullptr, &socket_server, + &field_trials_); + manager_without_monitor.StartUpdating(); + // A network created without a network monitor will get UNKNOWN type. + ifaddrs* addr_list = InstallIpv6Network(if_name, ipv6_address, ipv6_mask, + manager_without_monitor); + EXPECT_EQ(ADAPTER_TYPE_UNKNOWN, GetAdapterType(manager_without_monitor)); + ReleaseIfAddrs(addr_list); + + // With the fake network monitor the type should be correctly determined. + FakeNetworkMonitorFactory factory; + BasicNetworkManager manager_with_monitor(&factory, &socket_server, + &field_trials_); + manager_with_monitor.StartUpdating(); + // Add the same ipv6 address as before but it has the right network type + // detected by the network monitor now. + addr_list = InstallIpv6Network(if_name, ipv6_address, ipv6_mask, + manager_with_monitor); + EXPECT_EQ(ADAPTER_TYPE_WIFI, GetAdapterType(manager_with_monitor)); + ReleaseIfAddrs(addr_list); +} + +// Test that the network type can be determined based on name matching in +// a few cases. Note that UNKNOWN type for non-matching strings has been tested +// in the above test. +TEST_F(NetworkTest, TestGetAdapterTypeFromNameMatching) { + std::string ipv4_address1 = "192.0.0.121"; + std::string ipv4_mask = "255.255.255.0"; + std::string ipv6_address1 = "1000:2000:3000:4000:0:0:0:1"; + std::string ipv6_address2 = "1000:2000:3000:8000:0:0:0:1"; + std::string ipv6_mask = "FFFF:FFFF:FFFF:FFFF::"; + PhysicalSocketServer socket_server; + BasicNetworkManager manager(&socket_server); + manager.StartUpdating(); + + // IPSec interface; name is in form "ipsec<index>". + char if_name[20] = "ipsec11"; + ifaddrs* addr_list = + InstallIpv6Network(if_name, ipv6_address1, ipv6_mask, manager); + EXPECT_EQ(ADAPTER_TYPE_VPN, GetAdapterType(manager)); + ClearNetworks(manager); + ReleaseIfAddrs(addr_list); + + strcpy(if_name, "lo0"); + addr_list = InstallIpv6Network(if_name, ipv6_address1, ipv6_mask, manager); + EXPECT_EQ(ADAPTER_TYPE_LOOPBACK, GetAdapterType(manager)); + ClearNetworks(manager); + ReleaseIfAddrs(addr_list); + + strcpy(if_name, "eth0"); + addr_list = InstallIpv4Network(if_name, ipv4_address1, ipv4_mask, manager); + EXPECT_EQ(ADAPTER_TYPE_ETHERNET, GetAdapterType(manager)); + ClearNetworks(manager); + ReleaseIfAddrs(addr_list); + + strcpy(if_name, "wlan0"); + addr_list = InstallIpv6Network(if_name, ipv6_address1, ipv6_mask, manager); + EXPECT_EQ(ADAPTER_TYPE_WIFI, GetAdapterType(manager)); + ClearNetworks(manager); + ReleaseIfAddrs(addr_list); + +#if defined(WEBRTC_IOS) + strcpy(if_name, "pdp_ip0"); + addr_list = InstallIpv6Network(if_name, ipv6_address1, ipv6_mask, manager); + EXPECT_EQ(ADAPTER_TYPE_CELLULAR, GetAdapterType(manager)); + ClearNetworks(manager); + ReleaseIfAddrs(addr_list); + + strcpy(if_name, "en0"); + addr_list = InstallIpv6Network(if_name, ipv6_address1, ipv6_mask, manager); + EXPECT_EQ(ADAPTER_TYPE_WIFI, GetAdapterType(manager)); + ClearNetworks(manager); + ReleaseIfAddrs(addr_list); + +#elif defined(WEBRTC_ANDROID) + strcpy(if_name, "rmnet0"); + addr_list = InstallIpv6Network(if_name, ipv6_address1, ipv6_mask, manager); + EXPECT_EQ(ADAPTER_TYPE_CELLULAR, GetAdapterType(manager)); + ClearNetworks(manager); + ReleaseIfAddrs(addr_list); + + strcpy(if_name, "v4-rmnet_data0"); + addr_list = InstallIpv6Network(if_name, ipv6_address2, ipv6_mask, manager); + EXPECT_EQ(ADAPTER_TYPE_CELLULAR, GetAdapterType(manager)); + ClearNetworks(manager); + ReleaseIfAddrs(addr_list); + + strcpy(if_name, "clat4"); + addr_list = InstallIpv4Network(if_name, ipv4_address1, ipv4_mask, manager); + EXPECT_EQ(ADAPTER_TYPE_CELLULAR, GetAdapterType(manager)); + ClearNetworks(manager); + ReleaseIfAddrs(addr_list); +#endif +} + +// Test that an adapter won't be included in the network list if there's a +// network monitor that says it's unavailable. +TEST_F(NetworkTest, TestNetworkMonitorIsAdapterAvailable) { + char if_name1[20] = "pdp_ip0"; + char if_name2[20] = "pdp_ip1"; + ifaddrs* list = nullptr; + list = AddIpv6Address(list, if_name1, "1000:2000:3000:4000:0:0:0:1", + "FFFF:FFFF:FFFF:FFFF::", 0); + list = AddIpv6Address(list, if_name2, "1000:2000:3000:4000:0:0:0:2", + "FFFF:FFFF:FFFF:FFFF::", 0); + std::vector<std::unique_ptr<Network>> result; + + // Sanity check that both interfaces are included by default. + FakeNetworkMonitorFactory factory; + PhysicalSocketServer socket_server; + BasicNetworkManager manager(&factory, &socket_server, &field_trials_); + manager.StartUpdating(); + CallConvertIfAddrs(manager, list, /*include_ignored=*/false, &result); + EXPECT_EQ(2u, result.size()); + bool changed; + // This ensures we release the objects created in CallConvertIfAddrs. + MergeNetworkList(manager, std::move(result), &changed); + result.clear(); + + // Now simulate one interface being unavailable. + FakeNetworkMonitor* network_monitor = GetNetworkMonitor(manager); + network_monitor->set_unavailable_adapters({if_name1}); + CallConvertIfAddrs(manager, list, /*include_ignored=*/false, &result); + EXPECT_EQ(1u, result.size()); + EXPECT_EQ(if_name2, result[0]->name()); + + MergeNetworkList(manager, std::move(result), &changed); + ReleaseIfAddrs(list); +} + +#endif // defined(WEBRTC_POSIX) + +// Test MergeNetworkList successfully combines all IPs for the same +// prefix/length into a single Network. +TEST_F(NetworkTest, TestMergeNetworkList) { + PhysicalSocketServer socket_server; + BasicNetworkManager manager(&socket_server); + std::vector<std::unique_ptr<Network>> list; + + // Create 2 IPAddress classes with only last digit different. + IPAddress ip1, ip2; + EXPECT_TRUE(IPFromString("2400:4030:1:2c00:be30:0:0:1", &ip1)); + EXPECT_TRUE(IPFromString("2400:4030:1:2c00:be30:0:0:2", &ip2)); + + // Create 2 networks with the same prefix and length. + auto net1 = std::make_unique<Network>("em1", "em1", TruncateIP(ip1, 64), 64); + auto net2 = std::make_unique<Network>("em1", "em1", TruncateIP(ip1, 64), 64); + + // Add different IP into each. + net1->AddIP(ip1); + net2->AddIP(ip2); + + list.push_back(std::move(net1)); + list.push_back(std::move(net2)); + bool changed; + MergeNetworkList(manager, std::move(list), &changed); + EXPECT_TRUE(changed); + + std::vector<const Network*> list2 = manager.GetNetworks(); + + // Make sure the resulted networklist has only 1 element and 2 + // IPAddresses. + EXPECT_EQ(list2.size(), 1uL); + EXPECT_EQ(list2[0]->GetIPs().size(), 2uL); + EXPECT_THAT(list2[0]->GetIPs(), UnorderedElementsAre(InterfaceAddress(ip1), + InterfaceAddress(ip2))); +} + +// Test that MergeNetworkList successfully detects the change if +// a network becomes inactive and then active again. +TEST_F(NetworkTest, TestMergeNetworkListWithInactiveNetworks) { + PhysicalSocketServer socket_server; + BasicNetworkManager manager(&socket_server); + Network network1("test_wifi", "Test Network Adapter 1", + IPAddress(0x12345600U), 24); + Network network2("test_eth0", "Test Network Adapter 2", + IPAddress(0x00010000U), 16); + network1.AddIP(IPAddress(0x12345678)); + network2.AddIP(IPAddress(0x00010004)); + std::vector<std::unique_ptr<Network>> list; + auto net1 = std::make_unique<Network>(network1); + const Network* const net1_ptr = net1.get(); + list.push_back(std::move(net1)); + bool changed; + MergeNetworkList(manager, std::move(list), &changed); + EXPECT_TRUE(changed); + list.clear(); + + std::vector<const Network*> current = manager.GetNetworks(); + ASSERT_EQ(1U, current.size()); + EXPECT_EQ(net1_ptr, current[0]); + + list.clear(); + auto net2 = std::make_unique<Network>(network2); + const Network* const net2_ptr = net2.get(); + list.push_back(std::move(net2)); + MergeNetworkList(manager, std::move(list), &changed); + EXPECT_TRUE(changed); + list.clear(); + + current = manager.GetNetworks(); + ASSERT_EQ(1U, current.size()); + EXPECT_EQ(net2_ptr, current[0]); + // Now network1 is inactive. Try to merge it again. + list.clear(); + list.push_back(std::make_unique<Network>(network1)); + MergeNetworkList(manager, std::move(list), &changed); + EXPECT_TRUE(changed); + list.clear(); + current = manager.GetNetworks(); + ASSERT_EQ(1U, current.size()); + EXPECT_TRUE(current[0]->active()); + EXPECT_EQ(net1_ptr, current[0]); +} + +// Test that the filtering logic follows the defined ruleset in network.h. +TEST_F(NetworkTest, TestIPv6Selection) { + InterfaceAddress ip; + std::string ipstr; + + ipstr = "2401:fa00:4:1000:be30:5bff:fee5:c3"; + ASSERT_TRUE(IPFromString(ipstr, IPV6_ADDRESS_FLAG_DEPRECATED, &ip)); + + // Create a network with this prefix. + Network ipv6_network("test_eth0", "Test NetworkAdapter", TruncateIP(ip, 64), + 64); + EXPECT_EQ(AF_INET6, ipv6_network.family()); + + // When there is no address added, it should return an unspecified + // address. + EXPECT_EQ(ipv6_network.GetBestIP(), IPAddress()); + EXPECT_TRUE(IPIsUnspec(ipv6_network.GetBestIP())); + + // Deprecated one should not be returned. + ipv6_network.AddIP(ip); + EXPECT_EQ(ipv6_network.GetBestIP(), IPAddress()); + + // Add ULA one. ULA is unique local address which is starting either + // with 0xfc or 0xfd. + ipstr = "fd00:fa00:4:1000:be30:5bff:fee5:c4"; + ASSERT_TRUE(IPFromString(ipstr, IPV6_ADDRESS_FLAG_NONE, &ip)); + ipv6_network.AddIP(ip); + EXPECT_EQ(ipv6_network.GetBestIP(), static_cast<IPAddress>(ip)); + + // Add global one. + ipstr = "2401:fa00:4:1000:be30:5bff:fee5:c5"; + ASSERT_TRUE(IPFromString(ipstr, IPV6_ADDRESS_FLAG_NONE, &ip)); + ipv6_network.AddIP(ip); + EXPECT_EQ(ipv6_network.GetBestIP(), static_cast<IPAddress>(ip)); + + // Add global dynamic temporary one. + ipstr = "2401:fa00:4:1000:be30:5bff:fee5:c6"; + ASSERT_TRUE(IPFromString(ipstr, IPV6_ADDRESS_FLAG_TEMPORARY, &ip)); + ipv6_network.AddIP(ip); + EXPECT_EQ(ipv6_network.GetBestIP(), static_cast<IPAddress>(ip)); +} + +// Test that the filtering logic follows the defined ruleset in network.h. +TEST_F(NetworkTest, TestGetBestIPWithPreferGlobalIPv6ToLinkLocalEnabled) { + InterfaceAddress ip, link_local; + std::string ipstr; + + ipstr = "2401:fa00:4:1000:be30:5bff:fee5:c3"; + ASSERT_TRUE(IPFromString(ipstr, IPV6_ADDRESS_FLAG_DEPRECATED, &ip)); + + // Create a network with this prefix. + Network ipv6_network("test_eth0", "Test NetworkAdapter", TruncateIP(ip, 64), + 64, ADAPTER_TYPE_UNKNOWN); + + // When there is no address added, it should return an unspecified + // address. + EXPECT_EQ(ipv6_network.GetBestIP(), IPAddress()); + EXPECT_TRUE(IPIsUnspec(ipv6_network.GetBestIP())); + + // Deprecated one should not be returned. + ipv6_network.AddIP(ip); + EXPECT_EQ(ipv6_network.GetBestIP(), IPAddress()); + + // Add ULA one. ULA is unique local address which is starting either + // with 0xfc or 0xfd. + ipstr = "fd00:fa00:4:1000:be30:5bff:fee5:c4"; + ASSERT_TRUE(IPFromString(ipstr, IPV6_ADDRESS_FLAG_NONE, &ip)); + ipv6_network.AddIP(ip); + EXPECT_EQ(ipv6_network.GetBestIP(), static_cast<IPAddress>(ip)); + + // Add link local one. + ipstr = "fe80::aabb:ccff:fedd:eeff"; + ASSERT_TRUE(IPFromString(ipstr, IPV6_ADDRESS_FLAG_NONE, &link_local)); + ipv6_network.AddIP(link_local); + EXPECT_EQ(ipv6_network.GetBestIP(), static_cast<IPAddress>(link_local)); + + // Add global one. + ipstr = "2401:fa00:4:1000:be30:5bff:fee5:c5"; + ASSERT_TRUE(IPFromString(ipstr, IPV6_ADDRESS_FLAG_NONE, &ip)); + ipv6_network.AddIP(ip); + EXPECT_EQ(ipv6_network.GetBestIP(), static_cast<IPAddress>(ip)); + + // Add another link local address, then the compatible address is still global + // one. + ipstr = "fe80::aabb:ccff:fedd:eedd"; + ASSERT_TRUE(IPFromString(ipstr, IPV6_ADDRESS_FLAG_NONE, &link_local)); + ipv6_network.AddIP(link_local); + EXPECT_EQ(ipv6_network.GetBestIP(), static_cast<IPAddress>(ip)); + + // Add global dynamic temporary one. + ipstr = "2401:fa00:4:1000:be30:5bff:fee5:c6"; + ASSERT_TRUE(IPFromString(ipstr, IPV6_ADDRESS_FLAG_TEMPORARY, &ip)); + ipv6_network.AddIP(ip); + EXPECT_EQ(ipv6_network.GetBestIP(), static_cast<IPAddress>(ip)); + + // Add another link local address, then the compatible address is still global + // dynamic one. + ipstr = "fe80::aabb:ccff:fedd:eedd"; + ASSERT_TRUE(IPFromString(ipstr, IPV6_ADDRESS_FLAG_NONE, &link_local)); + ipv6_network.AddIP(link_local); + EXPECT_EQ(ipv6_network.GetBestIP(), static_cast<IPAddress>(ip)); +} + +TEST_F(NetworkTest, TestNetworkMonitoring) { + FakeNetworkMonitorFactory factory; + PhysicalSocketServer socket_server; + BasicNetworkManager manager(&factory, &socket_server, &field_trials_); + manager.SignalNetworksChanged.connect(static_cast<NetworkTest*>(this), + &NetworkTest::OnNetworksChanged); + manager.StartUpdating(); + FakeNetworkMonitor* network_monitor = GetNetworkMonitor(manager); + EXPECT_TRUE(network_monitor && network_monitor->started()); + EXPECT_TRUE_WAIT(callback_called_, 1000); + callback_called_ = false; + + // Clear the networks so that there will be network changes below. + ClearNetworks(manager); + // Network manager is started, so the callback is called when the network + // monitor fires the network-change event. + network_monitor->InovkeNetworksChangedCallbackForTesting(); + EXPECT_TRUE_WAIT(callback_called_, 1000); + + // Network manager is stopped. + manager.StopUpdating(); + EXPECT_FALSE(GetNetworkMonitor(manager)->started()); +} + +// Fails on Android: https://bugs.chromium.org/p/webrtc/issues/detail?id=4364. +#if defined(WEBRTC_ANDROID) +#define MAYBE_DefaultLocalAddress DISABLED_DefaultLocalAddress +#else +#define MAYBE_DefaultLocalAddress DefaultLocalAddress +#endif +TEST_F(NetworkTest, MAYBE_DefaultLocalAddress) { + MAYBE_SKIP_IPV4; + IPAddress ip; + FakeNetworkMonitorFactory factory; + PhysicalSocketServer socket_server; + TestBasicNetworkManager manager(&factory, &socket_server, field_trials_); + manager.SignalNetworksChanged.connect(static_cast<NetworkTest*>(this), + &NetworkTest::OnNetworksChanged); + manager.StartUpdating(); + EXPECT_TRUE_WAIT(callback_called_, 1000); + + // Make sure we can query default local address when an address for such + // address family exists. + std::vector<const Network*> networks = manager.GetNetworks(); + EXPECT_TRUE(!networks.empty()); + for (const Network* network : networks) { + if (network->GetBestIP().family() == AF_INET) { + EXPECT_TRUE(QueryDefaultLocalAddress(manager, AF_INET) != IPAddress()); + } else if (network->GetBestIP().family() == AF_INET6 && + !IPIsLoopback(network->GetBestIP())) { + // Existence of an IPv6 loopback address doesn't mean it has IPv6 network + // enabled. + EXPECT_TRUE(QueryDefaultLocalAddress(manager, AF_INET6) != IPAddress()); + } + } + + // GetDefaultLocalAddress should return the valid default address after set. + manager.set_default_local_addresses(GetLoopbackIP(AF_INET), + GetLoopbackIP(AF_INET6)); + EXPECT_TRUE(manager.GetDefaultLocalAddress(AF_INET, &ip)); + EXPECT_EQ(ip, GetLoopbackIP(AF_INET)); + EXPECT_TRUE(manager.GetDefaultLocalAddress(AF_INET6, &ip)); + EXPECT_EQ(ip, GetLoopbackIP(AF_INET6)); + + // More tests on GetDefaultLocalAddress with ipv6 addresses where the set + // default address may be different from the best IP address of any network. + InterfaceAddress ip1; + EXPECT_TRUE(IPFromString("abcd::1234:5678:abcd:1111", + IPV6_ADDRESS_FLAG_TEMPORARY, &ip1)); + // Create a network with a prefix of ip1. + Network ipv6_network("test_eth0", "Test NetworkAdapter", TruncateIP(ip1, 64), + 64); + IPAddress ip2; + EXPECT_TRUE(IPFromString("abcd::1234:5678:abcd:2222", &ip2)); + ipv6_network.AddIP(ip1); + ipv6_network.AddIP(ip2); + std::vector<std::unique_ptr<Network>> list; + list.push_back(std::make_unique<Network>(ipv6_network)); + bool changed; + MergeNetworkList(manager, std::move(list), &changed); + // If the set default address is not in any network, GetDefaultLocalAddress + // should return it. + IPAddress ip3; + EXPECT_TRUE(IPFromString("abcd::1234:5678:abcd:3333", &ip3)); + manager.set_default_local_addresses(GetLoopbackIP(AF_INET), ip3); + EXPECT_TRUE(manager.GetDefaultLocalAddress(AF_INET6, &ip)); + EXPECT_EQ(ip3, ip); + // If the set default address is in a network, GetDefaultLocalAddress will + // return the best IP in that network. + manager.set_default_local_addresses(GetLoopbackIP(AF_INET), ip2); + EXPECT_TRUE(manager.GetDefaultLocalAddress(AF_INET6, &ip)); + EXPECT_EQ(static_cast<IPAddress>(ip1), ip); + + manager.StopUpdating(); +} + +// Test that MergeNetworkList does not set change = true +// when changing from cellular_X to cellular_Y. +TEST_F(NetworkTest, TestWhenNetworkListChangeReturnsChangedFlag) { + PhysicalSocketServer socket_server; + BasicNetworkManager manager(&socket_server); + + IPAddress ip1; + EXPECT_TRUE(IPFromString("2400:4030:1:2c00:be30:0:0:1", &ip1)); + auto net1 = std::make_unique<Network>("em1", "em1", TruncateIP(ip1, 64), 64); + net1->set_type(ADAPTER_TYPE_CELLULAR_3G); + net1->AddIP(ip1); + std::vector<std::unique_ptr<Network>> list; + list.push_back(std::move(net1)); + + { + bool changed; + MergeNetworkList(manager, std::move(list), &changed); + EXPECT_TRUE(changed); + std::vector<const Network*> list2 = manager.GetNetworks(); + EXPECT_EQ(list2.size(), 1uL); + EXPECT_EQ(ADAPTER_TYPE_CELLULAR_3G, list2[0]->type()); + } + + // Modify net1 from 3G to 4G + { + auto net2 = + std::make_unique<Network>("em1", "em1", TruncateIP(ip1, 64), 64); + net2->set_type(ADAPTER_TYPE_CELLULAR_4G); + net2->AddIP(ip1); + list.clear(); + list.push_back(std::move(net2)); + bool changed; + MergeNetworkList(manager, std::move(list), &changed); + + // Change from 3G to 4G shall not trigger OnNetworksChanged, + // i.e changed = false. + EXPECT_FALSE(changed); + std::vector<const Network*> list2 = manager.GetNetworks(); + ASSERT_EQ(list2.size(), 1uL); + EXPECT_EQ(ADAPTER_TYPE_CELLULAR_4G, list2[0]->type()); + } + + // Don't modify. + { + auto net2 = + std::make_unique<Network>("em1", "em1", TruncateIP(ip1, 64), 64); + net2->set_type(ADAPTER_TYPE_CELLULAR_4G); + net2->AddIP(ip1); + list.clear(); + list.push_back(std::move(net2)); + bool changed; + MergeNetworkList(manager, std::move(list), &changed); + + // No change. + EXPECT_FALSE(changed); + std::vector<const Network*> list2 = manager.GetNetworks(); + ASSERT_EQ(list2.size(), 1uL); + EXPECT_EQ(ADAPTER_TYPE_CELLULAR_4G, list2[0]->type()); + } +} + +#if defined(WEBRTC_POSIX) +TEST_F(NetworkTest, IgnoresMACBasedIPv6Address) { + std::string ipv6_address = "2607:fc20:f340:1dc8:214:22ff:fe01:2345"; + std::string ipv6_mask = "FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF"; + PhysicalSocketServer socket_server; + BasicNetworkManager manager(&socket_server); + manager.StartUpdating(); + + // IPSec interface; name is in form "ipsec<index>". + char if_name[20] = "ipsec11"; + ifaddrs* addr_list = + InstallIpv6Network(if_name, ipv6_address, ipv6_mask, manager); + + std::vector<const Network*> list = manager.GetNetworks(); + EXPECT_EQ(list.size(), 0u); + ReleaseIfAddrs(addr_list); +} + +TEST_F(NetworkTest, WebRTC_AllowMACBasedIPv6Address) { + webrtc::test::ScopedFieldTrials field_trials( + "WebRTC-AllowMACBasedIPv6/Enabled/"); + std::string ipv6_address = "2607:fc20:f340:1dc8:214:22ff:fe01:2345"; + std::string ipv6_mask = "FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF"; + PhysicalSocketServer socket_server; + BasicNetworkManager manager(&socket_server); + manager.StartUpdating(); + + // IPSec interface; name is in form "ipsec<index>". + char if_name[20] = "ipsec11"; + ifaddrs* addr_list = + InstallIpv6Network(if_name, ipv6_address, ipv6_mask, manager); + + std::vector<const Network*> list = manager.GetNetworks(); + EXPECT_EQ(list.size(), 1u); + ReleaseIfAddrs(addr_list); +} +#endif + +#if defined(WEBRTC_POSIX) +TEST_F(NetworkTest, WebRTC_BindUsingInterfaceName) { + char if_name1[20] = "wlan0"; + char if_name2[20] = "v4-wlan0"; + ifaddrs* list = nullptr; + list = AddIpv6Address(list, if_name1, "1000:2000:3000:4000:0:0:0:1", + "FFFF:FFFF:FFFF:FFFF::", 0); + list = AddIpv4Address(list, if_name2, "192.168.0.2", "255.255.255.255"); + std::vector<std::unique_ptr<Network>> result; + + // Sanity check that both interfaces are included by default. + FakeNetworkMonitorFactory factory; + PhysicalSocketServer socket_server; + BasicNetworkManager manager(&factory, &socket_server, &field_trials_); + manager.StartUpdating(); + CallConvertIfAddrs(manager, list, /*include_ignored=*/false, &result); + EXPECT_EQ(2u, result.size()); + ReleaseIfAddrs(list); + bool changed; + // This ensures we release the objects created in CallConvertIfAddrs. + MergeNetworkList(manager, std::move(result), &changed); + result.clear(); + + FakeNetworkMonitor* network_monitor = GetNetworkMonitor(manager); + + IPAddress ipv6; + EXPECT_TRUE(IPFromString("1000:2000:3000:4000:0:0:0:1", &ipv6)); + IPAddress ipv4; + EXPECT_TRUE(IPFromString("192.168.0.2", &ipv4)); + + // The network monitor only knwos about the ipv6 address, interface. + network_monitor->set_adapters({"wlan0"}); + network_monitor->set_ip_addresses({ipv6}); + EXPECT_EQ(manager.BindSocketToNetwork(/* fd */ 77, ipv6), + NetworkBindingResult::SUCCESS); + + // But it will bind anyway using string matching... + EXPECT_EQ(manager.BindSocketToNetwork(/* fd */ 77, ipv4), + NetworkBindingResult::SUCCESS); +} +#endif + +TEST_F(NetworkTest, NetworkCostVpn_Default) { + IPAddress ip1; + EXPECT_TRUE(IPFromString("2400:4030:1:2c00:be30:0:0:1", &ip1)); + webrtc::test::ScopedKeyValueConfig field_trials; + + Network* net1 = new Network("em1", "em1", TruncateIP(ip1, 64), 64); + net1->set_type(ADAPTER_TYPE_VPN); + net1->set_underlying_type_for_vpn(ADAPTER_TYPE_ETHERNET); + + Network* net2 = new Network("em1", "em1", TruncateIP(ip1, 64), 64); + net2->set_type(ADAPTER_TYPE_ETHERNET); + + EXPECT_EQ(net1->GetCost(field_trials), net2->GetCost(field_trials)); + delete net1; + delete net2; +} + +TEST_F(NetworkTest, NetworkCostVpn_VpnMoreExpensive) { + webrtc::test::ScopedKeyValueConfig field_trials( + "WebRTC-AddNetworkCostToVpn/Enabled/"); + + IPAddress ip1; + EXPECT_TRUE(IPFromString("2400:4030:1:2c00:be30:0:0:1", &ip1)); + + Network* net1 = new Network("em1", "em1", TruncateIP(ip1, 64), 64); + net1->set_type(ADAPTER_TYPE_VPN); + net1->set_underlying_type_for_vpn(ADAPTER_TYPE_ETHERNET); + + Network* net2 = new Network("em1", "em1", TruncateIP(ip1, 64), 64); + net2->set_type(ADAPTER_TYPE_ETHERNET); + + EXPECT_GT(net1->GetCost(field_trials), net2->GetCost(field_trials)); + delete net1; + delete net2; +} + +TEST_F(NetworkTest, GuessAdapterFromNetworkCost) { + webrtc::test::ScopedKeyValueConfig field_trials( + "WebRTC-AddNetworkCostToVpn/Enabled/" + "WebRTC-UseDifferentiatedCellularCosts/Enabled/"); + + IPAddress ip1; + EXPECT_TRUE(IPFromString("2400:4030:1:2c00:be30:0:0:1", &ip1)); + + for (auto type : kAllAdapterTypes) { + if (type == rtc::ADAPTER_TYPE_VPN) + continue; + Network net1("em1", "em1", TruncateIP(ip1, 64), 64); + net1.set_type(type); + auto [guess, vpn] = + Network::GuessAdapterFromNetworkCost(net1.GetCost(field_trials)); + EXPECT_FALSE(vpn); + if (type == rtc::ADAPTER_TYPE_LOOPBACK) { + EXPECT_EQ(guess, rtc::ADAPTER_TYPE_ETHERNET); + } else { + EXPECT_EQ(type, guess); + } + } + + // VPN + for (auto type : kAllAdapterTypes) { + if (type == rtc::ADAPTER_TYPE_VPN) + continue; + Network net1("em1", "em1", TruncateIP(ip1, 64), 64); + net1.set_type(rtc::ADAPTER_TYPE_VPN); + net1.set_underlying_type_for_vpn(type); + auto [guess, vpn] = + Network::GuessAdapterFromNetworkCost(net1.GetCost(field_trials)); + EXPECT_TRUE(vpn); + if (type == rtc::ADAPTER_TYPE_LOOPBACK) { + EXPECT_EQ(guess, rtc::ADAPTER_TYPE_ETHERNET); + } else { + EXPECT_EQ(type, guess); + } + } +} + +TEST_F(NetworkTest, VpnList) { + PhysicalSocketServer socket_server; + { + BasicNetworkManager manager(&socket_server); + manager.set_vpn_list({NetworkMask(IPFromString("192.168.0.0"), 16)}); + manager.StartUpdating(); + EXPECT_TRUE(manager.IsConfiguredVpn(IPFromString("192.168.1.1"), 32)); + EXPECT_TRUE(manager.IsConfiguredVpn(IPFromString("192.168.12.1"), 24)); + EXPECT_TRUE(manager.IsConfiguredVpn(IPFromString("192.168.0.0"), 16)); + EXPECT_TRUE(manager.IsConfiguredVpn(IPFromString("192.168.0.0"), 24)); + EXPECT_FALSE(manager.IsConfiguredVpn(IPFromString("192.133.1.1"), 32)); + EXPECT_FALSE(manager.IsConfiguredVpn(IPFromString("192.133.0.0"), 16)); + EXPECT_FALSE(manager.IsConfiguredVpn(IPFromString("192.168.0.0"), 15)); + } + { + BasicNetworkManager manager(&socket_server); + manager.set_vpn_list({NetworkMask(IPFromString("192.168.0.0"), 24)}); + manager.StartUpdating(); + EXPECT_FALSE(manager.IsConfiguredVpn(IPFromString("192.168.1.1"), 32)); + EXPECT_TRUE(manager.IsConfiguredVpn(IPFromString("192.168.0.1"), 32)); + } +} + +#if defined(WEBRTC_POSIX) +// TODO(webrtc:13114): Implement the InstallIpv4Network for windows. +TEST_F(NetworkTest, VpnListOverrideAdapterType) { + PhysicalSocketServer socket_server; + BasicNetworkManager manager(&socket_server); + manager.set_vpn_list({NetworkMask(IPFromString("192.168.0.0"), 16)}); + manager.StartUpdating(); + + char if_name[20] = "eth0"; + auto addr_list = + InstallIpv4Network(if_name, "192.168.1.23", "255.255.255.255", manager); + + std::vector<const Network*> list = manager.GetNetworks(); + ASSERT_EQ(1u, list.size()); + EXPECT_EQ(ADAPTER_TYPE_VPN, list[0]->type()); + EXPECT_EQ(ADAPTER_TYPE_ETHERNET, list[0]->underlying_type_for_vpn()); + ClearNetworks(manager); + ReleaseIfAddrs(addr_list); +} +#endif // defined(WEBRTC_POSIX) + +TEST_F(NetworkTest, HardcodedVpn) { + const uint8_t cisco[] = {0x0, 0x5, 0x9A, 0x3C, 0x7A, 0x0}; + const uint8_t global[] = {0x2, 0x50, 0x41, 0x0, 0x0, 0x1}; + const uint8_t unknown[] = {0x2, 0x50, 0x41, 0x0, 0x0, 0x0}; + const uint8_t five_bytes[] = {0x2, 0x50, 0x41, 0x0, 0x0}; + EXPECT_TRUE(NetworkManagerBase::IsVpnMacAddress(cisco)); + EXPECT_TRUE(NetworkManagerBase::IsVpnMacAddress(global)); + + EXPECT_FALSE(NetworkManagerBase::IsVpnMacAddress( + rtc::ArrayView<const uint8_t>(cisco, 5))); + EXPECT_FALSE(NetworkManagerBase::IsVpnMacAddress(five_bytes)); + EXPECT_FALSE(NetworkManagerBase::IsVpnMacAddress(unknown)); + EXPECT_FALSE(NetworkManagerBase::IsVpnMacAddress(nullptr)); +} + +TEST(CompareNetworks, IrreflexivityTest) { + // x < x is false + auto network = std::make_unique<Network>( + "test_eth0", "Test Network Adapter 1", IPAddress(0x12345600U), 24); + EXPECT_FALSE(webrtc_network_internal::CompareNetworks(network, network)); +} + +TEST(CompareNetworks, AsymmetryTest) { + // x < y and y < x cannot be both true + auto network_a = std::make_unique<Network>( + "test_eth0", "Test Network Adapter 1", IPAddress(0x12345600U), 24); + auto network_b = std::make_unique<Network>( + "test_eth1", "Test Network Adapter 1", IPAddress(0x12345600U), 24); + EXPECT_TRUE(webrtc_network_internal::CompareNetworks(network_a, network_b)); + EXPECT_FALSE(webrtc_network_internal::CompareNetworks(network_b, network_a)); + + auto network_c = std::make_unique<Network>( + "test_eth0", "Test Network Adapter 1", IPAddress(0x12345500U), 24); + auto network_d = std::make_unique<Network>( + "test_eth0", "Test Network Adapter 1", IPAddress(0x12345600U), 24); + EXPECT_TRUE(webrtc_network_internal::CompareNetworks(network_c, network_d)); + EXPECT_FALSE(webrtc_network_internal::CompareNetworks(network_d, network_c)); +} + +TEST(CompareNetworks, TransitivityTest) { + // x < y and y < z imply x < z + auto network_a = std::make_unique<Network>( + "test_eth0", "Test Network Adapter 1", IPAddress(0x12345600U), 24); + auto network_b = std::make_unique<Network>( + "test_eth1", "Test Network Adapter 1", IPAddress(0x12345600U), 24); + auto network_c = std::make_unique<Network>( + "test_eth2", "Test Network Adapter 1", IPAddress(0x12345600U), 24); + EXPECT_TRUE(webrtc_network_internal::CompareNetworks(network_a, network_b)); + EXPECT_TRUE(webrtc_network_internal::CompareNetworks(network_b, network_c)); + + auto network_d = std::make_unique<Network>( + "test_eth0", "Test Network Adapter 1", IPAddress(0x12345600U), 24); + auto network_e = std::make_unique<Network>( + "test_eth0", "Test Network Adapter 1", IPAddress(0x12345700U), 24); + auto network_f = std::make_unique<Network>( + "test_eth0", "Test Network Adapter 1", IPAddress(0x12345800U), 24); + EXPECT_TRUE(webrtc_network_internal::CompareNetworks(network_d, network_e)); + EXPECT_TRUE(webrtc_network_internal::CompareNetworks(network_e, network_f)); + EXPECT_TRUE(webrtc_network_internal::CompareNetworks(network_d, network_f)); + EXPECT_TRUE(webrtc_network_internal::CompareNetworks(network_a, network_c)); +} + +TEST(CompareNetworks, TransitivityOfIncomparabilityTest) { + // x == y and y == z imply x == z, + // where x == y means x < y and y < x are both false + auto network_a = std::make_unique<Network>( + "test_eth0", "Test Network Adapter 1", IPAddress(0x12345600U), 23); + auto network_b = std::make_unique<Network>( + "test_eth0", "Test Network Adapter 1", IPAddress(0x12345600U), 24); + auto network_c = std::make_unique<Network>( + "test_eth0", "Test Network Adapter 1", IPAddress(0x12345700U), 24); + + // network_a < network_b + EXPECT_TRUE(webrtc_network_internal::CompareNetworks(network_a, network_b)); + EXPECT_FALSE(webrtc_network_internal::CompareNetworks(network_b, network_a)); + + // network_b < network_c + EXPECT_TRUE(webrtc_network_internal::CompareNetworks(network_b, network_c)); + EXPECT_FALSE(webrtc_network_internal::CompareNetworks(network_c, network_b)); + + // network_a < network_c + EXPECT_TRUE(webrtc_network_internal::CompareNetworks(network_a, network_c)); + EXPECT_FALSE(webrtc_network_internal::CompareNetworks(network_c, network_a)); + + auto network_d = std::make_unique<Network>( + "test_eth0", "Test Network Adapter 1", IPAddress(0x12345600U), 24); + auto network_e = std::make_unique<Network>( + "test_eth0", "Test Network Adapter 1", IPAddress(0x12345600U), 24); + auto network_f = std::make_unique<Network>( + "test_eth0", "Test Network Adapter 1", IPAddress(0x12345600U), 24); + + // network_d == network_e + EXPECT_FALSE(webrtc_network_internal::CompareNetworks(network_d, network_e)); + EXPECT_FALSE(webrtc_network_internal::CompareNetworks(network_e, network_d)); + + // network_e == network_f + EXPECT_FALSE(webrtc_network_internal::CompareNetworks(network_e, network_f)); + EXPECT_FALSE(webrtc_network_internal::CompareNetworks(network_f, network_e)); + + // network_d == network_f + EXPECT_FALSE(webrtc_network_internal::CompareNetworks(network_d, network_f)); + EXPECT_FALSE(webrtc_network_internal::CompareNetworks(network_f, network_d)); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/null_socket_server.cc b/third_party/libwebrtc/rtc_base/null_socket_server.cc new file mode 100644 index 0000000000..366349db3a --- /dev/null +++ b/third_party/libwebrtc/rtc_base/null_socket_server.cc @@ -0,0 +1,41 @@ +/* + * Copyright 2016 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 "rtc_base/null_socket_server.h" + +#include "api/units/time_delta.h" +#include "rtc_base/checks.h" +#include "rtc_base/event.h" +#include "rtc_base/socket_server.h" + +namespace rtc { + +NullSocketServer::NullSocketServer() = default; +NullSocketServer::~NullSocketServer() {} + +bool NullSocketServer::Wait(webrtc::TimeDelta max_wait_duration, + bool process_io) { + // Wait with the given timeout. Do not log a warning if we end up waiting for + // a long time; that just means no one has any work for us, which is perfectly + // legitimate. + event_.Wait(max_wait_duration, /*warn_after=*/Event::kForever); + return true; +} + +void NullSocketServer::WakeUp() { + event_.Set(); +} + +rtc::Socket* NullSocketServer::CreateSocket(int /* family */, int /* type */) { + RTC_DCHECK_NOTREACHED(); + return nullptr; +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/null_socket_server.h b/third_party/libwebrtc/rtc_base/null_socket_server.h new file mode 100644 index 0000000000..87f49f436e --- /dev/null +++ b/third_party/libwebrtc/rtc_base/null_socket_server.h @@ -0,0 +1,37 @@ +/* + * Copyright 2012 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 RTC_BASE_NULL_SOCKET_SERVER_H_ +#define RTC_BASE_NULL_SOCKET_SERVER_H_ + +#include "rtc_base/event.h" +#include "rtc_base/socket.h" +#include "rtc_base/socket_server.h" +#include "rtc_base/system/rtc_export.h" + +namespace rtc { + +class RTC_EXPORT NullSocketServer : public SocketServer { + public: + NullSocketServer(); + ~NullSocketServer() override; + + bool Wait(webrtc::TimeDelta max_wait_duration, bool process_io) override; + void WakeUp() override; + + Socket* CreateSocket(int family, int type) override; + + private: + Event event_; +}; + +} // namespace rtc + +#endif // RTC_BASE_NULL_SOCKET_SERVER_H_ diff --git a/third_party/libwebrtc/rtc_base/null_socket_server_gn/moz.build b/third_party/libwebrtc/rtc_base/null_socket_server_gn/moz.build new file mode 100644 index 0000000000..7385764373 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/null_socket_server_gn/moz.build @@ -0,0 +1,233 @@ +# 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/rtc_base/null_socket_server.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_ENABLE_LIBEVENT"] = 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 += [ + "GLESv2", + "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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("null_socket_server_gn") diff --git a/third_party/libwebrtc/rtc_base/null_socket_server_unittest.cc b/third_party/libwebrtc/rtc_base/null_socket_server_unittest.cc new file mode 100644 index 0000000000..58a6211aba --- /dev/null +++ b/third_party/libwebrtc/rtc_base/null_socket_server_unittest.cc @@ -0,0 +1,44 @@ +/* + * Copyright 2012 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 "rtc_base/null_socket_server.h" + +#include <stdint.h> + +#include <memory> + +#include "api/units/time_delta.h" +#include "rtc_base/gunit.h" +#include "rtc_base/thread.h" +#include "rtc_base/time_utils.h" +#include "test/gtest.h" + +namespace rtc { + +TEST(NullSocketServerTest, WaitAndSet) { + NullSocketServer ss; + auto thread = Thread::Create(); + EXPECT_TRUE(thread->Start()); + thread->PostTask([&ss] { ss.WakeUp(); }); + // The process_io will be ignored. + const bool process_io = true; + EXPECT_TRUE_WAIT(ss.Wait(SocketServer::kForever, process_io), 5'000); +} + +TEST(NullSocketServerTest, TestWait) { + NullSocketServer ss; + int64_t start = TimeMillis(); + ss.Wait(webrtc::TimeDelta::Millis(200), true); + // The actual wait time is dependent on the resolution of the timer used by + // the Event class. Allow for the event to signal ~20ms early. + EXPECT_GE(TimeSince(start), 180); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/numerics/divide_round.h b/third_party/libwebrtc/rtc_base/numerics/divide_round.h new file mode 100644 index 0000000000..90c67fca3c --- /dev/null +++ b/third_party/libwebrtc/rtc_base/numerics/divide_round.h @@ -0,0 +1,60 @@ +/* + * 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 RTC_BASE_NUMERICS_DIVIDE_ROUND_H_ +#define RTC_BASE_NUMERICS_DIVIDE_ROUND_H_ + +#include <type_traits> + +#include "rtc_base/checks.h" +#include "rtc_base/numerics/safe_compare.h" + +namespace webrtc { + +template <typename Dividend, typename Divisor> +inline auto constexpr DivideRoundUp(Dividend dividend, Divisor divisor) { + static_assert(std::is_integral<Dividend>(), ""); + static_assert(std::is_integral<Divisor>(), ""); + RTC_DCHECK_GE(dividend, 0); + RTC_DCHECK_GT(divisor, 0); + + auto quotient = dividend / divisor; + auto remainder = dividend % divisor; + return quotient + (remainder > 0 ? 1 : 0); +} + +template <typename Dividend, typename Divisor> +inline auto constexpr DivideRoundToNearest(Dividend dividend, Divisor divisor) { + static_assert(std::is_integral<Dividend>(), ""); + static_assert(std::is_integral<Divisor>(), ""); + RTC_DCHECK_GT(divisor, 0); + + if (dividend < Dividend{0}) { + auto half_of_divisor = divisor / 2; + auto quotient = dividend / divisor; + auto remainder = dividend % divisor; + if (rtc::SafeGt(-remainder, half_of_divisor)) { + --quotient; + } + return quotient; + } + + auto half_of_divisor = (divisor - 1) / 2; + auto quotient = dividend / divisor; + auto remainder = dividend % divisor; + if (rtc::SafeGt(remainder, half_of_divisor)) { + ++quotient; + } + return quotient; +} + +} // namespace webrtc + +#endif // RTC_BASE_NUMERICS_DIVIDE_ROUND_H_ diff --git a/third_party/libwebrtc/rtc_base/numerics/divide_round_unittest.cc b/third_party/libwebrtc/rtc_base/numerics/divide_round_unittest.cc new file mode 100644 index 0000000000..00548e1cb2 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/numerics/divide_round_unittest.cc @@ -0,0 +1,178 @@ +/* + * 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 "rtc_base/numerics/divide_round.h" + +#include <limits> + +#include "test/gtest.h" + +namespace webrtc { +namespace { + +TEST(DivideRoundUpTest, CanBeUsedAsConstexpr) { + static_assert(DivideRoundUp(5, 1) == 5, ""); + static_assert(DivideRoundUp(5, 2) == 3, ""); +} + +TEST(DivideRoundUpTest, ReturnsZeroForZeroDividend) { + EXPECT_EQ(DivideRoundUp(uint8_t{0}, 1), 0); + EXPECT_EQ(DivideRoundUp(uint8_t{0}, 3), 0); + EXPECT_EQ(DivideRoundUp(int{0}, 1), 0); + EXPECT_EQ(DivideRoundUp(int{0}, 3), 0); +} + +TEST(DivideRoundUpTest, WorksForMaxDividend) { + EXPECT_EQ(DivideRoundUp(uint8_t{255}, 2), 128); + EXPECT_EQ(DivideRoundUp(std::numeric_limits<int>::max(), 2), + std::numeric_limits<int>::max() / 2 + + (std::numeric_limits<int>::max() % 2)); +} + +TEST(DivideRoundToNearestTest, CanBeUsedAsConstexpr) { + static constexpr int kOne = DivideRoundToNearest(5, 4); + static constexpr int kTwo = DivideRoundToNearest(7, 4); + static_assert(kOne == 1); + static_assert(kTwo == 2); + static_assert(DivideRoundToNearest(-5, 4) == -1); + static_assert(DivideRoundToNearest(-7, 4) == -2); +} + +TEST(DivideRoundToNearestTest, DivideByOddNumber) { + EXPECT_EQ(DivideRoundToNearest(-5, 3), -2); + EXPECT_EQ(DivideRoundToNearest(-4, 3), -1); + EXPECT_EQ(DivideRoundToNearest(-3, 3), -1); + EXPECT_EQ(DivideRoundToNearest(-2, 3), -1); + EXPECT_EQ(DivideRoundToNearest(-1, 3), 0); + EXPECT_EQ(DivideRoundToNearest(0, 3), 0); + EXPECT_EQ(DivideRoundToNearest(1, 3), 0); + EXPECT_EQ(DivideRoundToNearest(2, 3), 1); + EXPECT_EQ(DivideRoundToNearest(3, 3), 1); + EXPECT_EQ(DivideRoundToNearest(4, 3), 1); + EXPECT_EQ(DivideRoundToNearest(5, 3), 2); + EXPECT_EQ(DivideRoundToNearest(6, 3), 2); +} + +TEST(DivideRoundToNearestTest, DivideByEvenNumberTieRoundsUp) { + EXPECT_EQ(DivideRoundToNearest(-7, 4), -2); + EXPECT_EQ(DivideRoundToNearest(-6, 4), -1); + EXPECT_EQ(DivideRoundToNearest(-5, 4), -1); + EXPECT_EQ(DivideRoundToNearest(-4, 4), -1); + EXPECT_EQ(DivideRoundToNearest(-3, 4), -1); + EXPECT_EQ(DivideRoundToNearest(-2, 4), 0); + EXPECT_EQ(DivideRoundToNearest(-1, 4), 0); + EXPECT_EQ(DivideRoundToNearest(0, 4), 0); + EXPECT_EQ(DivideRoundToNearest(1, 4), 0); + EXPECT_EQ(DivideRoundToNearest(2, 4), 1); + EXPECT_EQ(DivideRoundToNearest(3, 4), 1); + EXPECT_EQ(DivideRoundToNearest(4, 4), 1); + EXPECT_EQ(DivideRoundToNearest(5, 4), 1); + EXPECT_EQ(DivideRoundToNearest(6, 4), 2); + EXPECT_EQ(DivideRoundToNearest(7, 4), 2); +} + +TEST(DivideRoundToNearestTest, LargeDivisor) { + EXPECT_EQ(DivideRoundToNearest(std::numeric_limits<int>::max() - 1, + std::numeric_limits<int>::max()), + 1); + EXPECT_EQ(DivideRoundToNearest(std::numeric_limits<int>::min(), + std::numeric_limits<int>::max()), + -1); +} + +TEST(DivideRoundToNearestTest, DivideSmallTypeByLargeType) { + uint8_t small = 0xff; + uint16_t large = 0xffff; + EXPECT_EQ(DivideRoundToNearest(small, large), 0); +} + +using IntegerTypes = ::testing::Types<int8_t, + int16_t, + int32_t, + int64_t, + uint8_t, + uint16_t, + uint32_t, + uint64_t>; +template <typename T> +class DivideRoundTypedTest : public ::testing::Test {}; +TYPED_TEST_SUITE(DivideRoundTypedTest, IntegerTypes); + +TYPED_TEST(DivideRoundTypedTest, RoundToNearestPreservesType) { + static_assert( + std::is_same<decltype(DivideRoundToNearest(TypeParam{100}, int8_t{3})), + decltype(TypeParam{100} / int8_t{3})>::value, + ""); + static_assert( + std::is_same<decltype(DivideRoundToNearest(TypeParam{100}, int16_t{3})), + decltype(TypeParam{100} / int16_t{3})>::value, + ""); + static_assert( + std::is_same<decltype(DivideRoundToNearest(TypeParam{100}, int32_t{3})), + decltype(TypeParam{100} / int32_t{3})>::value, + ""); + static_assert( + std::is_same<decltype(DivideRoundToNearest(TypeParam{100}, int64_t{3})), + decltype(TypeParam{100} / int64_t{3})>::value, + ""); + static_assert( + std::is_same<decltype(DivideRoundToNearest(TypeParam{100}, uint8_t{3})), + decltype(TypeParam{100} / uint8_t{3})>::value, + ""); + static_assert( + std::is_same<decltype(DivideRoundToNearest(TypeParam{100}, uint16_t{3})), + decltype(TypeParam{100} / uint16_t{3})>::value, + ""); + static_assert( + std::is_same<decltype(DivideRoundToNearest(TypeParam{100}, uint32_t{3})), + decltype(TypeParam{100} / uint32_t{3})>::value, + ""); + static_assert( + std::is_same<decltype(DivideRoundToNearest(TypeParam{100}, uint64_t{3})), + decltype(TypeParam{100} / uint64_t{3})>::value, + ""); +} + +TYPED_TEST(DivideRoundTypedTest, RoundUpPreservesType) { + static_assert(std::is_same<decltype(DivideRoundUp(TypeParam{100}, int8_t{3})), + decltype(TypeParam{100} / int8_t{3})>::value, + ""); + static_assert( + std::is_same<decltype(DivideRoundUp(TypeParam{100}, int16_t{3})), + decltype(TypeParam{100} / int16_t{3})>::value, + ""); + static_assert( + std::is_same<decltype(DivideRoundUp(TypeParam{100}, int32_t{3})), + decltype(TypeParam{100} / int32_t{3})>::value, + ""); + static_assert( + std::is_same<decltype(DivideRoundUp(TypeParam{100}, int64_t{3})), + decltype(TypeParam{100} / int64_t{3})>::value, + ""); + static_assert( + std::is_same<decltype(DivideRoundUp(TypeParam{100}, uint8_t{3})), + decltype(TypeParam{100} / uint8_t{3})>::value, + ""); + static_assert( + std::is_same<decltype(DivideRoundUp(TypeParam{100}, uint16_t{3})), + decltype(TypeParam{100} / uint16_t{3})>::value, + ""); + static_assert( + std::is_same<decltype(DivideRoundUp(TypeParam{100}, uint32_t{3})), + decltype(TypeParam{100} / uint32_t{3})>::value, + ""); + static_assert( + std::is_same<decltype(DivideRoundUp(TypeParam{100}, uint64_t{3})), + decltype(TypeParam{100} / uint64_t{3})>::value, + ""); +} + +} // namespace +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/numerics/event_based_exponential_moving_average.cc b/third_party/libwebrtc/rtc_base/numerics/event_based_exponential_moving_average.cc new file mode 100644 index 0000000000..b426fdeed7 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/numerics/event_based_exponential_moving_average.cc @@ -0,0 +1,82 @@ +/* + * 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 "rtc_base/numerics/event_based_exponential_moving_average.h" + +#include <cmath> + +#include "rtc_base/checks.h" + +namespace { + +// For a normal distributed value, the 95% double sided confidence interval is +// is 1.96 * stddev. +constexpr double ninetyfive_percent_confidence = 1.96; + +} // namespace + +namespace rtc { + +// `half_time` specifies how much weight will be given to old samples, +// a sample gets exponentially less weight so that it's 50% +// after `half_time` time units has passed. +EventBasedExponentialMovingAverage::EventBasedExponentialMovingAverage( + int half_time) { + SetHalfTime(half_time); +} + +void EventBasedExponentialMovingAverage::SetHalfTime(int half_time) { + tau_ = static_cast<double>(half_time) / log(2); + Reset(); +} + +void EventBasedExponentialMovingAverage::Reset() { + value_ = std::nan("uninit"); + sample_variance_ = std::numeric_limits<double>::infinity(); + estimator_variance_ = 1; + last_observation_timestamp_.reset(); +} + +void EventBasedExponentialMovingAverage::AddSample(int64_t now, int sample) { + if (!last_observation_timestamp_.has_value()) { + value_ = sample; + } else { + // TODO(webrtc:11140): This should really be > (e.g not >=) + // but some pesky tests run with simulated clock and let + // samples arrive simultaneously! + RTC_DCHECK(now >= *last_observation_timestamp_); + // Variance gets computed after second sample. + int64_t age = now - *last_observation_timestamp_; + double e = exp(-age / tau_); + double alpha = e / (1 + e); + double one_minus_alpha = 1 - alpha; + double sample_diff = sample - value_; + value_ = one_minus_alpha * value_ + alpha * sample; + estimator_variance_ = + (one_minus_alpha * one_minus_alpha) * estimator_variance_ + + (alpha * alpha); + if (sample_variance_ == std::numeric_limits<double>::infinity()) { + // First variance. + sample_variance_ = sample_diff * sample_diff; + } else { + double new_variance = one_minus_alpha * sample_variance_ + + alpha * sample_diff * sample_diff; + sample_variance_ = new_variance; + } + } + last_observation_timestamp_ = now; +} + +double EventBasedExponentialMovingAverage::GetConfidenceInterval() const { + return ninetyfive_percent_confidence * + sqrt(sample_variance_ * estimator_variance_); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/numerics/event_based_exponential_moving_average.h b/third_party/libwebrtc/rtc_base/numerics/event_based_exponential_moving_average.h new file mode 100644 index 0000000000..69f4e614cb --- /dev/null +++ b/third_party/libwebrtc/rtc_base/numerics/event_based_exponential_moving_average.h @@ -0,0 +1,71 @@ +/* + * 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 RTC_BASE_NUMERICS_EVENT_BASED_EXPONENTIAL_MOVING_AVERAGE_H_ +#define RTC_BASE_NUMERICS_EVENT_BASED_EXPONENTIAL_MOVING_AVERAGE_H_ + +#include <cmath> +#include <cstdint> +#include <limits> + +#include "absl/types/optional.h" + +namespace rtc { + +/** + * This class implements exponential moving average for time series + * estimating both value, variance and variance of estimator based on + * https://en.wikipedia.org/w/index.php?title=Moving_average§ion=9#Application_to_measuring_computer_performance + * with the additions from nisse@ added to + * https://en.wikipedia.org/wiki/Talk:Moving_average. + * + * A sample gets exponentially less weight so that it's 50% + * after `half_time` time units. + */ +class EventBasedExponentialMovingAverage { + public: + // `half_time` specifies how much weight will be given to old samples, + // see example above. + explicit EventBasedExponentialMovingAverage(int half_time); + + void AddSample(int64_t now, int value); + + double GetAverage() const { return value_; } + double GetVariance() const { return sample_variance_; } + + // Compute 95% confidence interval assuming that + // - variance of samples are normal distributed. + // - variance of estimator is normal distributed. + // + // The returned values specifies the distance from the average, + // i.e if X = GetAverage(), m = GetConfidenceInterval() + // then a there is 95% likelihood that the observed variables is inside + // [ X +/- m ]. + double GetConfidenceInterval() const; + + // Reset + void Reset(); + + // Update the half_time. + // NOTE: resets estimate too. + void SetHalfTime(int half_time); + + private: + double tau_; + double value_ = std::nan("uninit"); + double sample_variance_ = std::numeric_limits<double>::infinity(); + // This is the ratio between variance of the estimate and variance of samples. + double estimator_variance_ = 1; + absl::optional<int64_t> last_observation_timestamp_; +}; + +} // namespace rtc + +#endif // RTC_BASE_NUMERICS_EVENT_BASED_EXPONENTIAL_MOVING_AVERAGE_H_ diff --git a/third_party/libwebrtc/rtc_base/numerics/event_based_exponential_moving_average_unittest.cc b/third_party/libwebrtc/rtc_base/numerics/event_based_exponential_moving_average_unittest.cc new file mode 100644 index 0000000000..967be41213 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/numerics/event_based_exponential_moving_average_unittest.cc @@ -0,0 +1,227 @@ +/* + * 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 "rtc_base/numerics/event_based_exponential_moving_average.h" + +#include <cmath> + +#include "test/gtest.h" + +namespace { + +constexpr int kHalfTime = 500; +constexpr double kError = 0.1; + +} // namespace + +namespace rtc { + +TEST(EventBasedExponentialMovingAverageTest, NoValue) { + EventBasedExponentialMovingAverage average(kHalfTime); + + EXPECT_TRUE(std::isnan(average.GetAverage())); + EXPECT_EQ(std::numeric_limits<double>::infinity(), average.GetVariance()); + EXPECT_EQ(std::numeric_limits<double>::infinity(), + average.GetConfidenceInterval()); +} + +TEST(EventBasedExponentialMovingAverageTest, FirstValue) { + EventBasedExponentialMovingAverage average(kHalfTime); + + int64_t time = 23; + constexpr int value = 1000; + average.AddSample(time, value); + EXPECT_NEAR(value, average.GetAverage(), kError); + EXPECT_EQ(std::numeric_limits<double>::infinity(), average.GetVariance()); + EXPECT_EQ(std::numeric_limits<double>::infinity(), + average.GetConfidenceInterval()); +} + +TEST(EventBasedExponentialMovingAverageTest, Half) { + EventBasedExponentialMovingAverage average(kHalfTime); + + int64_t time = 23; + constexpr int value = 1000; + average.AddSample(time, value); + average.AddSample(time + kHalfTime, 0); + EXPECT_NEAR(666.7, average.GetAverage(), kError); + EXPECT_NEAR(1000000, average.GetVariance(), kError); + EXPECT_NEAR(1460.9, average.GetConfidenceInterval(), kError); +} + +TEST(EventBasedExponentialMovingAverageTest, Same) { + EventBasedExponentialMovingAverage average(kHalfTime); + + int64_t time = 23; + constexpr int value = 1000; + average.AddSample(time, value); + average.AddSample(time + kHalfTime, value); + EXPECT_NEAR(value, average.GetAverage(), kError); + EXPECT_NEAR(0, average.GetVariance(), kError); + EXPECT_NEAR(0, average.GetConfidenceInterval(), kError); +} + +TEST(EventBasedExponentialMovingAverageTest, Almost100) { + EventBasedExponentialMovingAverage average(kHalfTime); + + int64_t time = 23; + constexpr int value = 100; + average.AddSample(time + 0 * kHalfTime, value - 10); + average.AddSample(time + 1 * kHalfTime, value + 10); + average.AddSample(time + 2 * kHalfTime, value - 15); + average.AddSample(time + 3 * kHalfTime, value + 15); + EXPECT_NEAR(100.2, average.GetAverage(), kError); + EXPECT_NEAR(372.6, average.GetVariance(), kError); + EXPECT_NEAR(19.7, average.GetConfidenceInterval(), kError); // 100 +/- 20 + + average.AddSample(time + 4 * kHalfTime, value); + average.AddSample(time + 5 * kHalfTime, value); + average.AddSample(time + 6 * kHalfTime, value); + average.AddSample(time + 7 * kHalfTime, value); + EXPECT_NEAR(100.0, average.GetAverage(), kError); + EXPECT_NEAR(73.6, average.GetVariance(), kError); + EXPECT_NEAR(7.6, average.GetConfidenceInterval(), kError); // 100 +/- 7 +} + +// Test that getting a value at X and another at X+1 +// is almost the same as getting another at X and a value at X+1. +TEST(EventBasedExponentialMovingAverageTest, AlmostSameTime) { + int64_t time = 23; + constexpr int value = 100; + + { + EventBasedExponentialMovingAverage average(kHalfTime); + average.AddSample(time + 0, value); + average.AddSample(time + 1, 0); + EXPECT_NEAR(50, average.GetAverage(), kError); + EXPECT_NEAR(10000, average.GetVariance(), kError); + EXPECT_NEAR(138.6, average.GetConfidenceInterval(), + kError); // 50 +/- 138.6 + } + + { + EventBasedExponentialMovingAverage average(kHalfTime); + average.AddSample(time + 0, 0); + average.AddSample(time + 1, 100); + EXPECT_NEAR(50, average.GetAverage(), kError); + EXPECT_NEAR(10000, average.GetVariance(), kError); + EXPECT_NEAR(138.6, average.GetConfidenceInterval(), + kError); // 50 +/- 138.6 + } +} + +// This test shows behavior of estimator with a half_time of 100. +// It is unclear if these set of observations are representative +// of any real world scenarios. +TEST(EventBasedExponentialMovingAverageTest, NonUniformSamplesHalftime100) { + int64_t time = 23; + constexpr int value = 100; + + { + // The observations at 100 and 101, are significantly close in + // time that the estimator returns approx. the average. + EventBasedExponentialMovingAverage average(100); + average.AddSample(time + 0, value); + average.AddSample(time + 100, value); + average.AddSample(time + 101, 0); + EXPECT_NEAR(50.2, average.GetAverage(), kError); + EXPECT_NEAR(86.2, average.GetConfidenceInterval(), kError); // 50 +/- 86 + } + + { + EventBasedExponentialMovingAverage average(100); + average.AddSample(time + 0, value); + average.AddSample(time + 1, value); + average.AddSample(time + 100, 0); + EXPECT_NEAR(66.5, average.GetAverage(), kError); + EXPECT_NEAR(65.4, average.GetConfidenceInterval(), kError); // 66 +/- 65 + } + + { + EventBasedExponentialMovingAverage average(100); + for (int i = 0; i < 10; i++) { + average.AddSample(time + i, value); + } + average.AddSample(time + 100, 0); + EXPECT_NEAR(65.3, average.GetAverage(), kError); + EXPECT_NEAR(59.1, average.GetConfidenceInterval(), kError); // 55 +/- 59 + } + + { + EventBasedExponentialMovingAverage average(100); + average.AddSample(time + 0, 100); + for (int i = 90; i <= 100; i++) { + average.AddSample(time + i, 0); + } + EXPECT_NEAR(0.05, average.GetAverage(), kError); + EXPECT_NEAR(4.9, average.GetConfidenceInterval(), kError); // 0 +/- 5 + } +} + +TEST(EventBasedExponentialMovingAverageTest, Reset) { + constexpr int64_t time = 23; + constexpr int value = 100; + + EventBasedExponentialMovingAverage average(100); + EXPECT_TRUE(std::isnan(average.GetAverage())); + EXPECT_EQ(std::numeric_limits<double>::infinity(), average.GetVariance()); + EXPECT_EQ(std::numeric_limits<double>::infinity(), + average.GetConfidenceInterval()); + + average.AddSample(time + 0, value); + average.AddSample(time + 100, value); + average.AddSample(time + 101, 0); + EXPECT_FALSE(std::isnan(average.GetAverage())); + + average.Reset(); + EXPECT_TRUE(std::isnan(average.GetAverage())); + EXPECT_EQ(std::numeric_limits<double>::infinity(), average.GetVariance()); + EXPECT_EQ(std::numeric_limits<double>::infinity(), + average.GetConfidenceInterval()); +} + +// Test that SetHalfTime modifies behavior and resets average. +TEST(EventBasedExponentialMovingAverageTest, SetHalfTime) { + constexpr int64_t time = 23; + constexpr int value = 100; + + EventBasedExponentialMovingAverage average(100); + + average.AddSample(time + 0, value); + average.AddSample(time + 100, 0); + EXPECT_NEAR(66.7, average.GetAverage(), kError); + + average.SetHalfTime(1000); + EXPECT_TRUE(std::isnan(average.GetAverage())); + EXPECT_EQ(std::numeric_limits<double>::infinity(), average.GetVariance()); + EXPECT_EQ(std::numeric_limits<double>::infinity(), + average.GetConfidenceInterval()); + + average.AddSample(time + 0, value); + average.AddSample(time + 100, 0); + EXPECT_NEAR(51.7, average.GetAverage(), kError); +} + +TEST(EventBasedExponentialMovingAverageTest, SimultaneousSamples) { + constexpr int64_t time = 23; + constexpr int value = 100; + + EventBasedExponentialMovingAverage average(100); + + average.AddSample(time, value); + // This should really NOT be supported, + // i.e 2 samples with same timestamp. + // But there are tests running with simulated clock + // that produce this. + // TODO(webrtc:11140) : Fix those tests and remove this! + average.AddSample(time, value); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/numerics/event_rate_counter.cc b/third_party/libwebrtc/rtc_base/numerics/event_rate_counter.cc new file mode 100644 index 0000000000..d7b7293918 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/numerics/event_rate_counter.cc @@ -0,0 +1,49 @@ +/* + * 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. + */ +#include "rtc_base/numerics/event_rate_counter.h" + +#include <algorithm> + +namespace webrtc { + +void EventRateCounter::AddEvent(Timestamp event_time) { + if (first_time_.IsFinite()) + interval_.AddSample(event_time - last_time_); + first_time_ = std::min(first_time_, event_time); + last_time_ = std::max(last_time_, event_time); + event_count_++; +} + +void EventRateCounter::AddEvents(EventRateCounter other) { + first_time_ = std::min(first_time_, other.first_time_); + last_time_ = std::max(last_time_, other.last_time_); + event_count_ += other.event_count_; + interval_.AddSamples(other.interval_); +} + +bool EventRateCounter::IsEmpty() const { + return first_time_ == last_time_; +} + +double EventRateCounter::Rate() const { + if (event_count_ == 0) + return 0; + if (event_count_ == 1) + return NAN; + return (event_count_ - 1) / (last_time_ - first_time_).seconds<double>(); +} + +TimeDelta EventRateCounter::TotalDuration() const { + if (first_time_.IsInfinite()) { + return TimeDelta::Zero(); + } + return last_time_ - first_time_; +} +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/numerics/event_rate_counter.h b/third_party/libwebrtc/rtc_base/numerics/event_rate_counter.h new file mode 100644 index 0000000000..60ec3ba416 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/numerics/event_rate_counter.h @@ -0,0 +1,44 @@ +/* + * 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 RTC_BASE_NUMERICS_EVENT_RATE_COUNTER_H_ +#define RTC_BASE_NUMERICS_EVENT_RATE_COUNTER_H_ + +#include "rtc_base/numerics/sample_stats.h" + +namespace webrtc { + +// Calculates statistics based on events. For example for computing frame rates. +// Note that it doesn't provide any running statistics or reset funcitonality, +// so it's mostly useful for end of call statistics. +class EventRateCounter { + public: + // Adds an event based on it's `event_time` for correct updates of the + // interval statistics, each event must be added past the previous events. + void AddEvent(Timestamp event_time); + // Adds the events from `other`. Note that the interval stats won't be + // recalculated, only merged, so this is not equivalent to if the events would + // have been added to the same counter from the start. + void AddEvents(EventRateCounter other); + bool IsEmpty() const; + // Average number of events per second. Defaults to 0 for no events and NAN + // for one event. + double Rate() const; + SampleStats<TimeDelta>& interval() { return interval_; } + TimeDelta TotalDuration() const; + int Count() const { return event_count_; } + + private: + Timestamp first_time_ = Timestamp::PlusInfinity(); + Timestamp last_time_ = Timestamp::MinusInfinity(); + int64_t event_count_ = 0; + SampleStats<TimeDelta> interval_; +}; +} // namespace webrtc +#endif // RTC_BASE_NUMERICS_EVENT_RATE_COUNTER_H_ diff --git a/third_party/libwebrtc/rtc_base/numerics/exp_filter.cc b/third_party/libwebrtc/rtc_base/numerics/exp_filter.cc new file mode 100644 index 0000000000..a58250abc4 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/numerics/exp_filter.cc @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2011 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 "rtc_base/numerics/exp_filter.h" + +#include <cmath> + +namespace rtc { + +const float ExpFilter::kValueUndefined = -1.0f; + +void ExpFilter::Reset(float alpha) { + alpha_ = alpha; + filtered_ = kValueUndefined; +} + +float ExpFilter::Apply(float exp, float sample) { + if (filtered_ == kValueUndefined) { + // Initialize filtered value. + filtered_ = sample; + } else if (exp == 1.0) { + filtered_ = alpha_ * filtered_ + (1 - alpha_) * sample; + } else { + float alpha = std::pow(alpha_, exp); + filtered_ = alpha * filtered_ + (1 - alpha) * sample; + } + if (max_ != kValueUndefined && filtered_ > max_) { + filtered_ = max_; + } + return filtered_; +} + +void ExpFilter::UpdateBase(float alpha) { + alpha_ = alpha; +} +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/numerics/exp_filter.h b/third_party/libwebrtc/rtc_base/numerics/exp_filter.h new file mode 100644 index 0000000000..6bded80d02 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/numerics/exp_filter.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2011 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 RTC_BASE_NUMERICS_EXP_FILTER_H_ +#define RTC_BASE_NUMERICS_EXP_FILTER_H_ + +namespace rtc { + +// This class can be used, for example, for smoothing the result of bandwidth +// estimation and packet loss estimation. + +class ExpFilter { + public: + static const float kValueUndefined; + + explicit ExpFilter(float alpha, float max = kValueUndefined) : max_(max) { + Reset(alpha); + } + + // Resets the filter to its initial state, and resets filter factor base to + // the given value `alpha`. + void Reset(float alpha); + + // Applies the filter with a given exponent on the provided sample: + // y(k) = min(alpha_^ exp * y(k-1) + (1 - alpha_^ exp) * sample, max_). + float Apply(float exp, float sample); + + // Returns current filtered value. + float filtered() const { return filtered_; } + + // Changes the filter factor base to the given value `alpha`. + void UpdateBase(float alpha); + + private: + float alpha_; // Filter factor base. + float filtered_; // Current filter output. + const float max_; +}; +} // namespace rtc + +#endif // RTC_BASE_NUMERICS_EXP_FILTER_H_ diff --git a/third_party/libwebrtc/rtc_base/numerics/exp_filter_unittest.cc b/third_party/libwebrtc/rtc_base/numerics/exp_filter_unittest.cc new file mode 100644 index 0000000000..f5b436f1b9 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/numerics/exp_filter_unittest.cc @@ -0,0 +1,72 @@ +/* + * Copyright 2014 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 "rtc_base/numerics/exp_filter.h" + +#include <cmath> + +#include "test/gtest.h" + +namespace rtc { + +TEST(ExpFilterTest, FirstTimeOutputEqualInput) { + // No max value defined. + ExpFilter filter = ExpFilter(0.9f); + filter.Apply(100.0f, 10.0f); + + // First time, first argument no effect. + double value = 10.0f; + EXPECT_FLOAT_EQ(value, filter.filtered()); +} + +TEST(ExpFilterTest, SecondTime) { + float value; + + ExpFilter filter = ExpFilter(0.9f); + filter.Apply(100.0f, 10.0f); + + // First time, first argument no effect. + value = 10.0f; + + filter.Apply(10.0f, 20.0f); + float alpha = std::pow(0.9f, 10.0f); + value = alpha * value + (1.0f - alpha) * 20.0f; + EXPECT_FLOAT_EQ(value, filter.filtered()); +} + +TEST(ExpFilterTest, Reset) { + ExpFilter filter = ExpFilter(0.9f); + filter.Apply(100.0f, 10.0f); + + filter.Reset(0.8f); + filter.Apply(100.0f, 1.0f); + + // Become first time after a reset. + double value = 1.0f; + EXPECT_FLOAT_EQ(value, filter.filtered()); +} + +TEST(ExpfilterTest, OutputLimitedByMax) { + double value; + + // Max value defined. + ExpFilter filter = ExpFilter(0.9f, 1.0f); + filter.Apply(100.0f, 10.0f); + + // Limited to max value. + value = 1.0f; + EXPECT_EQ(value, filter.filtered()); + + filter.Apply(1.0f, 0.0f); + value = 0.9f * value; + EXPECT_FLOAT_EQ(value, filter.filtered()); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/numerics/histogram_percentile_counter.cc b/third_party/libwebrtc/rtc_base/numerics/histogram_percentile_counter.cc new file mode 100644 index 0000000000..29d2341c85 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/numerics/histogram_percentile_counter.cc @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2017 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 "rtc_base/numerics/histogram_percentile_counter.h" + +#include <algorithm> +#include <cmath> + +#include "rtc_base/checks.h" + +namespace rtc { +HistogramPercentileCounter::HistogramPercentileCounter( + uint32_t long_tail_boundary) + : histogram_low_(size_t{long_tail_boundary}), + long_tail_boundary_(long_tail_boundary), + total_elements_(0), + total_elements_low_(0) {} + +HistogramPercentileCounter::~HistogramPercentileCounter() = default; + +void HistogramPercentileCounter::Add(const HistogramPercentileCounter& other) { + for (uint32_t value = 0; value < other.long_tail_boundary_; ++value) { + Add(value, other.histogram_low_[value]); + } + for (const auto& it : histogram_high_) { + Add(it.first, it.second); + } +} + +void HistogramPercentileCounter::Add(uint32_t value, size_t count) { + if (value < long_tail_boundary_) { + histogram_low_[value] += count; + total_elements_low_ += count; + } else { + histogram_high_[value] += count; + } + total_elements_ += count; +} + +void HistogramPercentileCounter::Add(uint32_t value) { + Add(value, 1); +} + +absl::optional<uint32_t> HistogramPercentileCounter::GetPercentile( + float fraction) { + RTC_CHECK_LE(fraction, 1.0); + RTC_CHECK_GE(fraction, 0.0); + if (total_elements_ == 0) + return absl::nullopt; + size_t elements_to_skip = static_cast<size_t>( + std::max(0.0f, std::ceil(total_elements_ * fraction) - 1)); + if (elements_to_skip >= total_elements_) + elements_to_skip = total_elements_ - 1; + if (elements_to_skip < total_elements_low_) { + for (uint32_t value = 0; value < long_tail_boundary_; ++value) { + if (elements_to_skip < histogram_low_[value]) + return value; + elements_to_skip -= histogram_low_[value]; + } + } else { + elements_to_skip -= total_elements_low_; + for (const auto& it : histogram_high_) { + if (elements_to_skip < it.second) + return it.first; + elements_to_skip -= it.second; + } + } + RTC_DCHECK_NOTREACHED(); + return absl::nullopt; +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/numerics/histogram_percentile_counter.h b/third_party/libwebrtc/rtc_base/numerics/histogram_percentile_counter.h new file mode 100644 index 0000000000..4787f2ef98 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/numerics/histogram_percentile_counter.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2017 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 RTC_BASE_NUMERICS_HISTOGRAM_PERCENTILE_COUNTER_H_ +#define RTC_BASE_NUMERICS_HISTOGRAM_PERCENTILE_COUNTER_H_ + +#include <stddef.h> +#include <stdint.h> + +#include <map> +#include <vector> + +#include "absl/types/optional.h" + +namespace rtc { +// Calculates percentiles on the stream of data. Use `Add` methods to add new +// values. Use `GetPercentile` to get percentile of the currently added values. +class HistogramPercentileCounter { + public: + // Values below `long_tail_boundary` are stored as the histogram in an array. + // Values above - in a map. + explicit HistogramPercentileCounter(uint32_t long_tail_boundary); + ~HistogramPercentileCounter(); + void Add(uint32_t value); + void Add(uint32_t value, size_t count); + void Add(const HistogramPercentileCounter& other); + // Argument should be from 0 to 1. + absl::optional<uint32_t> GetPercentile(float fraction); + + private: + std::vector<size_t> histogram_low_; + std::map<uint32_t, size_t> histogram_high_; + const uint32_t long_tail_boundary_; + size_t total_elements_; + size_t total_elements_low_; +}; +} // namespace rtc +#endif // RTC_BASE_NUMERICS_HISTOGRAM_PERCENTILE_COUNTER_H_ diff --git a/third_party/libwebrtc/rtc_base/numerics/histogram_percentile_counter_unittest.cc b/third_party/libwebrtc/rtc_base/numerics/histogram_percentile_counter_unittest.cc new file mode 100644 index 0000000000..fc36b59208 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/numerics/histogram_percentile_counter_unittest.cc @@ -0,0 +1,44 @@ +/* + * Copyright 2017 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 "rtc_base/numerics/histogram_percentile_counter.h" + +#include <cstdint> +#include <utility> +#include <vector> + +#include "test/gtest.h" + +TEST(HistogramPercentileCounterTest, ReturnsCorrectPercentiles) { + rtc::HistogramPercentileCounter counter(10); + const std::vector<int> kTestValues = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}; + + EXPECT_FALSE(counter.GetPercentile(0.5f)); + // Pairs of {fraction, percentile value} computed by hand + // for `kTestValues`. + const std::vector<std::pair<float, uint32_t>> kTestPercentiles = { + {0.0f, 1}, {0.01f, 1}, {0.5f, 10}, {0.9f, 18}, + {0.95f, 19}, {0.99f, 20}, {1.0f, 20}}; + for (int value : kTestValues) { + counter.Add(value); + } + for (const auto& test_percentile : kTestPercentiles) { + EXPECT_EQ(test_percentile.second, + counter.GetPercentile(test_percentile.first).value_or(0)); + } +} + +TEST(HistogramPercentileCounterTest, HandlesEmptySequence) { + rtc::HistogramPercentileCounter counter(10); + EXPECT_FALSE(counter.GetPercentile(0.5f)); + counter.Add(1u); + EXPECT_TRUE(counter.GetPercentile(0.5f)); +} diff --git a/third_party/libwebrtc/rtc_base/numerics/math_utils.h b/third_party/libwebrtc/rtc_base/numerics/math_utils.h new file mode 100644 index 0000000000..5482cec6e5 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/numerics/math_utils.h @@ -0,0 +1,75 @@ +/* + * Copyright 2005 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_NUMERICS_MATH_UTILS_H_ +#define API_NUMERICS_MATH_UTILS_H_ + +#include <limits> +#include <type_traits> + +#include "rtc_base/checks.h" + +namespace webrtc { +namespace webrtc_impl { +// Given two numbers `x` and `y` such that x >= y, computes the difference +// x - y without causing undefined behavior due to signed overflow. +template <typename T> +typename std::make_unsigned<T>::type unsigned_difference(T x, T y) { + static_assert( + std::is_signed<T>::value, + "Function unsigned_difference is only meaningful for signed types."); + RTC_DCHECK_GE(x, y); + typedef typename std::make_unsigned<T>::type unsigned_type; + // int -> unsigned conversion repeatedly adds UINT_MAX + 1 until the number + // can be represented as an unsigned. Since we know that the actual + // difference x - y can be represented as an unsigned, it is sufficient to + // compute the difference modulo UINT_MAX + 1, i.e using unsigned arithmetic. + return static_cast<unsigned_type>(x) - static_cast<unsigned_type>(y); +} + +// Provide neutral element with respect to min(). +// Typically used as an initial value for running minimum. +template <typename T, + typename std::enable_if<std::numeric_limits<T>::has_infinity>::type* = + nullptr> +constexpr T infinity_or_max() { + return std::numeric_limits<T>::infinity(); +} + +template <typename T, + typename std::enable_if< + !std::numeric_limits<T>::has_infinity>::type* = nullptr> +constexpr T infinity_or_max() { + // Fallback to max(). + return std::numeric_limits<T>::max(); +} + +// Provide neutral element with respect to max(). +// Typically used as an initial value for running maximum. +template <typename T, + typename std::enable_if<std::numeric_limits<T>::has_infinity>::type* = + nullptr> +constexpr T minus_infinity_or_min() { + static_assert(std::is_signed<T>::value, "Unsupported. Please open a bug."); + return -std::numeric_limits<T>::infinity(); +} + +template <typename T, + typename std::enable_if< + !std::numeric_limits<T>::has_infinity>::type* = nullptr> +constexpr T minus_infinity_or_min() { + // Fallback to min(). + return std::numeric_limits<T>::min(); +} + +} // namespace webrtc_impl +} // namespace webrtc + +#endif // API_NUMERICS_MATH_UTILS_H_ diff --git a/third_party/libwebrtc/rtc_base/numerics/mod_ops.h b/third_party/libwebrtc/rtc_base/numerics/mod_ops.h new file mode 100644 index 0000000000..65618b4876 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/numerics/mod_ops.h @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2016 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 RTC_BASE_NUMERICS_MOD_OPS_H_ +#define RTC_BASE_NUMERICS_MOD_OPS_H_ + +#include <algorithm> +#include <type_traits> + +#include "rtc_base/checks.h" + +namespace webrtc { + +template <unsigned long M> // NOLINT +inline unsigned long Add(unsigned long a, unsigned long b) { // NOLINT + RTC_DCHECK_LT(a, M); + unsigned long t = M - b % M; // NOLINT + unsigned long res = a - t; // NOLINT + if (t > a) + return res + M; + return res; +} + +template <unsigned long M> // NOLINT +inline unsigned long Subtract(unsigned long a, unsigned long b) { // NOLINT + RTC_DCHECK_LT(a, M); + unsigned long sub = b % M; // NOLINT + if (a < sub) + return M - (sub - a); + return a - sub; +} + +// Calculates the forward difference between two wrapping numbers. +// +// Example: +// uint8_t x = 253; +// uint8_t y = 2; +// +// ForwardDiff(x, y) == 5 +// +// 252 253 254 255 0 1 2 3 +// ################################################# +// | | x | | | | | y | | +// ################################################# +// |----->----->----->----->-----> +// +// ForwardDiff(y, x) == 251 +// +// 252 253 254 255 0 1 2 3 +// ################################################# +// | | x | | | | | y | | +// ################################################# +// -->-----> |----->--- +// +// If M > 0 then wrapping occurs at M, if M == 0 then wrapping occurs at the +// largest value representable by T. +template <typename T, T M> +inline typename std::enable_if<(M > 0), T>::type ForwardDiff(T a, T b) { + static_assert(std::is_unsigned<T>::value, + "Type must be an unsigned integer."); + RTC_DCHECK_LT(a, M); + RTC_DCHECK_LT(b, M); + return a <= b ? b - a : M - (a - b); +} + +template <typename T, T M> +inline typename std::enable_if<(M == 0), T>::type ForwardDiff(T a, T b) { + static_assert(std::is_unsigned<T>::value, + "Type must be an unsigned integer."); + return b - a; +} + +template <typename T> +inline T ForwardDiff(T a, T b) { + return ForwardDiff<T, 0>(a, b); +} + +// Calculates the reverse difference between two wrapping numbers. +// +// Example: +// uint8_t x = 253; +// uint8_t y = 2; +// +// ReverseDiff(y, x) == 5 +// +// 252 253 254 255 0 1 2 3 +// ################################################# +// | | x | | | | | y | | +// ################################################# +// <-----<-----<-----<-----<-----| +// +// ReverseDiff(x, y) == 251 +// +// 252 253 254 255 0 1 2 3 +// ################################################# +// | | x | | | | | y | | +// ################################################# +// ---<-----| |<-----<-- +// +// If M > 0 then wrapping occurs at M, if M == 0 then wrapping occurs at the +// largest value representable by T. +template <typename T, T M> +inline typename std::enable_if<(M > 0), T>::type ReverseDiff(T a, T b) { + static_assert(std::is_unsigned<T>::value, + "Type must be an unsigned integer."); + RTC_DCHECK_LT(a, M); + RTC_DCHECK_LT(b, M); + return b <= a ? a - b : M - (b - a); +} + +template <typename T, T M> +inline typename std::enable_if<(M == 0), T>::type ReverseDiff(T a, T b) { + static_assert(std::is_unsigned<T>::value, + "Type must be an unsigned integer."); + return a - b; +} + +template <typename T> +inline T ReverseDiff(T a, T b) { + return ReverseDiff<T, 0>(a, b); +} + +// Calculates the minimum distance between to wrapping numbers. +// +// The minimum distance is defined as min(ForwardDiff(a, b), ReverseDiff(a, b)) +template <typename T, T M = 0> +inline T MinDiff(T a, T b) { + static_assert(std::is_unsigned<T>::value, + "Type must be an unsigned integer."); + return std::min(ForwardDiff<T, M>(a, b), ReverseDiff<T, M>(a, b)); +} + +} // namespace webrtc + +#endif // RTC_BASE_NUMERICS_MOD_OPS_H_ diff --git a/third_party/libwebrtc/rtc_base/numerics/mod_ops_unittest.cc b/third_party/libwebrtc/rtc_base/numerics/mod_ops_unittest.cc new file mode 100644 index 0000000000..3bd20345a7 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/numerics/mod_ops_unittest.cc @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2016 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 "rtc_base/numerics/mod_ops.h" + +#include <stdint.h> + +#include "test/gtest.h" + +namespace webrtc { +class TestModOps : public ::testing::Test { + protected: + // Can't use std::numeric_limits<unsigned long>::max() since + // MSVC doesn't support constexpr. + static const unsigned long ulmax = ~0ul; // NOLINT +}; + +TEST_F(TestModOps, Add) { + const int D = 100; + ASSERT_EQ(1u, Add<D>(0, 1)); + ASSERT_EQ(0u, Add<D>(0, D)); + for (int i = 0; i < D; ++i) + ASSERT_EQ(0u, Add<D>(i, D - i)); + + int t = 37; + uint8_t a = t; + for (int i = 0; i < 256; ++i) { + ASSERT_EQ(a, static_cast<uint8_t>(t)); + t = Add<256>(t, 1); + ++a; + } +} + +TEST_F(TestModOps, AddLarge) { + const unsigned long D = ulmax - 10ul; // NOLINT + unsigned long l = D - 1ul; // NOLINT + ASSERT_EQ(D - 2ul, Add<D>(l, l)); + ASSERT_EQ(9ul, Add<D>(l, ulmax)); + ASSERT_EQ(10ul, Add<D>(0ul, ulmax)); +} + +TEST_F(TestModOps, Subtract) { + const int D = 100; + ASSERT_EQ(99u, Subtract<D>(0, 1)); + ASSERT_EQ(0u, Subtract<D>(0, D)); + for (int i = 0; i < D; ++i) + ASSERT_EQ(0u, Subtract<D>(i, D + i)); + + int t = 37; + uint8_t a = t; + for (int i = 0; i < 256; ++i) { + ASSERT_EQ(a, static_cast<uint8_t>(t)); + t = Subtract<256>(t, 1); + --a; + } +} + +TEST_F(TestModOps, SubtractLarge) { + // NOLINTNEXTLINE + const unsigned long D = ulmax - 10ul; // NOLINT + unsigned long l = D - 1ul; // NOLINT + ASSERT_EQ(0ul, Subtract<D>(l, l)); + ASSERT_EQ(D - 11ul, Subtract<D>(l, ulmax)); + ASSERT_EQ(D - 10ul, Subtract<D>(0ul, ulmax)); +} + +TEST_F(TestModOps, ForwardDiff) { + ASSERT_EQ(0u, ForwardDiff(4711u, 4711u)); + + uint8_t x = 0; + uint8_t y = 255; + for (int i = 0; i < 256; ++i) { + ASSERT_EQ(255u, ForwardDiff(x, y)); + ++x; + ++y; + } + + int yi = 255; + for (int i = 0; i < 256; ++i) { + ASSERT_EQ(255u, ForwardDiff<uint8_t>(x, yi)); + ++x; + ++yi; + } +} + +TEST_F(TestModOps, ForwardDiffWithDivisor) { + ASSERT_EQ(122, (ForwardDiff<uint8_t, 123>(0, 122))); + ASSERT_EQ(0, (ForwardDiff<uint8_t, 123>(122, 122))); + ASSERT_EQ(122, (ForwardDiff<uint8_t, 123>(1, 0))); + ASSERT_EQ(0, (ForwardDiff<uint8_t, 123>(0, 0))); + ASSERT_EQ(1, (ForwardDiff<uint8_t, 123>(122, 0))); +} + +TEST_F(TestModOps, ReverseDiff) { + ASSERT_EQ(0u, ReverseDiff(4711u, 4711u)); + + uint8_t x = 0; + uint8_t y = 255; + for (int i = 0; i < 256; ++i) { + ASSERT_EQ(1u, ReverseDiff(x, y)); + ++x; + ++y; + } + + int yi = 255; + for (int i = 0; i < 256; ++i) { + ASSERT_EQ(1u, ReverseDiff<uint8_t>(x, yi)); + ++x; + ++yi; + } +} + +TEST_F(TestModOps, ReverseDiffWithDivisor) { + ASSERT_EQ(1, (ReverseDiff<uint8_t, 123>(0, 122))); + ASSERT_EQ(0, (ReverseDiff<uint8_t, 123>(122, 122))); + ASSERT_EQ(1, (ReverseDiff<uint8_t, 123>(1, 0))); + ASSERT_EQ(0, (ReverseDiff<uint8_t, 123>(0, 0))); + ASSERT_EQ(122, (ReverseDiff<uint8_t, 123>(122, 0))); +} + +TEST_F(TestModOps, MinDiff) { + for (uint16_t i = 0; i < 256; ++i) { + ASSERT_EQ(0, MinDiff<uint8_t>(i, i)); + ASSERT_EQ(1, MinDiff<uint8_t>(i - 1, i)); + ASSERT_EQ(1, MinDiff<uint8_t>(i + 1, i)); + } + + for (uint8_t i = 0; i < 128; ++i) + ASSERT_EQ(i, MinDiff<uint8_t>(0, i)); + + for (uint8_t i = 0; i < 128; ++i) + ASSERT_EQ(128 - i, MinDiff<uint8_t>(0, 128 + i)); +} + +TEST_F(TestModOps, MinDiffWitDivisor) { + ASSERT_EQ(5u, (MinDiff<uint8_t, 11>(0, 5))); + ASSERT_EQ(5u, (MinDiff<uint8_t, 11>(0, 6))); + ASSERT_EQ(5u, (MinDiff<uint8_t, 11>(5, 0))); + ASSERT_EQ(5u, (MinDiff<uint8_t, 11>(6, 0))); + + const uint16_t D = 4711; + + for (uint16_t i = 0; i < D / 2; ++i) + ASSERT_EQ(i, (MinDiff<uint16_t, D>(0, i))); + + ASSERT_EQ(D / 2, (MinDiff<uint16_t, D>(0, D / 2))); + + for (uint16_t i = 0; i < D / 2; ++i) + ASSERT_EQ(D / 2 - i, (MinDiff<uint16_t, D>(0, D / 2 - i))); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/numerics/moving_average.cc b/third_party/libwebrtc/rtc_base/numerics/moving_average.cc new file mode 100644 index 0000000000..c825839227 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/numerics/moving_average.cc @@ -0,0 +1,60 @@ +/* + * 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 "rtc_base/numerics/moving_average.h" + +#include <algorithm> + +#include "rtc_base/checks.h" + +namespace rtc { + +MovingAverage::MovingAverage(size_t window_size) : history_(window_size, 0) { + // Limit window size to avoid overflow. + RTC_DCHECK_LE(window_size, (int64_t{1} << 32) - 1); +} +MovingAverage::~MovingAverage() = default; + +void MovingAverage::AddSample(int sample) { + count_++; + size_t index = count_ % history_.size(); + if (count_ > history_.size()) + sum_ -= history_[index]; + sum_ += sample; + history_[index] = sample; +} + +absl::optional<int> MovingAverage::GetAverageRoundedDown() const { + if (count_ == 0) + return absl::nullopt; + return sum_ / Size(); +} + +absl::optional<int> MovingAverage::GetAverageRoundedToClosest() const { + if (count_ == 0) + return absl::nullopt; + return (sum_ + Size() / 2) / Size(); +} + +absl::optional<double> MovingAverage::GetUnroundedAverage() const { + if (count_ == 0) + return absl::nullopt; + return sum_ / static_cast<double>(Size()); +} + +void MovingAverage::Reset() { + count_ = 0; + sum_ = 0; +} + +size_t MovingAverage::Size() const { + return std::min(count_, history_.size()); +} +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/numerics/moving_average.h b/third_party/libwebrtc/rtc_base/numerics/moving_average.h new file mode 100644 index 0000000000..41ce60348e --- /dev/null +++ b/third_party/libwebrtc/rtc_base/numerics/moving_average.h @@ -0,0 +1,66 @@ +/* + * 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 RTC_BASE_NUMERICS_MOVING_AVERAGE_H_ +#define RTC_BASE_NUMERICS_MOVING_AVERAGE_H_ + +#include <stddef.h> +#include <stdint.h> + +#include <vector> + +#include "absl/types/optional.h" + +namespace rtc { + +// Calculates average over fixed size window. If there are less than window +// size elements, calculates average of all inserted so far elements. +// +class MovingAverage { + public: + // Maximum supported window size is 2^32 - 1. + explicit MovingAverage(size_t window_size); + ~MovingAverage(); + // MovingAverage is neither copyable nor movable. + MovingAverage(const MovingAverage&) = delete; + MovingAverage& operator=(const MovingAverage&) = delete; + + // Adds new sample. If the window is full, the oldest element is pushed out. + void AddSample(int sample); + + // Returns rounded down average of last `window_size` elements or all + // elements if there are not enough of them. Returns nullopt if there were + // no elements added. + absl::optional<int> GetAverageRoundedDown() const; + + // Same as above but rounded to the closest integer. + absl::optional<int> GetAverageRoundedToClosest() const; + + // Returns unrounded average over the window. + absl::optional<double> GetUnroundedAverage() const; + + // Resets to the initial state before any elements were added. + void Reset(); + + // Returns number of elements in the window. + size_t Size() const; + + private: + // Total number of samples added to the class since last reset. + size_t count_ = 0; + // Sum of the samples in the moving window. + int64_t sum_ = 0; + // Circular buffer for all the samples in the moving window. + // Size is always `window_size` + std::vector<int> history_; +}; + +} // namespace rtc +#endif // RTC_BASE_NUMERICS_MOVING_AVERAGE_H_ diff --git a/third_party/libwebrtc/rtc_base/numerics/moving_average_unittest.cc b/third_party/libwebrtc/rtc_base/numerics/moving_average_unittest.cc new file mode 100644 index 0000000000..9bc9a1aef8 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/numerics/moving_average_unittest.cc @@ -0,0 +1,87 @@ +/* + * 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 "rtc_base/numerics/moving_average.h" + +#include "test/gtest.h" + +namespace test { + +TEST(MovingAverageTest, EmptyAverage) { + rtc::MovingAverage moving_average(1); + EXPECT_EQ(0u, moving_average.Size()); + EXPECT_EQ(absl::nullopt, moving_average.GetAverageRoundedDown()); +} + +// Test single value. +TEST(MovingAverageTest, OneElement) { + rtc::MovingAverage moving_average(1); + moving_average.AddSample(3); + EXPECT_EQ(1u, moving_average.Size()); + EXPECT_EQ(3, *moving_average.GetAverageRoundedDown()); +} + +TEST(MovingAverageTest, GetAverage) { + rtc::MovingAverage moving_average(1024); + moving_average.AddSample(1); + moving_average.AddSample(1); + moving_average.AddSample(3); + moving_average.AddSample(3); + EXPECT_EQ(*moving_average.GetAverageRoundedDown(), 2); + EXPECT_EQ(*moving_average.GetAverageRoundedToClosest(), 2); +} + +TEST(MovingAverageTest, GetAverageRoundedDownRounds) { + rtc::MovingAverage moving_average(1024); + moving_average.AddSample(1); + moving_average.AddSample(2); + moving_average.AddSample(2); + moving_average.AddSample(2); + EXPECT_EQ(*moving_average.GetAverageRoundedDown(), 1); +} + +TEST(MovingAverageTest, GetAverageRoundedToClosestRounds) { + rtc::MovingAverage moving_average(1024); + moving_average.AddSample(1); + moving_average.AddSample(2); + moving_average.AddSample(2); + moving_average.AddSample(2); + EXPECT_EQ(*moving_average.GetAverageRoundedToClosest(), 2); +} + +TEST(MovingAverageTest, Reset) { + rtc::MovingAverage moving_average(5); + moving_average.AddSample(1); + EXPECT_EQ(1, *moving_average.GetAverageRoundedDown()); + EXPECT_EQ(1, *moving_average.GetAverageRoundedToClosest()); + + moving_average.Reset(); + + EXPECT_FALSE(moving_average.GetAverageRoundedDown()); + moving_average.AddSample(10); + EXPECT_EQ(10, *moving_average.GetAverageRoundedDown()); + EXPECT_EQ(10, *moving_average.GetAverageRoundedToClosest()); +} + +TEST(MovingAverageTest, ManySamples) { + rtc::MovingAverage moving_average(10); + for (int i = 1; i < 11; i++) { + moving_average.AddSample(i); + } + EXPECT_EQ(*moving_average.GetAverageRoundedDown(), 5); + EXPECT_EQ(*moving_average.GetAverageRoundedToClosest(), 6); + for (int i = 1; i < 2001; i++) { + moving_average.AddSample(i); + } + EXPECT_EQ(*moving_average.GetAverageRoundedDown(), 1995); + EXPECT_EQ(*moving_average.GetAverageRoundedToClosest(), 1996); +} + +} // namespace test diff --git a/third_party/libwebrtc/rtc_base/numerics/moving_max_counter.h b/third_party/libwebrtc/rtc_base/numerics/moving_max_counter.h new file mode 100644 index 0000000000..5eb45d392b --- /dev/null +++ b/third_party/libwebrtc/rtc_base/numerics/moving_max_counter.h @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2017 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 RTC_BASE_NUMERICS_MOVING_MAX_COUNTER_H_ +#define RTC_BASE_NUMERICS_MOVING_MAX_COUNTER_H_ + +#include <stdint.h> + +#include <deque> +#include <limits> +#include <utility> + +#include "absl/types/optional.h" +#include "rtc_base/checks.h" + +namespace rtc { + +// Implements moving max: can add samples to it and calculate maximum over some +// fixed moving window. +// +// Window size is configured at constructor. +// Samples can be added with `Add()` and max over current window is returned by +// `MovingMax`. `current_time_ms` in successive calls to Add and MovingMax +// should never decrease as if it's a wallclock time. +template <class T> +class MovingMaxCounter { + public: + explicit MovingMaxCounter(int64_t window_length_ms); + + MovingMaxCounter(const MovingMaxCounter&) = delete; + MovingMaxCounter& operator=(const MovingMaxCounter&) = delete; + + // Advances the current time, and adds a new sample. The new current time must + // be at least as large as the old current time. + void Add(const T& sample, int64_t current_time_ms); + // Advances the current time, and returns the maximum sample in the time + // window ending at the current time. The new current time must be at least as + // large as the old current time. + absl::optional<T> Max(int64_t current_time_ms); + void Reset(); + + private: + // Throws out obsolete samples. + void RollWindow(int64_t new_time_ms); + const int64_t window_length_ms_; + // This deque stores (timestamp, sample) pairs in chronological order; new + // pairs are only ever added at the end. However, because they can't affect + // the Max() calculation, pairs older than window_length_ms_ are discarded, + // and if an older pair has a sample that's smaller than that of a younger + // pair, the older pair is discarded. As a result, the sequence of timestamps + // is strictly increasing, and the sequence of samples is strictly decreasing. + std::deque<std::pair<int64_t, T>> samples_; +#if RTC_DCHECK_IS_ON + int64_t last_call_time_ms_ = std::numeric_limits<int64_t>::min(); +#endif +}; + +template <class T> +MovingMaxCounter<T>::MovingMaxCounter(int64_t window_length_ms) + : window_length_ms_(window_length_ms) {} + +template <class T> +void MovingMaxCounter<T>::Add(const T& sample, int64_t current_time_ms) { + RollWindow(current_time_ms); + // Remove samples that will never be maximum in any window: newly added sample + // will always be in all windows the previous samples are. Thus, smaller or + // equal samples could be removed. This will maintain the invariant - deque + // contains strictly decreasing sequence of values. + while (!samples_.empty() && samples_.back().second <= sample) { + samples_.pop_back(); + } + // Add the new sample but only if there's no existing sample at the same time. + // Due to checks above, the already existing element will be larger, so the + // new sample will never be the maximum in any window. + if (samples_.empty() || samples_.back().first < current_time_ms) { + samples_.emplace_back(std::make_pair(current_time_ms, sample)); + } +} + +template <class T> +absl::optional<T> MovingMaxCounter<T>::Max(int64_t current_time_ms) { + RollWindow(current_time_ms); + absl::optional<T> res; + if (!samples_.empty()) { + res.emplace(samples_.front().second); + } + return res; +} + +template <class T> +void MovingMaxCounter<T>::Reset() { + samples_.clear(); +} + +template <class T> +void MovingMaxCounter<T>::RollWindow(int64_t new_time_ms) { +#if RTC_DCHECK_IS_ON + RTC_DCHECK_GE(new_time_ms, last_call_time_ms_); + last_call_time_ms_ = new_time_ms; +#endif + const int64_t window_begin_ms = new_time_ms - window_length_ms_; + auto it = samples_.begin(); + while (it != samples_.end() && it->first < window_begin_ms) { + ++it; + } + samples_.erase(samples_.begin(), it); +} + +} // namespace rtc + +#endif // RTC_BASE_NUMERICS_MOVING_MAX_COUNTER_H_ diff --git a/third_party/libwebrtc/rtc_base/numerics/moving_max_counter_unittest.cc b/third_party/libwebrtc/rtc_base/numerics/moving_max_counter_unittest.cc new file mode 100644 index 0000000000..0e3195f467 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/numerics/moving_max_counter_unittest.cc @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2017 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 "rtc_base/numerics/moving_max_counter.h" + +#include "test/gtest.h" + +TEST(MovingMaxCounter, ReportsMaximumInTheWindow) { + rtc::MovingMaxCounter<int> counter(100); + counter.Add(1, 1); + EXPECT_EQ(counter.Max(1), 1); + counter.Add(2, 30); + EXPECT_EQ(counter.Max(30), 2); + counter.Add(100, 60); + EXPECT_EQ(counter.Max(60), 100); + counter.Add(4, 70); + EXPECT_EQ(counter.Max(70), 100); + counter.Add(5, 90); + EXPECT_EQ(counter.Max(90), 100); +} + +TEST(MovingMaxCounter, IgnoresOldElements) { + rtc::MovingMaxCounter<int> counter(100); + counter.Add(1, 1); + counter.Add(2, 30); + counter.Add(100, 60); + counter.Add(4, 70); + counter.Add(5, 90); + EXPECT_EQ(counter.Max(160), 100); + // 100 is now out of the window. Next maximum is 5. + EXPECT_EQ(counter.Max(161), 5); +} + +TEST(MovingMaxCounter, HandlesEmptyWindow) { + rtc::MovingMaxCounter<int> counter(100); + counter.Add(123, 1); + EXPECT_TRUE(counter.Max(101).has_value()); + EXPECT_FALSE(counter.Max(102).has_value()); +} + +TEST(MovingMaxCounter, HandlesSamplesWithEqualTimestamps) { + rtc::MovingMaxCounter<int> counter(100); + counter.Add(2, 30); + EXPECT_EQ(counter.Max(30), 2); + counter.Add(5, 30); + EXPECT_EQ(counter.Max(30), 5); + counter.Add(4, 30); + EXPECT_EQ(counter.Max(30), 5); + counter.Add(1, 90); + EXPECT_EQ(counter.Max(150), 1); +} diff --git a/third_party/libwebrtc/rtc_base/numerics/moving_percentile_filter.h b/third_party/libwebrtc/rtc_base/numerics/moving_percentile_filter.h new file mode 100644 index 0000000000..d68814a25b --- /dev/null +++ b/third_party/libwebrtc/rtc_base/numerics/moving_percentile_filter.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2017 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 RTC_BASE_NUMERICS_MOVING_PERCENTILE_FILTER_H_ +#define RTC_BASE_NUMERICS_MOVING_PERCENTILE_FILTER_H_ + +#include <stddef.h> + +#include <cstddef> +#include <list> + +#include "rtc_base/checks.h" +#include "rtc_base/numerics/percentile_filter.h" + +namespace webrtc { + +// Class to efficiently get moving percentile filter from a stream of samples. +template <typename T> +class MovingPercentileFilter { + public: + // Construct filter. `percentile` defines what percentile to track and + // `window_size` is how many latest samples are stored for finding the + // percentile. `percentile` must be between 0.0 and 1.0 (inclusive) and + // `window_size` must be greater than 0. + MovingPercentileFilter(float percentile, size_t window_size); + + MovingPercentileFilter(const MovingPercentileFilter&) = delete; + MovingPercentileFilter& operator=(const MovingPercentileFilter&) = delete; + + // Insert a new sample. + void Insert(const T& value); + + // Removes all samples; + void Reset(); + + // Get percentile over the latest window. + T GetFilteredValue() const; + + // The number of samples that are currently stored. + size_t GetNumberOfSamplesStored() const; + + private: + PercentileFilter<T> percentile_filter_; + std::list<T> samples_; + size_t samples_stored_; + const size_t window_size_; +}; + +// Convenience type for the common median case. +template <typename T> +class MovingMedianFilter : public MovingPercentileFilter<T> { + public: + explicit MovingMedianFilter(size_t window_size) + : MovingPercentileFilter<T>(0.5f, window_size) {} +}; + +template <typename T> +MovingPercentileFilter<T>::MovingPercentileFilter(float percentile, + size_t window_size) + : percentile_filter_(percentile), + samples_stored_(0), + window_size_(window_size) { + RTC_CHECK_GT(window_size, 0); +} + +template <typename T> +void MovingPercentileFilter<T>::Insert(const T& value) { + percentile_filter_.Insert(value); + samples_.emplace_back(value); + ++samples_stored_; + if (samples_stored_ > window_size_) { + percentile_filter_.Erase(samples_.front()); + samples_.pop_front(); + --samples_stored_; + } +} + +template <typename T> +T MovingPercentileFilter<T>::GetFilteredValue() const { + return percentile_filter_.GetPercentileValue(); +} + +template <typename T> +void MovingPercentileFilter<T>::Reset() { + percentile_filter_.Reset(); + samples_.clear(); + samples_stored_ = 0; +} + +template <typename T> +size_t MovingPercentileFilter<T>::GetNumberOfSamplesStored() const { + return samples_stored_; +} + +} // namespace webrtc +#endif // RTC_BASE_NUMERICS_MOVING_PERCENTILE_FILTER_H_ diff --git a/third_party/libwebrtc/rtc_base/numerics/moving_percentile_filter_unittest.cc b/third_party/libwebrtc/rtc_base/numerics/moving_percentile_filter_unittest.cc new file mode 100644 index 0000000000..30c0ebb23d --- /dev/null +++ b/third_party/libwebrtc/rtc_base/numerics/moving_percentile_filter_unittest.cc @@ -0,0 +1,86 @@ +/* + * Copyright 2017 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 "rtc_base/numerics/moving_percentile_filter.h" + +#include <stdint.h> + +#include <algorithm> + +#include "test/gtest.h" + +namespace webrtc { + +// 25th percentile can be exactly found with a window of length 4. +TEST(MovingPercentileFilter, Percentile25ReturnsMovingPercentile25WithWindow4) { + MovingPercentileFilter<int> perc25(0.25f, 4); + const int64_t kSamples[10] = {1, 2, 3, 4, 4, 4, 5, 6, 7, 8}; + const int64_t kExpectedFilteredValues[10] = {1, 1, 1, 1, 2, 3, 4, 4, 4, 5}; + for (size_t i = 0; i < 10; ++i) { + perc25.Insert(kSamples[i]); + EXPECT_EQ(kExpectedFilteredValues[i], perc25.GetFilteredValue()); + EXPECT_EQ(std::min<size_t>(i + 1, 4), perc25.GetNumberOfSamplesStored()); + } +} + +// 90th percentile becomes the 67th percentile with a window of length 4. +TEST(MovingPercentileFilter, Percentile90ReturnsMovingPercentile67WithWindow4) { + MovingPercentileFilter<int> perc67(0.67f, 4); + MovingPercentileFilter<int> perc90(0.9f, 4); + const int64_t kSamples[8] = {1, 10, 1, 9, 1, 10, 1, 8}; + const int64_t kExpectedFilteredValues[9] = {1, 1, 1, 9, 9, 9, 9, 8}; + for (size_t i = 0; i < 8; ++i) { + perc67.Insert(kSamples[i]); + perc90.Insert(kSamples[i]); + EXPECT_EQ(kExpectedFilteredValues[i], perc67.GetFilteredValue()); + EXPECT_EQ(kExpectedFilteredValues[i], perc90.GetFilteredValue()); + } +} + +TEST(MovingMedianFilterTest, ProcessesNoSamples) { + MovingMedianFilter<int> filter(2); + EXPECT_EQ(0, filter.GetFilteredValue()); + EXPECT_EQ(0u, filter.GetNumberOfSamplesStored()); +} + +TEST(MovingMedianFilterTest, ReturnsMovingMedianWindow5) { + MovingMedianFilter<int> filter(5); + const int64_t kSamples[5] = {1, 5, 2, 3, 4}; + const int64_t kExpectedFilteredValues[5] = {1, 1, 2, 2, 3}; + for (size_t i = 0; i < 5; ++i) { + filter.Insert(kSamples[i]); + EXPECT_EQ(kExpectedFilteredValues[i], filter.GetFilteredValue()); + EXPECT_EQ(i + 1, filter.GetNumberOfSamplesStored()); + } +} + +TEST(MovingMedianFilterTest, ReturnsMovingMedianWindow3) { + MovingMedianFilter<int> filter(3); + const int64_t kSamples[5] = {1, 5, 2, 3, 4}; + const int64_t kExpectedFilteredValues[5] = {1, 1, 2, 3, 3}; + for (int i = 0; i < 5; ++i) { + filter.Insert(kSamples[i]); + EXPECT_EQ(kExpectedFilteredValues[i], filter.GetFilteredValue()); + EXPECT_EQ(std::min<size_t>(i + 1, 3), filter.GetNumberOfSamplesStored()); + } +} + +TEST(MovingMedianFilterTest, ReturnsMovingMedianWindow1) { + MovingMedianFilter<int> filter(1); + const int64_t kSamples[5] = {1, 5, 2, 3, 4}; + const int64_t kExpectedFilteredValues[5] = {1, 5, 2, 3, 4}; + for (int i = 0; i < 5; ++i) { + filter.Insert(kSamples[i]); + EXPECT_EQ(kExpectedFilteredValues[i], filter.GetFilteredValue()); + EXPECT_EQ(1u, filter.GetNumberOfSamplesStored()); + } +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/numerics/percentile_filter.h b/third_party/libwebrtc/rtc_base/numerics/percentile_filter.h new file mode 100644 index 0000000000..2a18c1aa73 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/numerics/percentile_filter.h @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2016 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 RTC_BASE_NUMERICS_PERCENTILE_FILTER_H_ +#define RTC_BASE_NUMERICS_PERCENTILE_FILTER_H_ + +#include <stdint.h> + +#include <iterator> +#include <set> + +#include "rtc_base/checks.h" + +namespace webrtc { + +// Class to efficiently get the percentile value from a group of observations. +// The percentile is the value below which a given percentage of the +// observations fall. +template <typename T> +class PercentileFilter { + public: + // Construct filter. `percentile` should be between 0 and 1. + explicit PercentileFilter(float percentile); + + // Insert one observation. The complexity of this operation is logarithmic in + // the size of the container. + void Insert(const T& value); + + // Remove one observation or return false if `value` doesn't exist in the + // container. The complexity of this operation is logarithmic in the size of + // the container. + bool Erase(const T& value); + + // Get the percentile value. The complexity of this operation is constant. + T GetPercentileValue() const; + + // Removes all the stored observations. + void Reset(); + + private: + // Update iterator and index to point at target percentile value. + void UpdatePercentileIterator(); + + const float percentile_; + std::multiset<T> set_; + // Maintain iterator and index of current target percentile value. + typename std::multiset<T>::iterator percentile_it_; + int64_t percentile_index_; +}; + +template <typename T> +PercentileFilter<T>::PercentileFilter(float percentile) + : percentile_(percentile), + percentile_it_(set_.begin()), + percentile_index_(0) { + RTC_CHECK_GE(percentile, 0.0f); + RTC_CHECK_LE(percentile, 1.0f); +} + +template <typename T> +void PercentileFilter<T>::Insert(const T& value) { + // Insert element at the upper bound. + set_.insert(value); + if (set_.size() == 1u) { + // First element inserted - initialize percentile iterator and index. + percentile_it_ = set_.begin(); + percentile_index_ = 0; + } else if (value < *percentile_it_) { + // If new element is before us, increment `percentile_index_`. + ++percentile_index_; + } + UpdatePercentileIterator(); +} + +template <typename T> +bool PercentileFilter<T>::Erase(const T& value) { + typename std::multiset<T>::const_iterator it = set_.lower_bound(value); + // Ignore erase operation if the element is not present in the current set. + if (it == set_.end() || *it != value) + return false; + if (it == percentile_it_) { + // If same iterator, update to the following element. Index is not + // affected. + percentile_it_ = set_.erase(it); + } else { + set_.erase(it); + // If erased element was before us, decrement `percentile_index_`. + if (value <= *percentile_it_) + --percentile_index_; + } + UpdatePercentileIterator(); + return true; +} + +template <typename T> +void PercentileFilter<T>::UpdatePercentileIterator() { + if (set_.empty()) + return; + const int64_t index = static_cast<int64_t>(percentile_ * (set_.size() - 1)); + std::advance(percentile_it_, index - percentile_index_); + percentile_index_ = index; +} + +template <typename T> +T PercentileFilter<T>::GetPercentileValue() const { + return set_.empty() ? 0 : *percentile_it_; +} + +template <typename T> +void PercentileFilter<T>::Reset() { + set_.clear(); + percentile_it_ = set_.begin(); + percentile_index_ = 0; +} +} // namespace webrtc + +#endif // RTC_BASE_NUMERICS_PERCENTILE_FILTER_H_ diff --git a/third_party/libwebrtc/rtc_base/numerics/percentile_filter_unittest.cc b/third_party/libwebrtc/rtc_base/numerics/percentile_filter_unittest.cc new file mode 100644 index 0000000000..d6baa32001 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/numerics/percentile_filter_unittest.cc @@ -0,0 +1,142 @@ +/* + * Copyright 2016 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 "rtc_base/numerics/percentile_filter.h" + +#include <stdlib.h> + +#include <array> +#include <climits> +#include <cstdint> +#include <random> + +#include "absl/algorithm/container.h" +#include "test/gtest.h" + +namespace webrtc { + +class PercentileFilterTest : public ::testing::TestWithParam<float> { + public: + PercentileFilterTest() : filter_(GetParam()) { + // Make sure the tests are deterministic by seeding with a constant. + srand(42); + } + + PercentileFilterTest(const PercentileFilterTest&) = delete; + PercentileFilterTest& operator=(const PercentileFilterTest&) = delete; + + protected: + PercentileFilter<int64_t> filter_; +}; + +INSTANTIATE_TEST_SUITE_P(PercentileFilterTests, + PercentileFilterTest, + ::testing::Values(0.0f, 0.1f, 0.5f, 0.9f, 1.0f)); + +TEST(PercentileFilterTest, MinFilter) { + PercentileFilter<int64_t> filter(0.0f); + filter.Insert(4); + EXPECT_EQ(4, filter.GetPercentileValue()); + filter.Insert(3); + EXPECT_EQ(3, filter.GetPercentileValue()); +} + +TEST(PercentileFilterTest, MaxFilter) { + PercentileFilter<int64_t> filter(1.0f); + filter.Insert(3); + EXPECT_EQ(3, filter.GetPercentileValue()); + filter.Insert(4); + EXPECT_EQ(4, filter.GetPercentileValue()); +} + +TEST(PercentileFilterTest, MedianFilterDouble) { + PercentileFilter<double> filter(0.5f); + filter.Insert(2.71828); + filter.Insert(3.14159); + filter.Insert(1.41421); + EXPECT_EQ(2.71828, filter.GetPercentileValue()); +} + +TEST(PercentileFilterTest, MedianFilterInt) { + PercentileFilter<int> filter(0.5f); + filter.Insert(INT_MIN); + filter.Insert(1); + filter.Insert(2); + EXPECT_EQ(1, filter.GetPercentileValue()); + filter.Insert(INT_MAX); + filter.Erase(INT_MIN); + EXPECT_EQ(2, filter.GetPercentileValue()); +} + +TEST(PercentileFilterTest, MedianFilterUnsigned) { + PercentileFilter<unsigned> filter(0.5f); + filter.Insert(UINT_MAX); + filter.Insert(2u); + filter.Insert(1u); + EXPECT_EQ(2u, filter.GetPercentileValue()); + filter.Insert(0u); + filter.Erase(UINT_MAX); + EXPECT_EQ(1u, filter.GetPercentileValue()); +} + +TEST_P(PercentileFilterTest, EmptyFilter) { + EXPECT_EQ(0, filter_.GetPercentileValue()); + filter_.Insert(3); + bool success = filter_.Erase(3); + EXPECT_TRUE(success); + EXPECT_EQ(0, filter_.GetPercentileValue()); +} + +TEST_P(PercentileFilterTest, EraseNonExistingElement) { + bool success = filter_.Erase(3); + EXPECT_FALSE(success); + EXPECT_EQ(0, filter_.GetPercentileValue()); + filter_.Insert(4); + success = filter_.Erase(3); + EXPECT_FALSE(success); + EXPECT_EQ(4, filter_.GetPercentileValue()); +} + +TEST_P(PercentileFilterTest, DuplicateElements) { + filter_.Insert(3); + filter_.Insert(3); + filter_.Erase(3); + EXPECT_EQ(3, filter_.GetPercentileValue()); +} + +TEST_P(PercentileFilterTest, InsertAndEraseTenValuesInRandomOrder) { + std::array<int64_t, 10> zero_to_nine = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + // The percentile value of the ten values above. + const int64_t expected_value = static_cast<int64_t>(GetParam() * 9); + + // Insert two sets of `zero_to_nine` in random order. + for (int i = 0; i < 2; ++i) { + absl::c_shuffle(zero_to_nine, std::mt19937(std::random_device()())); + for (int64_t value : zero_to_nine) + filter_.Insert(value); + // After inserting a full set of `zero_to_nine`, the percentile should + // stay constant. + EXPECT_EQ(expected_value, filter_.GetPercentileValue()); + } + + // Insert and erase sets of `zero_to_nine` in random order a few times. + for (int i = 0; i < 3; ++i) { + absl::c_shuffle(zero_to_nine, std::mt19937(std::random_device()())); + for (int64_t value : zero_to_nine) + filter_.Erase(value); + EXPECT_EQ(expected_value, filter_.GetPercentileValue()); + absl::c_shuffle(zero_to_nine, std::mt19937(std::random_device()())); + for (int64_t value : zero_to_nine) + filter_.Insert(value); + EXPECT_EQ(expected_value, filter_.GetPercentileValue()); + } +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/numerics/running_statistics.h b/third_party/libwebrtc/rtc_base/numerics/running_statistics.h new file mode 100644 index 0000000000..fe991b043f --- /dev/null +++ b/third_party/libwebrtc/rtc_base/numerics/running_statistics.h @@ -0,0 +1,171 @@ +/* + * 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_NUMERICS_RUNNING_STATISTICS_H_ +#define API_NUMERICS_RUNNING_STATISTICS_H_ + +#include <algorithm> +#include <cmath> +#include <limits> + +#include "absl/types/optional.h" +#include "rtc_base/checks.h" +#include "rtc_base/numerics/math_utils.h" + +namespace webrtc { +namespace webrtc_impl { + +// tl;dr: Robust and efficient online computation of statistics, +// using Welford's method for variance. [1] +// +// This should be your go-to class if you ever need to compute +// min, max, mean, variance and standard deviation. +// If you need to get percentiles, please use webrtc::SamplesStatsCounter. +// +// Please note RemoveSample() won't affect min and max. +// If you want a full-fledged moving window over N last samples, +// please use webrtc::RollingAccumulator. +// +// The measures return absl::nullopt if no samples were fed (Size() == 0), +// otherwise the returned optional is guaranteed to contain a value. +// +// [1] +// https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Welford's_online_algorithm + +// The type T is a scalar which must be convertible to double. +// Rationale: we often need greater precision for measures +// than for the samples themselves. +template <typename T> +class RunningStatistics { + public: + // Update stats //////////////////////////////////////////// + + // Add a value participating in the statistics in O(1) time. + void AddSample(T sample) { + max_ = std::max(max_, sample); + min_ = std::min(min_, sample); + sum_ += sample; + ++size_; + // Welford's incremental update. + const double delta = sample - mean_; + mean_ += delta / size_; + const double delta2 = sample - mean_; + cumul_ += delta * delta2; + } + + // Remove a previously added value in O(1) time. + // Nb: This doesn't affect min or max. + // Calling RemoveSample when Size()==0 is incorrect. + void RemoveSample(T sample) { + RTC_DCHECK_GT(Size(), 0); + // In production, just saturate at 0. + if (Size() == 0) { + return; + } + // Since samples order doesn't matter, this is the + // exact reciprocal of Welford's incremental update. + --size_; + const double delta = sample - mean_; + mean_ -= delta / size_; + const double delta2 = sample - mean_; + cumul_ -= delta * delta2; + } + + // Merge other stats, as if samples were added one by one, but in O(1). + void MergeStatistics(const RunningStatistics<T>& other) { + if (other.size_ == 0) { + return; + } + max_ = std::max(max_, other.max_); + min_ = std::min(min_, other.min_); + const int64_t new_size = size_ + other.size_; + const double new_mean = + (mean_ * size_ + other.mean_ * other.size_) / new_size; + // Each cumulant must be corrected. + // * from: sum((x_i - mean_)²) + // * to: sum((x_i - new_mean)²) + auto delta = [new_mean](const RunningStatistics<T>& stats) { + return stats.size_ * (new_mean * (new_mean - 2 * stats.mean_) + + stats.mean_ * stats.mean_); + }; + cumul_ = cumul_ + delta(*this) + other.cumul_ + delta(other); + mean_ = new_mean; + size_ = new_size; + } + + // Get Measures //////////////////////////////////////////// + + // Returns number of samples involved via AddSample() or MergeStatistics(), + // minus number of times RemoveSample() was called. + int64_t Size() const { return size_; } + + // Returns minimum among all seen samples, in O(1) time. + // This isn't affected by RemoveSample(). + absl::optional<T> GetMin() const { + if (size_ == 0) { + return absl::nullopt; + } + return min_; + } + + // Returns maximum among all seen samples, in O(1) time. + // This isn't affected by RemoveSample(). + absl::optional<T> GetMax() const { + if (size_ == 0) { + return absl::nullopt; + } + return max_; + } + + // Returns sum in O(1) time. + absl::optional<double> GetSum() const { + if (size_ == 0) { + return absl::nullopt; + } + return sum_; + } + + // Returns mean in O(1) time. + absl::optional<double> GetMean() const { + if (size_ == 0) { + return absl::nullopt; + } + return mean_; + } + + // Returns unbiased sample variance in O(1) time. + absl::optional<double> GetVariance() const { + if (size_ == 0) { + return absl::nullopt; + } + return cumul_ / size_; + } + + // Returns unbiased standard deviation in O(1) time. + absl::optional<double> GetStandardDeviation() const { + if (size_ == 0) { + return absl::nullopt; + } + return std::sqrt(*GetVariance()); + } + + private: + int64_t size_ = 0; // Samples seen. + T min_ = infinity_or_max<T>(); + T max_ = minus_infinity_or_min<T>(); + double mean_ = 0; + double cumul_ = 0; // Variance * size_, sometimes noted m2. + double sum_ = 0; +}; + +} // namespace webrtc_impl +} // namespace webrtc + +#endif // API_NUMERICS_RUNNING_STATISTICS_H_ diff --git a/third_party/libwebrtc/rtc_base/numerics/running_statistics_unittest.cc b/third_party/libwebrtc/rtc_base/numerics/running_statistics_unittest.cc new file mode 100644 index 0000000000..7f8adfba24 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/numerics/running_statistics_unittest.cc @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2016 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 "rtc_base/numerics/running_statistics.h" + +#include <math.h> + +#include <random> +#include <vector> + +#include "absl/algorithm/container.h" +#include "test/gtest.h" + +// Tests were copied from samples_stats_counter_unittest.cc. + +namespace webrtc { +namespace webrtc_impl { +namespace { + +RunningStatistics<double> CreateStatsFilledWithIntsFrom1ToN(int n) { + std::vector<double> data; + for (int i = 1; i <= n; i++) { + data.push_back(i); + } + absl::c_shuffle(data, std::mt19937(std::random_device()())); + + RunningStatistics<double> stats; + for (double v : data) { + stats.AddSample(v); + } + return stats; +} + +// Add n samples drawn from uniform distribution in [a;b]. +RunningStatistics<double> CreateStatsFromUniformDistribution(int n, + double a, + double b) { + std::mt19937 gen{std::random_device()()}; + std::uniform_real_distribution<> dis(a, b); + + RunningStatistics<double> stats; + for (int i = 1; i <= n; i++) { + stats.AddSample(dis(gen)); + } + return stats; +} + +class RunningStatisticsTest : public ::testing::TestWithParam<int> {}; + +constexpr int SIZE_FOR_MERGE = 5; + +TEST(RunningStatistics, FullSimpleTest) { + auto stats = CreateStatsFilledWithIntsFrom1ToN(100); + + EXPECT_DOUBLE_EQ(*stats.GetMin(), 1.0); + EXPECT_DOUBLE_EQ(*stats.GetMax(), 100.0); + EXPECT_DOUBLE_EQ(*stats.GetSum(), 5050.0); + // EXPECT_DOUBLE_EQ is too strict (max 4 ULP) for this one. + ASSERT_NEAR(*stats.GetMean(), 50.5, 1e-10); +} + +TEST(RunningStatistics, VarianceAndDeviation) { + RunningStatistics<int> stats; + stats.AddSample(2); + stats.AddSample(2); + stats.AddSample(-1); + stats.AddSample(5); + + EXPECT_DOUBLE_EQ(*stats.GetMean(), 2.0); + EXPECT_DOUBLE_EQ(*stats.GetVariance(), 4.5); + EXPECT_DOUBLE_EQ(*stats.GetStandardDeviation(), sqrt(4.5)); +} + +TEST(RunningStatistics, RemoveSample) { + // We check that adding then removing sample is no-op, + // or so (due to loss of precision). + RunningStatistics<int> stats; + stats.AddSample(2); + stats.AddSample(2); + stats.AddSample(-1); + stats.AddSample(5); + + constexpr int iterations = 1e5; + for (int i = 0; i < iterations; ++i) { + stats.AddSample(i); + stats.RemoveSample(i); + + EXPECT_NEAR(*stats.GetMean(), 2.0, 1e-8); + EXPECT_NEAR(*stats.GetVariance(), 4.5, 1e-3); + EXPECT_NEAR(*stats.GetStandardDeviation(), sqrt(4.5), 1e-4); + } +} + +TEST(RunningStatistics, RemoveSamplesSequence) { + // We check that adding then removing a sequence of samples is no-op, + // or so (due to loss of precision). + RunningStatistics<int> stats; + stats.AddSample(2); + stats.AddSample(2); + stats.AddSample(-1); + stats.AddSample(5); + + constexpr int iterations = 1e4; + for (int i = 0; i < iterations; ++i) { + stats.AddSample(i); + } + for (int i = 0; i < iterations; ++i) { + stats.RemoveSample(i); + } + + EXPECT_NEAR(*stats.GetMean(), 2.0, 1e-7); + EXPECT_NEAR(*stats.GetVariance(), 4.5, 1e-3); + EXPECT_NEAR(*stats.GetStandardDeviation(), sqrt(4.5), 1e-4); +} + +TEST(RunningStatistics, VarianceFromUniformDistribution) { + // Check variance converge to 1/12 for [0;1) uniform distribution. + // Acts as a sanity check for NumericStabilityForVariance test. + auto stats = CreateStatsFromUniformDistribution(1e6, 0, 1); + + EXPECT_NEAR(*stats.GetVariance(), 1. / 12, 1e-3); +} + +TEST(RunningStatistics, NumericStabilityForVariance) { + // Same test as VarianceFromUniformDistribution, + // except the range is shifted to [1e9;1e9+1). + // Variance should also converge to 1/12. + // NB: Although we lose precision for the samples themselves, the fractional + // part still enjoys 22 bits of mantissa and errors should even out, + // so that couldn't explain a mismatch. + auto stats = CreateStatsFromUniformDistribution(1e6, 1e9, 1e9 + 1); + + EXPECT_NEAR(*stats.GetVariance(), 1. / 12, 1e-3); +} + +TEST(RunningStatistics, MinRemainsUnchangedAfterRemove) { + // We don't want to recompute min (that's RollingAccumulator's role), + // check we get the overall min. + RunningStatistics<int> stats; + stats.AddSample(1); + stats.AddSample(2); + stats.RemoveSample(1); + EXPECT_EQ(stats.GetMin(), 1); +} + +TEST(RunningStatistics, MaxRemainsUnchangedAfterRemove) { + // We don't want to recompute max (that's RollingAccumulator's role), + // check we get the overall max. + RunningStatistics<int> stats; + stats.AddSample(1); + stats.AddSample(2); + stats.RemoveSample(2); + EXPECT_EQ(stats.GetMax(), 2); +} + +TEST_P(RunningStatisticsTest, MergeStatistics) { + int data[SIZE_FOR_MERGE] = {2, 2, -1, 5, 10}; + // Split the data in different partitions. + // We have 6 distinct tests: + // * Empty merged with full sequence. + // * 1 sample merged with 4 last. + // * 2 samples merged with 3 last. + // [...] + // * Full merged with empty sequence. + // All must lead to the same result. + // I miss QuickCheck so much. + RunningStatistics<int> stats0, stats1; + for (int i = 0; i < GetParam(); ++i) { + stats0.AddSample(data[i]); + } + for (int i = GetParam(); i < SIZE_FOR_MERGE; ++i) { + stats1.AddSample(data[i]); + } + stats0.MergeStatistics(stats1); + + EXPECT_EQ(stats0.Size(), SIZE_FOR_MERGE); + EXPECT_DOUBLE_EQ(*stats0.GetMin(), -1); + EXPECT_DOUBLE_EQ(*stats0.GetMax(), 10); + EXPECT_DOUBLE_EQ(*stats0.GetMean(), 3.6); + EXPECT_DOUBLE_EQ(*stats0.GetVariance(), 13.84); + EXPECT_DOUBLE_EQ(*stats0.GetStandardDeviation(), sqrt(13.84)); +} + +INSTANTIATE_TEST_SUITE_P(RunningStatisticsTests, + RunningStatisticsTest, + ::testing::Range(0, SIZE_FOR_MERGE + 1)); + +} // namespace +} // namespace webrtc_impl +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/numerics/safe_compare.h b/third_party/libwebrtc/rtc_base/numerics/safe_compare.h new file mode 100644 index 0000000000..85f0a30e83 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/numerics/safe_compare.h @@ -0,0 +1,176 @@ +/* + * Copyright 2016 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 file defines six constexpr functions: +// +// rtc::SafeEq // == +// rtc::SafeNe // != +// rtc::SafeLt // < +// rtc::SafeLe // <= +// rtc::SafeGt // > +// rtc::SafeGe // >= +// +// They each accept two arguments of arbitrary types, and in almost all cases, +// they simply call the appropriate comparison operator. However, if both +// arguments are integers, they don't compare them using C++'s quirky rules, +// but instead adhere to the true mathematical definitions. It is as if the +// arguments were first converted to infinite-range signed integers, and then +// compared, although of course nothing expensive like that actually takes +// place. In practice, for signed/signed and unsigned/unsigned comparisons and +// some mixed-signed comparisons with a compile-time constant, the overhead is +// zero; in the remaining cases, it is just a few machine instructions (no +// branches). + +#ifndef RTC_BASE_NUMERICS_SAFE_COMPARE_H_ +#define RTC_BASE_NUMERICS_SAFE_COMPARE_H_ + +#include <stddef.h> +#include <stdint.h> + +#include <type_traits> +#include <utility> + +#include "rtc_base/type_traits.h" + +namespace rtc { + +namespace safe_cmp_impl { + +template <size_t N> +struct LargerIntImpl : std::false_type {}; +template <> +struct LargerIntImpl<sizeof(int8_t)> : std::true_type { + using type = int16_t; +}; +template <> +struct LargerIntImpl<sizeof(int16_t)> : std::true_type { + using type = int32_t; +}; +template <> +struct LargerIntImpl<sizeof(int32_t)> : std::true_type { + using type = int64_t; +}; + +// LargerInt<T1, T2>::value is true iff there's a signed type that's larger +// than T1 (and no larger than the larger of T2 and int*, for performance +// reasons); and if there is such a type, LargerInt<T1, T2>::type is an alias +// for it. +template <typename T1, typename T2> +struct LargerInt + : LargerIntImpl<sizeof(T1) < sizeof(T2) || sizeof(T1) < sizeof(int*) + ? sizeof(T1) + : 0> {}; + +template <typename T> +constexpr typename std::make_unsigned<T>::type MakeUnsigned(T a) { + return static_cast<typename std::make_unsigned<T>::type>(a); +} + +// Overload for when both T1 and T2 have the same signedness. +template <typename Op, + typename T1, + typename T2, + typename std::enable_if<std::is_signed<T1>::value == + std::is_signed<T2>::value>::type* = nullptr> +constexpr bool Cmp(T1 a, T2 b) { + return Op::Op(a, b); +} + +// Overload for signed - unsigned comparison that can be promoted to a bigger +// signed type. +template <typename Op, + typename T1, + typename T2, + typename std::enable_if<std::is_signed<T1>::value && + std::is_unsigned<T2>::value && + LargerInt<T2, T1>::value>::type* = nullptr> +constexpr bool Cmp(T1 a, T2 b) { + return Op::Op(a, static_cast<typename LargerInt<T2, T1>::type>(b)); +} + +// Overload for unsigned - signed comparison that can be promoted to a bigger +// signed type. +template <typename Op, + typename T1, + typename T2, + typename std::enable_if<std::is_unsigned<T1>::value && + std::is_signed<T2>::value && + LargerInt<T1, T2>::value>::type* = nullptr> +constexpr bool Cmp(T1 a, T2 b) { + return Op::Op(static_cast<typename LargerInt<T1, T2>::type>(a), b); +} + +// Overload for signed - unsigned comparison that can't be promoted to a bigger +// signed type. +template <typename Op, + typename T1, + typename T2, + typename std::enable_if<std::is_signed<T1>::value && + std::is_unsigned<T2>::value && + !LargerInt<T2, T1>::value>::type* = nullptr> +constexpr bool Cmp(T1 a, T2 b) { + return a < 0 ? Op::Op(-1, 0) : Op::Op(safe_cmp_impl::MakeUnsigned(a), b); +} + +// Overload for unsigned - signed comparison that can't be promoted to a bigger +// signed type. +template <typename Op, + typename T1, + typename T2, + typename std::enable_if<std::is_unsigned<T1>::value && + std::is_signed<T2>::value && + !LargerInt<T1, T2>::value>::type* = nullptr> +constexpr bool Cmp(T1 a, T2 b) { + return b < 0 ? Op::Op(0, -1) : Op::Op(a, safe_cmp_impl::MakeUnsigned(b)); +} + +#define RTC_SAFECMP_MAKE_OP(name, op) \ + struct name { \ + template <typename T1, typename T2> \ + static constexpr bool Op(T1 a, T2 b) { \ + return a op b; \ + } \ + }; +RTC_SAFECMP_MAKE_OP(EqOp, ==) +RTC_SAFECMP_MAKE_OP(NeOp, !=) +RTC_SAFECMP_MAKE_OP(LtOp, <) +RTC_SAFECMP_MAKE_OP(LeOp, <=) +RTC_SAFECMP_MAKE_OP(GtOp, >) +RTC_SAFECMP_MAKE_OP(GeOp, >=) +#undef RTC_SAFECMP_MAKE_OP + +} // namespace safe_cmp_impl + +#define RTC_SAFECMP_MAKE_FUN(name) \ + template <typename T1, typename T2> \ + constexpr \ + typename std::enable_if<IsIntlike<T1>::value && IsIntlike<T2>::value, \ + bool>::type Safe##name(T1 a, T2 b) { \ + /* Unary plus here turns enums into real integral types. */ \ + return safe_cmp_impl::Cmp<safe_cmp_impl::name##Op>(+a, +b); \ + } \ + template <typename T1, typename T2> \ + constexpr \ + typename std::enable_if<!IsIntlike<T1>::value || !IsIntlike<T2>::value, \ + bool>::type Safe##name(const T1& a, \ + const T2& b) { \ + return safe_cmp_impl::name##Op::Op(a, b); \ + } +RTC_SAFECMP_MAKE_FUN(Eq) +RTC_SAFECMP_MAKE_FUN(Ne) +RTC_SAFECMP_MAKE_FUN(Lt) +RTC_SAFECMP_MAKE_FUN(Le) +RTC_SAFECMP_MAKE_FUN(Gt) +RTC_SAFECMP_MAKE_FUN(Ge) +#undef RTC_SAFECMP_MAKE_FUN + +} // namespace rtc + +#endif // RTC_BASE_NUMERICS_SAFE_COMPARE_H_ diff --git a/third_party/libwebrtc/rtc_base/numerics/safe_compare_unittest.cc b/third_party/libwebrtc/rtc_base/numerics/safe_compare_unittest.cc new file mode 100644 index 0000000000..92bde686ba --- /dev/null +++ b/third_party/libwebrtc/rtc_base/numerics/safe_compare_unittest.cc @@ -0,0 +1,395 @@ +/* + * Copyright 2016 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 "rtc_base/numerics/safe_compare.h" + +#include <limits> + +#include "test/gtest.h" + +namespace rtc { + +namespace { + +constexpr std::uintmax_t umax = std::numeric_limits<std::uintmax_t>::max(); +constexpr std::intmax_t imin = std::numeric_limits<std::intmax_t>::min(); +constexpr std::intmax_t m1 = -1; + +// m1 and umax have the same representation because we use 2's complement +// arithmetic, so naive casting will confuse them. +static_assert(static_cast<std::uintmax_t>(m1) == umax, ""); +static_assert(m1 == static_cast<std::intmax_t>(umax), ""); + +static const std::pair<int, int> p1(1, 1); +static const std::pair<int, int> p2(1, 2); + +} // namespace + +// clang-format off + +// These functions aren't used in the tests, but it's useful to look at the +// compiler output for them, and verify that (1) the same-signedness *Safe +// functions result in exactly the same code as their *Ref counterparts, and +// that (2) the mixed-signedness *Safe functions have just a few extra +// arithmetic and logic instructions (but no extra control flow instructions). +bool TestLessThanRef( int a, int b) { return a < b; } +bool TestLessThanRef( unsigned a, unsigned b) { return a < b; } +bool TestLessThanSafe( int a, int b) { return SafeLt(a, b); } +bool TestLessThanSafe(unsigned a, unsigned b) { return SafeLt(a, b); } +bool TestLessThanSafe(unsigned a, int b) { return SafeLt(a, b); } +bool TestLessThanSafe( int a, unsigned b) { return SafeLt(a, b); } + +// For these, we expect the *Ref and *Safe functions to result in identical +// code, except for the ones that compare a signed variable with an unsigned +// constant; in that case, the *Ref function does an unsigned comparison (fast +// but incorrect) and the *Safe function spends a few extra instructions on +// doing it right. +bool TestLessThan17Ref( int a) { return a < 17; } +bool TestLessThan17Ref( unsigned a) { return a < 17; } +bool TestLessThan17uRef( int a) { return static_cast<unsigned>(a) < 17u; } +bool TestLessThan17uRef( unsigned a) { return a < 17u; } +bool TestLessThan17Safe( int a) { return SafeLt(a, 17); } +bool TestLessThan17Safe( unsigned a) { return SafeLt(a, 17); } +bool TestLessThan17uSafe( int a) { return SafeLt(a, 17u); } +bool TestLessThan17uSafe(unsigned a) { return SafeLt(a, 17u); } + +// Cases where we can't convert to a larger signed type. +bool TestLessThanMax( intmax_t a, uintmax_t b) { return SafeLt(a, b); } +bool TestLessThanMax(uintmax_t a, intmax_t b) { return SafeLt(a, b); } +bool TestLessThanMax17u( intmax_t a) { return SafeLt(a, uintmax_t{17}); } +bool TestLessThanMax17( uintmax_t a) { return SafeLt(a, intmax_t{17}); } + +// Cases where the compiler should be able to compute the result at compile +// time. +bool TestLessThanConst1() { return SafeLt( -1, 1); } +bool TestLessThanConst2() { return SafeLt( m1, umax); } +bool TestLessThanConst3() { return SafeLt(umax, imin); } +bool TestLessThanConst4(unsigned a) { return SafeLt( a, -1); } +bool TestLessThanConst5(unsigned a) { return SafeLt(-1, a); } +bool TestLessThanConst6(unsigned a) { return SafeLt( a, a); } + +// clang-format on + +TEST(SafeCmpTest, Eq) { + static_assert(!SafeEq(-1, 2), ""); + static_assert(!SafeEq(-1, 2u), ""); + static_assert(!SafeEq(2, -1), ""); + static_assert(!SafeEq(2u, -1), ""); + + static_assert(!SafeEq(1, 2), ""); + static_assert(!SafeEq(1, 2u), ""); + static_assert(!SafeEq(1u, 2), ""); + static_assert(!SafeEq(1u, 2u), ""); + static_assert(!SafeEq(2, 1), ""); + static_assert(!SafeEq(2, 1u), ""); + static_assert(!SafeEq(2u, 1), ""); + static_assert(!SafeEq(2u, 1u), ""); + + static_assert(SafeEq(2, 2), ""); + static_assert(SafeEq(2, 2u), ""); + static_assert(SafeEq(2u, 2), ""); + static_assert(SafeEq(2u, 2u), ""); + + static_assert(SafeEq(imin, imin), ""); + static_assert(!SafeEq(imin, umax), ""); + static_assert(!SafeEq(umax, imin), ""); + static_assert(SafeEq(umax, umax), ""); + + static_assert(SafeEq(m1, m1), ""); + static_assert(!SafeEq(m1, umax), ""); + static_assert(!SafeEq(umax, m1), ""); + static_assert(SafeEq(umax, umax), ""); + + static_assert(!SafeEq(1, 2), ""); + static_assert(!SafeEq(1, 2.0), ""); + static_assert(!SafeEq(1.0, 2), ""); + static_assert(!SafeEq(1.0, 2.0), ""); + static_assert(!SafeEq(2, 1), ""); + static_assert(!SafeEq(2, 1.0), ""); + static_assert(!SafeEq(2.0, 1), ""); + static_assert(!SafeEq(2.0, 1.0), ""); + + static_assert(SafeEq(2, 2), ""); + static_assert(SafeEq(2, 2.0), ""); + static_assert(SafeEq(2.0, 2), ""); + static_assert(SafeEq(2.0, 2.0), ""); + + EXPECT_TRUE(SafeEq(p1, p1)); + EXPECT_FALSE(SafeEq(p1, p2)); + EXPECT_FALSE(SafeEq(p2, p1)); + EXPECT_TRUE(SafeEq(p2, p2)); +} + +TEST(SafeCmpTest, Ne) { + static_assert(SafeNe(-1, 2), ""); + static_assert(SafeNe(-1, 2u), ""); + static_assert(SafeNe(2, -1), ""); + static_assert(SafeNe(2u, -1), ""); + + static_assert(SafeNe(1, 2), ""); + static_assert(SafeNe(1, 2u), ""); + static_assert(SafeNe(1u, 2), ""); + static_assert(SafeNe(1u, 2u), ""); + static_assert(SafeNe(2, 1), ""); + static_assert(SafeNe(2, 1u), ""); + static_assert(SafeNe(2u, 1), ""); + static_assert(SafeNe(2u, 1u), ""); + + static_assert(!SafeNe(2, 2), ""); + static_assert(!SafeNe(2, 2u), ""); + static_assert(!SafeNe(2u, 2), ""); + static_assert(!SafeNe(2u, 2u), ""); + + static_assert(!SafeNe(imin, imin), ""); + static_assert(SafeNe(imin, umax), ""); + static_assert(SafeNe(umax, imin), ""); + static_assert(!SafeNe(umax, umax), ""); + + static_assert(!SafeNe(m1, m1), ""); + static_assert(SafeNe(m1, umax), ""); + static_assert(SafeNe(umax, m1), ""); + static_assert(!SafeNe(umax, umax), ""); + + static_assert(SafeNe(1, 2), ""); + static_assert(SafeNe(1, 2.0), ""); + static_assert(SafeNe(1.0, 2), ""); + static_assert(SafeNe(1.0, 2.0), ""); + static_assert(SafeNe(2, 1), ""); + static_assert(SafeNe(2, 1.0), ""); + static_assert(SafeNe(2.0, 1), ""); + static_assert(SafeNe(2.0, 1.0), ""); + + static_assert(!SafeNe(2, 2), ""); + static_assert(!SafeNe(2, 2.0), ""); + static_assert(!SafeNe(2.0, 2), ""); + static_assert(!SafeNe(2.0, 2.0), ""); + + EXPECT_FALSE(SafeNe(p1, p1)); + EXPECT_TRUE(SafeNe(p1, p2)); + EXPECT_TRUE(SafeNe(p2, p1)); + EXPECT_FALSE(SafeNe(p2, p2)); +} + +TEST(SafeCmpTest, Lt) { + static_assert(SafeLt(-1, 2), ""); + static_assert(SafeLt(-1, 2u), ""); + static_assert(!SafeLt(2, -1), ""); + static_assert(!SafeLt(2u, -1), ""); + + static_assert(SafeLt(1, 2), ""); + static_assert(SafeLt(1, 2u), ""); + static_assert(SafeLt(1u, 2), ""); + static_assert(SafeLt(1u, 2u), ""); + static_assert(!SafeLt(2, 1), ""); + static_assert(!SafeLt(2, 1u), ""); + static_assert(!SafeLt(2u, 1), ""); + static_assert(!SafeLt(2u, 1u), ""); + + static_assert(!SafeLt(2, 2), ""); + static_assert(!SafeLt(2, 2u), ""); + static_assert(!SafeLt(2u, 2), ""); + static_assert(!SafeLt(2u, 2u), ""); + + static_assert(!SafeLt(imin, imin), ""); + static_assert(SafeLt(imin, umax), ""); + static_assert(!SafeLt(umax, imin), ""); + static_assert(!SafeLt(umax, umax), ""); + + static_assert(!SafeLt(m1, m1), ""); + static_assert(SafeLt(m1, umax), ""); + static_assert(!SafeLt(umax, m1), ""); + static_assert(!SafeLt(umax, umax), ""); + + static_assert(SafeLt(1, 2), ""); + static_assert(SafeLt(1, 2.0), ""); + static_assert(SafeLt(1.0, 2), ""); + static_assert(SafeLt(1.0, 2.0), ""); + static_assert(!SafeLt(2, 1), ""); + static_assert(!SafeLt(2, 1.0), ""); + static_assert(!SafeLt(2.0, 1), ""); + static_assert(!SafeLt(2.0, 1.0), ""); + + static_assert(!SafeLt(2, 2), ""); + static_assert(!SafeLt(2, 2.0), ""); + static_assert(!SafeLt(2.0, 2), ""); + static_assert(!SafeLt(2.0, 2.0), ""); + + EXPECT_FALSE(SafeLt(p1, p1)); + EXPECT_TRUE(SafeLt(p1, p2)); + EXPECT_FALSE(SafeLt(p2, p1)); + EXPECT_FALSE(SafeLt(p2, p2)); +} + +TEST(SafeCmpTest, Le) { + static_assert(SafeLe(-1, 2), ""); + static_assert(SafeLe(-1, 2u), ""); + static_assert(!SafeLe(2, -1), ""); + static_assert(!SafeLe(2u, -1), ""); + + static_assert(SafeLe(1, 2), ""); + static_assert(SafeLe(1, 2u), ""); + static_assert(SafeLe(1u, 2), ""); + static_assert(SafeLe(1u, 2u), ""); + static_assert(!SafeLe(2, 1), ""); + static_assert(!SafeLe(2, 1u), ""); + static_assert(!SafeLe(2u, 1), ""); + static_assert(!SafeLe(2u, 1u), ""); + + static_assert(SafeLe(2, 2), ""); + static_assert(SafeLe(2, 2u), ""); + static_assert(SafeLe(2u, 2), ""); + static_assert(SafeLe(2u, 2u), ""); + + static_assert(SafeLe(imin, imin), ""); + static_assert(SafeLe(imin, umax), ""); + static_assert(!SafeLe(umax, imin), ""); + static_assert(SafeLe(umax, umax), ""); + + static_assert(SafeLe(m1, m1), ""); + static_assert(SafeLe(m1, umax), ""); + static_assert(!SafeLe(umax, m1), ""); + static_assert(SafeLe(umax, umax), ""); + + static_assert(SafeLe(1, 2), ""); + static_assert(SafeLe(1, 2.0), ""); + static_assert(SafeLe(1.0, 2), ""); + static_assert(SafeLe(1.0, 2.0), ""); + static_assert(!SafeLe(2, 1), ""); + static_assert(!SafeLe(2, 1.0), ""); + static_assert(!SafeLe(2.0, 1), ""); + static_assert(!SafeLe(2.0, 1.0), ""); + + static_assert(SafeLe(2, 2), ""); + static_assert(SafeLe(2, 2.0), ""); + static_assert(SafeLe(2.0, 2), ""); + static_assert(SafeLe(2.0, 2.0), ""); + + EXPECT_TRUE(SafeLe(p1, p1)); + EXPECT_TRUE(SafeLe(p1, p2)); + EXPECT_FALSE(SafeLe(p2, p1)); + EXPECT_TRUE(SafeLe(p2, p2)); +} + +TEST(SafeCmpTest, Gt) { + static_assert(!SafeGt(-1, 2), ""); + static_assert(!SafeGt(-1, 2u), ""); + static_assert(SafeGt(2, -1), ""); + static_assert(SafeGt(2u, -1), ""); + + static_assert(!SafeGt(1, 2), ""); + static_assert(!SafeGt(1, 2u), ""); + static_assert(!SafeGt(1u, 2), ""); + static_assert(!SafeGt(1u, 2u), ""); + static_assert(SafeGt(2, 1), ""); + static_assert(SafeGt(2, 1u), ""); + static_assert(SafeGt(2u, 1), ""); + static_assert(SafeGt(2u, 1u), ""); + + static_assert(!SafeGt(2, 2), ""); + static_assert(!SafeGt(2, 2u), ""); + static_assert(!SafeGt(2u, 2), ""); + static_assert(!SafeGt(2u, 2u), ""); + + static_assert(!SafeGt(imin, imin), ""); + static_assert(!SafeGt(imin, umax), ""); + static_assert(SafeGt(umax, imin), ""); + static_assert(!SafeGt(umax, umax), ""); + + static_assert(!SafeGt(m1, m1), ""); + static_assert(!SafeGt(m1, umax), ""); + static_assert(SafeGt(umax, m1), ""); + static_assert(!SafeGt(umax, umax), ""); + + static_assert(!SafeGt(1, 2), ""); + static_assert(!SafeGt(1, 2.0), ""); + static_assert(!SafeGt(1.0, 2), ""); + static_assert(!SafeGt(1.0, 2.0), ""); + static_assert(SafeGt(2, 1), ""); + static_assert(SafeGt(2, 1.0), ""); + static_assert(SafeGt(2.0, 1), ""); + static_assert(SafeGt(2.0, 1.0), ""); + + static_assert(!SafeGt(2, 2), ""); + static_assert(!SafeGt(2, 2.0), ""); + static_assert(!SafeGt(2.0, 2), ""); + static_assert(!SafeGt(2.0, 2.0), ""); + + EXPECT_FALSE(SafeGt(p1, p1)); + EXPECT_FALSE(SafeGt(p1, p2)); + EXPECT_TRUE(SafeGt(p2, p1)); + EXPECT_FALSE(SafeGt(p2, p2)); +} + +TEST(SafeCmpTest, Ge) { + static_assert(!SafeGe(-1, 2), ""); + static_assert(!SafeGe(-1, 2u), ""); + static_assert(SafeGe(2, -1), ""); + static_assert(SafeGe(2u, -1), ""); + + static_assert(!SafeGe(1, 2), ""); + static_assert(!SafeGe(1, 2u), ""); + static_assert(!SafeGe(1u, 2), ""); + static_assert(!SafeGe(1u, 2u), ""); + static_assert(SafeGe(2, 1), ""); + static_assert(SafeGe(2, 1u), ""); + static_assert(SafeGe(2u, 1), ""); + static_assert(SafeGe(2u, 1u), ""); + + static_assert(SafeGe(2, 2), ""); + static_assert(SafeGe(2, 2u), ""); + static_assert(SafeGe(2u, 2), ""); + static_assert(SafeGe(2u, 2u), ""); + + static_assert(SafeGe(imin, imin), ""); + static_assert(!SafeGe(imin, umax), ""); + static_assert(SafeGe(umax, imin), ""); + static_assert(SafeGe(umax, umax), ""); + + static_assert(SafeGe(m1, m1), ""); + static_assert(!SafeGe(m1, umax), ""); + static_assert(SafeGe(umax, m1), ""); + static_assert(SafeGe(umax, umax), ""); + + static_assert(!SafeGe(1, 2), ""); + static_assert(!SafeGe(1, 2.0), ""); + static_assert(!SafeGe(1.0, 2), ""); + static_assert(!SafeGe(1.0, 2.0), ""); + static_assert(SafeGe(2, 1), ""); + static_assert(SafeGe(2, 1.0), ""); + static_assert(SafeGe(2.0, 1), ""); + static_assert(SafeGe(2.0, 1.0), ""); + + static_assert(SafeGe(2, 2), ""); + static_assert(SafeGe(2, 2.0), ""); + static_assert(SafeGe(2.0, 2), ""); + static_assert(SafeGe(2.0, 2.0), ""); + + EXPECT_TRUE(SafeGe(p1, p1)); + EXPECT_FALSE(SafeGe(p1, p2)); + EXPECT_TRUE(SafeGe(p2, p1)); + EXPECT_TRUE(SafeGe(p2, p2)); +} + +TEST(SafeCmpTest, Enum) { + enum E1 { e1 = 13 }; + enum { e2 = 13 }; + enum E3 : unsigned { e3 = 13 }; + enum : unsigned { e4 = 13 }; + static_assert(SafeEq(13, e1), ""); + static_assert(SafeEq(13u, e1), ""); + static_assert(SafeEq(13, e2), ""); + static_assert(SafeEq(13u, e2), ""); + static_assert(SafeEq(13, e3), ""); + static_assert(SafeEq(13u, e3), ""); + static_assert(SafeEq(13, e4), ""); + static_assert(SafeEq(13u, e4), ""); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/numerics/safe_conversions.h b/third_party/libwebrtc/rtc_base/numerics/safe_conversions.h new file mode 100644 index 0000000000..e00219cbd7 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/numerics/safe_conversions.h @@ -0,0 +1,74 @@ +/* + * Copyright 2014 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. + */ + +// Borrowed from Chromium's src/base/numerics/safe_conversions.h. + +#ifndef RTC_BASE_NUMERICS_SAFE_CONVERSIONS_H_ +#define RTC_BASE_NUMERICS_SAFE_CONVERSIONS_H_ + +#include <limits> + +#include "rtc_base/checks.h" +#include "rtc_base/numerics/safe_conversions_impl.h" + +namespace rtc { + +// Convenience function that returns true if the supplied value is in range +// for the destination type. +template <typename Dst, typename Src> +inline constexpr bool IsValueInRangeForNumericType(Src value) { + return internal::RangeCheck<Dst>(value) == internal::TYPE_VALID; +} + +// checked_cast<> and dchecked_cast<> are analogous to static_cast<> for +// numeric types, except that they [D]CHECK that the specified numeric +// conversion will not overflow or underflow. NaN source will always trigger +// the [D]CHECK. +template <typename Dst, typename Src> +inline constexpr Dst checked_cast(Src value) { + RTC_CHECK(IsValueInRangeForNumericType<Dst>(value)); + return static_cast<Dst>(value); +} +template <typename Dst, typename Src> +inline constexpr Dst dchecked_cast(Src value) { + RTC_DCHECK(IsValueInRangeForNumericType<Dst>(value)); + return static_cast<Dst>(value); +} + +// saturated_cast<> is analogous to static_cast<> for numeric types, except +// that the specified numeric conversion will saturate rather than overflow or +// underflow. NaN assignment to an integral will trigger a RTC_CHECK condition. +template <typename Dst, typename Src> +inline constexpr Dst saturated_cast(Src value) { + // Optimization for floating point values, which already saturate. + if (std::numeric_limits<Dst>::is_iec559) + return static_cast<Dst>(value); + + switch (internal::RangeCheck<Dst>(value)) { + case internal::TYPE_VALID: + return static_cast<Dst>(value); + + case internal::TYPE_UNDERFLOW: + return std::numeric_limits<Dst>::min(); + + case internal::TYPE_OVERFLOW: + return std::numeric_limits<Dst>::max(); + + // Should fail only on attempting to assign NaN to a saturated integer. + case internal::TYPE_INVALID: + RTC_CHECK_NOTREACHED(); + } + + RTC_CHECK_NOTREACHED(); +} + +} // namespace rtc + +#endif // RTC_BASE_NUMERICS_SAFE_CONVERSIONS_H_ diff --git a/third_party/libwebrtc/rtc_base/numerics/safe_conversions_impl.h b/third_party/libwebrtc/rtc_base/numerics/safe_conversions_impl.h new file mode 100644 index 0000000000..e924ce3256 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/numerics/safe_conversions_impl.h @@ -0,0 +1,177 @@ +/* + * Copyright 2014 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. + */ + +// Borrowed from Chromium's src/base/numerics/safe_conversions_impl.h. + +#ifndef RTC_BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_ +#define RTC_BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_ + +#include <limits> + +namespace rtc { +namespace internal { + +enum DstSign { DST_UNSIGNED, DST_SIGNED }; + +enum SrcSign { SRC_UNSIGNED, SRC_SIGNED }; + +enum DstRange { OVERLAPS_RANGE, CONTAINS_RANGE }; + +// Helper templates to statically determine if our destination type can contain +// all values represented by the source type. + +template <typename Dst, + typename Src, + DstSign IsDstSigned = + std::numeric_limits<Dst>::is_signed ? DST_SIGNED : DST_UNSIGNED, + SrcSign IsSrcSigned = + std::numeric_limits<Src>::is_signed ? SRC_SIGNED : SRC_UNSIGNED> +struct StaticRangeCheck {}; + +template <typename Dst, typename Src> +struct StaticRangeCheck<Dst, Src, DST_SIGNED, SRC_SIGNED> { + typedef std::numeric_limits<Dst> DstLimits; + typedef std::numeric_limits<Src> SrcLimits; + // Compare based on max_exponent, which we must compute for integrals. + static const size_t kDstMaxExponent = + DstLimits::is_iec559 ? DstLimits::max_exponent : (sizeof(Dst) * 8 - 1); + static const size_t kSrcMaxExponent = + SrcLimits::is_iec559 ? SrcLimits::max_exponent : (sizeof(Src) * 8 - 1); + static const DstRange value = + kDstMaxExponent >= kSrcMaxExponent ? CONTAINS_RANGE : OVERLAPS_RANGE; +}; + +template <typename Dst, typename Src> +struct StaticRangeCheck<Dst, Src, DST_UNSIGNED, SRC_UNSIGNED> { + static const DstRange value = + sizeof(Dst) >= sizeof(Src) ? CONTAINS_RANGE : OVERLAPS_RANGE; +}; + +template <typename Dst, typename Src> +struct StaticRangeCheck<Dst, Src, DST_SIGNED, SRC_UNSIGNED> { + typedef std::numeric_limits<Dst> DstLimits; + typedef std::numeric_limits<Src> SrcLimits; + // Compare based on max_exponent, which we must compute for integrals. + static const size_t kDstMaxExponent = + DstLimits::is_iec559 ? DstLimits::max_exponent : (sizeof(Dst) * 8 - 1); + static const size_t kSrcMaxExponent = sizeof(Src) * 8; + static const DstRange value = + kDstMaxExponent >= kSrcMaxExponent ? CONTAINS_RANGE : OVERLAPS_RANGE; +}; + +template <typename Dst, typename Src> +struct StaticRangeCheck<Dst, Src, DST_UNSIGNED, SRC_SIGNED> { + static const DstRange value = OVERLAPS_RANGE; +}; + +enum RangeCheckResult { + TYPE_VALID = 0, // Value can be represented by the destination type. + TYPE_UNDERFLOW = 1, // Value would overflow. + TYPE_OVERFLOW = 2, // Value would underflow. + TYPE_INVALID = 3 // Source value is invalid (i.e. NaN). +}; + +// This macro creates a RangeCheckResult from an upper and lower bound +// check by taking advantage of the fact that only NaN can be out of range in +// both directions at once. +#define BASE_NUMERIC_RANGE_CHECK_RESULT(is_in_upper_bound, is_in_lower_bound) \ + RangeCheckResult(((is_in_upper_bound) ? 0 : TYPE_OVERFLOW) | \ + ((is_in_lower_bound) ? 0 : TYPE_UNDERFLOW)) + +template <typename Dst, + typename Src, + DstSign IsDstSigned = + std::numeric_limits<Dst>::is_signed ? DST_SIGNED : DST_UNSIGNED, + SrcSign IsSrcSigned = + std::numeric_limits<Src>::is_signed ? SRC_SIGNED : SRC_UNSIGNED, + DstRange IsSrcRangeContained = StaticRangeCheck<Dst, Src>::value> +struct RangeCheckImpl {}; + +// The following templates are for ranges that must be verified at runtime. We +// split it into checks based on signedness to avoid confusing casts and +// compiler warnings on signed an unsigned comparisons. + +// Dst range always contains the result: nothing to check. +template <typename Dst, typename Src, DstSign IsDstSigned, SrcSign IsSrcSigned> +struct RangeCheckImpl<Dst, Src, IsDstSigned, IsSrcSigned, CONTAINS_RANGE> { + static constexpr RangeCheckResult Check(Src value) { return TYPE_VALID; } +}; + +// Signed to signed narrowing. +template <typename Dst, typename Src> +struct RangeCheckImpl<Dst, Src, DST_SIGNED, SRC_SIGNED, OVERLAPS_RANGE> { + static constexpr RangeCheckResult Check(Src value) { + typedef std::numeric_limits<Dst> DstLimits; + return DstLimits::is_iec559 + ? BASE_NUMERIC_RANGE_CHECK_RESULT( + value <= static_cast<Src>(DstLimits::max()), + value >= static_cast<Src>(DstLimits::max() * -1)) + : BASE_NUMERIC_RANGE_CHECK_RESULT( + value <= static_cast<Src>(DstLimits::max()), + value >= static_cast<Src>(DstLimits::min())); + } +}; + +// Unsigned to unsigned narrowing. +template <typename Dst, typename Src> +struct RangeCheckImpl<Dst, Src, DST_UNSIGNED, SRC_UNSIGNED, OVERLAPS_RANGE> { + static constexpr RangeCheckResult Check(Src value) { + typedef std::numeric_limits<Dst> DstLimits; + return BASE_NUMERIC_RANGE_CHECK_RESULT( + value <= static_cast<Src>(DstLimits::max()), true); + } +}; + +// Unsigned to signed. +template <typename Dst, typename Src> +struct RangeCheckImpl<Dst, Src, DST_SIGNED, SRC_UNSIGNED, OVERLAPS_RANGE> { + static constexpr RangeCheckResult Check(Src value) { + typedef std::numeric_limits<Dst> DstLimits; + return sizeof(Dst) > sizeof(Src) + ? TYPE_VALID + : BASE_NUMERIC_RANGE_CHECK_RESULT( + value <= static_cast<Src>(DstLimits::max()), true); + } +}; + +// Signed to unsigned. +template <typename Dst, typename Src> +struct RangeCheckImpl<Dst, Src, DST_UNSIGNED, SRC_SIGNED, OVERLAPS_RANGE> { + typedef std::numeric_limits<Dst> DstLimits; + typedef std::numeric_limits<Src> SrcLimits; + // Compare based on max_exponent, which we must compute for integrals. + static constexpr size_t DstMaxExponent() { return sizeof(Dst) * 8; } + static constexpr size_t SrcMaxExponent() { + return SrcLimits::is_iec559 ? SrcLimits::max_exponent + : (sizeof(Src) * 8 - 1); + } + static constexpr RangeCheckResult Check(Src value) { + return (DstMaxExponent() >= SrcMaxExponent()) + ? BASE_NUMERIC_RANGE_CHECK_RESULT(true, + value >= static_cast<Src>(0)) + : BASE_NUMERIC_RANGE_CHECK_RESULT( + value <= static_cast<Src>(DstLimits::max()), + value >= static_cast<Src>(0)); + } +}; + +template <typename Dst, typename Src> +inline constexpr RangeCheckResult RangeCheck(Src value) { + static_assert(std::numeric_limits<Src>::is_specialized, + "argument must be numeric"); + static_assert(std::numeric_limits<Dst>::is_specialized, + "result must be numeric"); + return RangeCheckImpl<Dst, Src>::Check(value); +} + +} // namespace internal +} // namespace rtc + +#endif // RTC_BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_ diff --git a/third_party/libwebrtc/rtc_base/numerics/safe_minmax.h b/third_party/libwebrtc/rtc_base/numerics/safe_minmax.h new file mode 100644 index 0000000000..8356536dbc --- /dev/null +++ b/third_party/libwebrtc/rtc_base/numerics/safe_minmax.h @@ -0,0 +1,335 @@ +/* + * Copyright 2017 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. + */ + +// Minimum and maximum +// =================== +// +// rtc::SafeMin(x, y) +// rtc::SafeMax(x, y) +// +// (These are both constexpr.) +// +// Accept two arguments of either any two integral or any two floating-point +// types, and return the smaller and larger value, respectively, with no +// truncation or wrap-around. If only one of the input types is statically +// guaranteed to be able to represent the result, the return type is that type; +// if either one would do, the result type is the smaller type. (One of these +// two cases always applies.) +// +// * The case with one floating-point and one integral type is not allowed, +// because the floating-point type will have greater range, but may not +// have sufficient precision to represent the integer value exactly.) +// +// Clamp (a.k.a. constrain to a given interval) +// ============================================ +// +// rtc::SafeClamp(x, a, b) +// +// Accepts three arguments of any mix of integral types or any mix of +// floating-point types, and returns the value in the closed interval [a, b] +// that is closest to x (that is, if x < a it returns a; if x > b it returns b; +// and if a <= x <= b it returns x). As for SafeMin() and SafeMax(), there is +// no truncation or wrap-around. The result type +// +// 1. is statically guaranteed to be able to represent the result; +// +// 2. is no larger than the largest of the three argument types; and +// +// 3. has the same signedness as the type of the first argument, if this is +// possible without violating the First or Second Law. +// +// There is always at least one type that meets criteria 1 and 2. If more than +// one type meets these criteria equally well, the result type is one of the +// types that is smallest. Note that unlike SafeMin() and SafeMax(), +// SafeClamp() will sometimes pick a return type that isn't the type of any of +// its arguments. +// +// * In this context, a type A is smaller than a type B if it has a smaller +// range; that is, if A::max() - A::min() < B::max() - B::min(). For +// example, int8_t < int16_t == uint16_t < int32_t, and all integral types +// are smaller than all floating-point types.) +// +// * As for SafeMin and SafeMax, mixing integer and floating-point arguments +// is not allowed, because floating-point types have greater range than +// integer types, but do not have sufficient precision to represent the +// values of most integer types exactly. +// +// Requesting a specific return type +// ================================= +// +// All three functions allow callers to explicitly specify the return type as a +// template parameter, overriding the default return type. E.g. +// +// rtc::SafeMin<int>(x, y) // returns an int +// +// If the requested type is statically guaranteed to be able to represent the +// result, then everything's fine, and the return type is as requested. But if +// the requested type is too small, a static_assert is triggered. + +#ifndef RTC_BASE_NUMERICS_SAFE_MINMAX_H_ +#define RTC_BASE_NUMERICS_SAFE_MINMAX_H_ + +#include <limits> +#include <type_traits> + +#include "rtc_base/checks.h" +#include "rtc_base/numerics/safe_compare.h" +#include "rtc_base/type_traits.h" + +namespace rtc { + +namespace safe_minmax_impl { + +// Make the range of a type available via something other than a constexpr +// function, to work around MSVC limitations. See +// https://blogs.msdn.microsoft.com/vcblog/2015/12/02/partial-support-for-expression-sfinae-in-vs-2015-update-1/ +template <typename T> +struct Limits { + static constexpr T lowest = std::numeric_limits<T>::lowest(); + static constexpr T max = std::numeric_limits<T>::max(); +}; + +template <typename T, bool is_enum = std::is_enum<T>::value> +struct UnderlyingType; + +template <typename T> +struct UnderlyingType<T, false> { + using type = T; +}; + +template <typename T> +struct UnderlyingType<T, true> { + using type = typename std::underlying_type<T>::type; +}; + +// Given two types T1 and T2, find types that can hold the smallest (in +// ::min_t) and the largest (in ::max_t) of the two values. +template <typename T1, + typename T2, + bool int1 = IsIntlike<T1>::value, + bool int2 = IsIntlike<T2>::value> +struct MType { + static_assert(int1 == int2, + "You may not mix integral and floating-point arguments"); +}; + +// Specialization for when neither type is integral (and therefore presumably +// floating-point). +template <typename T1, typename T2> +struct MType<T1, T2, false, false> { + using min_t = typename std::common_type<T1, T2>::type; + static_assert(std::is_same<min_t, T1>::value || + std::is_same<min_t, T2>::value, + ""); + + using max_t = typename std::common_type<T1, T2>::type; + static_assert(std::is_same<max_t, T1>::value || + std::is_same<max_t, T2>::value, + ""); +}; + +// Specialization for when both types are integral. +template <typename T1, typename T2> +struct MType<T1, T2, true, true> { + // The type with the lowest minimum value. In case of a tie, the type with + // the lowest maximum value. In case that too is a tie, the types have the + // same range, and we arbitrarily pick T1. + using min_t = typename std::conditional< + SafeLt(Limits<T1>::lowest, Limits<T2>::lowest), + T1, + typename std::conditional< + SafeGt(Limits<T1>::lowest, Limits<T2>::lowest), + T2, + typename std::conditional<SafeLe(Limits<T1>::max, Limits<T2>::max), + T1, + T2>::type>::type>::type; + static_assert(std::is_same<min_t, T1>::value || + std::is_same<min_t, T2>::value, + ""); + + // The type with the highest maximum value. In case of a tie, the types have + // the same range (because in C++, integer types with the same maximum also + // have the same minimum). + static_assert(SafeNe(Limits<T1>::max, Limits<T2>::max) || + SafeEq(Limits<T1>::lowest, Limits<T2>::lowest), + "integer types with the same max should have the same min"); + using max_t = typename std:: + conditional<SafeGe(Limits<T1>::max, Limits<T2>::max), T1, T2>::type; + static_assert(std::is_same<max_t, T1>::value || + std::is_same<max_t, T2>::value, + ""); +}; + +// A dummy type that we pass around at compile time but never actually use. +// Declared but not defined. +struct DefaultType; + +// ::type is A, except we fall back to B if A is DefaultType. We static_assert +// that the chosen type can hold all values that B can hold. +template <typename A, typename B> +struct TypeOr { + using type = typename std:: + conditional<std::is_same<A, DefaultType>::value, B, A>::type; + static_assert(SafeLe(Limits<type>::lowest, Limits<B>::lowest) && + SafeGe(Limits<type>::max, Limits<B>::max), + "The specified type isn't large enough"); + static_assert(IsIntlike<type>::value == IsIntlike<B>::value && + std::is_floating_point<type>::value == + std::is_floating_point<type>::value, + "float<->int conversions not allowed"); +}; + +} // namespace safe_minmax_impl + +template < + typename R = safe_minmax_impl::DefaultType, + typename T1 = safe_minmax_impl::DefaultType, + typename T2 = safe_minmax_impl::DefaultType, + typename R2 = typename safe_minmax_impl::TypeOr< + R, + typename safe_minmax_impl::MType< + typename safe_minmax_impl::UnderlyingType<T1>::type, + typename safe_minmax_impl::UnderlyingType<T2>::type>::min_t>::type> +constexpr R2 SafeMin(T1 a, T2 b) { + static_assert(IsIntlike<T1>::value || std::is_floating_point<T1>::value, + "The first argument must be integral or floating-point"); + static_assert(IsIntlike<T2>::value || std::is_floating_point<T2>::value, + "The second argument must be integral or floating-point"); + return SafeLt(a, b) ? static_cast<R2>(a) : static_cast<R2>(b); +} + +template < + typename R = safe_minmax_impl::DefaultType, + typename T1 = safe_minmax_impl::DefaultType, + typename T2 = safe_minmax_impl::DefaultType, + typename R2 = typename safe_minmax_impl::TypeOr< + R, + typename safe_minmax_impl::MType< + typename safe_minmax_impl::UnderlyingType<T1>::type, + typename safe_minmax_impl::UnderlyingType<T2>::type>::max_t>::type> +constexpr R2 SafeMax(T1 a, T2 b) { + static_assert(IsIntlike<T1>::value || std::is_floating_point<T1>::value, + "The first argument must be integral or floating-point"); + static_assert(IsIntlike<T2>::value || std::is_floating_point<T2>::value, + "The second argument must be integral or floating-point"); + return SafeGt(a, b) ? static_cast<R2>(a) : static_cast<R2>(b); +} + +namespace safe_minmax_impl { + +// Given three types T, L, and H, let ::type be a suitable return value for +// SafeClamp(T, L, H). See the docs at the top of this file for details. +template <typename T, + typename L, + typename H, + bool int1 = IsIntlike<T>::value, + bool int2 = IsIntlike<L>::value, + bool int3 = IsIntlike<H>::value> +struct ClampType { + static_assert(int1 == int2 && int1 == int3, + "You may not mix integral and floating-point arguments"); +}; + +// Specialization for when all three types are floating-point. +template <typename T, typename L, typename H> +struct ClampType<T, L, H, false, false, false> { + using type = typename std::common_type<T, L, H>::type; +}; + +// Specialization for when all three types are integral. +template <typename T, typename L, typename H> +struct ClampType<T, L, H, true, true, true> { + private: + // Range of the return value. The return type must be able to represent this + // full range. + static constexpr auto r_min = + SafeMax(Limits<L>::lowest, SafeMin(Limits<H>::lowest, Limits<T>::lowest)); + static constexpr auto r_max = + SafeMin(Limits<H>::max, SafeMax(Limits<L>::max, Limits<T>::max)); + + // Is the given type an acceptable return type? (That is, can it represent + // all possible return values, and is it no larger than the largest of the + // input types?) + template <typename A> + struct AcceptableType { + private: + static constexpr bool not_too_large = sizeof(A) <= sizeof(L) || + sizeof(A) <= sizeof(H) || + sizeof(A) <= sizeof(T); + static constexpr bool range_contained = + SafeLe(Limits<A>::lowest, r_min) && SafeLe(r_max, Limits<A>::max); + + public: + static constexpr bool value = not_too_large && range_contained; + }; + + using best_signed_type = typename std::conditional< + AcceptableType<int8_t>::value, + int8_t, + typename std::conditional< + AcceptableType<int16_t>::value, + int16_t, + typename std::conditional<AcceptableType<int32_t>::value, + int32_t, + int64_t>::type>::type>::type; + + using best_unsigned_type = typename std::conditional< + AcceptableType<uint8_t>::value, + uint8_t, + typename std::conditional< + AcceptableType<uint16_t>::value, + uint16_t, + typename std::conditional<AcceptableType<uint32_t>::value, + uint32_t, + uint64_t>::type>::type>::type; + + public: + // Pick the best type, preferring the same signedness as T but falling back + // to the other one if necessary. + using type = typename std::conditional< + std::is_signed<T>::value, + typename std::conditional<AcceptableType<best_signed_type>::value, + best_signed_type, + best_unsigned_type>::type, + typename std::conditional<AcceptableType<best_unsigned_type>::value, + best_unsigned_type, + best_signed_type>::type>::type; + static_assert(AcceptableType<type>::value, ""); +}; + +} // namespace safe_minmax_impl + +template < + typename R = safe_minmax_impl::DefaultType, + typename T = safe_minmax_impl::DefaultType, + typename L = safe_minmax_impl::DefaultType, + typename H = safe_minmax_impl::DefaultType, + typename R2 = typename safe_minmax_impl::TypeOr< + R, + typename safe_minmax_impl::ClampType< + typename safe_minmax_impl::UnderlyingType<T>::type, + typename safe_minmax_impl::UnderlyingType<L>::type, + typename safe_minmax_impl::UnderlyingType<H>::type>::type>::type> +R2 SafeClamp(T x, L min, H max) { + static_assert(IsIntlike<H>::value || std::is_floating_point<H>::value, + "The first argument must be integral or floating-point"); + static_assert(IsIntlike<T>::value || std::is_floating_point<T>::value, + "The second argument must be integral or floating-point"); + static_assert(IsIntlike<L>::value || std::is_floating_point<L>::value, + "The third argument must be integral or floating-point"); + RTC_DCHECK_LE(min, max); + return SafeLe(x, min) ? static_cast<R2>(min) + : SafeGe(x, max) ? static_cast<R2>(max) + : static_cast<R2>(x); +} + +} // namespace rtc + +#endif // RTC_BASE_NUMERICS_SAFE_MINMAX_H_ diff --git a/third_party/libwebrtc/rtc_base/numerics/safe_minmax_unittest.cc b/third_party/libwebrtc/rtc_base/numerics/safe_minmax_unittest.cc new file mode 100644 index 0000000000..c52b3f93dc --- /dev/null +++ b/third_party/libwebrtc/rtc_base/numerics/safe_minmax_unittest.cc @@ -0,0 +1,345 @@ +/* + * Copyright 2017 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 "rtc_base/numerics/safe_minmax.h" + +#include <algorithm> +#include <limits> + +#include "test/gtest.h" + +namespace rtc { + +namespace { + +// Functions that check that SafeMin(), SafeMax(), and SafeClamp() return the +// specified type. The functions that end in "R" use an explicitly given return +// type. + +template <typename T1, typename T2, typename Tmin, typename Tmax> +constexpr bool TypeCheckMinMax() { + return std::is_same<decltype(SafeMin(std::declval<T1>(), std::declval<T2>())), + Tmin>::value && + std::is_same<decltype(SafeMax(std::declval<T1>(), std::declval<T2>())), + Tmax>::value; +} + +template <typename T1, typename T2, typename R> +constexpr bool TypeCheckMinR() { + return std::is_same< + decltype(SafeMin<R>(std::declval<T1>(), std::declval<T2>())), R>::value; +} + +template <typename T1, typename T2, typename R> +constexpr bool TypeCheckMaxR() { + return std::is_same< + decltype(SafeMax<R>(std::declval<T1>(), std::declval<T2>())), R>::value; +} + +template <typename T, typename L, typename H, typename R> +constexpr bool TypeCheckClamp() { + return std::is_same<decltype(SafeClamp(std::declval<T>(), std::declval<L>(), + std::declval<H>())), + R>::value; +} + +template <typename T, typename L, typename H, typename R> +constexpr bool TypeCheckClampR() { + return std::is_same<decltype(SafeClamp<R>(std::declval<T>(), + std::declval<L>(), + std::declval<H>())), + R>::value; +} + +// clang-format off + +// SafeMin/SafeMax: Check that all combinations of signed/unsigned 8/64 bits +// give the correct default result type. +static_assert(TypeCheckMinMax< int8_t, int8_t, int8_t, int8_t>(), ""); +static_assert(TypeCheckMinMax< int8_t, uint8_t, int8_t, uint8_t>(), ""); +static_assert(TypeCheckMinMax< int8_t, int64_t, int64_t, int64_t>(), ""); +static_assert(TypeCheckMinMax< int8_t, uint64_t, int8_t, uint64_t>(), ""); +static_assert(TypeCheckMinMax< uint8_t, int8_t, int8_t, uint8_t>(), ""); +static_assert(TypeCheckMinMax< uint8_t, uint8_t, uint8_t, uint8_t>(), ""); +static_assert(TypeCheckMinMax< uint8_t, int64_t, int64_t, int64_t>(), ""); +static_assert(TypeCheckMinMax< uint8_t, uint64_t, uint8_t, uint64_t>(), ""); +static_assert(TypeCheckMinMax< int64_t, int8_t, int64_t, int64_t>(), ""); +static_assert(TypeCheckMinMax< int64_t, uint8_t, int64_t, int64_t>(), ""); +static_assert(TypeCheckMinMax< int64_t, int64_t, int64_t, int64_t>(), ""); +static_assert(TypeCheckMinMax< int64_t, uint64_t, int64_t, uint64_t>(), ""); +static_assert(TypeCheckMinMax<uint64_t, int8_t, int8_t, uint64_t>(), ""); +static_assert(TypeCheckMinMax<uint64_t, uint8_t, uint8_t, uint64_t>(), ""); +static_assert(TypeCheckMinMax<uint64_t, int64_t, int64_t, uint64_t>(), ""); +static_assert(TypeCheckMinMax<uint64_t, uint64_t, uint64_t, uint64_t>(), ""); + +// SafeClamp: Check that all combinations of signed/unsigned 8/64 bits give the +// correct result type. +static_assert(TypeCheckClamp< int8_t, int8_t, int8_t, int8_t>(), ""); +static_assert(TypeCheckClamp< int8_t, int8_t, uint8_t, int8_t>(), ""); +static_assert(TypeCheckClamp< int8_t, int8_t, int64_t, int8_t>(), ""); +static_assert(TypeCheckClamp< int8_t, int8_t, uint64_t, int8_t>(), ""); +static_assert(TypeCheckClamp< int8_t, uint8_t, int8_t, int8_t>(), ""); +static_assert(TypeCheckClamp< int8_t, uint8_t, uint8_t, uint8_t>(), ""); +static_assert(TypeCheckClamp< int8_t, uint8_t, int64_t, int16_t>(), ""); +static_assert(TypeCheckClamp< int8_t, uint8_t, uint64_t, int16_t>(), ""); +static_assert(TypeCheckClamp< int8_t, int64_t, int8_t, int8_t>(), ""); +static_assert(TypeCheckClamp< int8_t, int64_t, uint8_t, int16_t>(), ""); +static_assert(TypeCheckClamp< int8_t, int64_t, int64_t, int64_t>(), ""); +static_assert(TypeCheckClamp< int8_t, int64_t, uint64_t, int64_t>(), ""); +static_assert(TypeCheckClamp< int8_t, uint64_t, int8_t, int8_t>(), ""); +static_assert(TypeCheckClamp< int8_t, uint64_t, uint8_t, int16_t>(), ""); +static_assert(TypeCheckClamp< int8_t, uint64_t, int64_t, int64_t>(), ""); +static_assert(TypeCheckClamp< int8_t, uint64_t, uint64_t, uint64_t>(), ""); +static_assert(TypeCheckClamp< uint8_t, int8_t, int8_t, int8_t>(), ""); +static_assert(TypeCheckClamp< uint8_t, int8_t, uint8_t, uint8_t>(), ""); +static_assert(TypeCheckClamp< uint8_t, int8_t, int64_t, int16_t>(), ""); +static_assert(TypeCheckClamp< uint8_t, int8_t, uint64_t, uint8_t>(), ""); +static_assert(TypeCheckClamp< uint8_t, uint8_t, int8_t, uint8_t>(), ""); +static_assert(TypeCheckClamp< uint8_t, uint8_t, uint8_t, uint8_t>(), ""); +static_assert(TypeCheckClamp< uint8_t, uint8_t, int64_t, uint8_t>(), ""); +static_assert(TypeCheckClamp< uint8_t, uint8_t, uint64_t, uint8_t>(), ""); +static_assert(TypeCheckClamp< uint8_t, int64_t, int8_t, int8_t>(), ""); +static_assert(TypeCheckClamp< uint8_t, int64_t, uint8_t, uint8_t>(), ""); +static_assert(TypeCheckClamp< uint8_t, int64_t, int64_t, int64_t>(), ""); +static_assert(TypeCheckClamp< uint8_t, int64_t, uint64_t, uint64_t>(), ""); +static_assert(TypeCheckClamp< uint8_t, uint64_t, int8_t, uint8_t>(), ""); +static_assert(TypeCheckClamp< uint8_t, uint64_t, uint8_t, uint8_t>(), ""); +static_assert(TypeCheckClamp< uint8_t, uint64_t, int64_t, uint64_t>(), ""); +static_assert(TypeCheckClamp< uint8_t, uint64_t, uint64_t, uint64_t>(), ""); +static_assert(TypeCheckClamp< int64_t, int8_t, int8_t, int8_t>(), ""); +static_assert(TypeCheckClamp< int64_t, int8_t, uint8_t, int16_t>(), ""); +static_assert(TypeCheckClamp< int64_t, int8_t, int64_t, int64_t>(), ""); +static_assert(TypeCheckClamp< int64_t, int8_t, uint64_t, int64_t>(), ""); +static_assert(TypeCheckClamp< int64_t, uint8_t, int8_t, int8_t>(), ""); +static_assert(TypeCheckClamp< int64_t, uint8_t, uint8_t, int16_t>(), ""); +static_assert(TypeCheckClamp< int64_t, uint8_t, int64_t, int64_t>(), ""); +static_assert(TypeCheckClamp< int64_t, uint8_t, uint64_t, int64_t>(), ""); +static_assert(TypeCheckClamp< int64_t, int64_t, int8_t, int64_t>(), ""); +static_assert(TypeCheckClamp< int64_t, int64_t, uint8_t, int64_t>(), ""); +static_assert(TypeCheckClamp< int64_t, int64_t, int64_t, int64_t>(), ""); +static_assert(TypeCheckClamp< int64_t, int64_t, uint64_t, int64_t>(), ""); +static_assert(TypeCheckClamp< int64_t, uint64_t, int8_t, int8_t>(), ""); +static_assert(TypeCheckClamp< int64_t, uint64_t, uint8_t, int16_t>(), ""); +static_assert(TypeCheckClamp< int64_t, uint64_t, int64_t, int64_t>(), ""); +static_assert(TypeCheckClamp< int64_t, uint64_t, uint64_t, uint64_t>(), ""); +static_assert(TypeCheckClamp<uint64_t, int8_t, int8_t, int8_t>(), ""); +static_assert(TypeCheckClamp<uint64_t, int8_t, uint8_t, uint8_t>(), ""); +static_assert(TypeCheckClamp<uint64_t, int8_t, int64_t, int64_t>(), ""); +static_assert(TypeCheckClamp<uint64_t, int8_t, uint64_t, uint64_t>(), ""); +static_assert(TypeCheckClamp<uint64_t, uint8_t, int8_t, uint8_t>(), ""); +static_assert(TypeCheckClamp<uint64_t, uint8_t, uint8_t, uint8_t>(), ""); +static_assert(TypeCheckClamp<uint64_t, uint8_t, int64_t, uint64_t>(), ""); +static_assert(TypeCheckClamp<uint64_t, uint8_t, uint64_t, uint64_t>(), ""); +static_assert(TypeCheckClamp<uint64_t, int64_t, int8_t, int8_t>(), ""); +static_assert(TypeCheckClamp<uint64_t, int64_t, uint8_t, uint8_t>(), ""); +static_assert(TypeCheckClamp<uint64_t, int64_t, int64_t, int64_t>(), ""); +static_assert(TypeCheckClamp<uint64_t, int64_t, uint64_t, uint64_t>(), ""); +static_assert(TypeCheckClamp<uint64_t, uint64_t, int8_t, uint8_t>(), ""); +static_assert(TypeCheckClamp<uint64_t, uint64_t, uint8_t, uint8_t>(), ""); +static_assert(TypeCheckClamp<uint64_t, uint64_t, int64_t, uint64_t>(), ""); +static_assert(TypeCheckClamp<uint64_t, uint64_t, uint64_t, uint64_t>(), ""); + +enum DefaultE { kFoo = -17 }; +enum UInt8E : uint8_t { kBar = 17 }; + +// SafeMin/SafeMax: Check that we can use enum types. +static_assert(TypeCheckMinMax<unsigned, unsigned, unsigned, unsigned>(), ""); +static_assert(TypeCheckMinMax<unsigned, DefaultE, int, unsigned>(), ""); +static_assert(TypeCheckMinMax<unsigned, UInt8E, uint8_t, unsigned>(), ""); +static_assert(TypeCheckMinMax<DefaultE, unsigned, int, unsigned>(), ""); +static_assert(TypeCheckMinMax<DefaultE, DefaultE, int, int>(), ""); +static_assert(TypeCheckMinMax<DefaultE, UInt8E, int, int>(), ""); +static_assert(TypeCheckMinMax< UInt8E, unsigned, uint8_t, unsigned>(), ""); +static_assert(TypeCheckMinMax< UInt8E, DefaultE, int, int>(), ""); +static_assert(TypeCheckMinMax< UInt8E, UInt8E, uint8_t, uint8_t>(), ""); + +// SafeClamp: Check that we can use enum types. +static_assert(TypeCheckClamp<unsigned, unsigned, unsigned, unsigned>(), ""); +static_assert(TypeCheckClamp<unsigned, unsigned, DefaultE, unsigned>(), ""); +static_assert(TypeCheckClamp<unsigned, unsigned, UInt8E, uint8_t>(), ""); +static_assert(TypeCheckClamp<unsigned, DefaultE, unsigned, unsigned>(), ""); +static_assert(TypeCheckClamp<unsigned, DefaultE, DefaultE, int>(), ""); +static_assert(TypeCheckClamp<unsigned, DefaultE, UInt8E, uint8_t>(), ""); +static_assert(TypeCheckClamp<unsigned, UInt8E, unsigned, unsigned>(), ""); +static_assert(TypeCheckClamp<unsigned, UInt8E, DefaultE, unsigned>(), ""); +static_assert(TypeCheckClamp<unsigned, UInt8E, UInt8E, uint8_t>(), ""); +static_assert(TypeCheckClamp<DefaultE, unsigned, unsigned, unsigned>(), ""); +static_assert(TypeCheckClamp<DefaultE, unsigned, DefaultE, int>(), ""); +static_assert(TypeCheckClamp<DefaultE, unsigned, UInt8E, int16_t>(), ""); +static_assert(TypeCheckClamp<DefaultE, DefaultE, unsigned, int>(), ""); +static_assert(TypeCheckClamp<DefaultE, DefaultE, DefaultE, int>(), ""); +static_assert(TypeCheckClamp<DefaultE, DefaultE, UInt8E, int>(), ""); +static_assert(TypeCheckClamp<DefaultE, UInt8E, unsigned, int>(), ""); +static_assert(TypeCheckClamp<DefaultE, UInt8E, DefaultE, int>(), ""); +static_assert(TypeCheckClamp<DefaultE, UInt8E, UInt8E, int16_t>(), ""); +static_assert(TypeCheckClamp< UInt8E, unsigned, unsigned, unsigned>(), ""); +static_assert(TypeCheckClamp< UInt8E, unsigned, DefaultE, unsigned>(), ""); +static_assert(TypeCheckClamp< UInt8E, unsigned, UInt8E, uint8_t>(), ""); +static_assert(TypeCheckClamp< UInt8E, DefaultE, unsigned, unsigned>(), ""); +static_assert(TypeCheckClamp< UInt8E, DefaultE, DefaultE, int>(), ""); +static_assert(TypeCheckClamp< UInt8E, DefaultE, UInt8E, uint8_t>(), ""); +static_assert(TypeCheckClamp< UInt8E, UInt8E, unsigned, uint8_t>(), ""); +static_assert(TypeCheckClamp< UInt8E, UInt8E, DefaultE, uint8_t>(), ""); +static_assert(TypeCheckClamp< UInt8E, UInt8E, UInt8E, uint8_t>(), ""); + +using ld = long double; + +// SafeMin/SafeMax: Check that all floating-point combinations give the +// correct result type. +static_assert(TypeCheckMinMax< float, float, float, float>(), ""); +static_assert(TypeCheckMinMax< float, double, double, double>(), ""); +static_assert(TypeCheckMinMax< float, ld, ld, ld>(), ""); +static_assert(TypeCheckMinMax<double, float, double, double>(), ""); +static_assert(TypeCheckMinMax<double, double, double, double>(), ""); +static_assert(TypeCheckMinMax<double, ld, ld, ld>(), ""); +static_assert(TypeCheckMinMax< ld, float, ld, ld>(), ""); +static_assert(TypeCheckMinMax< ld, double, ld, ld>(), ""); +static_assert(TypeCheckMinMax< ld, ld, ld, ld>(), ""); + +// SafeClamp: Check that all floating-point combinations give the correct +// result type. +static_assert(TypeCheckClamp< float, float, float, float>(), ""); +static_assert(TypeCheckClamp< float, float, double, double>(), ""); +static_assert(TypeCheckClamp< float, float, ld, ld>(), ""); +static_assert(TypeCheckClamp< float, double, float, double>(), ""); +static_assert(TypeCheckClamp< float, double, double, double>(), ""); +static_assert(TypeCheckClamp< float, double, ld, ld>(), ""); +static_assert(TypeCheckClamp< float, ld, float, ld>(), ""); +static_assert(TypeCheckClamp< float, ld, double, ld>(), ""); +static_assert(TypeCheckClamp< float, ld, ld, ld>(), ""); +static_assert(TypeCheckClamp<double, float, float, double>(), ""); +static_assert(TypeCheckClamp<double, float, double, double>(), ""); +static_assert(TypeCheckClamp<double, float, ld, ld>(), ""); +static_assert(TypeCheckClamp<double, double, float, double>(), ""); +static_assert(TypeCheckClamp<double, double, double, double>(), ""); +static_assert(TypeCheckClamp<double, double, ld, ld>(), ""); +static_assert(TypeCheckClamp<double, ld, float, ld>(), ""); +static_assert(TypeCheckClamp<double, ld, double, ld>(), ""); +static_assert(TypeCheckClamp<double, ld, ld, ld>(), ""); +static_assert(TypeCheckClamp< ld, float, float, ld>(), ""); +static_assert(TypeCheckClamp< ld, float, double, ld>(), ""); +static_assert(TypeCheckClamp< ld, float, ld, ld>(), ""); +static_assert(TypeCheckClamp< ld, double, float, ld>(), ""); +static_assert(TypeCheckClamp< ld, double, double, ld>(), ""); +static_assert(TypeCheckClamp< ld, double, ld, ld>(), ""); +static_assert(TypeCheckClamp< ld, ld, float, ld>(), ""); +static_assert(TypeCheckClamp< ld, ld, double, ld>(), ""); +static_assert(TypeCheckClamp< ld, ld, ld, ld>(), ""); + +// clang-format on + +// SafeMin/SafeMax: Check some cases of explicitly specified return type. The +// commented-out lines give compilation errors due to the requested return type +// being too small or requiring an int<->float conversion. +static_assert(TypeCheckMinR<int8_t, int8_t, int16_t>(), ""); +// static_assert(TypeCheckMinR<int8_t, int8_t, float>(), ""); +static_assert(TypeCheckMinR<uint32_t, uint64_t, uint32_t>(), ""); +// static_assert(TypeCheckMaxR<uint64_t, float, float>(), ""); +// static_assert(TypeCheckMaxR<uint64_t, double, float>(), ""); +static_assert(TypeCheckMaxR<uint32_t, int32_t, uint32_t>(), ""); +// static_assert(TypeCheckMaxR<uint32_t, int32_t, int32_t>(), ""); + +// SafeClamp: Check some cases of explicitly specified return type. The +// commented-out lines give compilation errors due to the requested return type +// being too small. +static_assert(TypeCheckClampR<int16_t, int8_t, uint8_t, int16_t>(), ""); +static_assert(TypeCheckClampR<int16_t, int8_t, uint8_t, int32_t>(), ""); +// static_assert(TypeCheckClampR<int16_t, int8_t, uint8_t, uint32_t>(), ""); + +template <typename T1, typename T2, typename Tmin, typename Tmax> +constexpr bool CheckMinMax(T1 a, T2 b, Tmin min, Tmax max) { + return TypeCheckMinMax<T1, T2, Tmin, Tmax>() && SafeMin(a, b) == min && + SafeMax(a, b) == max; +} + +template <typename T, typename L, typename H, typename R> +bool CheckClamp(T x, L min, H max, R clamped) { + return TypeCheckClamp<T, L, H, R>() && SafeClamp(x, min, max) == clamped; +} + +// SafeMin/SafeMax: Check a few values. +static_assert(CheckMinMax(int8_t{1}, int8_t{-1}, int8_t{-1}, int8_t{1}), ""); +static_assert(CheckMinMax(uint8_t{1}, int8_t{-1}, int8_t{-1}, uint8_t{1}), ""); +static_assert(CheckMinMax(uint8_t{5}, uint64_t{2}, uint8_t{2}, uint64_t{5}), + ""); +static_assert(CheckMinMax(std::numeric_limits<int32_t>::min(), + std::numeric_limits<uint32_t>::max(), + std::numeric_limits<int32_t>::min(), + std::numeric_limits<uint32_t>::max()), + ""); +static_assert(CheckMinMax(std::numeric_limits<int32_t>::min(), + std::numeric_limits<uint16_t>::max(), + std::numeric_limits<int32_t>::min(), + int32_t{std::numeric_limits<uint16_t>::max()}), + ""); +// static_assert(CheckMinMax(1.f, 2, 1.f, 2.f), ""); +static_assert(CheckMinMax(1.f, 0.0, 0.0, 1.0), ""); + +// SafeClamp: Check a few values. +TEST(SafeMinmaxTest, Clamp) { + EXPECT_TRUE(CheckClamp(int32_t{-1000000}, std::numeric_limits<int16_t>::min(), + std::numeric_limits<int16_t>::max(), + std::numeric_limits<int16_t>::min())); + EXPECT_TRUE(CheckClamp(uint32_t{1000000}, std::numeric_limits<int16_t>::min(), + std::numeric_limits<int16_t>::max(), + std::numeric_limits<int16_t>::max())); + EXPECT_TRUE(CheckClamp(3.f, -1.0, 1.f, 1.0)); + EXPECT_TRUE(CheckClamp(3.0, -1.f, 1.f, 1.0)); +} + +} // namespace + +// These functions aren't used in the tests, but it's useful to look at the +// compiler output for them, and verify that (1) the same-signedness Test*Safe +// functions result in exactly the same code as their Test*Ref counterparts, +// and that (2) the mixed-signedness Test*Safe functions have just a few extra +// arithmetic and logic instructions (but no extra control flow instructions). + +// clang-format off +int32_t TestMinRef( int32_t a, int32_t b) { return std::min(a, b); } +uint32_t TestMinRef( uint32_t a, uint32_t b) { return std::min(a, b); } +int32_t TestMinSafe( int32_t a, int32_t b) { return SafeMin(a, b); } +int32_t TestMinSafe( int32_t a, uint32_t b) { return SafeMin(a, b); } +int32_t TestMinSafe(uint32_t a, int32_t b) { return SafeMin(a, b); } +uint32_t TestMinSafe(uint32_t a, uint32_t b) { return SafeMin(a, b); } +// clang-format on + +int32_t TestClampRef(int32_t x, int32_t a, int32_t b) { + return std::max(a, std::min(x, b)); +} +uint32_t TestClampRef(uint32_t x, uint32_t a, uint32_t b) { + return std::max(a, std::min(x, b)); +} +int32_t TestClampSafe(int32_t x, int32_t a, int32_t b) { + return SafeClamp(x, a, b); +} +int32_t TestClampSafe(int32_t x, int32_t a, uint32_t b) { + return SafeClamp(x, a, b); +} +int32_t TestClampSafe(int32_t x, uint32_t a, int32_t b) { + return SafeClamp(x, a, b); +} +uint32_t TestClampSafe(int32_t x, uint32_t a, uint32_t b) { + return SafeClamp(x, a, b); +} +int32_t TestClampSafe(uint32_t x, int32_t a, int32_t b) { + return SafeClamp(x, a, b); +} +uint32_t TestClampSafe(uint32_t x, int32_t a, uint32_t b) { + return SafeClamp(x, a, b); +} +int32_t TestClampSafe(uint32_t x, uint32_t a, int32_t b) { + return SafeClamp(x, a, b); +} +uint32_t TestClampSafe(uint32_t x, uint32_t a, uint32_t b) { + return SafeClamp(x, a, b); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/numerics/sample_counter.cc b/third_party/libwebrtc/rtc_base/numerics/sample_counter.cc new file mode 100644 index 0000000000..78e35fdb5b --- /dev/null +++ b/third_party/libwebrtc/rtc_base/numerics/sample_counter.cc @@ -0,0 +1,118 @@ +/* + * 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 "rtc_base/numerics/sample_counter.h" + +#include <limits> + +#include "rtc_base/checks.h" +#include "rtc_base/numerics/safe_conversions.h" + +namespace rtc { + +SampleCounter::SampleCounter() = default; +SampleCounter::~SampleCounter() = default; + +void SampleCounter::Add(int sample) { + if (sum_ > 0) { + RTC_DCHECK_LE(sample, std::numeric_limits<int64_t>::max() - sum_); + } else { + RTC_DCHECK_GE(sample, std::numeric_limits<int64_t>::min() - sum_); + } + sum_ += sample; + ++num_samples_; + if (!max_ || sample > *max_) { + max_ = sample; + } + if (!min_ || sample < *min_) { + min_ = sample; + } +} + +void SampleCounter::Add(const SampleCounter& other) { + if (sum_ > 0) { + RTC_DCHECK_LE(other.sum_, std::numeric_limits<int64_t>::max() - sum_); + } else { + RTC_DCHECK_GE(other.sum_, std::numeric_limits<int64_t>::min() - sum_); + } + sum_ += other.sum_; + RTC_DCHECK_LE(other.num_samples_, + std::numeric_limits<int64_t>::max() - num_samples_); + num_samples_ += other.num_samples_; + if (other.max_ && (!max_ || *max_ < *other.max_)) + max_ = other.max_; + if (other.min_ && (!min_ || *min_ > *other.min_)) + min_ = other.min_; +} + +absl::optional<int> SampleCounter::Avg(int64_t min_required_samples) const { + RTC_DCHECK_GT(min_required_samples, 0); + if (num_samples_ < min_required_samples) + return absl::nullopt; + return rtc::dchecked_cast<int>(sum_ / num_samples_); +} + +absl::optional<int> SampleCounter::Max() const { + return max_; +} + +absl::optional<int> SampleCounter::Min() const { + return min_; +} + +absl::optional<int64_t> SampleCounter::Sum(int64_t min_required_samples) const { + RTC_DCHECK_GT(min_required_samples, 0); + if (num_samples_ < min_required_samples) + return absl::nullopt; + return sum_; +} + +int64_t SampleCounter::NumSamples() const { + return num_samples_; +} + +void SampleCounter::Reset() { + *this = {}; +} + +SampleCounterWithVariance::SampleCounterWithVariance() = default; +SampleCounterWithVariance::~SampleCounterWithVariance() = default; + +absl::optional<int64_t> SampleCounterWithVariance::Variance( + int64_t min_required_samples) const { + RTC_DCHECK_GT(min_required_samples, 0); + if (num_samples_ < min_required_samples) + return absl::nullopt; + // E[(x-mean)^2] = E[x^2] - mean^2 + int64_t mean = sum_ / num_samples_; + return sum_squared_ / num_samples_ - mean * mean; +} + +void SampleCounterWithVariance::Add(int sample) { + SampleCounter::Add(sample); + // Prevent overflow in squaring. + RTC_DCHECK_GT(sample, std::numeric_limits<int32_t>::min()); + RTC_DCHECK_LE(int64_t{sample} * sample, + std::numeric_limits<int64_t>::max() - sum_squared_); + sum_squared_ += int64_t{sample} * sample; +} + +void SampleCounterWithVariance::Add(const SampleCounterWithVariance& other) { + SampleCounter::Add(other); + RTC_DCHECK_LE(other.sum_squared_, + std::numeric_limits<int64_t>::max() - sum_squared_); + sum_squared_ += other.sum_squared_; +} + +void SampleCounterWithVariance::Reset() { + *this = {}; +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/numerics/sample_counter.h b/third_party/libwebrtc/rtc_base/numerics/sample_counter.h new file mode 100644 index 0000000000..2b41f95fc0 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/numerics/sample_counter.h @@ -0,0 +1,60 @@ +/* + * 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 RTC_BASE_NUMERICS_SAMPLE_COUNTER_H_ +#define RTC_BASE_NUMERICS_SAMPLE_COUNTER_H_ + +#include <stdint.h> + +#include "absl/types/optional.h" + +namespace rtc { + +// Simple utility class for counting basic statistics (max./avg./variance) on +// stream of samples. +class SampleCounter { + public: + SampleCounter(); + ~SampleCounter(); + void Add(int sample); + absl::optional<int> Avg(int64_t min_required_samples) const; + absl::optional<int> Max() const; + absl::optional<int> Min() const; + absl::optional<int64_t> Sum(int64_t min_required_samples) const; + int64_t NumSamples() const; + void Reset(); + // Adds all the samples from the `other` SampleCounter as if they were all + // individually added using `Add(int)` method. + void Add(const SampleCounter& other); + + protected: + int64_t sum_ = 0; + int64_t num_samples_ = 0; + absl::optional<int> max_; + absl::optional<int> min_; +}; + +class SampleCounterWithVariance : public SampleCounter { + public: + SampleCounterWithVariance(); + ~SampleCounterWithVariance(); + void Add(int sample); + absl::optional<int64_t> Variance(int64_t min_required_samples) const; + void Reset(); + // Adds all the samples from the `other` SampleCounter as if they were all + // individually added using `Add(int)` method. + void Add(const SampleCounterWithVariance& other); + + private: + int64_t sum_squared_ = 0; +}; + +} // namespace rtc +#endif // RTC_BASE_NUMERICS_SAMPLE_COUNTER_H_ diff --git a/third_party/libwebrtc/rtc_base/numerics/sample_counter_unittest.cc b/third_party/libwebrtc/rtc_base/numerics/sample_counter_unittest.cc new file mode 100644 index 0000000000..ffc8b89f6f --- /dev/null +++ b/third_party/libwebrtc/rtc_base/numerics/sample_counter_unittest.cc @@ -0,0 +1,84 @@ +/* + * 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. + */ + +#include "rtc_base/numerics/sample_counter.h" + +#include <initializer_list> + +#include "test/gmock.h" +#include "test/gtest.h" + +using ::testing::Eq; + +namespace rtc { + +TEST(SampleCounterTest, ProcessesNoSamples) { + constexpr int kMinSamples = 1; + SampleCounter counter; + EXPECT_THAT(counter.Avg(kMinSamples), Eq(absl::nullopt)); + EXPECT_THAT(counter.Max(), Eq(absl::nullopt)); + EXPECT_THAT(counter.Min(), Eq(absl::nullopt)); +} + +TEST(SampleCounterTest, NotEnoughSamples) { + constexpr int kMinSamples = 6; + SampleCounter counter; + for (int value : {1, 2, 3, 4, 5}) { + counter.Add(value); + } + EXPECT_THAT(counter.Avg(kMinSamples), Eq(absl::nullopt)); + EXPECT_THAT(counter.Sum(kMinSamples), Eq(absl::nullopt)); + EXPECT_THAT(counter.Max(), Eq(5)); + EXPECT_THAT(counter.Min(), Eq(1)); +} + +TEST(SampleCounterTest, EnoughSamples) { + constexpr int kMinSamples = 5; + SampleCounter counter; + for (int value : {1, 2, 3, 4, 5}) { + counter.Add(value); + } + EXPECT_THAT(counter.Avg(kMinSamples), Eq(3)); + EXPECT_THAT(counter.Sum(kMinSamples), Eq(15)); + EXPECT_THAT(counter.Max(), Eq(5)); + EXPECT_THAT(counter.Min(), Eq(1)); +} + +TEST(SampleCounterTest, ComputesVariance) { + constexpr int kMinSamples = 5; + SampleCounterWithVariance counter; + for (int value : {1, 2, 3, 4, 5}) { + counter.Add(value); + } + EXPECT_THAT(counter.Variance(kMinSamples), Eq(2)); +} + +TEST(SampleCounterTest, AggregatesTwoCounters) { + constexpr int kMinSamples = 5; + SampleCounterWithVariance counter1; + for (int value : {1, 2, 3}) { + counter1.Add(value); + } + SampleCounterWithVariance counter2; + for (int value : {4, 5}) { + counter2.Add(value); + } + // Before aggregation there is not enough samples. + EXPECT_THAT(counter1.Avg(kMinSamples), Eq(absl::nullopt)); + EXPECT_THAT(counter1.Variance(kMinSamples), Eq(absl::nullopt)); + // Aggregate counter2 in counter1. + counter1.Add(counter2); + EXPECT_THAT(counter1.Avg(kMinSamples), Eq(3)); + EXPECT_THAT(counter1.Max(), Eq(5)); + EXPECT_THAT(counter1.Min(), Eq(1)); + EXPECT_THAT(counter1.Variance(kMinSamples), Eq(2)); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/numerics/sample_stats.cc b/third_party/libwebrtc/rtc_base/numerics/sample_stats.cc new file mode 100644 index 0000000000..6000b2b88f --- /dev/null +++ b/third_party/libwebrtc/rtc_base/numerics/sample_stats.cc @@ -0,0 +1,152 @@ +/* + * 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. + */ +#include "rtc_base/numerics/sample_stats.h" + +namespace webrtc { + +double SampleStats<double>::Max() { + if (IsEmpty()) + return INFINITY; + return GetMax(); +} + +double SampleStats<double>::Mean() { + if (IsEmpty()) + return 0; + return GetAverage(); +} + +double SampleStats<double>::Median() { + return Quantile(0.5); +} + +double SampleStats<double>::Quantile(double quantile) { + if (IsEmpty()) + return 0; + return GetPercentile(quantile); +} + +double SampleStats<double>::Min() { + if (IsEmpty()) + return -INFINITY; + return GetMin(); +} + +double SampleStats<double>::Variance() { + if (IsEmpty()) + return 0; + return GetVariance(); +} + +double SampleStats<double>::StandardDeviation() { + return sqrt(Variance()); +} + +int SampleStats<double>::Count() { + return static_cast<int>(GetSamples().size()); +} + +void SampleStats<TimeDelta>::AddSample(TimeDelta delta) { + RTC_DCHECK(delta.IsFinite()); + stats_.AddSample(delta.seconds<double>()); +} + +void SampleStats<TimeDelta>::AddSampleMs(double delta_ms) { + AddSample(TimeDelta::Millis(delta_ms)); +} +void SampleStats<TimeDelta>::AddSamples(const SampleStats<TimeDelta>& other) { + stats_.AddSamples(other.stats_); +} + +bool SampleStats<TimeDelta>::IsEmpty() { + return stats_.IsEmpty(); +} + +TimeDelta SampleStats<TimeDelta>::Max() { + return TimeDelta::Seconds(stats_.Max()); +} + +TimeDelta SampleStats<TimeDelta>::Mean() { + return TimeDelta::Seconds(stats_.Mean()); +} + +TimeDelta SampleStats<TimeDelta>::Median() { + return Quantile(0.5); +} + +TimeDelta SampleStats<TimeDelta>::Quantile(double quantile) { + return TimeDelta::Seconds(stats_.Quantile(quantile)); +} + +TimeDelta SampleStats<TimeDelta>::Min() { + return TimeDelta::Seconds(stats_.Min()); +} + +TimeDelta SampleStats<TimeDelta>::Variance() { + return TimeDelta::Seconds(stats_.Variance()); +} + +TimeDelta SampleStats<TimeDelta>::StandardDeviation() { + return TimeDelta::Seconds(stats_.StandardDeviation()); +} + +int SampleStats<TimeDelta>::Count() { + return stats_.Count(); +} + +void SampleStats<DataRate>::AddSample(DataRate sample) { + stats_.AddSample(sample.bps<double>()); +} + +void SampleStats<DataRate>::AddSampleBps(double rate_bps) { + stats_.AddSample(rate_bps); +} + +void SampleStats<DataRate>::AddSamples(const SampleStats<DataRate>& other) { + stats_.AddSamples(other.stats_); +} + +bool SampleStats<DataRate>::IsEmpty() { + return stats_.IsEmpty(); +} + +DataRate SampleStats<DataRate>::Max() { + return DataRate::BitsPerSec(stats_.Max()); +} + +DataRate SampleStats<DataRate>::Mean() { + return DataRate::BitsPerSec(stats_.Mean()); +} + +DataRate SampleStats<DataRate>::Median() { + return Quantile(0.5); +} + +DataRate SampleStats<DataRate>::Quantile(double quantile) { + return DataRate::BitsPerSec(stats_.Quantile(quantile)); +} + +DataRate SampleStats<DataRate>::Min() { + return DataRate::BitsPerSec(stats_.Min()); +} + +DataRate SampleStats<DataRate>::Variance() { + return DataRate::BitsPerSec(stats_.Variance()); +} + +DataRate SampleStats<DataRate>::StandardDeviation() { + return DataRate::BitsPerSec(stats_.StandardDeviation()); +} + +int SampleStats<DataRate>::Count() { + return stats_.Count(); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/numerics/sample_stats.h b/third_party/libwebrtc/rtc_base/numerics/sample_stats.h new file mode 100644 index 0000000000..39af1c6a37 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/numerics/sample_stats.h @@ -0,0 +1,77 @@ +/* + * 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 RTC_BASE_NUMERICS_SAMPLE_STATS_H_ +#define RTC_BASE_NUMERICS_SAMPLE_STATS_H_ + +#include "api/numerics/samples_stats_counter.h" +#include "api/units/data_rate.h" +#include "api/units/time_delta.h" +#include "api/units/timestamp.h" + +namespace webrtc { +template <typename T> +class SampleStats; + +// TODO(srte): Merge this implementation with SamplesStatsCounter. +template <> +class SampleStats<double> : public SamplesStatsCounter { + public: + double Max(); + double Mean(); + double Median(); + double Quantile(double quantile); + double Min(); + double Variance(); + double StandardDeviation(); + int Count(); +}; + +template <> +class SampleStats<TimeDelta> { + public: + void AddSample(TimeDelta delta); + void AddSampleMs(double delta_ms); + void AddSamples(const SampleStats<TimeDelta>& other); + bool IsEmpty(); + TimeDelta Max(); + TimeDelta Mean(); + TimeDelta Median(); + TimeDelta Quantile(double quantile); + TimeDelta Min(); + TimeDelta Variance(); + TimeDelta StandardDeviation(); + int Count(); + + private: + SampleStats<double> stats_; +}; + +template <> +class SampleStats<DataRate> { + public: + void AddSample(DataRate rate); + void AddSampleBps(double rate_bps); + void AddSamples(const SampleStats<DataRate>& other); + bool IsEmpty(); + DataRate Max(); + DataRate Mean(); + DataRate Median(); + DataRate Quantile(double quantile); + DataRate Min(); + DataRate Variance(); + DataRate StandardDeviation(); + int Count(); + + private: + SampleStats<double> stats_; +}; +} // namespace webrtc + +#endif // RTC_BASE_NUMERICS_SAMPLE_STATS_H_ diff --git a/third_party/libwebrtc/rtc_base/numerics/sequence_number_unwrapper.h b/third_party/libwebrtc/rtc_base/numerics/sequence_number_unwrapper.h new file mode 100644 index 0000000000..d741b5c910 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/numerics/sequence_number_unwrapper.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2022 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 RTC_BASE_NUMERICS_SEQUENCE_NUMBER_UNWRAPPER_H_ +#define RTC_BASE_NUMERICS_SEQUENCE_NUMBER_UNWRAPPER_H_ + +#include <stdint.h> + +#include <limits> + +#include "absl/types/optional.h" +#include "rtc_base/numerics/sequence_number_util.h" + +namespace webrtc { + +// A sequence number unwrapper where the first unwrapped value equals the +// first value being unwrapped. +template <typename T, T M = 0> +class SeqNumUnwrapper { + static_assert( + std::is_unsigned<T>::value && + std::numeric_limits<T>::max() < std::numeric_limits<int64_t>::max(), + "Type unwrapped must be an unsigned integer smaller than int64_t."); + + public: + // Unwraps `value` and updates the internal state of the unwrapper. + int64_t Unwrap(T value) { + if (!last_value_) { + last_unwrapped_ = {value}; + } else { + last_unwrapped_ += Delta(*last_value_, value); + } + + last_value_ = value; + return last_unwrapped_; + } + + // Returns the `value` without updating the internal state of the unwrapper. + int64_t PeekUnwrap(T value) const { + if (!last_value_) { + return value; + } + return last_unwrapped_ + Delta(*last_value_, value); + } + + // Resets the unwrapper to its initial state. Unwrapped sequence numbers will + // being at 0 after resetting. + void Reset() { + last_unwrapped_ = 0; + last_value_.reset(); + } + + private: + static int64_t Delta(T last_value, T new_value) { + constexpr int64_t kBackwardAdjustment = + M == 0 ? int64_t{std::numeric_limits<T>::max()} + 1 : M; + int64_t result = ForwardDiff<T, M>(last_value, new_value); + if (!AheadOrAt<T, M>(new_value, last_value)) { + result -= kBackwardAdjustment; + } + return result; + } + + int64_t last_unwrapped_ = 0; + absl::optional<T> last_value_; +}; + +using RtpTimestampUnwrapper = SeqNumUnwrapper<uint32_t>; +using RtpSequenceNumberUnwrapper = SeqNumUnwrapper<uint16_t>; + +} // namespace webrtc + +#endif // RTC_BASE_NUMERICS_SEQUENCE_NUMBER_UNWRAPPER_H_ diff --git a/third_party/libwebrtc/rtc_base/numerics/sequence_number_unwrapper_unittest.cc b/third_party/libwebrtc/rtc_base/numerics/sequence_number_unwrapper_unittest.cc new file mode 100644 index 0000000000..fcd903bab4 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/numerics/sequence_number_unwrapper_unittest.cc @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2022 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 "rtc_base/numerics/sequence_number_unwrapper.h" + +#include <cstdint> + +#include "test/gtest.h" + +namespace webrtc { + +TEST(SeqNumUnwrapper, PreserveStartValue) { + SeqNumUnwrapper<uint8_t> unwrapper; + EXPECT_EQ(123, unwrapper.Unwrap(123)); +} + +TEST(SeqNumUnwrapper, ForwardWrap) { + SeqNumUnwrapper<uint8_t> unwrapper; + EXPECT_EQ(255, unwrapper.Unwrap(255)); + EXPECT_EQ(256, unwrapper.Unwrap(0)); +} + +TEST(SeqNumUnwrapper, ForwardWrapWithDivisor) { + SeqNumUnwrapper<uint8_t, 33> unwrapper; + EXPECT_EQ(30, unwrapper.Unwrap(30)); + EXPECT_EQ(36, unwrapper.Unwrap(3)); +} + +TEST(SeqNumUnwrapper, BackWardWrap) { + SeqNumUnwrapper<uint8_t> unwrapper; + EXPECT_EQ(0, unwrapper.Unwrap(0)); + EXPECT_EQ(-2, unwrapper.Unwrap(254)); +} + +TEST(SeqNumUnwrapper, BackWardWrapWithDivisor) { + SeqNumUnwrapper<uint8_t, 33> unwrapper; + EXPECT_EQ(0, unwrapper.Unwrap(0)); + EXPECT_EQ(-2, unwrapper.Unwrap(31)); +} + +TEST(SeqNumUnwrapper, Unwrap) { + SeqNumUnwrapper<uint16_t> unwrapper; + const uint16_t kMax = std::numeric_limits<uint16_t>::max(); + const uint16_t kMaxDist = kMax / 2 + 1; + + EXPECT_EQ(0, unwrapper.Unwrap(0)); + EXPECT_EQ(kMaxDist, unwrapper.Unwrap(kMaxDist)); + EXPECT_EQ(0, unwrapper.Unwrap(0)); + + EXPECT_EQ(kMaxDist, unwrapper.Unwrap(kMaxDist)); + EXPECT_EQ(kMax, unwrapper.Unwrap(kMax)); + EXPECT_EQ(kMax + 1, unwrapper.Unwrap(0)); + EXPECT_EQ(kMax, unwrapper.Unwrap(kMax)); + EXPECT_EQ(kMaxDist, unwrapper.Unwrap(kMaxDist)); + EXPECT_EQ(0, unwrapper.Unwrap(0)); +} + +TEST(SeqNumUnwrapper, UnwrapOddDivisor) { + SeqNumUnwrapper<uint8_t, 11> unwrapper; + + EXPECT_EQ(10, unwrapper.Unwrap(10)); + EXPECT_EQ(11, unwrapper.Unwrap(0)); + EXPECT_EQ(16, unwrapper.Unwrap(5)); + EXPECT_EQ(21, unwrapper.Unwrap(10)); + EXPECT_EQ(22, unwrapper.Unwrap(0)); + EXPECT_EQ(17, unwrapper.Unwrap(6)); + EXPECT_EQ(12, unwrapper.Unwrap(1)); + EXPECT_EQ(7, unwrapper.Unwrap(7)); + EXPECT_EQ(2, unwrapper.Unwrap(2)); + EXPECT_EQ(0, unwrapper.Unwrap(0)); +} + +TEST(SeqNumUnwrapper, ManyForwardWraps) { + const int kLargeNumber = 4711; + const int kMaxStep = kLargeNumber / 2; + const int kNumWraps = 100; + SeqNumUnwrapper<uint16_t, kLargeNumber> unwrapper; + + uint16_t next_unwrap = 0; + int64_t expected = 0; + for (int i = 0; i < kNumWraps * 2 + 1; ++i) { + EXPECT_EQ(expected, unwrapper.Unwrap(next_unwrap)); + expected += kMaxStep; + next_unwrap = (next_unwrap + kMaxStep) % kLargeNumber; + } +} + +TEST(SeqNumUnwrapper, ManyBackwardWraps) { + const int kLargeNumber = 4711; + const int kMaxStep = kLargeNumber / 2; + const int kNumWraps = 100; + SeqNumUnwrapper<uint16_t, kLargeNumber> unwrapper; + + uint16_t next_unwrap = 0; + int64_t expected = 0; + for (uint16_t i = 0; i < kNumWraps * 2 + 1; ++i) { + EXPECT_EQ(expected, unwrapper.Unwrap(next_unwrap)); + expected -= kMaxStep; + next_unwrap = (next_unwrap + kMaxStep + 1) % kLargeNumber; + } +} + +TEST(SeqNumUnwrapper, Reset) { + const uint16_t kMax = std::numeric_limits<uint16_t>::max(); + const uint16_t kMaxStep = kMax / 2; + SeqNumUnwrapper<uint16_t> unwrapper; + EXPECT_EQ(10, unwrapper.Unwrap(10)); + EXPECT_EQ(kMaxStep + 10, unwrapper.Unwrap(kMaxStep + 10)); + + EXPECT_EQ(kMax + 3, unwrapper.PeekUnwrap(2)); + unwrapper.Reset(); + // After Reset() the range is reset back to the start. + EXPECT_EQ(2, unwrapper.PeekUnwrap(2)); +} + +TEST(SeqNumUnwrapper, PeekUnwrap) { + const uint16_t kMax = std::numeric_limits<uint16_t>::max(); + const uint16_t kMaxStep = kMax / 2; + const uint16_t kMaxDist = kMaxStep + 1; + SeqNumUnwrapper<uint16_t> unwrapper; + // No previous unwraps, so PeekUnwrap(x) == x. + EXPECT_EQ(10, unwrapper.PeekUnwrap(10)); + EXPECT_EQ(kMaxDist + 10, unwrapper.PeekUnwrap(kMaxDist + 10)); + + EXPECT_EQ(10, unwrapper.Unwrap(10)); + EXPECT_EQ(12, unwrapper.PeekUnwrap(12)); + // State should not have updated, so kMaxDist + 12 should be negative. + EXPECT_EQ(-kMaxDist + 12, unwrapper.Unwrap(kMaxDist + 12)); + + // Test PeekUnwrap after around. + unwrapper.Reset(); + EXPECT_EQ(kMaxStep, unwrapper.Unwrap(kMaxStep)); + EXPECT_EQ(2 * kMaxStep, unwrapper.Unwrap(2 * kMaxStep)); + EXPECT_EQ(kMax + 1, unwrapper.PeekUnwrap(0)); + // Wrap back to last range. + EXPECT_EQ(kMax - 3, unwrapper.PeekUnwrap(kMax - 3)); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/numerics/sequence_number_util.h b/third_party/libwebrtc/rtc_base/numerics/sequence_number_util.h new file mode 100644 index 0000000000..702b82fa2b --- /dev/null +++ b/third_party/libwebrtc/rtc_base/numerics/sequence_number_util.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2016 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 RTC_BASE_NUMERICS_SEQUENCE_NUMBER_UTIL_H_ +#define RTC_BASE_NUMERICS_SEQUENCE_NUMBER_UTIL_H_ + +#include <stdint.h> + +#include <limits> +#include <type_traits> + +#include "rtc_base/numerics/mod_ops.h" + +namespace webrtc { + +// Test if the sequence number `a` is ahead or at sequence number `b`. +// +// If `M` is an even number and the two sequence numbers are at max distance +// from each other, then the sequence number with the highest value is +// considered to be ahead. +template <typename T, T M> +inline typename std::enable_if<(M > 0), bool>::type AheadOrAt(T a, T b) { + static_assert(std::is_unsigned<T>::value, + "Type must be an unsigned integer."); + const T maxDist = M / 2; + if (!(M & 1) && MinDiff<T, M>(a, b) == maxDist) + return b < a; + return ForwardDiff<T, M>(b, a) <= maxDist; +} + +template <typename T, T M> +inline typename std::enable_if<(M == 0), bool>::type AheadOrAt(T a, T b) { + static_assert(std::is_unsigned<T>::value, + "Type must be an unsigned integer."); + const T maxDist = std::numeric_limits<T>::max() / 2 + T(1); + if (a - b == maxDist) + return b < a; + return ForwardDiff(b, a) < maxDist; +} + +template <typename T> +inline bool AheadOrAt(T a, T b) { + return AheadOrAt<T, 0>(a, b); +} + +// Test if the sequence number `a` is ahead of sequence number `b`. +// +// If `M` is an even number and the two sequence numbers are at max distance +// from each other, then the sequence number with the highest value is +// considered to be ahead. +template <typename T, T M = 0> +inline bool AheadOf(T a, T b) { + static_assert(std::is_unsigned<T>::value, + "Type must be an unsigned integer."); + return a != b && AheadOrAt<T, M>(a, b); +} + +// Comparator used to compare sequence numbers in a continuous fashion. +// +// WARNING! If used to sort sequence numbers of length M then the interval +// covered by the sequence numbers may not be larger than floor(M/2). +template <typename T, T M = 0> +struct AscendingSeqNumComp { + bool operator()(T a, T b) const { return AheadOf<T, M>(a, b); } +}; + +// Comparator used to compare sequence numbers in a continuous fashion. +// +// WARNING! If used to sort sequence numbers of length M then the interval +// covered by the sequence numbers may not be larger than floor(M/2). +template <typename T, T M = 0> +struct DescendingSeqNumComp { + bool operator()(T a, T b) const { return AheadOf<T, M>(b, a); } +}; + +} // namespace webrtc + +#endif // RTC_BASE_NUMERICS_SEQUENCE_NUMBER_UTIL_H_ diff --git a/third_party/libwebrtc/rtc_base/numerics/sequence_number_util_unittest.cc b/third_party/libwebrtc/rtc_base/numerics/sequence_number_util_unittest.cc new file mode 100644 index 0000000000..d44127bfa5 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/numerics/sequence_number_util_unittest.cc @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2016 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 "rtc_base/numerics/sequence_number_util.h" + +#include <cstdint> +#include <iterator> +#include <set> + +#include "test/gtest.h" + +namespace webrtc { +class TestSeqNumUtil : public ::testing::Test { + protected: + // Can't use std::numeric_limits<unsigned long>::max() since + // MSVC doesn't support constexpr. + static const unsigned long ulmax = ~0ul; // NOLINT +}; + +TEST_F(TestSeqNumUtil, AheadOrAt) { + uint8_t x = 0; + uint8_t y = 0; + ASSERT_TRUE(AheadOrAt(x, y)); + ++x; + ASSERT_TRUE(AheadOrAt(x, y)); + ASSERT_FALSE(AheadOrAt(y, x)); + for (int i = 0; i < 256; ++i) { + ASSERT_TRUE(AheadOrAt(x, y)); + ++x; + ++y; + } + + x = 128; + y = 0; + ASSERT_TRUE(AheadOrAt(x, y)); + ASSERT_FALSE(AheadOrAt(y, x)); + + x = 129; + ASSERT_FALSE(AheadOrAt(x, y)); + ASSERT_TRUE(AheadOrAt(y, x)); + ASSERT_TRUE(AheadOrAt<uint16_t>(x, y)); + ASSERT_FALSE(AheadOrAt<uint16_t>(y, x)); +} + +TEST_F(TestSeqNumUtil, AheadOrAtWithDivisor) { + ASSERT_TRUE((AheadOrAt<uint8_t, 11>(5, 0))); + ASSERT_FALSE((AheadOrAt<uint8_t, 11>(6, 0))); + ASSERT_FALSE((AheadOrAt<uint8_t, 11>(0, 5))); + ASSERT_TRUE((AheadOrAt<uint8_t, 11>(0, 6))); + + ASSERT_TRUE((AheadOrAt<uint8_t, 10>(5, 0))); + ASSERT_FALSE((AheadOrAt<uint8_t, 10>(6, 0))); + ASSERT_FALSE((AheadOrAt<uint8_t, 10>(0, 5))); + ASSERT_TRUE((AheadOrAt<uint8_t, 10>(0, 6))); + + const uint8_t D = 211; + uint8_t x = 0; + for (int i = 0; i < D; ++i) { + uint8_t next_x = Add<D>(x, 1); + ASSERT_TRUE((AheadOrAt<uint8_t, D>(i, i))); + ASSERT_TRUE((AheadOrAt<uint8_t, D>(next_x, i))); + ASSERT_FALSE((AheadOrAt<uint8_t, D>(i, next_x))); + x = next_x; + } +} + +TEST_F(TestSeqNumUtil, AheadOf) { + uint8_t x = 0; + uint8_t y = 0; + ASSERT_FALSE(AheadOf(x, y)); + ++x; + ASSERT_TRUE(AheadOf(x, y)); + ASSERT_FALSE(AheadOf(y, x)); + for (int i = 0; i < 256; ++i) { + ASSERT_TRUE(AheadOf(x, y)); + ++x; + ++y; + } + + x = 128; + y = 0; + for (int i = 0; i < 128; ++i) { + ASSERT_TRUE(AheadOf(x, y)); + ASSERT_FALSE(AheadOf(y, x)); + x++; + y++; + } + + for (int i = 0; i < 128; ++i) { + ASSERT_FALSE(AheadOf(x, y)); + ASSERT_TRUE(AheadOf(y, x)); + x++; + y++; + } + + x = 129; + y = 0; + ASSERT_FALSE(AheadOf(x, y)); + ASSERT_TRUE(AheadOf(y, x)); + ASSERT_TRUE(AheadOf<uint16_t>(x, y)); + ASSERT_FALSE(AheadOf<uint16_t>(y, x)); +} + +TEST_F(TestSeqNumUtil, AheadOfWithDivisor) { + ASSERT_TRUE((AheadOf<uint8_t, 11>(5, 0))); + ASSERT_FALSE((AheadOf<uint8_t, 11>(6, 0))); + ASSERT_FALSE((AheadOf<uint8_t, 11>(0, 5))); + ASSERT_TRUE((AheadOf<uint8_t, 11>(0, 6))); + + ASSERT_TRUE((AheadOf<uint8_t, 10>(5, 0))); + ASSERT_FALSE((AheadOf<uint8_t, 10>(6, 0))); + ASSERT_FALSE((AheadOf<uint8_t, 10>(0, 5))); + ASSERT_TRUE((AheadOf<uint8_t, 10>(0, 6))); + + const uint8_t D = 211; + uint8_t x = 0; + for (int i = 0; i < D; ++i) { + uint8_t next_x = Add<D>(x, 1); + ASSERT_FALSE((AheadOf<uint8_t, D>(i, i))); + ASSERT_TRUE((AheadOf<uint8_t, D>(next_x, i))); + ASSERT_FALSE((AheadOf<uint8_t, D>(i, next_x))); + x = next_x; + } +} + +TEST_F(TestSeqNumUtil, ForwardDiffWithDivisor) { + const uint8_t kDivisor = 211; + + for (uint8_t i = 0; i < kDivisor - 1; ++i) { + ASSERT_EQ(0, (ForwardDiff<uint8_t, kDivisor>(i, i))); + ASSERT_EQ(1, (ForwardDiff<uint8_t, kDivisor>(i, i + 1))); + ASSERT_EQ(kDivisor - 1, (ForwardDiff<uint8_t, kDivisor>(i + 1, i))); + } + + for (uint8_t i = 1; i < kDivisor; ++i) { + ASSERT_EQ(i, (ForwardDiff<uint8_t, kDivisor>(0, i))); + ASSERT_EQ(kDivisor - i, (ForwardDiff<uint8_t, kDivisor>(i, 0))); + } +} + +TEST_F(TestSeqNumUtil, ReverseDiffWithDivisor) { + const uint8_t kDivisor = 241; + + for (uint8_t i = 0; i < kDivisor - 1; ++i) { + ASSERT_EQ(0, (ReverseDiff<uint8_t, kDivisor>(i, i))); + ASSERT_EQ(kDivisor - 1, (ReverseDiff<uint8_t, kDivisor>(i, i + 1))); + ASSERT_EQ(1, (ReverseDiff<uint8_t, kDivisor>(i + 1, i))); + } + + for (uint8_t i = 1; i < kDivisor; ++i) { + ASSERT_EQ(kDivisor - i, (ReverseDiff<uint8_t, kDivisor>(0, i))); + ASSERT_EQ(i, (ReverseDiff<uint8_t, kDivisor>(i, 0))); + } +} + +TEST_F(TestSeqNumUtil, SeqNumComparator) { + std::set<uint8_t, AscendingSeqNumComp<uint8_t>> seq_nums_asc; + std::set<uint8_t, DescendingSeqNumComp<uint8_t>> seq_nums_desc; + + uint8_t x = 0; + for (int i = 0; i < 128; ++i) { + seq_nums_asc.insert(x); + seq_nums_desc.insert(x); + ASSERT_EQ(x, *seq_nums_asc.begin()); + ASSERT_EQ(x, *seq_nums_desc.rbegin()); + ++x; + } + + seq_nums_asc.clear(); + seq_nums_desc.clear(); + x = 199; + for (int i = 0; i < 128; ++i) { + seq_nums_asc.insert(x); + seq_nums_desc.insert(x); + ASSERT_EQ(x, *seq_nums_asc.begin()); + ASSERT_EQ(x, *seq_nums_desc.rbegin()); + ++x; + } +} + +TEST_F(TestSeqNumUtil, SeqNumComparatorWithDivisor) { + const uint8_t D = 223; + + std::set<uint8_t, AscendingSeqNumComp<uint8_t, D>> seq_nums_asc; + std::set<uint8_t, DescendingSeqNumComp<uint8_t, D>> seq_nums_desc; + + uint8_t x = 0; + for (int i = 0; i < D / 2; ++i) { + seq_nums_asc.insert(x); + seq_nums_desc.insert(x); + ASSERT_EQ(x, *seq_nums_asc.begin()); + ASSERT_EQ(x, *seq_nums_desc.rbegin()); + x = Add<D>(x, 1); + } + + seq_nums_asc.clear(); + seq_nums_desc.clear(); + x = 200; + for (int i = 0; i < D / 2; ++i) { + seq_nums_asc.insert(x); + seq_nums_desc.insert(x); + ASSERT_EQ(x, *seq_nums_asc.begin()); + ASSERT_EQ(x, *seq_nums_desc.rbegin()); + x = Add<D>(x, 1); + } +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/one_time_event.h b/third_party/libwebrtc/rtc_base/one_time_event.h new file mode 100644 index 0000000000..d33ddbd587 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/one_time_event.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2016 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 RTC_BASE_ONE_TIME_EVENT_H_ +#define RTC_BASE_ONE_TIME_EVENT_H_ + +#include "rtc_base/synchronization/mutex.h" + +namespace webrtc { +// Provides a simple way to perform an operation (such as logging) one +// time in a certain scope. +// Example: +// OneTimeEvent firstFrame; +// ... +// if (firstFrame()) { +// RTC_LOG(LS_INFO) << "This is the first frame". +// } +class OneTimeEvent { + public: + OneTimeEvent() {} + bool operator()() { + MutexLock lock(&mutex_); + if (happened_) { + return false; + } + happened_ = true; + return true; + } + + private: + bool happened_ = false; + Mutex mutex_; +}; + +// A non-thread-safe, ligher-weight version of the OneTimeEvent class. +class ThreadUnsafeOneTimeEvent { + public: + ThreadUnsafeOneTimeEvent() {} + bool operator()() { + if (happened_) { + return false; + } + happened_ = true; + return true; + } + + private: + bool happened_ = false; +}; + +} // namespace webrtc + +#endif // RTC_BASE_ONE_TIME_EVENT_H_ diff --git a/third_party/libwebrtc/rtc_base/one_time_event_gn/moz.build b/third_party/libwebrtc/rtc_base/one_time_event_gn/moz.build new file mode 100644 index 0000000000..d5afd56fb6 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/one_time_event_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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("one_time_event_gn") diff --git a/third_party/libwebrtc/rtc_base/one_time_event_unittest.cc b/third_party/libwebrtc/rtc_base/one_time_event_unittest.cc new file mode 100644 index 0000000000..39fd8f9725 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/one_time_event_unittest.cc @@ -0,0 +1,34 @@ +/* + * Copyright 2016 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 "rtc_base/one_time_event.h" + +#include "test/gtest.h" + +namespace webrtc { + +TEST(OneTimeEventTest, ThreadSafe) { + OneTimeEvent ot; + + // The one time event is expected to evaluate to true only the first time. + EXPECT_TRUE(ot()); + EXPECT_FALSE(ot()); + EXPECT_FALSE(ot()); +} + +TEST(OneTimeEventTest, ThreadUnsafe) { + ThreadUnsafeOneTimeEvent ot; + + EXPECT_TRUE(ot()); + EXPECT_FALSE(ot()); + EXPECT_FALSE(ot()); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/openssl.h b/third_party/libwebrtc/rtc_base/openssl.h new file mode 100644 index 0000000000..eeed373c43 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/openssl.h @@ -0,0 +1,25 @@ +/* + * Copyright 2013 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 RTC_BASE_OPENSSL_H_ +#define RTC_BASE_OPENSSL_H_ + +#if defined(WEBRTC_WIN) +// Must be included first before openssl headers. +#include "rtc_base/win32.h" // NOLINT +#endif // WEBRTC_WIN + +#include <openssl/ssl.h> + +#if (OPENSSL_VERSION_NUMBER < 0x10100000L) +#error OpenSSL is older than 1.1.0, which is the minimum supported version. +#endif + +#endif // RTC_BASE_OPENSSL_H_ diff --git a/third_party/libwebrtc/rtc_base/openssl_adapter.cc b/third_party/libwebrtc/rtc_base/openssl_adapter.cc new file mode 100644 index 0000000000..c68eb22f5c --- /dev/null +++ b/third_party/libwebrtc/rtc_base/openssl_adapter.cc @@ -0,0 +1,1126 @@ +/* + * Copyright 2008 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 "rtc_base/openssl_adapter.h" + +#include <errno.h> +#include <openssl/bio.h> +#include <openssl/err.h> + +#include "absl/strings/string_view.h" +#ifdef OPENSSL_IS_BORINGSSL +#include <openssl/pool.h> +#endif +#include <openssl/rand.h> +#include <openssl/x509.h> +#include <string.h> +#include <time.h> + +#include <memory> + +// Use CRYPTO_BUFFER APIs if available and we have no dependency on X509 +// objects. +#if defined(OPENSSL_IS_BORINGSSL) && \ + defined(WEBRTC_EXCLUDE_BUILT_IN_SSL_ROOT_CERTS) +#define WEBRTC_USE_CRYPTO_BUFFER_CALLBACK +#endif + +#include "absl/memory/memory.h" +#include "api/units/time_delta.h" +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" +#include "rtc_base/numerics/safe_conversions.h" +#include "rtc_base/openssl.h" +#ifdef OPENSSL_IS_BORINGSSL +#include "rtc_base/boringssl_identity.h" +#else +#include "rtc_base/openssl_identity.h" +#endif +#include "rtc_base/openssl_utility.h" +#include "rtc_base/strings/string_builder.h" +#include "rtc_base/thread.h" + +////////////////////////////////////////////////////////////////////// +// SocketBIO +////////////////////////////////////////////////////////////////////// + +static int socket_write(BIO* h, const char* buf, int num); +static int socket_read(BIO* h, char* buf, int size); +static int socket_puts(BIO* h, const char* str); +static long socket_ctrl(BIO* h, int cmd, long arg1, void* arg2); // NOLINT +static int socket_new(BIO* h); +static int socket_free(BIO* data); + +static BIO_METHOD* BIO_socket_method() { + static BIO_METHOD* methods = [] { + BIO_METHOD* methods = BIO_meth_new(BIO_TYPE_BIO, "socket"); + BIO_meth_set_write(methods, socket_write); + BIO_meth_set_read(methods, socket_read); + BIO_meth_set_puts(methods, socket_puts); + BIO_meth_set_ctrl(methods, socket_ctrl); + BIO_meth_set_create(methods, socket_new); + BIO_meth_set_destroy(methods, socket_free); + return methods; + }(); + return methods; +} + +static BIO* BIO_new_socket(rtc::Socket* socket) { + BIO* ret = BIO_new(BIO_socket_method()); + if (ret == nullptr) { + return nullptr; + } + BIO_set_data(ret, socket); + return ret; +} + +static int socket_new(BIO* b) { + BIO_set_shutdown(b, 0); + BIO_set_init(b, 1); + BIO_set_data(b, 0); + return 1; +} + +static int socket_free(BIO* b) { + if (b == nullptr) + return 0; + return 1; +} + +static int socket_read(BIO* b, char* out, int outl) { + if (!out) + return -1; + rtc::Socket* socket = static_cast<rtc::Socket*>(BIO_get_data(b)); + BIO_clear_retry_flags(b); + int result = socket->Recv(out, outl, nullptr); + if (result > 0) { + return result; + } else if (socket->IsBlocking()) { + BIO_set_retry_read(b); + } + return -1; +} + +static int socket_write(BIO* b, const char* in, int inl) { + if (!in) + return -1; + rtc::Socket* socket = static_cast<rtc::Socket*>(BIO_get_data(b)); + BIO_clear_retry_flags(b); + int result = socket->Send(in, inl); + if (result > 0) { + return result; + } else if (socket->IsBlocking()) { + BIO_set_retry_write(b); + } + return -1; +} + +static int socket_puts(BIO* b, const char* str) { + return socket_write(b, str, rtc::checked_cast<int>(strlen(str))); +} + +static long socket_ctrl(BIO* b, int cmd, long num, void* ptr) { // NOLINT + switch (cmd) { + case BIO_CTRL_RESET: + return 0; + case BIO_CTRL_EOF: { + rtc::Socket* socket = static_cast<rtc::Socket*>(ptr); + // 1 means socket closed. + return (socket->GetState() == rtc::Socket::CS_CLOSED) ? 1 : 0; + } + case BIO_CTRL_WPENDING: + case BIO_CTRL_PENDING: + return 0; + case BIO_CTRL_FLUSH: + return 1; + default: + return 0; + } +} + +static void LogSslError() { + // Walk down the error stack to find the SSL error. + uint32_t error_code; + const char* file; + int line; + do { + error_code = ERR_get_error_line(&file, &line); + if (ERR_GET_LIB(error_code) == ERR_LIB_SSL) { + RTC_LOG(LS_ERROR) << "ERR_LIB_SSL: " << error_code << ", " << file << ":" + << line; + break; + } + } while (error_code != 0); +} + +///////////////////////////////////////////////////////////////////////////// +// OpenSSLAdapter +///////////////////////////////////////////////////////////////////////////// + +namespace rtc { + +using ::webrtc::TimeDelta; + +namespace webrtc_openssl_adapter_internal { + +// Simple O(n^2) implementation is sufficient for current use case. +std::string StrJoin(const std::vector<std::string>& list, char delimiter) { + RTC_CHECK(!list.empty()); + StringBuilder sb; + sb << list[0]; + for (size_t i = 1; i < list.size(); i++) { + sb.AppendFormat("%c", delimiter); + sb << list[i]; + } + return sb.Release(); +} +} // namespace webrtc_openssl_adapter_internal + +using webrtc_openssl_adapter_internal::StrJoin; + +bool OpenSSLAdapter::InitializeSSL() { + if (!SSL_library_init()) + return false; +#if !defined(ADDRESS_SANITIZER) || !defined(WEBRTC_MAC) || defined(WEBRTC_IOS) + // Loading the error strings crashes mac_asan. Omit this debugging aid there. + SSL_load_error_strings(); +#endif + ERR_load_BIO_strings(); + OpenSSL_add_all_algorithms(); + RAND_poll(); + return true; +} + +bool OpenSSLAdapter::CleanupSSL() { + return true; +} + +OpenSSLAdapter::OpenSSLAdapter(Socket* socket, + OpenSSLSessionCache* ssl_session_cache, + SSLCertificateVerifier* ssl_cert_verifier) + : SSLAdapter(socket), + ssl_session_cache_(ssl_session_cache), + ssl_cert_verifier_(ssl_cert_verifier), + state_(SSL_NONE), + role_(SSL_CLIENT), + ssl_read_needs_write_(false), + ssl_write_needs_read_(false), + ssl_(nullptr), + ssl_ctx_(nullptr), + ssl_mode_(SSL_MODE_TLS), + ignore_bad_cert_(false), + custom_cert_verifier_status_(false) { + // If a factory is used, take a reference on the factory's SSL_CTX. + // Otherwise, we'll create our own later. + // Either way, we'll release our reference via SSL_CTX_free() in Cleanup(). + if (ssl_session_cache_ != nullptr) { + ssl_ctx_ = ssl_session_cache_->GetSSLContext(); + RTC_DCHECK(ssl_ctx_); + // Note: if using OpenSSL, requires version 1.1.0 or later. + SSL_CTX_up_ref(ssl_ctx_); + } +} + +OpenSSLAdapter::~OpenSSLAdapter() { + Cleanup(); +} + +void OpenSSLAdapter::SetIgnoreBadCert(bool ignore) { + ignore_bad_cert_ = ignore; +} + +void OpenSSLAdapter::SetAlpnProtocols(const std::vector<std::string>& protos) { + alpn_protocols_ = protos; +} + +void OpenSSLAdapter::SetEllipticCurves(const std::vector<std::string>& curves) { + elliptic_curves_ = curves; +} + +void OpenSSLAdapter::SetMode(SSLMode mode) { + RTC_DCHECK(!ssl_ctx_); + RTC_DCHECK(state_ == SSL_NONE); + ssl_mode_ = mode; +} + +void OpenSSLAdapter::SetCertVerifier( + SSLCertificateVerifier* ssl_cert_verifier) { + RTC_DCHECK(!ssl_ctx_); + ssl_cert_verifier_ = ssl_cert_verifier; +} + +void OpenSSLAdapter::SetIdentity(std::unique_ptr<SSLIdentity> identity) { + RTC_DCHECK(!identity_); +#ifdef OPENSSL_IS_BORINGSSL + identity_ = + absl::WrapUnique(static_cast<BoringSSLIdentity*>(identity.release())); +#else + identity_ = + absl::WrapUnique(static_cast<OpenSSLIdentity*>(identity.release())); +#endif +} + +void OpenSSLAdapter::SetRole(SSLRole role) { + role_ = role; +} + +int OpenSSLAdapter::StartSSL(absl::string_view hostname) { + if (state_ != SSL_NONE) + return -1; + + ssl_host_name_.assign(hostname.data(), hostname.size()); + + if (GetSocket()->GetState() != Socket::CS_CONNECTED) { + state_ = SSL_WAIT; + return 0; + } + + state_ = SSL_CONNECTING; + if (int err = BeginSSL()) { + Error("BeginSSL", err, false); + return err; + } + + return 0; +} + +int OpenSSLAdapter::BeginSSL() { + RTC_LOG(LS_INFO) << "OpenSSLAdapter::BeginSSL: " << ssl_host_name_; + RTC_DCHECK(state_ == SSL_CONNECTING); + + // Cleanup action to deal with on error cleanup a bit cleaner. + EarlyExitCatcher early_exit_catcher(*this); + + // First set up the context. We should either have a factory, with its own + // pre-existing context, or be running standalone, in which case we will + // need to create one, and specify `false` to disable session caching. + if (ssl_session_cache_ == nullptr) { + RTC_DCHECK(!ssl_ctx_); + ssl_ctx_ = CreateContext(ssl_mode_, false); + } + + if (!ssl_ctx_) { + return -1; + } + + if (identity_ && !identity_->ConfigureIdentity(ssl_ctx_)) { + return -1; + } + + std::unique_ptr<BIO, decltype(&::BIO_free)> bio{BIO_new_socket(GetSocket()), + ::BIO_free}; + if (!bio) { + return -1; + } + + ssl_ = SSL_new(ssl_ctx_); + if (!ssl_) { + return -1; + } + + SSL_set_app_data(ssl_, this); + + // SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER allows different buffers to be passed + // into SSL_write when a record could only be partially transmitted (and thus + // requires another call to SSL_write to finish transmission). This allows us + // to copy the data into our own buffer when this occurs, since the original + // buffer can't safely be accessed after control exits Send. + // TODO(deadbeef): Do we want SSL_MODE_ENABLE_PARTIAL_WRITE? It doesn't + // appear Send handles partial writes properly, though maybe we never notice + // since we never send more than 16KB at once.. + SSL_set_mode(ssl_, SSL_MODE_ENABLE_PARTIAL_WRITE | + SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); + + // Enable SNI, if a hostname is supplied. + if (!ssl_host_name_.empty()) { + SSL_set_tlsext_host_name(ssl_, ssl_host_name_.c_str()); + + // Enable session caching, if configured and a hostname is supplied. + if (ssl_session_cache_ != nullptr) { + SSL_SESSION* cached = ssl_session_cache_->LookupSession(ssl_host_name_); + if (cached) { + if (SSL_set_session(ssl_, cached) == 0) { + RTC_LOG(LS_WARNING) << "Failed to apply SSL session from cache"; + return -1; + } + + RTC_LOG(LS_INFO) << "Attempting to resume SSL session to " + << ssl_host_name_; + } + } + } + +#ifdef OPENSSL_IS_BORINGSSL + // Set a couple common TLS extensions; even though we don't use them yet. + SSL_enable_ocsp_stapling(ssl_); + SSL_enable_signed_cert_timestamps(ssl_); +#endif + + if (!alpn_protocols_.empty()) { + std::string tls_alpn_string = TransformAlpnProtocols(alpn_protocols_); + if (!tls_alpn_string.empty()) { + SSL_set_alpn_protos( + ssl_, reinterpret_cast<const unsigned char*>(tls_alpn_string.data()), + rtc::dchecked_cast<unsigned>(tls_alpn_string.size())); + } + } + + if (!elliptic_curves_.empty()) { + SSL_set1_curves_list(ssl_, StrJoin(elliptic_curves_, ':').c_str()); + } + + // Now that the initial config is done, transfer ownership of `bio` to the + // SSL object. If ContinueSSL() fails, the bio will be freed in Cleanup(). + SSL_set_bio(ssl_, bio.get(), bio.get()); + bio.release(); + + // Do the connect. + int err = ContinueSSL(); + if (err != 0) { + return err; + } + early_exit_catcher.disable(); + return 0; +} + +int OpenSSLAdapter::ContinueSSL() { + RTC_DCHECK(state_ == SSL_CONNECTING); + + // Clear the DTLS timer + timer_.reset(); + + int code = (role_ == SSL_CLIENT) ? SSL_connect(ssl_) : SSL_accept(ssl_); + switch (SSL_get_error(ssl_, code)) { + case SSL_ERROR_NONE: + if (!SSLPostConnectionCheck(ssl_, ssl_host_name_)) { + RTC_LOG(LS_ERROR) << "TLS post connection check failed"; + // make sure we close the socket + Cleanup(); + // The connect failed so return -1 to shut down the socket + return -1; + } + + state_ = SSL_CONNECTED; + AsyncSocketAdapter::OnConnectEvent(this); + // TODO(benwright): Refactor this code path. + // Don't let ourselves go away during the callbacks + // PRefPtr<OpenSSLAdapter> lock(this); + // RTC_LOG(LS_INFO) << " -- onStreamReadable"; + // AsyncSocketAdapter::OnReadEvent(this); + // RTC_LOG(LS_INFO) << " -- onStreamWriteable"; + // AsyncSocketAdapter::OnWriteEvent(this); + break; + + case SSL_ERROR_WANT_READ: + RTC_LOG(LS_VERBOSE) << " -- error want read"; + struct timeval timeout; + if (DTLSv1_get_timeout(ssl_, &timeout)) { + TimeDelta delay = TimeDelta::Seconds(timeout.tv_sec) + + TimeDelta::Micros(timeout.tv_usec); + Thread::Current()->PostDelayedTask( + SafeTask(timer_.flag(), [this] { OnTimeout(); }), delay); + } + break; + + case SSL_ERROR_WANT_WRITE: + break; + + case SSL_ERROR_ZERO_RETURN: + default: + RTC_LOG(LS_WARNING) << "ContinueSSL -- error " << code; + return (code != 0) ? code : -1; + } + + return 0; +} + +void OpenSSLAdapter::Error(absl::string_view context, int err, bool signal) { + RTC_LOG(LS_WARNING) << "OpenSSLAdapter::Error(" << context << ", " << err + << ")"; + state_ = SSL_ERROR; + SetError(err); + if (signal) { + AsyncSocketAdapter::OnCloseEvent(this, err); + } +} + +void OpenSSLAdapter::Cleanup() { + RTC_LOG(LS_INFO) << "OpenSSLAdapter::Cleanup"; + + state_ = SSL_NONE; + ssl_read_needs_write_ = false; + ssl_write_needs_read_ = false; + custom_cert_verifier_status_ = false; + pending_data_.Clear(); + + if (ssl_) { + SSL_free(ssl_); + ssl_ = nullptr; + } + + if (ssl_ctx_) { + SSL_CTX_free(ssl_ctx_); + ssl_ctx_ = nullptr; + } + identity_.reset(); + + // Clear the DTLS timer + timer_.reset(); +} + +int OpenSSLAdapter::DoSslWrite(const void* pv, size_t cb, int* error) { + // If we have pending data (that was previously only partially written by + // SSL_write), we shouldn't be attempting to write anything else. + RTC_DCHECK(pending_data_.empty() || pv == pending_data_.data()); + RTC_DCHECK(error != nullptr); + + ssl_write_needs_read_ = false; + int ret = SSL_write(ssl_, pv, checked_cast<int>(cb)); + *error = SSL_get_error(ssl_, ret); + switch (*error) { + case SSL_ERROR_NONE: + // Success! + return ret; + case SSL_ERROR_WANT_READ: + RTC_LOG(LS_INFO) << " -- error want read"; + ssl_write_needs_read_ = true; + SetError(EWOULDBLOCK); + break; + case SSL_ERROR_WANT_WRITE: + RTC_LOG(LS_INFO) << " -- error want write"; + SetError(EWOULDBLOCK); + break; + case SSL_ERROR_ZERO_RETURN: + SetError(EWOULDBLOCK); + // do we need to signal closure? + break; + case SSL_ERROR_SSL: + LogSslError(); + Error("SSL_write", ret ? ret : -1, false); + break; + default: + Error("SSL_write", ret ? ret : -1, false); + break; + } + + return SOCKET_ERROR; +} + +/////////////////////////////////////////////////////////////////////////////// +// Socket Implementation +/////////////////////////////////////////////////////////////////////////////// + +int OpenSSLAdapter::Send(const void* pv, size_t cb) { + switch (state_) { + case SSL_NONE: + return AsyncSocketAdapter::Send(pv, cb); + case SSL_WAIT: + case SSL_CONNECTING: + SetError(ENOTCONN); + return SOCKET_ERROR; + case SSL_CONNECTED: + break; + case SSL_ERROR: + default: + return SOCKET_ERROR; + } + + int ret; + int error; + + if (!pending_data_.empty()) { + ret = DoSslWrite(pending_data_.data(), pending_data_.size(), &error); + if (ret != static_cast<int>(pending_data_.size())) { + // We couldn't finish sending the pending data, so we definitely can't + // send any more data. Return with an EWOULDBLOCK error. + SetError(EWOULDBLOCK); + return SOCKET_ERROR; + } + // We completed sending the data previously passed into SSL_write! Now + // we're allowed to send more data. + pending_data_.Clear(); + } + + // OpenSSL will return an error if we try to write zero bytes + if (cb == 0) { + return 0; + } + + ret = DoSslWrite(pv, cb, &error); + + // If SSL_write fails with SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE, this + // means the underlying socket is blocked on reading or (more typically) + // writing. When this happens, OpenSSL requires that the next call to + // SSL_write uses the same arguments (though, with + // SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER, the actual buffer pointer may be + // different). + // + // However, after Send exits, we will have lost access to data the user of + // this class is trying to send, and there's no guarantee that the user of + // this class will call Send with the same arguements when it fails. So, we + // buffer the data ourselves. When we know the underlying socket is writable + // again from OnWriteEvent (or if Send is called again before that happens), + // we'll retry sending this buffered data. + if (error == SSL_ERROR_WANT_READ || error == SSL_ERROR_WANT_WRITE) { + // Shouldn't be able to get to this point if we already have pending data. + RTC_DCHECK(pending_data_.empty()); + RTC_LOG(LS_WARNING) + << "SSL_write couldn't write to the underlying socket; buffering data."; + pending_data_.SetData(static_cast<const uint8_t*>(pv), cb); + // Since we're taking responsibility for sending this data, return its full + // size. The user of this class can consider it sent. + return rtc::dchecked_cast<int>(cb); + } + return ret; +} + +int OpenSSLAdapter::SendTo(const void* pv, + size_t cb, + const SocketAddress& addr) { + if (GetSocket()->GetState() == Socket::CS_CONNECTED && + addr == GetSocket()->GetRemoteAddress()) { + return Send(pv, cb); + } + + SetError(ENOTCONN); + return SOCKET_ERROR; +} + +int OpenSSLAdapter::Recv(void* pv, size_t cb, int64_t* timestamp) { + switch (state_) { + case SSL_NONE: + return AsyncSocketAdapter::Recv(pv, cb, timestamp); + case SSL_WAIT: + case SSL_CONNECTING: + SetError(ENOTCONN); + return SOCKET_ERROR; + case SSL_CONNECTED: + break; + case SSL_ERROR: + default: + return SOCKET_ERROR; + } + + // Don't trust OpenSSL with zero byte reads + if (cb == 0) { + return 0; + } + + ssl_read_needs_write_ = false; + int code = SSL_read(ssl_, pv, checked_cast<int>(cb)); + int error = SSL_get_error(ssl_, code); + + switch (error) { + case SSL_ERROR_NONE: + return code; + case SSL_ERROR_WANT_READ: + SetError(EWOULDBLOCK); + break; + case SSL_ERROR_WANT_WRITE: + ssl_read_needs_write_ = true; + SetError(EWOULDBLOCK); + break; + case SSL_ERROR_ZERO_RETURN: + SetError(EWOULDBLOCK); + // do we need to signal closure? + break; + case SSL_ERROR_SSL: + LogSslError(); + Error("SSL_read", (code ? code : -1), false); + break; + default: + Error("SSL_read", (code ? code : -1), false); + break; + } + return SOCKET_ERROR; +} + +int OpenSSLAdapter::RecvFrom(void* pv, + size_t cb, + SocketAddress* paddr, + int64_t* timestamp) { + if (GetSocket()->GetState() == Socket::CS_CONNECTED) { + int ret = Recv(pv, cb, timestamp); + *paddr = GetRemoteAddress(); + return ret; + } + + SetError(ENOTCONN); + return SOCKET_ERROR; +} + +int OpenSSLAdapter::Close() { + Cleanup(); + state_ = SSL_NONE; + return AsyncSocketAdapter::Close(); +} + +Socket::ConnState OpenSSLAdapter::GetState() const { + ConnState state = GetSocket()->GetState(); + if ((state == CS_CONNECTED) && + ((state_ == SSL_WAIT) || (state_ == SSL_CONNECTING))) { + state = CS_CONNECTING; + } + return state; +} + +bool OpenSSLAdapter::IsResumedSession() { + return (ssl_ && SSL_session_reused(ssl_) == 1); +} + +void OpenSSLAdapter::OnTimeout() { + RTC_LOG(LS_INFO) << "DTLS timeout expired"; + DTLSv1_handle_timeout(ssl_); + ContinueSSL(); +} + +void OpenSSLAdapter::OnConnectEvent(Socket* socket) { + RTC_LOG(LS_INFO) << "OpenSSLAdapter::OnConnectEvent"; + if (state_ != SSL_WAIT) { + RTC_DCHECK(state_ == SSL_NONE); + AsyncSocketAdapter::OnConnectEvent(socket); + return; + } + + state_ = SSL_CONNECTING; + if (int err = BeginSSL()) { + AsyncSocketAdapter::OnCloseEvent(socket, err); + } +} + +void OpenSSLAdapter::OnReadEvent(Socket* socket) { + if (state_ == SSL_NONE) { + AsyncSocketAdapter::OnReadEvent(socket); + return; + } + + if (state_ == SSL_CONNECTING) { + if (int err = ContinueSSL()) { + Error("ContinueSSL", err); + } + return; + } + + if (state_ != SSL_CONNECTED) { + return; + } + + // Don't let ourselves go away during the callbacks + // PRefPtr<OpenSSLAdapter> lock(this); // TODO(benwright): fix this + if (ssl_write_needs_read_) { + AsyncSocketAdapter::OnWriteEvent(socket); + } + + AsyncSocketAdapter::OnReadEvent(socket); +} + +void OpenSSLAdapter::OnWriteEvent(Socket* socket) { + if (state_ == SSL_NONE) { + AsyncSocketAdapter::OnWriteEvent(socket); + return; + } + + if (state_ == SSL_CONNECTING) { + if (int err = ContinueSSL()) { + Error("ContinueSSL", err); + } + return; + } + + if (state_ != SSL_CONNECTED) { + return; + } + + // Don't let ourselves go away during the callbacks + // PRefPtr<OpenSSLAdapter> lock(this); // TODO(benwright): fix this + + if (ssl_read_needs_write_) { + AsyncSocketAdapter::OnReadEvent(socket); + } + + // If a previous SSL_write failed due to the underlying socket being blocked, + // this will attempt finishing the write operation. + if (!pending_data_.empty()) { + int error; + if (DoSslWrite(pending_data_.data(), pending_data_.size(), &error) == + static_cast<int>(pending_data_.size())) { + pending_data_.Clear(); + } + } + + AsyncSocketAdapter::OnWriteEvent(socket); +} + +void OpenSSLAdapter::OnCloseEvent(Socket* socket, int err) { + RTC_LOG(LS_INFO) << "OpenSSLAdapter::OnCloseEvent(" << err << ")"; + AsyncSocketAdapter::OnCloseEvent(socket, err); +} + +bool OpenSSLAdapter::SSLPostConnectionCheck(SSL* ssl, absl::string_view host) { + bool is_valid_cert_name = + openssl::VerifyPeerCertMatchesHost(ssl, host) && + (SSL_get_verify_result(ssl) == X509_V_OK || custom_cert_verifier_status_); + + if (!is_valid_cert_name && ignore_bad_cert_) { + RTC_DLOG(LS_WARNING) << "Other TLS post connection checks failed. " + "ignore_bad_cert_ set to true. Overriding name " + "verification failure!"; + is_valid_cert_name = true; + } + return is_valid_cert_name; +} + +void OpenSSLAdapter::SSLInfoCallback(const SSL* s, int where, int value) { + std::string type; + bool info_log = false; + bool alert_log = false; + switch (where) { + case SSL_CB_EXIT: + info_log = true; + type = "exit"; + break; + case SSL_CB_ALERT: + alert_log = true; + type = "alert"; + break; + case SSL_CB_READ_ALERT: + alert_log = true; + type = "read_alert"; + break; + case SSL_CB_WRITE_ALERT: + alert_log = true; + type = "write_alert"; + break; + case SSL_CB_ACCEPT_LOOP: + info_log = true; + type = "accept_loop"; + break; + case SSL_CB_ACCEPT_EXIT: + info_log = true; + type = "accept_exit"; + break; + case SSL_CB_CONNECT_LOOP: + info_log = true; + type = "connect_loop"; + break; + case SSL_CB_CONNECT_EXIT: + info_log = true; + type = "connect_exit"; + break; + case SSL_CB_HANDSHAKE_START: + info_log = true; + type = "handshake_start"; + break; + case SSL_CB_HANDSHAKE_DONE: + info_log = true; + type = "handshake_done"; + break; + case SSL_CB_LOOP: + case SSL_CB_READ: + case SSL_CB_WRITE: + default: + break; + } + + if (info_log) { + RTC_LOG(LS_INFO) << type << " " << SSL_state_string_long(s); + } + if (alert_log) { + RTC_LOG(LS_WARNING) << type << " " << SSL_alert_type_string_long(value) + << " " << SSL_alert_desc_string_long(value) << " " + << SSL_state_string_long(s); + } +} + +#ifdef WEBRTC_USE_CRYPTO_BUFFER_CALLBACK +// static +enum ssl_verify_result_t OpenSSLAdapter::SSLVerifyCallback(SSL* ssl, + uint8_t* out_alert) { + // Get our stream pointer from the SSL context. + OpenSSLAdapter* stream = + reinterpret_cast<OpenSSLAdapter*>(SSL_get_app_data(ssl)); + + ssl_verify_result_t ret = stream->SSLVerifyInternal(ssl, out_alert); + + // Should only be used for debugging and development. + if (ret != ssl_verify_ok && stream->ignore_bad_cert_) { + RTC_DLOG(LS_WARNING) << "Ignoring cert error while verifying cert chain"; + return ssl_verify_ok; + } + + return ret; +} + +enum ssl_verify_result_t OpenSSLAdapter::SSLVerifyInternal(SSL* ssl, + uint8_t* out_alert) { + if (ssl_cert_verifier_ == nullptr) { + RTC_LOG(LS_WARNING) << "Built-in trusted root certificates disabled but no " + "SSL verify callback provided."; + return ssl_verify_invalid; + } + + RTC_LOG(LS_INFO) << "Invoking SSL Verify Callback."; + const STACK_OF(CRYPTO_BUFFER)* chain = SSL_get0_peer_certificates(ssl); + if (sk_CRYPTO_BUFFER_num(chain) == 0) { + RTC_LOG(LS_ERROR) << "Peer certificate chain empty?"; + return ssl_verify_invalid; + } + + BoringSSLCertificate cert(bssl::UpRef(sk_CRYPTO_BUFFER_value(chain, 0))); + if (!ssl_cert_verifier_->Verify(cert)) { + RTC_LOG(LS_WARNING) << "Failed to verify certificate using custom callback"; + return ssl_verify_invalid; + } + + custom_cert_verifier_status_ = true; + RTC_LOG(LS_INFO) << "Validated certificate using custom callback"; + return ssl_verify_ok; +} +#else // WEBRTC_USE_CRYPTO_BUFFER_CALLBACK +int OpenSSLAdapter::SSLVerifyCallback(int status, X509_STORE_CTX* store) { + // Get our stream pointer from the store + SSL* ssl = reinterpret_cast<SSL*>( + X509_STORE_CTX_get_ex_data(store, SSL_get_ex_data_X509_STORE_CTX_idx())); + + OpenSSLAdapter* stream = + reinterpret_cast<OpenSSLAdapter*>(SSL_get_app_data(ssl)); + // Update status with the custom verifier. + // Status is unchanged if verification fails. + status = stream->SSLVerifyInternal(status, ssl, store); + + // Should only be used for debugging and development. + if (!status && stream->ignore_bad_cert_) { + RTC_DLOG(LS_WARNING) << "Ignoring cert error while verifying cert chain"; + return 1; + } + + return status; +} + +int OpenSSLAdapter::SSLVerifyInternal(int previous_status, + SSL* ssl, + X509_STORE_CTX* store) { +#if !defined(NDEBUG) + if (!previous_status) { + char data[256]; + X509* cert = X509_STORE_CTX_get_current_cert(store); + int depth = X509_STORE_CTX_get_error_depth(store); + int err = X509_STORE_CTX_get_error(store); + + RTC_DLOG(LS_INFO) << "Error with certificate at depth: " << depth; + X509_NAME_oneline(X509_get_issuer_name(cert), data, sizeof(data)); + RTC_DLOG(LS_INFO) << " issuer = " << data; + X509_NAME_oneline(X509_get_subject_name(cert), data, sizeof(data)); + RTC_DLOG(LS_INFO) << " subject = " << data; + RTC_DLOG(LS_INFO) << " err = " << err << ":" + << X509_verify_cert_error_string(err); + } +#endif + // `ssl_cert_verifier_` is used to override errors; if there is no error + // there is no reason to call it. + if (previous_status || ssl_cert_verifier_ == nullptr) { + return previous_status; + } + + RTC_LOG(LS_INFO) << "Invoking SSL Verify Callback."; +#ifdef OPENSSL_IS_BORINGSSL + // Convert X509 to CRYPTO_BUFFER. + uint8_t* data = nullptr; + int length = i2d_X509(X509_STORE_CTX_get_current_cert(store), &data); + if (length < 0) { + RTC_LOG(LS_ERROR) << "Failed to encode X509."; + return previous_status; + } + bssl::UniquePtr<uint8_t> owned_data(data); + bssl::UniquePtr<CRYPTO_BUFFER> crypto_buffer( + CRYPTO_BUFFER_new(data, length, openssl::GetBufferPool())); + if (!crypto_buffer) { + RTC_LOG(LS_ERROR) << "Failed to allocate CRYPTO_BUFFER."; + return previous_status; + } + const BoringSSLCertificate cert(std::move(crypto_buffer)); +#else + const OpenSSLCertificate cert(X509_STORE_CTX_get_current_cert(store)); +#endif + if (!ssl_cert_verifier_->Verify(cert)) { + RTC_LOG(LS_INFO) << "Failed to verify certificate using custom callback"; + return previous_status; + } + + custom_cert_verifier_status_ = true; + RTC_LOG(LS_INFO) << "Validated certificate using custom callback"; + return 1; +} +#endif // !defined(WEBRTC_USE_CRYPTO_BUFFER_CALLBACK) + +int OpenSSLAdapter::NewSSLSessionCallback(SSL* ssl, SSL_SESSION* session) { + OpenSSLAdapter* stream = + reinterpret_cast<OpenSSLAdapter*>(SSL_get_app_data(ssl)); + RTC_DCHECK(stream->ssl_session_cache_); + RTC_LOG(LS_INFO) << "Caching SSL session for " << stream->ssl_host_name_; + stream->ssl_session_cache_->AddSession(stream->ssl_host_name_, session); + return 1; // We've taken ownership of the session; OpenSSL shouldn't free it. +} + +SSL_CTX* OpenSSLAdapter::CreateContext(SSLMode mode, bool enable_cache) { +#ifdef WEBRTC_USE_CRYPTO_BUFFER_CALLBACK + // If X509 objects aren't used, we can use these methods to avoid + // linking the sizable crypto/x509 code. + SSL_CTX* ctx = SSL_CTX_new(mode == SSL_MODE_DTLS ? DTLS_with_buffers_method() + : TLS_with_buffers_method()); +#else + SSL_CTX* ctx = + SSL_CTX_new(mode == SSL_MODE_DTLS ? DTLS_method() : TLS_method()); +#endif + if (ctx == nullptr) { + unsigned long error = ERR_get_error(); // NOLINT: type used by OpenSSL. + RTC_LOG(LS_WARNING) << "SSL_CTX creation failed: " << '"' + << ERR_reason_error_string(error) + << "\" " + "(error=" + << error << ')'; + return nullptr; + } + +#ifndef WEBRTC_EXCLUDE_BUILT_IN_SSL_ROOT_CERTS + if (!openssl::LoadBuiltinSSLRootCertificates(ctx)) { + RTC_LOG(LS_ERROR) << "SSL_CTX creation failed: Failed to load any trusted " + "ssl root certificates."; + SSL_CTX_free(ctx); + return nullptr; + } +#endif // WEBRTC_EXCLUDE_BUILT_IN_SSL_ROOT_CERTS + +#if !defined(NDEBUG) + SSL_CTX_set_info_callback(ctx, SSLInfoCallback); +#endif + +#ifdef OPENSSL_IS_BORINGSSL + SSL_CTX_set0_buffer_pool(ctx, openssl::GetBufferPool()); +#endif + +#ifdef WEBRTC_USE_CRYPTO_BUFFER_CALLBACK + SSL_CTX_set_custom_verify(ctx, SSL_VERIFY_PEER, SSLVerifyCallback); +#else + SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, SSLVerifyCallback); + // Verify certificate chains up to a depth of 4. This is not + // needed for DTLS-SRTP which uses self-signed certificates + // (so the depth is 0) but is required to support TURN/TLS. + SSL_CTX_set_verify_depth(ctx, 4); +#endif + // Use defaults, but disable HMAC-SHA256 and HMAC-SHA384 ciphers + // (note that SHA256 and SHA384 only select legacy CBC ciphers). + // Additionally disable HMAC-SHA1 ciphers in ECDSA. These are the remaining + // CBC-mode ECDSA ciphers. Finally, disable 3DES. + SSL_CTX_set_cipher_list( + ctx, "ALL:!SHA256:!SHA384:!aPSK:!ECDSA+SHA1:!ADH:!LOW:!EXP:!MD5:!3DES"); + + if (mode == SSL_MODE_DTLS) { + SSL_CTX_set_read_ahead(ctx, 1); + } + + if (enable_cache) { + SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_CLIENT); + SSL_CTX_sess_set_new_cb(ctx, &OpenSSLAdapter::NewSSLSessionCallback); + } + + return ctx; +} + +std::string TransformAlpnProtocols( + const std::vector<std::string>& alpn_protocols) { + // Transforms the alpn_protocols list to the format expected by + // Open/BoringSSL. This requires joining the protocols into a single string + // and prepending a character with the size of the protocol string before + // each protocol. + std::string transformed_alpn; + for (const std::string& proto : alpn_protocols) { + if (proto.size() == 0 || proto.size() > 0xFF) { + RTC_LOG(LS_ERROR) << "OpenSSLAdapter::Error(" + "TransformAlpnProtocols received proto with size " + << proto.size() << ")"; + return ""; + } + transformed_alpn += static_cast<char>(proto.size()); + transformed_alpn += proto; + RTC_LOG(LS_VERBOSE) << "TransformAlpnProtocols: Adding proto: " << proto; + } + return transformed_alpn; +} + +////////////////////////////////////////////////////////////////////// +// OpenSSLAdapterFactory +////////////////////////////////////////////////////////////////////// + +OpenSSLAdapterFactory::OpenSSLAdapterFactory() = default; + +OpenSSLAdapterFactory::~OpenSSLAdapterFactory() = default; + +void OpenSSLAdapterFactory::SetMode(SSLMode mode) { + RTC_DCHECK(!ssl_session_cache_); + ssl_mode_ = mode; +} + +void OpenSSLAdapterFactory::SetCertVerifier( + SSLCertificateVerifier* ssl_cert_verifier) { + RTC_DCHECK(!ssl_session_cache_); + ssl_cert_verifier_ = ssl_cert_verifier; +} + +void OpenSSLAdapterFactory::SetIdentity(std::unique_ptr<SSLIdentity> identity) { + RTC_DCHECK(!ssl_session_cache_); + identity_ = std::move(identity); +} + +void OpenSSLAdapterFactory::SetRole(SSLRole role) { + RTC_DCHECK(!ssl_session_cache_); + ssl_role_ = role; +} + +void OpenSSLAdapterFactory::SetIgnoreBadCert(bool ignore) { + RTC_DCHECK(!ssl_session_cache_); + ignore_bad_cert_ = ignore; +} + +OpenSSLAdapter* OpenSSLAdapterFactory::CreateAdapter(Socket* socket) { + if (ssl_session_cache_ == nullptr) { + SSL_CTX* ssl_ctx = OpenSSLAdapter::CreateContext(ssl_mode_, true); + if (ssl_ctx == nullptr) { + return nullptr; + } + // The OpenSSLSessionCache will upref the ssl_ctx. + ssl_session_cache_ = + std::make_unique<OpenSSLSessionCache>(ssl_mode_, ssl_ctx); + SSL_CTX_free(ssl_ctx); + } + OpenSSLAdapter* ssl_adapter = + new OpenSSLAdapter(socket, ssl_session_cache_.get(), ssl_cert_verifier_); + ssl_adapter->SetRole(ssl_role_); + ssl_adapter->SetIgnoreBadCert(ignore_bad_cert_); + if (identity_) { + ssl_adapter->SetIdentity(identity_->Clone()); + } + return ssl_adapter; +} + +OpenSSLAdapter::EarlyExitCatcher::EarlyExitCatcher(OpenSSLAdapter& adapter_ptr) + : adapter_ptr_(adapter_ptr) {} + +void OpenSSLAdapter::EarlyExitCatcher::disable() { + disabled_ = true; +} + +OpenSSLAdapter::EarlyExitCatcher::~EarlyExitCatcher() { + if (!disabled_) { + adapter_ptr_.Cleanup(); + } +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/openssl_adapter.h b/third_party/libwebrtc/rtc_base/openssl_adapter.h new file mode 100644 index 0000000000..558a04077a --- /dev/null +++ b/third_party/libwebrtc/rtc_base/openssl_adapter.h @@ -0,0 +1,245 @@ +/* + * 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 RTC_BASE_OPENSSL_ADAPTER_H_ +#define RTC_BASE_OPENSSL_ADAPTER_H_ + +#include <openssl/ossl_typ.h> +#include <stddef.h> +#include <stdint.h> + +#include <memory> +#include <string> +#include <vector> + +#include "absl/strings/string_view.h" +#include "api/task_queue/pending_task_safety_flag.h" +#include "rtc_base/buffer.h" +#ifdef OPENSSL_IS_BORINGSSL +#include "rtc_base/boringssl_identity.h" +#else +#include "rtc_base/openssl_identity.h" +#endif +#include "rtc_base/openssl_session_cache.h" +#include "rtc_base/socket.h" +#include "rtc_base/socket_address.h" +#include "rtc_base/ssl_adapter.h" +#include "rtc_base/ssl_certificate.h" +#include "rtc_base/ssl_identity.h" +#include "rtc_base/ssl_stream_adapter.h" + +namespace rtc { + +namespace webrtc_openssl_adapter_internal { + +// Local definition, since absl::StrJoin is not allow-listed. Declared in header +// file only for unittests. +std::string StrJoin(const std::vector<std::string>& list, char delimiter); + +} // namespace webrtc_openssl_adapter_internal + +class OpenSSLAdapter final : public SSLAdapter { + public: + static bool InitializeSSL(); + static bool CleanupSSL(); + + // Creating an OpenSSLAdapter requires a socket to bind to, an optional + // session cache if you wish to improve performance by caching sessions for + // hostnames you have previously connected to and an optional + // SSLCertificateVerifier which can override any existing trusted roots to + // validate a peer certificate. The cache and verifier are effectively + // immutable after the the SSL connection starts. + explicit OpenSSLAdapter(Socket* socket, + OpenSSLSessionCache* ssl_session_cache = nullptr, + SSLCertificateVerifier* ssl_cert_verifier = nullptr); + ~OpenSSLAdapter() override; + + void SetIgnoreBadCert(bool ignore) override; + void SetAlpnProtocols(const std::vector<std::string>& protos) override; + void SetEllipticCurves(const std::vector<std::string>& curves) override; + void SetMode(SSLMode mode) override; + void SetCertVerifier(SSLCertificateVerifier* ssl_cert_verifier) override; + void SetIdentity(std::unique_ptr<SSLIdentity> identity) override; + void SetRole(SSLRole role) override; + int StartSSL(absl::string_view hostname) override; + int Send(const void* pv, size_t cb) override; + int SendTo(const void* pv, size_t cb, const SocketAddress& addr) override; + int Recv(void* pv, size_t cb, int64_t* timestamp) override; + int RecvFrom(void* pv, + size_t cb, + SocketAddress* paddr, + int64_t* timestamp) override; + int Close() override; + // Note that the socket returns ST_CONNECTING while SSL is being negotiated. + ConnState GetState() const override; + bool IsResumedSession() override; + // Creates a new SSL_CTX object, configured for client-to-server usage + // with SSLMode `mode`, and if `enable_cache` is true, with support for + // storing successful sessions so that they can be later resumed. + // OpenSSLAdapterFactory will call this method to create its own internal + // SSL_CTX, and OpenSSLAdapter will also call this when used without a + // factory. + static SSL_CTX* CreateContext(SSLMode mode, bool enable_cache); + + protected: + void OnConnectEvent(Socket* socket) override; + void OnReadEvent(Socket* socket) override; + void OnWriteEvent(Socket* socket) override; + void OnCloseEvent(Socket* socket, int err) override; + + private: + class EarlyExitCatcher { + public: + EarlyExitCatcher(OpenSSLAdapter& adapter_ptr); + void disable(); + ~EarlyExitCatcher(); + + private: + bool disabled_ = false; + OpenSSLAdapter& adapter_ptr_; + }; + enum SSLState { + SSL_NONE, + SSL_WAIT, + SSL_CONNECTING, + SSL_CONNECTED, + SSL_ERROR + }; + + int BeginSSL(); + int ContinueSSL(); + void Error(absl::string_view context, int err, bool signal = true); + void Cleanup(); + void OnTimeout(); + + // Return value and arguments have the same meanings as for Send; `error` is + // an output parameter filled with the result of SSL_get_error. + int DoSslWrite(const void* pv, size_t cb, int* error); + bool SSLPostConnectionCheck(SSL* ssl, absl::string_view host); + + // Logs info about the state of the SSL connection. + static void SSLInfoCallback(const SSL* ssl, int where, int ret); + +#if defined(OPENSSL_IS_BORINGSSL) && \ + defined(WEBRTC_EXCLUDE_BUILT_IN_SSL_ROOT_CERTS) + static enum ssl_verify_result_t SSLVerifyCallback(SSL* ssl, + uint8_t* out_alert); + enum ssl_verify_result_t SSLVerifyInternal(SSL* ssl, uint8_t* out_alert); +#else + static int SSLVerifyCallback(int ok, X509_STORE_CTX* store); + // Call a custom verifier, if installed. + // Returns 1 on success, `status_on_error` on error or verification failure. + int SSLVerifyInternal(int status_on_error, SSL* ssl, X509_STORE_CTX* store); +#endif + friend class OpenSSLStreamAdapter; // for custom_verify_callback_; + + // If the SSL_CTX was created with `enable_cache` set to true, this callback + // will be called when a SSL session has been successfully established, + // to allow its SSL_SESSION* to be cached for later resumption. + static int NewSSLSessionCallback(SSL* ssl, SSL_SESSION* session); + + // Optional SSL Shared session cache to improve performance. + OpenSSLSessionCache* ssl_session_cache_ = nullptr; + // Optional SSL Certificate verifier which can be set by a third party. + SSLCertificateVerifier* ssl_cert_verifier_ = nullptr; + // The current connection state of the (d)TLS connection. + SSLState state_; + +#ifdef OPENSSL_IS_BORINGSSL + std::unique_ptr<BoringSSLIdentity> identity_; +#else + std::unique_ptr<OpenSSLIdentity> identity_; +#endif + // Indicates whethere this is a client or a server. + SSLRole role_; + bool ssl_read_needs_write_; + bool ssl_write_needs_read_; + // This buffer is used if SSL_write fails with SSL_ERROR_WANT_WRITE, which + // means we need to keep retrying with *the same exact data* until it + // succeeds. Afterwards it will be cleared. + Buffer pending_data_; + SSL* ssl_; + // Holds the SSL context, which may be shared if an session cache is provided. + SSL_CTX* ssl_ctx_; + // Hostname of server that is being connected, used for SNI. + std::string ssl_host_name_; + // Set the adapter to DTLS or TLS mode before creating the context. + SSLMode ssl_mode_; + // If true, the server certificate need not match the configured hostname. + bool ignore_bad_cert_; + // List of protocols to be used in the TLS ALPN extension. + std::vector<std::string> alpn_protocols_; + // List of elliptic curves to be used in the TLS elliptic curves extension. + std::vector<std::string> elliptic_curves_; + // Holds the result of the call to run of the ssl_cert_verify_->Verify() + bool custom_cert_verifier_status_; + // Flag to cancel pending timeout task. + webrtc::ScopedTaskSafety timer_; +}; + +// The OpenSSLAdapterFactory is responsbile for creating multiple new +// OpenSSLAdapters with a shared SSL_CTX and a shared SSL_SESSION cache. The +// SSL_SESSION cache allows existing SSL_SESSIONS to be reused instead of +// recreating them leading to a significant performance improvement. +class OpenSSLAdapterFactory : public SSLAdapterFactory { + public: + OpenSSLAdapterFactory(); + ~OpenSSLAdapterFactory() override; + // Set the SSL Mode to use with this factory. This should only be set before + // the first adapter is created with the factory. If it is called after it + // will DCHECK. + void SetMode(SSLMode mode) override; + + // Set a custom certificate verifier to be passed down to each instance + // created with this factory. This should only ever be set before the first + // call to the factory and cannot be changed after the fact. + void SetCertVerifier(SSLCertificateVerifier* ssl_cert_verifier) override; + + void SetIdentity(std::unique_ptr<SSLIdentity> identity) override; + + // Choose whether the socket acts as a server socket or client socket. + void SetRole(SSLRole role) override; + + // Methods that control server certificate verification, used in unit tests. + // Do not call these methods in production code. + void SetIgnoreBadCert(bool ignore) override; + + // Constructs a new socket using the shared OpenSSLSessionCache. This means + // existing SSLSessions already in the cache will be reused instead of + // re-created for improved performance. + OpenSSLAdapter* CreateAdapter(Socket* socket) override; + + private: + // Holds the SSLMode (DTLS,TLS) that will be used to set the session cache. + SSLMode ssl_mode_ = SSL_MODE_TLS; + SSLRole ssl_role_ = SSL_CLIENT; + bool ignore_bad_cert_ = false; + + std::unique_ptr<SSLIdentity> identity_; + + // Holds a cache of existing SSL Sessions. + std::unique_ptr<OpenSSLSessionCache> ssl_session_cache_; + // Provides an optional custom callback for verifying SSL certificates, this + // in currently only used for TLS-TURN connections. + SSLCertificateVerifier* ssl_cert_verifier_ = nullptr; + // TODO(benwright): Remove this when context is moved to OpenSSLCommon. + // Hold a friend class to the OpenSSLAdapter to retrieve the context. + friend class OpenSSLAdapter; +}; + +// The EarlyExitCatcher is responsible for calling OpenSSLAdapter::Cleanup on +// destruction. By doing this we have scoped cleanup which can be disabled if +// there were no errors, aka early exits. + +std::string TransformAlpnProtocols(const std::vector<std::string>& protos); + +} // namespace rtc + +#endif // RTC_BASE_OPENSSL_ADAPTER_H_ diff --git a/third_party/libwebrtc/rtc_base/openssl_adapter_unittest.cc b/third_party/libwebrtc/rtc_base/openssl_adapter_unittest.cc new file mode 100644 index 0000000000..ce351dc98e --- /dev/null +++ b/third_party/libwebrtc/rtc_base/openssl_adapter_unittest.cc @@ -0,0 +1,134 @@ +/* + * Copyright 2017 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 "rtc_base/openssl_adapter.h" + +#include <sstream> +#include <string> +#include <vector> + +#include "absl/memory/memory.h" +#include "rtc_base/gunit.h" +#include "rtc_base/socket.h" +#include "test/gmock.h" + +namespace rtc { +namespace { + +class MockAsyncSocket : public Socket { + public: + virtual ~MockAsyncSocket() = default; + MOCK_METHOD(Socket*, Accept, (SocketAddress*), (override)); + MOCK_METHOD(SocketAddress, GetLocalAddress, (), (const, override)); + MOCK_METHOD(SocketAddress, GetRemoteAddress, (), (const, override)); + MOCK_METHOD(int, Bind, (const SocketAddress&), (override)); + MOCK_METHOD(int, Connect, (const SocketAddress&), (override)); + MOCK_METHOD(int, Send, (const void*, size_t), (override)); + MOCK_METHOD(int, + SendTo, + (const void*, size_t, const SocketAddress&), + (override)); + MOCK_METHOD(int, Recv, (void*, size_t, int64_t*), (override)); + MOCK_METHOD(int, + RecvFrom, + (void*, size_t, SocketAddress*, int64_t*), + (override)); + MOCK_METHOD(int, Listen, (int), (override)); + MOCK_METHOD(int, Close, (), (override)); + MOCK_METHOD(int, GetError, (), (const, override)); + MOCK_METHOD(void, SetError, (int), (override)); + MOCK_METHOD(ConnState, GetState, (), (const, override)); + MOCK_METHOD(int, GetOption, (Option, int*), (override)); + MOCK_METHOD(int, SetOption, (Option, int), (override)); +}; + +class MockCertVerifier : public SSLCertificateVerifier { + public: + virtual ~MockCertVerifier() = default; + MOCK_METHOD(bool, Verify, (const SSLCertificate&), (override)); +}; + +} // namespace + +using ::testing::_; +using ::testing::Return; + +TEST(OpenSSLAdapterTest, TestTransformAlpnProtocols) { + EXPECT_EQ("", TransformAlpnProtocols(std::vector<std::string>())); + + // Protocols larger than 255 characters (whose size can't be fit in a byte), + // can't be converted, and an empty string will be returned. + std::string large_protocol(256, 'a'); + EXPECT_EQ("", + TransformAlpnProtocols(std::vector<std::string>{large_protocol})); + + // One protocol test. + std::vector<std::string> alpn_protos{"h2"}; + std::stringstream expected_response; + expected_response << static_cast<char>(2) << "h2"; + EXPECT_EQ(expected_response.str(), TransformAlpnProtocols(alpn_protos)); + + // Standard protocols test (h2,http/1.1). + alpn_protos.push_back("http/1.1"); + expected_response << static_cast<char>(8) << "http/1.1"; + EXPECT_EQ(expected_response.str(), TransformAlpnProtocols(alpn_protos)); +} + +// Verifies that SSLStart works when OpenSSLAdapter is started in standalone +// mode. +TEST(OpenSSLAdapterTest, TestBeginSSLBeforeConnection) { + rtc::AutoThread main_thread; + Socket* async_socket = new MockAsyncSocket(); + OpenSSLAdapter adapter(async_socket); + EXPECT_EQ(adapter.StartSSL("webrtc.org"), 0); +} + +// Verifies that the adapter factory can create new adapters. +TEST(OpenSSLAdapterFactoryTest, CreateSingleOpenSSLAdapter) { + rtc::AutoThread main_thread; + OpenSSLAdapterFactory adapter_factory; + Socket* async_socket = new MockAsyncSocket(); + auto simple_adapter = std::unique_ptr<OpenSSLAdapter>( + adapter_factory.CreateAdapter(async_socket)); + EXPECT_NE(simple_adapter, nullptr); +} + +// Verifies that setting a custom verifier still allows for adapters to be +// created. +TEST(OpenSSLAdapterFactoryTest, CreateWorksWithCustomVerifier) { + rtc::AutoThread main_thread; + MockCertVerifier* mock_verifier = new MockCertVerifier(); + EXPECT_CALL(*mock_verifier, Verify(_)).WillRepeatedly(Return(true)); + auto cert_verifier = std::unique_ptr<SSLCertificateVerifier>(mock_verifier); + + OpenSSLAdapterFactory adapter_factory; + adapter_factory.SetCertVerifier(cert_verifier.get()); + Socket* async_socket = new MockAsyncSocket(); + auto simple_adapter = std::unique_ptr<OpenSSLAdapter>( + adapter_factory.CreateAdapter(async_socket)); + EXPECT_NE(simple_adapter, nullptr); +} + +TEST(StrJoinTest, SingleElement) { + EXPECT_EQ(webrtc_openssl_adapter_internal::StrJoin({"a"}, ','), "a"); +} + +TEST(StrJoinTest, TwoElements) { + EXPECT_EQ(webrtc_openssl_adapter_internal::StrJoin({"first", "second"}, ':'), + "first:second"); +} + +TEST(StrJoinTest, WithEmptyElement) { + EXPECT_EQ( + webrtc_openssl_adapter_internal::StrJoin({"first", "", "second"}, ':'), + "first::second"); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/openssl_certificate.cc b/third_party/libwebrtc/rtc_base/openssl_certificate.cc new file mode 100644 index 0000000000..faed72b4db --- /dev/null +++ b/third_party/libwebrtc/rtc_base/openssl_certificate.cc @@ -0,0 +1,290 @@ +/* + * 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 "rtc_base/openssl_certificate.h" + +#if defined(WEBRTC_WIN) +// Must be included first before openssl headers. +#include "rtc_base/win32.h" // NOLINT +#endif // WEBRTC_WIN + +#include <openssl/bio.h> +#include <openssl/bn.h> +#include <openssl/pem.h> +#include <time.h> + +#include <memory> + +#include "rtc_base/checks.h" +#include "rtc_base/helpers.h" +#include "rtc_base/logging.h" +#include "rtc_base/message_digest.h" +#include "rtc_base/openssl_digest.h" +#include "rtc_base/openssl_identity.h" +#include "rtc_base/openssl_utility.h" + +namespace rtc { +namespace { + +// Random bits for certificate serial number +static const int SERIAL_RAND_BITS = 64; + +#if !defined(NDEBUG) +// Print a certificate to the log, for debugging. +static void PrintCert(X509* x509) { + BIO* temp_memory_bio = BIO_new(BIO_s_mem()); + if (!temp_memory_bio) { + RTC_DLOG_F(LS_ERROR) << "Failed to allocate temporary memory bio"; + return; + } + X509_print_ex(temp_memory_bio, x509, XN_FLAG_SEP_CPLUS_SPC, 0); + BIO_write(temp_memory_bio, "\0", 1); + char* buffer; + BIO_get_mem_data(temp_memory_bio, &buffer); + RTC_DLOG(LS_VERBOSE) << buffer; + BIO_free(temp_memory_bio); +} +#endif + +// Generate a self-signed certificate, with the public key from the +// given key pair. Caller is responsible for freeing the returned object. +static X509* MakeCertificate(EVP_PKEY* pkey, const SSLIdentityParams& params) { + RTC_LOG(LS_INFO) << "Making certificate for " << params.common_name; + + ASN1_INTEGER* asn1_serial_number = nullptr; + std::unique_ptr<BIGNUM, decltype(&::BN_free)> serial_number{nullptr, + ::BN_free}; + std::unique_ptr<X509, decltype(&::X509_free)> x509{nullptr, ::X509_free}; + std::unique_ptr<X509_NAME, decltype(&::X509_NAME_free)> name{ + nullptr, ::X509_NAME_free}; + time_t epoch_off = 0; // Time offset since epoch. + x509.reset(X509_new()); + if (x509 == nullptr) { + return nullptr; + } + if (!X509_set_pubkey(x509.get(), pkey)) { + return nullptr; + } + // serial number - temporary reference to serial number inside x509 struct + serial_number.reset(BN_new()); + if (serial_number == nullptr || + !BN_pseudo_rand(serial_number.get(), SERIAL_RAND_BITS, 0, 0) || + (asn1_serial_number = X509_get_serialNumber(x509.get())) == nullptr || + !BN_to_ASN1_INTEGER(serial_number.get(), asn1_serial_number)) { + return nullptr; + } + // Set version to X509.V3 + if (!X509_set_version(x509.get(), 2L)) { + return nullptr; + } + + // There are a lot of possible components for the name entries. In + // our P2P SSL mode however, the certificates are pre-exchanged + // (through the secure XMPP channel), and so the certificate + // identification is arbitrary. It can't be empty, so we set some + // arbitrary common_name. Note that this certificate goes out in + // clear during SSL negotiation, so there may be a privacy issue in + // putting anything recognizable here. + name.reset(X509_NAME_new()); + if (name == nullptr || + !X509_NAME_add_entry_by_NID(name.get(), NID_commonName, MBSTRING_UTF8, + (unsigned char*)params.common_name.c_str(), + -1, -1, 0) || + !X509_set_subject_name(x509.get(), name.get()) || + !X509_set_issuer_name(x509.get(), name.get())) { + return nullptr; + } + if (!X509_time_adj(X509_get_notBefore(x509.get()), params.not_before, + &epoch_off) || + !X509_time_adj(X509_get_notAfter(x509.get()), params.not_after, + &epoch_off)) { + return nullptr; + } + if (!X509_sign(x509.get(), pkey, EVP_sha256())) { + return nullptr; + } + + RTC_LOG(LS_INFO) << "Returning certificate"; + return x509.release(); +} + +} // namespace + +OpenSSLCertificate::OpenSSLCertificate(X509* x509) : x509_(x509) { + RTC_DCHECK(x509_ != nullptr); + X509_up_ref(x509_); +} + +std::unique_ptr<OpenSSLCertificate> OpenSSLCertificate::Generate( + OpenSSLKeyPair* key_pair, + const SSLIdentityParams& params) { + SSLIdentityParams actual_params(params); + if (actual_params.common_name.empty()) { + // Use a random string, arbitrarily 8chars long. + actual_params.common_name = CreateRandomString(8); + } + X509* x509 = MakeCertificate(key_pair->pkey(), actual_params); + if (!x509) { + openssl::LogSSLErrors("Generating certificate"); + return nullptr; + } +#if !defined(NDEBUG) + PrintCert(x509); +#endif + auto ret = std::make_unique<OpenSSLCertificate>(x509); + X509_free(x509); + return ret; +} + +std::unique_ptr<OpenSSLCertificate> OpenSSLCertificate::FromPEMString( + absl::string_view pem_string) { + BIO* bio = BIO_new_mem_buf(const_cast<char*>(pem_string.data()), -1); + if (!bio) { + return nullptr; + } + + BIO_set_mem_eof_return(bio, 0); + X509* x509 = + PEM_read_bio_X509(bio, nullptr, nullptr, const_cast<char*>("\0")); + BIO_free(bio); // Frees the BIO, but not the pointed-to string. + + if (!x509) { + return nullptr; + } + auto ret = std::make_unique<OpenSSLCertificate>(x509); + X509_free(x509); + return ret; +} + +// NOTE: This implementation only functions correctly after InitializeSSL +// and before CleanupSSL. +bool OpenSSLCertificate::GetSignatureDigestAlgorithm( + std::string* algorithm) const { + int nid = X509_get_signature_nid(x509_); + switch (nid) { + case NID_md5WithRSA: + case NID_md5WithRSAEncryption: + *algorithm = DIGEST_MD5; + break; + case NID_ecdsa_with_SHA1: + case NID_dsaWithSHA1: + case NID_dsaWithSHA1_2: + case NID_sha1WithRSA: + case NID_sha1WithRSAEncryption: + *algorithm = DIGEST_SHA_1; + break; + case NID_ecdsa_with_SHA224: + case NID_sha224WithRSAEncryption: + case NID_dsa_with_SHA224: + *algorithm = DIGEST_SHA_224; + break; + case NID_ecdsa_with_SHA256: + case NID_sha256WithRSAEncryption: + case NID_dsa_with_SHA256: + *algorithm = DIGEST_SHA_256; + break; + case NID_ecdsa_with_SHA384: + case NID_sha384WithRSAEncryption: + *algorithm = DIGEST_SHA_384; + break; + case NID_ecdsa_with_SHA512: + case NID_sha512WithRSAEncryption: + *algorithm = DIGEST_SHA_512; + break; + default: + // Unknown algorithm. There are several unhandled options that are less + // common and more complex. + RTC_LOG(LS_ERROR) << "Unknown signature algorithm NID: " << nid; + algorithm->clear(); + return false; + } + return true; +} + +bool OpenSSLCertificate::ComputeDigest(absl::string_view algorithm, + unsigned char* digest, + size_t size, + size_t* length) const { + return ComputeDigest(x509_, algorithm, digest, size, length); +} + +bool OpenSSLCertificate::ComputeDigest(const X509* x509, + absl::string_view algorithm, + unsigned char* digest, + size_t size, + size_t* length) { + const EVP_MD* md = nullptr; + unsigned int n = 0; + if (!OpenSSLDigest::GetDigestEVP(algorithm, &md)) { + return false; + } + if (size < static_cast<size_t>(EVP_MD_size(md))) { + return false; + } + X509_digest(x509, md, digest, &n); + *length = n; + return true; +} + +OpenSSLCertificate::~OpenSSLCertificate() { + X509_free(x509_); +} + +std::unique_ptr<SSLCertificate> OpenSSLCertificate::Clone() const { + return std::make_unique<OpenSSLCertificate>(x509_); +} + +std::string OpenSSLCertificate::ToPEMString() const { + BIO* bio = BIO_new(BIO_s_mem()); + RTC_CHECK(bio); + RTC_CHECK(PEM_write_bio_X509(bio, x509_)); + BIO_write(bio, "\0", 1); + char* buffer; + BIO_get_mem_data(bio, &buffer); + std::string ret(buffer); + BIO_free(bio); + return ret; +} + +void OpenSSLCertificate::ToDER(Buffer* der_buffer) const { + // In case of failure, make sure to leave the buffer empty. + der_buffer->SetSize(0); + // Calculates the DER representation of the certificate, from scratch. + BIO* bio = BIO_new(BIO_s_mem()); + RTC_CHECK(bio); + RTC_CHECK(i2d_X509_bio(bio, x509_)); + char* data = nullptr; + size_t length = BIO_get_mem_data(bio, &data); + der_buffer->SetData(data, length); + BIO_free(bio); +} + +bool OpenSSLCertificate::operator==(const OpenSSLCertificate& other) const { + return X509_cmp(x509_, other.x509_) == 0; +} + +bool OpenSSLCertificate::operator!=(const OpenSSLCertificate& other) const { + return !(*this == other); +} + +int64_t OpenSSLCertificate::CertificateExpirationTime() const { + ASN1_TIME* expire_time = X509_get_notAfter(x509_); + bool long_format; + if (expire_time->type == V_ASN1_UTCTIME) { + long_format = false; + } else if (expire_time->type == V_ASN1_GENERALIZEDTIME) { + long_format = true; + } else { + return -1; + } + return ASN1TimeToSec(expire_time->data, expire_time->length, long_format); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/openssl_certificate.h b/third_party/libwebrtc/rtc_base/openssl_certificate.h new file mode 100644 index 0000000000..3f1b8c82f9 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/openssl_certificate.h @@ -0,0 +1,79 @@ +/* + * 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 RTC_BASE_OPENSSL_CERTIFICATE_H_ +#define RTC_BASE_OPENSSL_CERTIFICATE_H_ + +#include <openssl/ossl_typ.h> +#include <stddef.h> +#include <stdint.h> + +#include <string> + +#include "rtc_base/buffer.h" +#include "rtc_base/ssl_certificate.h" +#include "rtc_base/ssl_identity.h" + +namespace rtc { + +class OpenSSLKeyPair; + +// OpenSSLCertificate encapsulates an OpenSSL X509* certificate object, +// which is also reference counted inside the OpenSSL library. +class OpenSSLCertificate final : public SSLCertificate { + public: + // X509 object has its reference count incremented. So the caller and + // OpenSSLCertificate share ownership. + explicit OpenSSLCertificate(X509* x509); + + static std::unique_ptr<OpenSSLCertificate> Generate( + OpenSSLKeyPair* key_pair, + const SSLIdentityParams& params); + static std::unique_ptr<OpenSSLCertificate> FromPEMString( + absl::string_view pem_string); + + ~OpenSSLCertificate() override; + + OpenSSLCertificate(const OpenSSLCertificate&) = delete; + OpenSSLCertificate& operator=(const OpenSSLCertificate&) = delete; + + std::unique_ptr<SSLCertificate> Clone() const override; + + X509* x509() const { return x509_; } + + std::string ToPEMString() const override; + void ToDER(Buffer* der_buffer) const override; + bool operator==(const OpenSSLCertificate& other) const; + bool operator!=(const OpenSSLCertificate& other) const; + + // Compute the digest of the certificate given algorithm + bool ComputeDigest(absl::string_view algorithm, + unsigned char* digest, + size_t size, + size_t* length) const override; + + // Compute the digest of a certificate as an X509 * + static bool ComputeDigest(const X509* x509, + absl::string_view algorithm, + unsigned char* digest, + size_t size, + size_t* length); + + bool GetSignatureDigestAlgorithm(std::string* algorithm) const override; + + int64_t CertificateExpirationTime() const override; + + private: + X509* x509_; // NOT OWNED +}; + +} // namespace rtc + +#endif // RTC_BASE_OPENSSL_CERTIFICATE_H_ diff --git a/third_party/libwebrtc/rtc_base/openssl_digest.cc b/third_party/libwebrtc/rtc_base/openssl_digest.cc new file mode 100644 index 0000000000..bbf39570f6 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/openssl_digest.cc @@ -0,0 +1,118 @@ +/* + * 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 "rtc_base/openssl_digest.h" + +#include "absl/strings/string_view.h" +#include "rtc_base/checks.h" // RTC_DCHECK, RTC_CHECK +#include "rtc_base/openssl.h" + +namespace rtc { + +OpenSSLDigest::OpenSSLDigest(absl::string_view algorithm) { + ctx_ = EVP_MD_CTX_new(); + RTC_CHECK(ctx_ != nullptr); + EVP_MD_CTX_init(ctx_); + if (GetDigestEVP(algorithm, &md_)) { + EVP_DigestInit_ex(ctx_, md_, nullptr); + } else { + md_ = nullptr; + } +} + +OpenSSLDigest::~OpenSSLDigest() { + EVP_MD_CTX_destroy(ctx_); +} + +size_t OpenSSLDigest::Size() const { + if (!md_) { + return 0; + } + return EVP_MD_size(md_); +} + +void OpenSSLDigest::Update(const void* buf, size_t len) { + if (!md_) { + return; + } + EVP_DigestUpdate(ctx_, buf, len); +} + +size_t OpenSSLDigest::Finish(void* buf, size_t len) { + if (!md_ || len < Size()) { + return 0; + } + unsigned int md_len; + EVP_DigestFinal_ex(ctx_, static_cast<unsigned char*>(buf), &md_len); + EVP_DigestInit_ex(ctx_, md_, nullptr); // prepare for future Update()s + RTC_DCHECK(md_len == Size()); + return md_len; +} + +bool OpenSSLDigest::GetDigestEVP(absl::string_view algorithm, + const EVP_MD** mdp) { + const EVP_MD* md; + if (algorithm == DIGEST_MD5) { + md = EVP_md5(); + } else if (algorithm == DIGEST_SHA_1) { + md = EVP_sha1(); + } else if (algorithm == DIGEST_SHA_224) { + md = EVP_sha224(); + } else if (algorithm == DIGEST_SHA_256) { + md = EVP_sha256(); + } else if (algorithm == DIGEST_SHA_384) { + md = EVP_sha384(); + } else if (algorithm == DIGEST_SHA_512) { + md = EVP_sha512(); + } else { + return false; + } + + // Can't happen + RTC_DCHECK(EVP_MD_size(md) >= 16); + *mdp = md; + return true; +} + +bool OpenSSLDigest::GetDigestName(const EVP_MD* md, std::string* algorithm) { + RTC_DCHECK(md != nullptr); + RTC_DCHECK(algorithm != nullptr); + + int md_type = EVP_MD_type(md); + if (md_type == NID_md5) { + *algorithm = DIGEST_MD5; + } else if (md_type == NID_sha1) { + *algorithm = DIGEST_SHA_1; + } else if (md_type == NID_sha224) { + *algorithm = DIGEST_SHA_224; + } else if (md_type == NID_sha256) { + *algorithm = DIGEST_SHA_256; + } else if (md_type == NID_sha384) { + *algorithm = DIGEST_SHA_384; + } else if (md_type == NID_sha512) { + *algorithm = DIGEST_SHA_512; + } else { + algorithm->clear(); + return false; + } + + return true; +} + +bool OpenSSLDigest::GetDigestSize(absl::string_view algorithm, size_t* length) { + const EVP_MD* md; + if (!GetDigestEVP(algorithm, &md)) + return false; + + *length = EVP_MD_size(md); + return true; +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/openssl_digest.h b/third_party/libwebrtc/rtc_base/openssl_digest.h new file mode 100644 index 0000000000..c6cc3bb86d --- /dev/null +++ b/third_party/libwebrtc/rtc_base/openssl_digest.h @@ -0,0 +1,51 @@ +/* + * 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 RTC_BASE_OPENSSL_DIGEST_H_ +#define RTC_BASE_OPENSSL_DIGEST_H_ + +#include <openssl/ossl_typ.h> +#include <stddef.h> + +#include <string> + +#include "absl/strings/string_view.h" +#include "rtc_base/message_digest.h" + +namespace rtc { + +// An implementation of the digest class that uses OpenSSL. +class OpenSSLDigest final : public MessageDigest { + public: + // Creates an OpenSSLDigest with `algorithm` as the hash algorithm. + explicit OpenSSLDigest(absl::string_view algorithm); + ~OpenSSLDigest() override; + // Returns the digest output size (e.g. 16 bytes for MD5). + size_t Size() const override; + // Updates the digest with `len` bytes from `buf`. + void Update(const void* buf, size_t len) override; + // Outputs the digest value to `buf` with length `len`. + size_t Finish(void* buf, size_t len) override; + + // Helper function to look up a digest's EVP by name. + static bool GetDigestEVP(absl::string_view algorithm, const EVP_MD** md); + // Helper function to look up a digest's name by EVP. + static bool GetDigestName(const EVP_MD* md, std::string* algorithm); + // Helper function to get the length of a digest. + static bool GetDigestSize(absl::string_view algorithm, size_t* len); + + private: + EVP_MD_CTX* ctx_ = nullptr; + const EVP_MD* md_; +}; + +} // namespace rtc + +#endif // RTC_BASE_OPENSSL_DIGEST_H_ diff --git a/third_party/libwebrtc/rtc_base/openssl_identity.cc b/third_party/libwebrtc/rtc_base/openssl_identity.cc new file mode 100644 index 0000000000..186497836d --- /dev/null +++ b/third_party/libwebrtc/rtc_base/openssl_identity.cc @@ -0,0 +1,205 @@ +/* + * 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 "rtc_base/openssl_identity.h" + +#include <memory> +#include <utility> +#include <vector> + +#if defined(WEBRTC_WIN) +// Must be included first before openssl headers. +#include "rtc_base/win32.h" // NOLINT +#endif // WEBRTC_WIN + +#include <openssl/bio.h> +#include <openssl/err.h> +#include <openssl/pem.h> +#include <stdint.h> + +#include "absl/memory/memory.h" +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" +#include "rtc_base/numerics/safe_conversions.h" +#include "rtc_base/openssl.h" +#include "rtc_base/openssl_utility.h" + +namespace rtc { + +OpenSSLIdentity::OpenSSLIdentity( + std::unique_ptr<OpenSSLKeyPair> key_pair, + std::unique_ptr<OpenSSLCertificate> certificate) + : key_pair_(std::move(key_pair)) { + RTC_DCHECK(key_pair_ != nullptr); + RTC_DCHECK(certificate != nullptr); + std::vector<std::unique_ptr<SSLCertificate>> certs; + certs.push_back(std::move(certificate)); + cert_chain_.reset(new SSLCertChain(std::move(certs))); +} + +OpenSSLIdentity::OpenSSLIdentity(std::unique_ptr<OpenSSLKeyPair> key_pair, + std::unique_ptr<SSLCertChain> cert_chain) + : key_pair_(std::move(key_pair)), cert_chain_(std::move(cert_chain)) { + RTC_DCHECK(key_pair_ != nullptr); + RTC_DCHECK(cert_chain_ != nullptr); +} + +OpenSSLIdentity::~OpenSSLIdentity() = default; + +std::unique_ptr<OpenSSLIdentity> OpenSSLIdentity::CreateInternal( + const SSLIdentityParams& params) { + auto key_pair = OpenSSLKeyPair::Generate(params.key_params); + if (key_pair) { + std::unique_ptr<OpenSSLCertificate> certificate( + OpenSSLCertificate::Generate(key_pair.get(), params)); + if (certificate != nullptr) { + return absl::WrapUnique( + new OpenSSLIdentity(std::move(key_pair), std::move(certificate))); + } + } + RTC_LOG(LS_ERROR) << "Identity generation failed"; + return nullptr; +} + +// static +std::unique_ptr<OpenSSLIdentity> OpenSSLIdentity::CreateWithExpiration( + absl::string_view common_name, + const KeyParams& key_params, + time_t certificate_lifetime) { + SSLIdentityParams params; + params.key_params = key_params; + params.common_name = std::string(common_name); + time_t now = time(nullptr); + params.not_before = now + kCertificateWindowInSeconds; + params.not_after = now + certificate_lifetime; + if (params.not_before > params.not_after) + return nullptr; + return CreateInternal(params); +} + +std::unique_ptr<OpenSSLIdentity> OpenSSLIdentity::CreateForTest( + const SSLIdentityParams& params) { + return CreateInternal(params); +} + +std::unique_ptr<SSLIdentity> OpenSSLIdentity::CreateFromPEMStrings( + absl::string_view private_key, + absl::string_view certificate) { + std::unique_ptr<OpenSSLCertificate> cert( + OpenSSLCertificate::FromPEMString(certificate)); + if (!cert) { + RTC_LOG(LS_ERROR) << "Failed to create OpenSSLCertificate from PEM string."; + return nullptr; + } + + auto key_pair = OpenSSLKeyPair::FromPrivateKeyPEMString(private_key); + if (!key_pair) { + RTC_LOG(LS_ERROR) << "Failed to create key pair from PEM string."; + return nullptr; + } + + return absl::WrapUnique( + new OpenSSLIdentity(std::move(key_pair), std::move(cert))); +} + +std::unique_ptr<SSLIdentity> OpenSSLIdentity::CreateFromPEMChainStrings( + absl::string_view private_key, + absl::string_view certificate_chain) { + BIO* bio = BIO_new_mem_buf(certificate_chain.data(), + rtc::dchecked_cast<int>(certificate_chain.size())); + if (!bio) + return nullptr; + BIO_set_mem_eof_return(bio, 0); + std::vector<std::unique_ptr<SSLCertificate>> certs; + while (true) { + X509* x509 = + PEM_read_bio_X509(bio, nullptr, nullptr, const_cast<char*>("\0")); + if (x509 == nullptr) { + uint32_t err = ERR_peek_error(); + if (ERR_GET_LIB(err) == ERR_LIB_PEM && + ERR_GET_REASON(err) == PEM_R_NO_START_LINE) { + break; + } + RTC_LOG(LS_ERROR) << "Failed to parse certificate from PEM string."; + BIO_free(bio); + return nullptr; + } + certs.emplace_back(new OpenSSLCertificate(x509)); + X509_free(x509); + } + BIO_free(bio); + if (certs.empty()) { + RTC_LOG(LS_ERROR) << "Found no certificates in PEM string."; + return nullptr; + } + + auto key_pair = OpenSSLKeyPair::FromPrivateKeyPEMString(private_key); + if (!key_pair) { + RTC_LOG(LS_ERROR) << "Failed to create key pair from PEM string."; + return nullptr; + } + + return absl::WrapUnique(new OpenSSLIdentity( + std::move(key_pair), std::make_unique<SSLCertChain>(std::move(certs)))); +} + +const OpenSSLCertificate& OpenSSLIdentity::certificate() const { + return *static_cast<const OpenSSLCertificate*>(&cert_chain_->Get(0)); +} + +const SSLCertChain& OpenSSLIdentity::cert_chain() const { + return *cert_chain_.get(); +} + +std::unique_ptr<SSLIdentity> OpenSSLIdentity::CloneInternal() const { + // We cannot use std::make_unique here because the referenced OpenSSLIdentity + // constructor is private. + return absl::WrapUnique( + new OpenSSLIdentity(key_pair_->Clone(), cert_chain_->Clone())); +} + +bool OpenSSLIdentity::ConfigureIdentity(SSL_CTX* ctx) { + // 1 is the documented success return code. + const OpenSSLCertificate* cert = &certificate(); + if (SSL_CTX_use_certificate(ctx, cert->x509()) != 1 || + SSL_CTX_use_PrivateKey(ctx, key_pair_->pkey()) != 1) { + openssl::LogSSLErrors("Configuring key and certificate"); + return false; + } + // If a chain is available, use it. + for (size_t i = 1; i < cert_chain_->GetSize(); ++i) { + cert = static_cast<const OpenSSLCertificate*>(&cert_chain_->Get(i)); + if (SSL_CTX_add1_chain_cert(ctx, cert->x509()) != 1) { + openssl::LogSSLErrors("Configuring intermediate certificate"); + return false; + } + } + + return true; +} + +std::string OpenSSLIdentity::PrivateKeyToPEMString() const { + return key_pair_->PrivateKeyToPEMString(); +} + +std::string OpenSSLIdentity::PublicKeyToPEMString() const { + return key_pair_->PublicKeyToPEMString(); +} + +bool OpenSSLIdentity::operator==(const OpenSSLIdentity& other) const { + return *this->key_pair_ == *other.key_pair_ && + this->certificate() == other.certificate(); +} + +bool OpenSSLIdentity::operator!=(const OpenSSLIdentity& other) const { + return !(*this == other); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/openssl_identity.h b/third_party/libwebrtc/rtc_base/openssl_identity.h new file mode 100644 index 0000000000..a7372109c3 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/openssl_identity.h @@ -0,0 +1,75 @@ +/* + * 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 RTC_BASE_OPENSSL_IDENTITY_H_ +#define RTC_BASE_OPENSSL_IDENTITY_H_ + +#include <openssl/ossl_typ.h> + +#include <ctime> +#include <memory> +#include <string> + +#include "rtc_base/openssl_certificate.h" +#include "rtc_base/openssl_key_pair.h" +#include "rtc_base/ssl_certificate.h" +#include "rtc_base/ssl_identity.h" + +namespace rtc { + +// Holds a keypair and certificate together, and a method to generate +// them consistently. +class OpenSSLIdentity final : public SSLIdentity { + public: + static std::unique_ptr<OpenSSLIdentity> CreateWithExpiration( + absl::string_view common_name, + const KeyParams& key_params, + time_t certificate_lifetime); + static std::unique_ptr<OpenSSLIdentity> CreateForTest( + const SSLIdentityParams& params); + static std::unique_ptr<SSLIdentity> CreateFromPEMStrings( + absl::string_view private_key, + absl::string_view certificate); + static std::unique_ptr<SSLIdentity> CreateFromPEMChainStrings( + absl::string_view private_key, + absl::string_view certificate_chain); + ~OpenSSLIdentity() override; + + OpenSSLIdentity(const OpenSSLIdentity&) = delete; + OpenSSLIdentity& operator=(const OpenSSLIdentity&) = delete; + + const OpenSSLCertificate& certificate() const override; + const SSLCertChain& cert_chain() const override; + + // Configure an SSL context object to use our key and certificate. + bool ConfigureIdentity(SSL_CTX* ctx); + + std::string PrivateKeyToPEMString() const override; + std::string PublicKeyToPEMString() const override; + bool operator==(const OpenSSLIdentity& other) const; + bool operator!=(const OpenSSLIdentity& other) const; + + private: + OpenSSLIdentity(std::unique_ptr<OpenSSLKeyPair> key_pair, + std::unique_ptr<OpenSSLCertificate> certificate); + OpenSSLIdentity(std::unique_ptr<OpenSSLKeyPair> key_pair, + std::unique_ptr<SSLCertChain> cert_chain); + std::unique_ptr<SSLIdentity> CloneInternal() const override; + + static std::unique_ptr<OpenSSLIdentity> CreateInternal( + const SSLIdentityParams& params); + + std::unique_ptr<OpenSSLKeyPair> key_pair_; + std::unique_ptr<SSLCertChain> cert_chain_; +}; + +} // namespace rtc + +#endif // RTC_BASE_OPENSSL_IDENTITY_H_ diff --git a/third_party/libwebrtc/rtc_base/openssl_key_pair.cc b/third_party/libwebrtc/rtc_base/openssl_key_pair.cc new file mode 100644 index 0000000000..4c474f2d54 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/openssl_key_pair.cc @@ -0,0 +1,194 @@ +/* + * 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 "rtc_base/openssl_key_pair.h" + +#include <memory> +#include <utility> + +#include "absl/strings/string_view.h" + +#if defined(WEBRTC_WIN) +// Must be included first before openssl headers. +#include "rtc_base/win32.h" // NOLINT +#endif // WEBRTC_WIN + +#include <openssl/bio.h> +#include <openssl/bn.h> +#include <openssl/pem.h> +#include <openssl/rsa.h> + +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" +#include "rtc_base/openssl.h" +#include "rtc_base/openssl_utility.h" + +namespace rtc { + +// We could have exposed a myriad of parameters for the crypto stuff, +// but keeping it simple seems best. + +// Generate a key pair. Caller is responsible for freeing the returned object. +static EVP_PKEY* MakeKey(const KeyParams& key_params) { + RTC_LOG(LS_INFO) << "Making key pair"; + EVP_PKEY* pkey = EVP_PKEY_new(); + if (key_params.type() == KT_RSA) { + int key_length = key_params.rsa_params().mod_size; + BIGNUM* exponent = BN_new(); + RSA* rsa = RSA_new(); + if (!pkey || !exponent || !rsa || + !BN_set_word(exponent, key_params.rsa_params().pub_exp) || + !RSA_generate_key_ex(rsa, key_length, exponent, nullptr) || + !EVP_PKEY_assign_RSA(pkey, rsa)) { + EVP_PKEY_free(pkey); + BN_free(exponent); + RSA_free(rsa); + RTC_LOG(LS_ERROR) << "Failed to make RSA key pair"; + return nullptr; + } + // ownership of rsa struct was assigned, don't free it. + BN_free(exponent); + } else if (key_params.type() == KT_ECDSA) { + if (key_params.ec_curve() == EC_NIST_P256) { + EC_KEY* ec_key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); + if (!ec_key) { + EVP_PKEY_free(pkey); + RTC_LOG(LS_ERROR) << "Failed to allocate EC key"; + return nullptr; + } + + // Ensure curve name is included when EC key is serialized. + // Without this call, OpenSSL versions before 1.1.0 will create + // certificates that don't work for TLS. + // This is a no-op for BoringSSL and OpenSSL 1.1.0+ + EC_KEY_set_asn1_flag(ec_key, OPENSSL_EC_NAMED_CURVE); + + if (!pkey || !ec_key || !EC_KEY_generate_key(ec_key) || + !EVP_PKEY_assign_EC_KEY(pkey, ec_key)) { + EVP_PKEY_free(pkey); + EC_KEY_free(ec_key); + RTC_LOG(LS_ERROR) << "Failed to make EC key pair"; + return nullptr; + } + // ownership of ec_key struct was assigned, don't free it. + } else { + // Add generation of any other curves here. + EVP_PKEY_free(pkey); + RTC_LOG(LS_ERROR) << "ECDSA key requested for unknown curve"; + return nullptr; + } + } else { + EVP_PKEY_free(pkey); + RTC_LOG(LS_ERROR) << "Key type requested not understood"; + return nullptr; + } + + RTC_LOG(LS_INFO) << "Returning key pair"; + return pkey; +} + +std::unique_ptr<OpenSSLKeyPair> OpenSSLKeyPair::Generate( + const KeyParams& key_params) { + EVP_PKEY* pkey = MakeKey(key_params); + if (!pkey) { + openssl::LogSSLErrors("Generating key pair"); + return nullptr; + } + return std::make_unique<OpenSSLKeyPair>(pkey); +} + +std::unique_ptr<OpenSSLKeyPair> OpenSSLKeyPair::FromPrivateKeyPEMString( + absl::string_view pem_string) { + BIO* bio = + BIO_new_mem_buf(const_cast<char*>(pem_string.data()), pem_string.size()); + if (!bio) { + RTC_LOG(LS_ERROR) << "Failed to create a new BIO buffer."; + return nullptr; + } + BIO_set_mem_eof_return(bio, 0); + EVP_PKEY* pkey = PEM_read_bio_PrivateKey(bio, nullptr, nullptr, nullptr); + BIO_free(bio); // Frees the BIO, but not the pointed-to string. + if (!pkey) { + RTC_LOG(LS_ERROR) << "Failed to create the private key from PEM string."; + return nullptr; + } + if (EVP_PKEY_missing_parameters(pkey) != 0) { + RTC_LOG(LS_ERROR) + << "The resulting key pair is missing public key parameters."; + EVP_PKEY_free(pkey); + return nullptr; + } + return std::make_unique<OpenSSLKeyPair>(pkey); +} + +OpenSSLKeyPair::~OpenSSLKeyPair() { + EVP_PKEY_free(pkey_); +} + +std::unique_ptr<OpenSSLKeyPair> OpenSSLKeyPair::Clone() { + AddReference(); + return std::make_unique<OpenSSLKeyPair>(pkey_); +} + +void OpenSSLKeyPair::AddReference() { + EVP_PKEY_up_ref(pkey_); +} + +std::string OpenSSLKeyPair::PrivateKeyToPEMString() const { + BIO* temp_memory_bio = BIO_new(BIO_s_mem()); + if (!temp_memory_bio) { + RTC_LOG_F(LS_ERROR) << "Failed to allocate temporary memory bio"; + RTC_DCHECK_NOTREACHED(); + return ""; + } + if (!PEM_write_bio_PrivateKey(temp_memory_bio, pkey_, nullptr, nullptr, 0, + nullptr, nullptr)) { + RTC_LOG_F(LS_ERROR) << "Failed to write private key"; + BIO_free(temp_memory_bio); + RTC_DCHECK_NOTREACHED(); + return ""; + } + char* buffer; + size_t len = BIO_get_mem_data(temp_memory_bio, &buffer); + std::string priv_key_str(buffer, len); + BIO_free(temp_memory_bio); + return priv_key_str; +} + +std::string OpenSSLKeyPair::PublicKeyToPEMString() const { + BIO* temp_memory_bio = BIO_new(BIO_s_mem()); + if (!temp_memory_bio) { + RTC_LOG_F(LS_ERROR) << "Failed to allocate temporary memory bio"; + RTC_DCHECK_NOTREACHED(); + return ""; + } + if (!PEM_write_bio_PUBKEY(temp_memory_bio, pkey_)) { + RTC_LOG_F(LS_ERROR) << "Failed to write public key"; + BIO_free(temp_memory_bio); + RTC_DCHECK_NOTREACHED(); + return ""; + } + BIO_write(temp_memory_bio, "\0", 1); + char* buffer; + BIO_get_mem_data(temp_memory_bio, &buffer); + std::string pub_key_str = buffer; + BIO_free(temp_memory_bio); + return pub_key_str; +} + +bool OpenSSLKeyPair::operator==(const OpenSSLKeyPair& other) const { + return EVP_PKEY_cmp(this->pkey_, other.pkey_) == 1; +} + +bool OpenSSLKeyPair::operator!=(const OpenSSLKeyPair& other) const { + return !(*this == other); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/openssl_key_pair.h b/third_party/libwebrtc/rtc_base/openssl_key_pair.h new file mode 100644 index 0000000000..d09bdb0d5e --- /dev/null +++ b/third_party/libwebrtc/rtc_base/openssl_key_pair.h @@ -0,0 +1,61 @@ +/* + * 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 RTC_BASE_OPENSSL_KEY_PAIR_H_ +#define RTC_BASE_OPENSSL_KEY_PAIR_H_ + +#include <openssl/ossl_typ.h> + +#include <memory> +#include <string> + +#include "absl/strings/string_view.h" +#include "rtc_base/checks.h" +#include "rtc_base/ssl_identity.h" + +namespace rtc { + +// OpenSSLKeyPair encapsulates an OpenSSL EVP_PKEY* keypair object, +// which is reference counted inside the OpenSSL library. +class OpenSSLKeyPair final { + public: + // Takes ownership of the key. + explicit OpenSSLKeyPair(EVP_PKEY* pkey) : pkey_(pkey) { + RTC_DCHECK(pkey_ != nullptr); + } + + static std::unique_ptr<OpenSSLKeyPair> Generate(const KeyParams& key_params); + // Constructs a key pair from the private key PEM string. This must not result + // in missing public key parameters. Returns null on error. + static std::unique_ptr<OpenSSLKeyPair> FromPrivateKeyPEMString( + absl::string_view pem_string); + + ~OpenSSLKeyPair(); + + OpenSSLKeyPair(const OpenSSLKeyPair&) = delete; + OpenSSLKeyPair& operator=(const OpenSSLKeyPair&) = delete; + + std::unique_ptr<OpenSSLKeyPair> Clone(); + + EVP_PKEY* pkey() const { return pkey_; } + std::string PrivateKeyToPEMString() const; + std::string PublicKeyToPEMString() const; + bool operator==(const OpenSSLKeyPair& other) const; + bool operator!=(const OpenSSLKeyPair& other) const; + + private: + void AddReference(); + + EVP_PKEY* pkey_; +}; + +} // namespace rtc + +#endif // RTC_BASE_OPENSSL_KEY_PAIR_H_ diff --git a/third_party/libwebrtc/rtc_base/openssl_session_cache.cc b/third_party/libwebrtc/rtc_base/openssl_session_cache.cc new file mode 100644 index 0000000000..d63724242a --- /dev/null +++ b/third_party/libwebrtc/rtc_base/openssl_session_cache.cc @@ -0,0 +1,54 @@ +/* + * 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. + */ + +#include "rtc_base/openssl_session_cache.h" + +#include "absl/strings/string_view.h" +#include "rtc_base/checks.h" +#include "rtc_base/openssl.h" + +namespace rtc { + +OpenSSLSessionCache::OpenSSLSessionCache(SSLMode ssl_mode, SSL_CTX* ssl_ctx) + : ssl_mode_(ssl_mode), ssl_ctx_(ssl_ctx) { + // It is invalid to pass in a null context. + RTC_DCHECK(ssl_ctx != nullptr); + SSL_CTX_up_ref(ssl_ctx); +} + +OpenSSLSessionCache::~OpenSSLSessionCache() { + for (const auto& it : sessions_) { + SSL_SESSION_free(it.second); + } + SSL_CTX_free(ssl_ctx_); +} + +SSL_SESSION* OpenSSLSessionCache::LookupSession( + absl::string_view hostname) const { + auto it = sessions_.find(hostname); + return (it != sessions_.end()) ? it->second : nullptr; +} + +void OpenSSLSessionCache::AddSession(absl::string_view hostname, + SSL_SESSION* new_session) { + SSL_SESSION* old_session = LookupSession(hostname); + SSL_SESSION_free(old_session); + sessions_.insert_or_assign(std::string(hostname), new_session); +} + +SSL_CTX* OpenSSLSessionCache::GetSSLContext() const { + return ssl_ctx_; +} + +SSLMode OpenSSLSessionCache::GetSSLMode() const { + return ssl_mode_; +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/openssl_session_cache.h b/third_party/libwebrtc/rtc_base/openssl_session_cache.h new file mode 100644 index 0000000000..75d8d9a0cf --- /dev/null +++ b/third_party/libwebrtc/rtc_base/openssl_session_cache.h @@ -0,0 +1,72 @@ +/* + * 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 RTC_BASE_OPENSSL_SESSION_CACHE_H_ +#define RTC_BASE_OPENSSL_SESSION_CACHE_H_ + +#include <openssl/ossl_typ.h> + +#include <map> +#include <string> + +#include "absl/strings/string_view.h" +#include "rtc_base/ssl_stream_adapter.h" +#include "rtc_base/string_utils.h" + +#ifndef OPENSSL_IS_BORINGSSL +typedef struct ssl_session_st SSL_SESSION; +#endif + +namespace rtc { + +// The OpenSSLSessionCache maps hostnames to SSL_SESSIONS. This cache is +// owned by the OpenSSLAdapterFactory and is passed down to each OpenSSLAdapter +// created with the factory. +class OpenSSLSessionCache final { + public: + // Creates a new OpenSSLSessionCache using the provided the SSL_CTX and + // the ssl_mode. The SSL_CTX will be up_refed. ssl_ctx cannot be nullptr, + // the constructor immediately dchecks this. + OpenSSLSessionCache(SSLMode ssl_mode, SSL_CTX* ssl_ctx); + // Frees the cached SSL_SESSIONS and then frees the SSL_CTX. + ~OpenSSLSessionCache(); + + OpenSSLSessionCache(const OpenSSLSessionCache&) = delete; + OpenSSLSessionCache& operator=(const OpenSSLSessionCache&) = delete; + + // Looks up a session by hostname. The returned SSL_SESSION is not up_refed. + SSL_SESSION* LookupSession(absl::string_view hostname) const; + // Adds a session to the cache, and up_refs it. Any existing session with the + // same hostname is replaced. + void AddSession(absl::string_view hostname, SSL_SESSION* session); + // Returns the true underlying SSL Context that holds these cached sessions. + SSL_CTX* GetSSLContext() const; + // The SSL Mode tht the OpenSSLSessionCache was constructed with. This cannot + // be changed after launch. + SSLMode GetSSLMode() const; + + private: + // Holds the SSL Mode that the OpenSSLCache was initialized with. This is + // immutable after creation and cannot change. + const SSLMode ssl_mode_; + /// SSL Context for all shared cached sessions. This SSL_CTX is initialized + // with SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_CLIENT); Meaning + // all client sessions will be added to the cache internal to the context. + SSL_CTX* ssl_ctx_ = nullptr; + // Map of hostnames to SSL_SESSIONs; holds references to the SSL_SESSIONs, + // which are cleaned up when the factory is destroyed. + // TODO(juberti): Add LRU eviction to keep the cache from growing forever. + std::map<std::string, SSL_SESSION*, rtc::AbslStringViewCmp> sessions_; + // The cache should never be copied or assigned directly. +}; + +} // namespace rtc + +#endif // RTC_BASE_OPENSSL_SESSION_CACHE_H_ diff --git a/third_party/libwebrtc/rtc_base/openssl_session_cache_unittest.cc b/third_party/libwebrtc/rtc_base/openssl_session_cache_unittest.cc new file mode 100644 index 0000000000..0441d5c012 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/openssl_session_cache_unittest.cc @@ -0,0 +1,104 @@ +/* + * 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. + */ + +#include "rtc_base/openssl_session_cache.h" + +#include <openssl/ssl.h> +#include <stdlib.h> + +#include <map> +#include <memory> + +#include "rtc_base/gunit.h" +#include "rtc_base/openssl.h" + +namespace { +// Use methods that avoid X509 objects if possible. +SSL_CTX* NewDtlsContext() { +#ifdef OPENSSL_IS_BORINGSSL + return SSL_CTX_new(DTLS_with_buffers_method()); +#else + return SSL_CTX_new(DTLS_method()); +#endif +} +SSL_CTX* NewTlsContext() { +#ifdef OPENSSL_IS_BORINGSSL + return SSL_CTX_new(TLS_with_buffers_method()); +#else + return SSL_CTX_new(TLS_method()); +#endif +} +} // namespace + +namespace rtc { + +TEST(OpenSSLSessionCache, DTLSModeSetCorrectly) { + SSL_CTX* ssl_ctx = NewDtlsContext(); + + OpenSSLSessionCache session_cache(SSL_MODE_DTLS, ssl_ctx); + EXPECT_EQ(session_cache.GetSSLMode(), SSL_MODE_DTLS); + + SSL_CTX_free(ssl_ctx); +} + +TEST(OpenSSLSessionCache, TLSModeSetCorrectly) { + SSL_CTX* ssl_ctx = NewTlsContext(); + + OpenSSLSessionCache session_cache(SSL_MODE_TLS, ssl_ctx); + EXPECT_EQ(session_cache.GetSSLMode(), SSL_MODE_TLS); + + SSL_CTX_free(ssl_ctx); +} + +TEST(OpenSSLSessionCache, SSLContextSetCorrectly) { + SSL_CTX* ssl_ctx = NewDtlsContext(); + + OpenSSLSessionCache session_cache(SSL_MODE_DTLS, ssl_ctx); + EXPECT_EQ(session_cache.GetSSLContext(), ssl_ctx); + + SSL_CTX_free(ssl_ctx); +} + +TEST(OpenSSLSessionCache, InvalidLookupReturnsNullptr) { + SSL_CTX* ssl_ctx = NewDtlsContext(); + + OpenSSLSessionCache session_cache(SSL_MODE_DTLS, ssl_ctx); + EXPECT_EQ(session_cache.LookupSession("Invalid"), nullptr); + EXPECT_EQ(session_cache.LookupSession(""), nullptr); + EXPECT_EQ(session_cache.LookupSession("."), nullptr); + + SSL_CTX_free(ssl_ctx); +} + +TEST(OpenSSLSessionCache, SimpleValidSessionLookup) { + SSL_CTX* ssl_ctx = NewDtlsContext(); + SSL_SESSION* ssl_session = SSL_SESSION_new(ssl_ctx); + + OpenSSLSessionCache session_cache(SSL_MODE_DTLS, ssl_ctx); + session_cache.AddSession("webrtc.org", ssl_session); + EXPECT_EQ(session_cache.LookupSession("webrtc.org"), ssl_session); + + SSL_CTX_free(ssl_ctx); +} + +TEST(OpenSSLSessionCache, AddToExistingReplacesPrevious) { + SSL_CTX* ssl_ctx = NewDtlsContext(); + SSL_SESSION* ssl_session_1 = SSL_SESSION_new(ssl_ctx); + SSL_SESSION* ssl_session_2 = SSL_SESSION_new(ssl_ctx); + + OpenSSLSessionCache session_cache(SSL_MODE_DTLS, ssl_ctx); + session_cache.AddSession("webrtc.org", ssl_session_1); + session_cache.AddSession("webrtc.org", ssl_session_2); + EXPECT_EQ(session_cache.LookupSession("webrtc.org"), ssl_session_2); + + SSL_CTX_free(ssl_ctx); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/openssl_stream_adapter.cc b/third_party/libwebrtc/rtc_base/openssl_stream_adapter.cc new file mode 100644 index 0000000000..353cbbe681 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/openssl_stream_adapter.cc @@ -0,0 +1,1305 @@ +/* + * 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 "rtc_base/openssl_stream_adapter.h" + +#include <openssl/bio.h> +#include <openssl/crypto.h> +#include <openssl/err.h> +#include <openssl/rand.h> +#include <openssl/tls1.h> +#include <openssl/x509v3.h> + +#include "absl/strings/string_view.h" +#ifndef OPENSSL_IS_BORINGSSL +#include <openssl/dtls1.h> +#include <openssl/ssl.h> +#endif + +#include <atomic> +#include <memory> +#include <utility> +#include <vector> + +#include "api/array_view.h" +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" +#include "rtc_base/numerics/safe_conversions.h" +#include "rtc_base/openssl.h" +#include "rtc_base/openssl_adapter.h" +#include "rtc_base/openssl_digest.h" +#ifdef OPENSSL_IS_BORINGSSL +#include "rtc_base/boringssl_identity.h" +#else +#include "rtc_base/openssl_identity.h" +#endif +#include "rtc_base/openssl_utility.h" +#include "rtc_base/ssl_certificate.h" +#include "rtc_base/stream.h" +#include "rtc_base/string_encode.h" +#include "rtc_base/thread.h" +#include "rtc_base/time_utils.h" +#include "system_wrappers/include/field_trial.h" + +#if (OPENSSL_VERSION_NUMBER < 0x10100000L) +#error "webrtc requires at least OpenSSL version 1.1.0, to support DTLS-SRTP" +#endif + +// Defines for the TLS Cipher Suite Map. +#define DEFINE_CIPHER_ENTRY_SSL3(name) \ + { SSL3_CK_##name, "TLS_" #name } +#define DEFINE_CIPHER_ENTRY_TLS1(name) \ + { TLS1_CK_##name, "TLS_" #name } + +namespace rtc { +namespace { +using ::webrtc::SafeTask; +// SRTP cipher suite table. `internal_name` is used to construct a +// colon-separated profile strings which is needed by +// SSL_CTX_set_tlsext_use_srtp(). +struct SrtpCipherMapEntry { + const char* internal_name; + const int id; +}; + +// Cipher name table. Maps internal OpenSSL cipher ids to the RFC name. +struct SslCipherMapEntry { + uint32_t openssl_id; + const char* rfc_name; +}; + +// This isn't elegant, but it's better than an external reference +constexpr SrtpCipherMapEntry kSrtpCipherMap[] = { + {"SRTP_AES128_CM_SHA1_80", kSrtpAes128CmSha1_80}, + {"SRTP_AES128_CM_SHA1_32", kSrtpAes128CmSha1_32}, + {"SRTP_AEAD_AES_128_GCM", kSrtpAeadAes128Gcm}, + {"SRTP_AEAD_AES_256_GCM", kSrtpAeadAes256Gcm}}; + +#ifndef OPENSSL_IS_BORINGSSL +// The "SSL_CIPHER_standard_name" function is only available in OpenSSL when +// compiled with tracing, so we need to define the mapping manually here. +constexpr SslCipherMapEntry kSslCipherMap[] = { + // TLS v1.0 ciphersuites from RFC2246. + DEFINE_CIPHER_ENTRY_SSL3(RSA_RC4_128_SHA), + {SSL3_CK_RSA_DES_192_CBC3_SHA, "TLS_RSA_WITH_3DES_EDE_CBC_SHA"}, + + // AES ciphersuites from RFC3268. + {TLS1_CK_RSA_WITH_AES_128_SHA, "TLS_RSA_WITH_AES_128_CBC_SHA"}, + {TLS1_CK_DHE_RSA_WITH_AES_128_SHA, "TLS_DHE_RSA_WITH_AES_128_CBC_SHA"}, + {TLS1_CK_RSA_WITH_AES_256_SHA, "TLS_RSA_WITH_AES_256_CBC_SHA"}, + {TLS1_CK_DHE_RSA_WITH_AES_256_SHA, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA"}, + + // ECC ciphersuites from RFC4492. + DEFINE_CIPHER_ENTRY_TLS1(ECDHE_ECDSA_WITH_RC4_128_SHA), + {TLS1_CK_ECDHE_ECDSA_WITH_DES_192_CBC3_SHA, + "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA"}, + DEFINE_CIPHER_ENTRY_TLS1(ECDHE_ECDSA_WITH_AES_128_CBC_SHA), + DEFINE_CIPHER_ENTRY_TLS1(ECDHE_ECDSA_WITH_AES_256_CBC_SHA), + + DEFINE_CIPHER_ENTRY_TLS1(ECDHE_RSA_WITH_RC4_128_SHA), + {TLS1_CK_ECDHE_RSA_WITH_DES_192_CBC3_SHA, + "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA"}, + DEFINE_CIPHER_ENTRY_TLS1(ECDHE_RSA_WITH_AES_128_CBC_SHA), + DEFINE_CIPHER_ENTRY_TLS1(ECDHE_RSA_WITH_AES_256_CBC_SHA), + + // TLS v1.2 ciphersuites. + {TLS1_CK_RSA_WITH_AES_128_SHA256, "TLS_RSA_WITH_AES_128_CBC_SHA256"}, + {TLS1_CK_RSA_WITH_AES_256_SHA256, "TLS_RSA_WITH_AES_256_CBC_SHA256"}, + {TLS1_CK_DHE_RSA_WITH_AES_128_SHA256, + "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256"}, + {TLS1_CK_DHE_RSA_WITH_AES_256_SHA256, + "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256"}, + + // TLS v1.2 GCM ciphersuites from RFC5288. + DEFINE_CIPHER_ENTRY_TLS1(RSA_WITH_AES_128_GCM_SHA256), + DEFINE_CIPHER_ENTRY_TLS1(RSA_WITH_AES_256_GCM_SHA384), + DEFINE_CIPHER_ENTRY_TLS1(DHE_RSA_WITH_AES_128_GCM_SHA256), + DEFINE_CIPHER_ENTRY_TLS1(DHE_RSA_WITH_AES_256_GCM_SHA384), + DEFINE_CIPHER_ENTRY_TLS1(DH_RSA_WITH_AES_128_GCM_SHA256), + DEFINE_CIPHER_ENTRY_TLS1(DH_RSA_WITH_AES_256_GCM_SHA384), + + // ECDH HMAC based ciphersuites from RFC5289. + {TLS1_CK_ECDHE_ECDSA_WITH_AES_128_SHA256, + "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256"}, + {TLS1_CK_ECDHE_ECDSA_WITH_AES_256_SHA384, + "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384"}, + {TLS1_CK_ECDHE_RSA_WITH_AES_128_SHA256, + "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256"}, + {TLS1_CK_ECDHE_RSA_WITH_AES_256_SHA384, + "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384"}, + + // ECDH GCM based ciphersuites from RFC5289. + DEFINE_CIPHER_ENTRY_TLS1(ECDHE_ECDSA_WITH_AES_128_GCM_SHA256), + DEFINE_CIPHER_ENTRY_TLS1(ECDHE_ECDSA_WITH_AES_256_GCM_SHA384), + DEFINE_CIPHER_ENTRY_TLS1(ECDHE_RSA_WITH_AES_128_GCM_SHA256), + DEFINE_CIPHER_ENTRY_TLS1(ECDHE_RSA_WITH_AES_256_GCM_SHA384), + + {0, nullptr}}; +#endif // #ifndef OPENSSL_IS_BORINGSSL + +#ifdef OPENSSL_IS_BORINGSSL +// Enabled by EnableTimeCallbackForTesting. Should never be set in production +// code. +bool g_use_time_callback_for_testing = false; +// Not used in production code. Actual time should be relative to Jan 1, 1970. +void TimeCallbackForTesting(const SSL* ssl, struct timeval* out_clock) { + int64_t time = TimeNanos(); + out_clock->tv_sec = time / kNumNanosecsPerSec; + out_clock->tv_usec = (time % kNumNanosecsPerSec) / kNumNanosecsPerMicrosec; +} +#endif + +} // namespace + +////////////////////////////////////////////////////////////////////// +// StreamBIO +////////////////////////////////////////////////////////////////////// + +static int stream_write(BIO* h, const char* buf, int num); +static int stream_read(BIO* h, char* buf, int size); +static int stream_puts(BIO* h, const char* str); +static long stream_ctrl(BIO* h, int cmd, long arg1, void* arg2); +static int stream_new(BIO* h); +static int stream_free(BIO* data); + +static BIO_METHOD* BIO_stream_method() { + static BIO_METHOD* method = [] { + BIO_METHOD* method = BIO_meth_new(BIO_TYPE_BIO, "stream"); + BIO_meth_set_write(method, stream_write); + BIO_meth_set_read(method, stream_read); + BIO_meth_set_puts(method, stream_puts); + BIO_meth_set_ctrl(method, stream_ctrl); + BIO_meth_set_create(method, stream_new); + BIO_meth_set_destroy(method, stream_free); + return method; + }(); + return method; +} + +static BIO* BIO_new_stream(StreamInterface* stream) { + BIO* ret = BIO_new(BIO_stream_method()); + if (ret == nullptr) { + return nullptr; + } + BIO_set_data(ret, stream); + return ret; +} + +// bio methods return 1 (or at least non-zero) on success and 0 on failure. + +static int stream_new(BIO* b) { + BIO_set_shutdown(b, 0); + BIO_set_init(b, 1); + BIO_set_data(b, 0); + return 1; +} + +static int stream_free(BIO* b) { + if (b == nullptr) { + return 0; + } + return 1; +} + +static int stream_read(BIO* b, char* out, int outl) { + if (!out) { + return -1; + } + StreamInterface* stream = static_cast<StreamInterface*>(BIO_get_data(b)); + BIO_clear_retry_flags(b); + size_t read; + int error; + StreamResult result = stream->Read( + rtc::MakeArrayView(reinterpret_cast<uint8_t*>(out), outl), read, error); + if (result == SR_SUCCESS) { + return checked_cast<int>(read); + } else if (result == SR_BLOCK) { + BIO_set_retry_read(b); + } + return -1; +} + +static int stream_write(BIO* b, const char* in, int inl) { + if (!in) { + return -1; + } + StreamInterface* stream = static_cast<StreamInterface*>(BIO_get_data(b)); + BIO_clear_retry_flags(b); + size_t written; + int error; + StreamResult result = stream->Write( + rtc::MakeArrayView(reinterpret_cast<const uint8_t*>(in), inl), written, + error); + if (result == SR_SUCCESS) { + return checked_cast<int>(written); + } else if (result == SR_BLOCK) { + BIO_set_retry_write(b); + } + return -1; +} + +static int stream_puts(BIO* b, const char* str) { + return stream_write(b, str, checked_cast<int>(strlen(str))); +} + +static long stream_ctrl(BIO* b, int cmd, long num, void* ptr) { + switch (cmd) { + case BIO_CTRL_RESET: + return 0; + case BIO_CTRL_EOF: { + StreamInterface* stream = static_cast<StreamInterface*>(ptr); + // 1 means end-of-stream. + return (stream->GetState() == SS_CLOSED) ? 1 : 0; + } + case BIO_CTRL_WPENDING: + case BIO_CTRL_PENDING: + return 0; + case BIO_CTRL_FLUSH: + return 1; + case BIO_CTRL_DGRAM_QUERY_MTU: + // openssl defaults to mtu=256 unless we return something here. + // The handshake doesn't actually need to send packets above 1k, + // so this seems like a sensible value that should work in most cases. + // Webrtc uses the same value for video packets. + return 1200; + default: + return 0; + } +} + +///////////////////////////////////////////////////////////////////////////// +// OpenSSLStreamAdapter +///////////////////////////////////////////////////////////////////////////// + +static std::atomic<bool> g_use_legacy_tls_protocols_override(false); +static std::atomic<bool> g_allow_legacy_tls_protocols(false); + +void SetAllowLegacyTLSProtocols(const absl::optional<bool>& allow) { + g_use_legacy_tls_protocols_override.store(allow.has_value()); + if (allow.has_value()) + g_allow_legacy_tls_protocols.store(allow.value()); +} + +bool ShouldAllowLegacyTLSProtocols() { + return g_use_legacy_tls_protocols_override.load() + ? g_allow_legacy_tls_protocols.load() + : webrtc::field_trial::IsEnabled("WebRTC-LegacyTlsProtocols"); +} + +OpenSSLStreamAdapter::OpenSSLStreamAdapter( + std::unique_ptr<StreamInterface> stream, + absl::AnyInvocable<void(SSLHandshakeError)> handshake_error) + : stream_(std::move(stream)), + handshake_error_(std::move(handshake_error)), + owner_(rtc::Thread::Current()), + state_(SSL_NONE), + role_(SSL_CLIENT), + ssl_read_needs_write_(false), + ssl_write_needs_read_(false), + ssl_(nullptr), + ssl_ctx_(nullptr), + ssl_mode_(SSL_MODE_TLS), + ssl_max_version_(SSL_PROTOCOL_TLS_12), + // Default is to support legacy TLS protocols. + // This will be changed to default non-support in M82 or M83. + support_legacy_tls_protocols_flag_(ShouldAllowLegacyTLSProtocols()) { + stream_->SignalEvent.connect(this, &OpenSSLStreamAdapter::OnEvent); +} + +OpenSSLStreamAdapter::~OpenSSLStreamAdapter() { + timeout_task_.Stop(); + Cleanup(0); +} + +void OpenSSLStreamAdapter::SetIdentity(std::unique_ptr<SSLIdentity> identity) { + RTC_DCHECK(!identity_); +#ifdef OPENSSL_IS_BORINGSSL + identity_.reset(static_cast<BoringSSLIdentity*>(identity.release())); +#else + identity_.reset(static_cast<OpenSSLIdentity*>(identity.release())); +#endif +} + +SSLIdentity* OpenSSLStreamAdapter::GetIdentityForTesting() const { + return identity_.get(); +} + +void OpenSSLStreamAdapter::SetServerRole(SSLRole role) { + role_ = role; +} + +bool OpenSSLStreamAdapter::SetPeerCertificateDigest( + absl::string_view digest_alg, + const unsigned char* digest_val, + size_t digest_len, + SSLPeerCertificateDigestError* error) { + RTC_DCHECK(!peer_certificate_verified_); + RTC_DCHECK(!HasPeerCertificateDigest()); + size_t expected_len; + if (error) { + *error = SSLPeerCertificateDigestError::NONE; + } + + if (!OpenSSLDigest::GetDigestSize(digest_alg, &expected_len)) { + RTC_LOG(LS_WARNING) << "Unknown digest algorithm: " << digest_alg; + if (error) { + *error = SSLPeerCertificateDigestError::UNKNOWN_ALGORITHM; + } + return false; + } + if (expected_len != digest_len) { + if (error) { + *error = SSLPeerCertificateDigestError::INVALID_LENGTH; + } + return false; + } + + peer_certificate_digest_value_.SetData(digest_val, digest_len); + peer_certificate_digest_algorithm_ = std::string(digest_alg); + + if (!peer_cert_chain_) { + // Normal case, where the digest is set before we obtain the certificate + // from the handshake. + return true; + } + + if (!VerifyPeerCertificate()) { + Error("SetPeerCertificateDigest", -1, SSL_AD_BAD_CERTIFICATE, false); + if (error) { + *error = SSLPeerCertificateDigestError::VERIFICATION_FAILED; + } + return false; + } + + if (state_ == SSL_CONNECTED) { + // Post the event asynchronously to unwind the stack. The caller + // of ContinueSSL may be the same object listening for these + // events and may not be prepared for reentrancy. + PostEvent(SE_OPEN | SE_READ | SE_WRITE, 0); + } + + return true; +} + +std::string OpenSSLStreamAdapter::SslCipherSuiteToName(int cipher_suite) { +#ifdef OPENSSL_IS_BORINGSSL + const SSL_CIPHER* ssl_cipher = SSL_get_cipher_by_value(cipher_suite); + if (!ssl_cipher) { + return std::string(); + } + return SSL_CIPHER_standard_name(ssl_cipher); +#else + const int openssl_cipher_id = 0x03000000L | cipher_suite; + for (const SslCipherMapEntry* entry = kSslCipherMap; entry->rfc_name; + ++entry) { + if (openssl_cipher_id == static_cast<int>(entry->openssl_id)) { + return entry->rfc_name; + } + } + return std::string(); +#endif +} + +bool OpenSSLStreamAdapter::GetSslCipherSuite(int* cipher_suite) { + if (state_ != SSL_CONNECTED) { + return false; + } + + const SSL_CIPHER* current_cipher = SSL_get_current_cipher(ssl_); + if (current_cipher == nullptr) { + return false; + } + + *cipher_suite = static_cast<uint16_t>(SSL_CIPHER_get_id(current_cipher)); + return true; +} + +SSLProtocolVersion OpenSSLStreamAdapter::GetSslVersion() const { + if (state_ != SSL_CONNECTED) { + return SSL_PROTOCOL_NOT_GIVEN; + } + + int ssl_version = SSL_version(ssl_); + if (ssl_mode_ == SSL_MODE_DTLS) { + if (ssl_version == DTLS1_VERSION) { + return SSL_PROTOCOL_DTLS_10; + } else if (ssl_version == DTLS1_2_VERSION) { + return SSL_PROTOCOL_DTLS_12; + } + } else { + if (ssl_version == TLS1_VERSION) { + return SSL_PROTOCOL_TLS_10; + } else if (ssl_version == TLS1_1_VERSION) { + return SSL_PROTOCOL_TLS_11; + } else if (ssl_version == TLS1_2_VERSION) { + return SSL_PROTOCOL_TLS_12; + } + } + + return SSL_PROTOCOL_NOT_GIVEN; +} + +bool OpenSSLStreamAdapter::GetSslVersionBytes(int* version) const { + if (state_ != SSL_CONNECTED) { + return false; + } + *version = SSL_version(ssl_); + return true; +} + +// Key Extractor interface +bool OpenSSLStreamAdapter::ExportKeyingMaterial(absl::string_view label, + const uint8_t* context, + size_t context_len, + bool use_context, + uint8_t* result, + size_t result_len) { + if (SSL_export_keying_material(ssl_, result, result_len, label.data(), + label.length(), context, context_len, + use_context) != 1) { + return false; + } + return true; +} + +uint16_t OpenSSLStreamAdapter::GetPeerSignatureAlgorithm() const { + if (state_ != SSL_CONNECTED) { + return 0; + } +#ifdef OPENSSL_IS_BORINGSSL + return SSL_get_peer_signature_algorithm(ssl_); +#else + return kSslSignatureAlgorithmUnknown; +#endif +} + +bool OpenSSLStreamAdapter::SetDtlsSrtpCryptoSuites( + const std::vector<int>& ciphers) { + if (state_ != SSL_NONE) { + return false; + } + + std::string internal_ciphers; + for (const int cipher : ciphers) { + bool found = false; + for (const auto& entry : kSrtpCipherMap) { + if (cipher == entry.id) { + found = true; + if (!internal_ciphers.empty()) { + internal_ciphers += ":"; + } + internal_ciphers += entry.internal_name; + break; + } + } + + if (!found) { + RTC_LOG(LS_ERROR) << "Could not find cipher: " << cipher; + return false; + } + } + + if (internal_ciphers.empty()) { + return false; + } + + srtp_ciphers_ = internal_ciphers; + return true; +} + +bool OpenSSLStreamAdapter::GetDtlsSrtpCryptoSuite(int* crypto_suite) { + RTC_DCHECK(state_ == SSL_CONNECTED); + if (state_ != SSL_CONNECTED) { + return false; + } + + const SRTP_PROTECTION_PROFILE* srtp_profile = + SSL_get_selected_srtp_profile(ssl_); + + if (!srtp_profile) { + return false; + } + + *crypto_suite = srtp_profile->id; + RTC_DCHECK(!SrtpCryptoSuiteToName(*crypto_suite).empty()); + return true; +} + +bool OpenSSLStreamAdapter::IsTlsConnected() { + return state_ == SSL_CONNECTED; +} + +int OpenSSLStreamAdapter::StartSSL() { + // Don't allow StartSSL to be called twice. + if (state_ != SSL_NONE) { + return -1; + } + + if (stream_->GetState() != SS_OPEN) { + state_ = SSL_WAIT; + return 0; + } + + state_ = SSL_CONNECTING; + if (int err = BeginSSL()) { + Error("BeginSSL", err, 0, false); + return err; + } + + return 0; +} + +void OpenSSLStreamAdapter::SetMode(SSLMode mode) { + RTC_DCHECK(state_ == SSL_NONE); + ssl_mode_ = mode; +} + +void OpenSSLStreamAdapter::SetMaxProtocolVersion(SSLProtocolVersion version) { + RTC_DCHECK(ssl_ctx_ == nullptr); + ssl_max_version_ = version; +} + +void OpenSSLStreamAdapter::SetInitialRetransmissionTimeout(int timeout_ms) { + RTC_DCHECK(ssl_ctx_ == nullptr); + dtls_handshake_timeout_ms_ = timeout_ms; +} + +// +// StreamInterface Implementation +// +StreamResult OpenSSLStreamAdapter::Write(rtc::ArrayView<const uint8_t> data, + size_t& written, + int& error) { + RTC_DLOG(LS_VERBOSE) << "OpenSSLStreamAdapter::Write(" << data.size() << ")"; + + switch (state_) { + case SSL_NONE: + // pass-through in clear text + return stream_->Write(data, written, error); + + case SSL_WAIT: + case SSL_CONNECTING: + return SR_BLOCK; + + case SSL_CONNECTED: + if (WaitingToVerifyPeerCertificate()) { + return SR_BLOCK; + } + break; + + case SSL_ERROR: + case SSL_CLOSED: + default: + error = ssl_error_code_; + return SR_ERROR; + } + + // OpenSSL will return an error if we try to write zero bytes + if (data.size() == 0) { + written = 0; + return SR_SUCCESS; + } + + ssl_write_needs_read_ = false; + + int code = SSL_write(ssl_, data.data(), checked_cast<int>(data.size())); + int ssl_error = SSL_get_error(ssl_, code); + switch (ssl_error) { + case SSL_ERROR_NONE: + RTC_DLOG(LS_VERBOSE) << " -- success"; + RTC_DCHECK_GT(code, 0); + RTC_DCHECK_LE(code, data.size()); + written = code; + return SR_SUCCESS; + case SSL_ERROR_WANT_READ: + RTC_DLOG(LS_VERBOSE) << " -- error want read"; + ssl_write_needs_read_ = true; + return SR_BLOCK; + case SSL_ERROR_WANT_WRITE: + RTC_DLOG(LS_VERBOSE) << " -- error want write"; + return SR_BLOCK; + + case SSL_ERROR_ZERO_RETURN: + default: + Error("SSL_write", (ssl_error ? ssl_error : -1), 0, false); + error = ssl_error_code_; + return SR_ERROR; + } + // not reached +} + +StreamResult OpenSSLStreamAdapter::Read(rtc::ArrayView<uint8_t> data, + size_t& read, + int& error) { + RTC_DLOG(LS_VERBOSE) << "OpenSSLStreamAdapter::Read(" << data.size() << ")"; + switch (state_) { + case SSL_NONE: + // pass-through in clear text + return stream_->Read(data, read, error); + case SSL_WAIT: + case SSL_CONNECTING: + return SR_BLOCK; + case SSL_CONNECTED: + if (WaitingToVerifyPeerCertificate()) { + return SR_BLOCK; + } + break; + case SSL_CLOSED: + return SR_EOS; + case SSL_ERROR: + default: + error = ssl_error_code_; + return SR_ERROR; + } + + // Don't trust OpenSSL with zero byte reads + if (data.size() == 0) { + read = 0; + return SR_SUCCESS; + } + + ssl_read_needs_write_ = false; + + const int code = SSL_read(ssl_, data.data(), checked_cast<int>(data.size())); + const int ssl_error = SSL_get_error(ssl_, code); + + switch (ssl_error) { + case SSL_ERROR_NONE: + RTC_DLOG(LS_VERBOSE) << " -- success"; + RTC_DCHECK_GT(code, 0); + RTC_DCHECK_LE(code, data.size()); + read = code; + + if (ssl_mode_ == SSL_MODE_DTLS) { + // Enforce atomic reads -- this is a short read + unsigned int pending = SSL_pending(ssl_); + + if (pending) { + RTC_DLOG(LS_INFO) << " -- short DTLS read. flushing"; + FlushInput(pending); + error = SSE_MSG_TRUNC; + return SR_ERROR; + } + } + return SR_SUCCESS; + case SSL_ERROR_WANT_READ: + RTC_DLOG(LS_VERBOSE) << " -- error want read"; + return SR_BLOCK; + case SSL_ERROR_WANT_WRITE: + RTC_DLOG(LS_VERBOSE) << " -- error want write"; + ssl_read_needs_write_ = true; + return SR_BLOCK; + case SSL_ERROR_ZERO_RETURN: + RTC_DLOG(LS_VERBOSE) << " -- remote side closed"; + Close(); + return SR_EOS; + default: + Error("SSL_read", (ssl_error ? ssl_error : -1), 0, false); + error = ssl_error_code_; + return SR_ERROR; + } + // not reached +} + +void OpenSSLStreamAdapter::FlushInput(unsigned int left) { + unsigned char buf[2048]; + + while (left) { + // This should always succeed + const int toread = (sizeof(buf) < left) ? sizeof(buf) : left; + const int code = SSL_read(ssl_, buf, toread); + + const int ssl_error = SSL_get_error(ssl_, code); + RTC_DCHECK(ssl_error == SSL_ERROR_NONE); + + if (ssl_error != SSL_ERROR_NONE) { + RTC_DLOG(LS_VERBOSE) << " -- error " << code; + Error("SSL_read", (ssl_error ? ssl_error : -1), 0, false); + return; + } + + RTC_DLOG(LS_VERBOSE) << " -- flushed " << code << " bytes"; + left -= code; + } +} + +void OpenSSLStreamAdapter::Close() { + Cleanup(0); + RTC_DCHECK(state_ == SSL_CLOSED || state_ == SSL_ERROR); + // When we're closed at SSL layer, also close the stream level which + // performs necessary clean up. Otherwise, a new incoming packet after + // this could overflow the stream buffer. + stream_->Close(); +} + +StreamState OpenSSLStreamAdapter::GetState() const { + switch (state_) { + case SSL_WAIT: + case SSL_CONNECTING: + return SS_OPENING; + case SSL_CONNECTED: + if (WaitingToVerifyPeerCertificate()) { + return SS_OPENING; + } + return SS_OPEN; + default: + return SS_CLOSED; + } + // not reached +} + +void OpenSSLStreamAdapter::OnEvent(StreamInterface* stream, + int events, + int err) { + int events_to_signal = 0; + int signal_error = 0; + RTC_DCHECK(stream == stream_.get()); + + if ((events & SE_OPEN)) { + RTC_DLOG(LS_VERBOSE) << "OpenSSLStreamAdapter::OnEvent SE_OPEN"; + if (state_ != SSL_WAIT) { + RTC_DCHECK(state_ == SSL_NONE); + events_to_signal |= SE_OPEN; + } else { + state_ = SSL_CONNECTING; + if (int err = BeginSSL()) { + Error("BeginSSL", err, 0, true); + return; + } + } + } + + if ((events & (SE_READ | SE_WRITE))) { + RTC_DLOG(LS_VERBOSE) << "OpenSSLStreamAdapter::OnEvent" + << ((events & SE_READ) ? " SE_READ" : "") + << ((events & SE_WRITE) ? " SE_WRITE" : ""); + if (state_ == SSL_NONE) { + events_to_signal |= events & (SE_READ | SE_WRITE); + } else if (state_ == SSL_CONNECTING) { + if (int err = ContinueSSL()) { + Error("ContinueSSL", err, 0, true); + return; + } + } else if (state_ == SSL_CONNECTED) { + if (((events & SE_READ) && ssl_write_needs_read_) || + (events & SE_WRITE)) { + RTC_DLOG(LS_VERBOSE) << " -- onStreamWriteable"; + events_to_signal |= SE_WRITE; + } + if (((events & SE_WRITE) && ssl_read_needs_write_) || + (events & SE_READ)) { + RTC_DLOG(LS_VERBOSE) << " -- onStreamReadable"; + events_to_signal |= SE_READ; + } + } + } + + if ((events & SE_CLOSE)) { + RTC_DLOG(LS_VERBOSE) << "OpenSSLStreamAdapter::OnEvent(SE_CLOSE, " << err + << ")"; + Cleanup(0); + events_to_signal |= SE_CLOSE; + // SE_CLOSE is the only event that uses the final parameter to OnEvent(). + RTC_DCHECK(signal_error == 0); + signal_error = err; + } + + if (events_to_signal) { + // Note that the adapter presents itself as the origin of the stream events, + // since users of the adapter may not recognize the adapted object. + SignalEvent(this, events_to_signal, signal_error); + } +} + +void OpenSSLStreamAdapter::PostEvent(int events, int err) { + owner_->PostTask(SafeTask(task_safety_.flag(), [this, events, err]() { + SignalEvent(this, events, err); + })); +} + +void OpenSSLStreamAdapter::SetTimeout(int delay_ms) { + // We need to accept 0 delay here as well as >0 delay, because + // DTLSv1_get_timeout seems to frequently return 0 ms. + RTC_DCHECK_GE(delay_ms, 0); + RTC_DCHECK(!timeout_task_.Running()); + + timeout_task_ = webrtc::RepeatingTaskHandle::DelayedStart( + owner_, webrtc::TimeDelta::Millis(delay_ms), + [flag = task_safety_.flag(), this]() { + if (flag->alive()) { + RTC_DLOG(LS_INFO) << "DTLS timeout expired"; + timeout_task_.Stop(); + int res = DTLSv1_handle_timeout(ssl_); + if (res > 0) { + RTC_LOG(LS_INFO) << "DTLS retransmission"; + } else if (res < 0) { + RTC_LOG(LS_INFO) << "DTLSv1_handle_timeout() return -1"; + Error("DTLSv1_handle_timeout", res, -1, true); + return webrtc::TimeDelta::PlusInfinity(); + } + ContinueSSL(); + } else { + RTC_DCHECK_NOTREACHED(); + } + // This callback will never run again (stopped above). + return webrtc::TimeDelta::PlusInfinity(); + }); +} + +int OpenSSLStreamAdapter::BeginSSL() { + RTC_DCHECK(state_ == SSL_CONNECTING); + // The underlying stream has opened. + RTC_DLOG(LS_INFO) << "BeginSSL with peer."; + + BIO* bio = nullptr; + + // First set up the context. + RTC_DCHECK(ssl_ctx_ == nullptr); + ssl_ctx_ = SetupSSLContext(); + if (!ssl_ctx_) { + return -1; + } + + bio = BIO_new_stream(stream_.get()); + if (!bio) { + return -1; + } + + ssl_ = SSL_new(ssl_ctx_); + if (!ssl_) { + BIO_free(bio); + return -1; + } + + SSL_set_app_data(ssl_, this); + + SSL_set_bio(ssl_, bio, bio); // the SSL object owns the bio now. + if (ssl_mode_ == SSL_MODE_DTLS) { +#ifdef OPENSSL_IS_BORINGSSL + DTLSv1_set_initial_timeout_duration(ssl_, dtls_handshake_timeout_ms_); +#else + // Enable read-ahead for DTLS so whole packets are read from internal BIO + // before parsing. This is done internally by BoringSSL for DTLS. + SSL_set_read_ahead(ssl_, 1); +#endif + } + + SSL_set_mode(ssl_, SSL_MODE_ENABLE_PARTIAL_WRITE | + SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); + + // Do the connect + return ContinueSSL(); +} + +int OpenSSLStreamAdapter::ContinueSSL() { + RTC_DLOG(LS_VERBOSE) << "ContinueSSL"; + RTC_DCHECK(state_ == SSL_CONNECTING); + + // Clear the DTLS timer + timeout_task_.Stop(); + + const int code = (role_ == SSL_CLIENT) ? SSL_connect(ssl_) : SSL_accept(ssl_); + const int ssl_error = SSL_get_error(ssl_, code); + + switch (ssl_error) { + case SSL_ERROR_NONE: + RTC_DLOG(LS_VERBOSE) << " -- success"; + // By this point, OpenSSL should have given us a certificate, or errored + // out if one was missing. + RTC_DCHECK(peer_cert_chain_ || !GetClientAuthEnabled()); + + state_ = SSL_CONNECTED; + if (!WaitingToVerifyPeerCertificate()) { + // We have everything we need to start the connection, so signal + // SE_OPEN. If we need a client certificate fingerprint and don't have + // it yet, we'll instead signal SE_OPEN in SetPeerCertificateDigest. + // + // TODO(deadbeef): Post this event asynchronously to unwind the stack. + // The caller of ContinueSSL may be the same object listening for these + // events and may not be prepared for reentrancy. + // PostEvent(SE_OPEN | SE_READ | SE_WRITE, 0); + SignalEvent(this, SE_OPEN | SE_READ | SE_WRITE, 0); + } + break; + + case SSL_ERROR_WANT_READ: { + RTC_DLOG(LS_VERBOSE) << " -- error want read"; + struct timeval timeout; + if (DTLSv1_get_timeout(ssl_, &timeout)) { + int delay = timeout.tv_sec * 1000 + timeout.tv_usec / 1000; + SetTimeout(delay); + } + } break; + + case SSL_ERROR_WANT_WRITE: + RTC_DLOG(LS_VERBOSE) << " -- error want write"; + break; + + case SSL_ERROR_ZERO_RETURN: + default: + SSLHandshakeError ssl_handshake_err = SSLHandshakeError::UNKNOWN; + int err_code = ERR_peek_last_error(); + if (err_code != 0 && ERR_GET_REASON(err_code) == SSL_R_NO_SHARED_CIPHER) { + ssl_handshake_err = SSLHandshakeError::INCOMPATIBLE_CIPHERSUITE; + } + RTC_DLOG(LS_VERBOSE) << " -- error " << code << ", " << err_code << ", " + << ERR_GET_REASON(err_code); + if (handshake_error_) { + handshake_error_(ssl_handshake_err); + } + return (ssl_error != 0) ? ssl_error : -1; + } + + return 0; +} + +void OpenSSLStreamAdapter::Error(absl::string_view context, + int err, + uint8_t alert, + bool signal) { + RTC_LOG(LS_WARNING) << "OpenSSLStreamAdapter::Error(" << context << ", " + << err << ", " << static_cast<int>(alert) << ")"; + state_ = SSL_ERROR; + ssl_error_code_ = err; + Cleanup(alert); + if (signal) { + SignalEvent(this, SE_CLOSE, err); + } +} + +void OpenSSLStreamAdapter::Cleanup(uint8_t alert) { + RTC_DLOG(LS_INFO) << "Cleanup"; + + if (state_ != SSL_ERROR) { + state_ = SSL_CLOSED; + ssl_error_code_ = 0; + } + + if (ssl_) { + int ret; +// SSL_send_fatal_alert is only available in BoringSSL. +#ifdef OPENSSL_IS_BORINGSSL + if (alert) { + ret = SSL_send_fatal_alert(ssl_, alert); + if (ret < 0) { + RTC_LOG(LS_WARNING) << "SSL_send_fatal_alert failed, error = " + << SSL_get_error(ssl_, ret); + } + } else { +#endif + ret = SSL_shutdown(ssl_); + if (ret < 0) { + RTC_LOG(LS_WARNING) + << "SSL_shutdown failed, error = " << SSL_get_error(ssl_, ret); + } +#ifdef OPENSSL_IS_BORINGSSL + } +#endif + SSL_free(ssl_); + ssl_ = nullptr; + } + if (ssl_ctx_) { + SSL_CTX_free(ssl_ctx_); + ssl_ctx_ = nullptr; + } + identity_.reset(); + peer_cert_chain_.reset(); + + // Clear the DTLS timer + timeout_task_.Stop(); +} + +SSL_CTX* OpenSSLStreamAdapter::SetupSSLContext() { +#ifdef OPENSSL_IS_BORINGSSL + // If X509 objects aren't used, we can use these methods to avoid + // linking the sizable crypto/x509 code, using CRYPTO_BUFFER instead. + SSL_CTX* ctx = + SSL_CTX_new(ssl_mode_ == SSL_MODE_DTLS ? DTLS_with_buffers_method() + : TLS_with_buffers_method()); +#else + SSL_CTX* ctx = + SSL_CTX_new(ssl_mode_ == SSL_MODE_DTLS ? DTLS_method() : TLS_method()); +#endif + if (ctx == nullptr) { + return nullptr; + } + + if (support_legacy_tls_protocols_flag_) { + // TODO(https://bugs.webrtc.org/10261): Completely remove this branch in + // M84. + SSL_CTX_set_min_proto_version( + ctx, ssl_mode_ == SSL_MODE_DTLS ? DTLS1_VERSION : TLS1_VERSION); + switch (ssl_max_version_) { + case SSL_PROTOCOL_TLS_10: + SSL_CTX_set_max_proto_version( + ctx, ssl_mode_ == SSL_MODE_DTLS ? DTLS1_VERSION : TLS1_VERSION); + break; + case SSL_PROTOCOL_TLS_11: + SSL_CTX_set_max_proto_version( + ctx, ssl_mode_ == SSL_MODE_DTLS ? DTLS1_VERSION : TLS1_1_VERSION); + break; + case SSL_PROTOCOL_TLS_12: + default: + SSL_CTX_set_max_proto_version( + ctx, ssl_mode_ == SSL_MODE_DTLS ? DTLS1_2_VERSION : TLS1_2_VERSION); + break; + } + } else { + // TODO(https://bugs.webrtc.org/10261): Make this the default in M84. + SSL_CTX_set_min_proto_version( + ctx, ssl_mode_ == SSL_MODE_DTLS ? DTLS1_2_VERSION : TLS1_2_VERSION); + SSL_CTX_set_max_proto_version( + ctx, ssl_mode_ == SSL_MODE_DTLS ? DTLS1_2_VERSION : TLS1_2_VERSION); + } + +#ifdef OPENSSL_IS_BORINGSSL + // SSL_CTX_set_current_time_cb is only supported in BoringSSL. + if (g_use_time_callback_for_testing) { + SSL_CTX_set_current_time_cb(ctx, &TimeCallbackForTesting); + } + SSL_CTX_set0_buffer_pool(ctx, openssl::GetBufferPool()); +#endif + + if (identity_ && !identity_->ConfigureIdentity(ctx)) { + SSL_CTX_free(ctx); + return nullptr; + } + + SSL_CTX_set_info_callback(ctx, OpenSSLAdapter::SSLInfoCallback); + + int mode = SSL_VERIFY_PEER; + if (GetClientAuthEnabled()) { + // Require a certificate from the client. + // Note: Normally this is always true in production, but it may be disabled + // for testing purposes (e.g. SSLAdapter unit tests). + mode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT; + } + + // Configure a custom certificate verification callback to check the peer + // certificate digest. +#ifdef OPENSSL_IS_BORINGSSL + // Use CRYPTO_BUFFER version of the callback if building with BoringSSL. + SSL_CTX_set_custom_verify(ctx, mode, SSLVerifyCallback); +#else + // Note the second argument to SSL_CTX_set_verify is to override individual + // errors in the default verification logic, which is not what we want here. + SSL_CTX_set_verify(ctx, mode, nullptr); + SSL_CTX_set_cert_verify_callback(ctx, SSLVerifyCallback, nullptr); +#endif + + // Select list of available ciphers. Note that !SHA256 and !SHA384 only + // remove HMAC-SHA256 and HMAC-SHA384 cipher suites, not GCM cipher suites + // with SHA256 or SHA384 as the handshake hash. + // This matches the list of SSLClientSocketImpl in Chromium. + SSL_CTX_set_cipher_list( + ctx, + "DEFAULT:!NULL:!aNULL:!SHA256:!SHA384:!aECDH:!AESGCM+AES256:!aPSK:!3DES"); + + if (!srtp_ciphers_.empty()) { + if (SSL_CTX_set_tlsext_use_srtp(ctx, srtp_ciphers_.c_str())) { + SSL_CTX_free(ctx); + return nullptr; + } + } + +#ifdef OPENSSL_IS_BORINGSSL + SSL_CTX_set_permute_extensions( + ctx, webrtc::field_trial::IsEnabled("WebRTC-PermuteTlsClientHello")); +#endif + + return ctx; +} + +bool OpenSSLStreamAdapter::VerifyPeerCertificate() { + if (!HasPeerCertificateDigest() || !peer_cert_chain_ || + !peer_cert_chain_->GetSize()) { + RTC_LOG(LS_WARNING) << "Missing digest or peer certificate."; + return false; + } + + unsigned char digest[EVP_MAX_MD_SIZE]; + size_t digest_length; + if (!peer_cert_chain_->Get(0).ComputeDigest( + peer_certificate_digest_algorithm_, digest, sizeof(digest), + &digest_length)) { + RTC_LOG(LS_WARNING) << "Failed to compute peer cert digest."; + return false; + } + + Buffer computed_digest(digest, digest_length); + if (computed_digest != peer_certificate_digest_value_) { + RTC_LOG(LS_WARNING) + << "Rejected peer certificate due to mismatched digest using " + << peer_certificate_digest_algorithm_ << ". Expected " + << rtc::hex_encode_with_delimiter(peer_certificate_digest_value_, ':') + << " got " << rtc::hex_encode_with_delimiter(computed_digest, ':'); + return false; + } + // Ignore any verification error if the digest matches, since there is no + // value in checking the validity of a self-signed cert issued by untrusted + // sources. + RTC_DLOG(LS_INFO) << "Accepted peer certificate."; + peer_certificate_verified_ = true; + return true; +} + +std::unique_ptr<SSLCertChain> OpenSSLStreamAdapter::GetPeerSSLCertChain() + const { + return peer_cert_chain_ ? peer_cert_chain_->Clone() : nullptr; +} + +#ifdef OPENSSL_IS_BORINGSSL +enum ssl_verify_result_t OpenSSLStreamAdapter::SSLVerifyCallback( + SSL* ssl, + uint8_t* out_alert) { + // Get our OpenSSLStreamAdapter from the context. + OpenSSLStreamAdapter* stream = + reinterpret_cast<OpenSSLStreamAdapter*>(SSL_get_app_data(ssl)); + const STACK_OF(CRYPTO_BUFFER)* chain = SSL_get0_peer_certificates(ssl); + // Creates certificate chain. + std::vector<std::unique_ptr<SSLCertificate>> cert_chain; + for (CRYPTO_BUFFER* cert : chain) { + cert_chain.emplace_back(new BoringSSLCertificate(bssl::UpRef(cert))); + } + stream->peer_cert_chain_.reset(new SSLCertChain(std::move(cert_chain))); + + // If the peer certificate digest isn't known yet, we'll wait to verify + // until it's known, and for now just return a success status. + if (stream->peer_certificate_digest_algorithm_.empty()) { + RTC_LOG(LS_INFO) << "Waiting to verify certificate until digest is known."; + // TODO(deadbeef): Use ssl_verify_retry? + return ssl_verify_ok; + } + + if (!stream->VerifyPeerCertificate()) { + return ssl_verify_invalid; + } + + return ssl_verify_ok; +} +#else // OPENSSL_IS_BORINGSSL +int OpenSSLStreamAdapter::SSLVerifyCallback(X509_STORE_CTX* store, void* arg) { + // Get our SSL structure and OpenSSLStreamAdapter from the store. + SSL* ssl = reinterpret_cast<SSL*>( + X509_STORE_CTX_get_ex_data(store, SSL_get_ex_data_X509_STORE_CTX_idx())); + OpenSSLStreamAdapter* stream = + reinterpret_cast<OpenSSLStreamAdapter*>(SSL_get_app_data(ssl)); + + // Record the peer's certificate. + X509* cert = X509_STORE_CTX_get0_cert(store); + stream->peer_cert_chain_.reset( + new SSLCertChain(std::make_unique<OpenSSLCertificate>(cert))); + + // If the peer certificate digest isn't known yet, we'll wait to verify + // until it's known, and for now just return a success status. + if (stream->peer_certificate_digest_algorithm_.empty()) { + RTC_DLOG(LS_INFO) << "Waiting to verify certificate until digest is known."; + return 1; + } + + if (!stream->VerifyPeerCertificate()) { + X509_STORE_CTX_set_error(store, X509_V_ERR_CERT_REJECTED); + return 0; + } + + return 1; +} +#endif // !OPENSSL_IS_BORINGSSL + +bool OpenSSLStreamAdapter::IsBoringSsl() { +#ifdef OPENSSL_IS_BORINGSSL + return true; +#else + return false; +#endif +} + +#define CDEF(X) \ + { static_cast<uint16_t>(TLS1_CK_##X & 0xffff), "TLS_" #X } + +struct cipher_list { + uint16_t cipher; + const char* cipher_str; +}; + +// TODO(torbjorng): Perhaps add more cipher suites to these lists. +static const cipher_list OK_RSA_ciphers[] = { + CDEF(ECDHE_RSA_WITH_AES_128_CBC_SHA), + CDEF(ECDHE_RSA_WITH_AES_256_CBC_SHA), + CDEF(ECDHE_RSA_WITH_AES_128_GCM_SHA256), +#ifdef TLS1_CK_ECDHE_RSA_WITH_AES_256_GCM_SHA256 + CDEF(ECDHE_RSA_WITH_AES_256_GCM_SHA256), +#endif +#ifdef TLS1_CK_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 + CDEF(ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256), +#endif +}; + +static const cipher_list OK_ECDSA_ciphers[] = { + CDEF(ECDHE_ECDSA_WITH_AES_128_CBC_SHA), + CDEF(ECDHE_ECDSA_WITH_AES_256_CBC_SHA), + CDEF(ECDHE_ECDSA_WITH_AES_128_GCM_SHA256), +#ifdef TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA256 + CDEF(ECDHE_ECDSA_WITH_AES_256_GCM_SHA256), +#endif +#ifdef TLS1_CK_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 + CDEF(ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256), +#endif +}; +#undef CDEF + +bool OpenSSLStreamAdapter::IsAcceptableCipher(int cipher, KeyType key_type) { + if (key_type == KT_RSA) { + for (const cipher_list& c : OK_RSA_ciphers) { + if (cipher == c.cipher) { + return true; + } + } + } + + if (key_type == KT_ECDSA) { + for (const cipher_list& c : OK_ECDSA_ciphers) { + if (cipher == c.cipher) { + return true; + } + } + } + + return false; +} + +bool OpenSSLStreamAdapter::IsAcceptableCipher(absl::string_view cipher, + KeyType key_type) { + if (key_type == KT_RSA) { + for (const cipher_list& c : OK_RSA_ciphers) { + if (cipher == c.cipher_str) { + return true; + } + } + } + + if (key_type == KT_ECDSA) { + for (const cipher_list& c : OK_ECDSA_ciphers) { + if (cipher == c.cipher_str) { + return true; + } + } + } + + return false; +} + +void OpenSSLStreamAdapter::EnableTimeCallbackForTesting() { +#ifdef OPENSSL_IS_BORINGSSL + g_use_time_callback_for_testing = true; +#endif +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/openssl_stream_adapter.h b/third_party/libwebrtc/rtc_base/openssl_stream_adapter.h new file mode 100644 index 0000000000..42fdb08aae --- /dev/null +++ b/third_party/libwebrtc/rtc_base/openssl_stream_adapter.h @@ -0,0 +1,264 @@ +/* + * 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 RTC_BASE_OPENSSL_STREAM_ADAPTER_H_ +#define RTC_BASE_OPENSSL_STREAM_ADAPTER_H_ + +#include <openssl/ossl_typ.h> +#include <stddef.h> +#include <stdint.h> + +#include <memory> +#include <string> +#include <vector> + +#include "absl/functional/any_invocable.h" +#include "absl/strings/string_view.h" +#include "absl/types/optional.h" +#include "rtc_base/buffer.h" +#ifdef OPENSSL_IS_BORINGSSL +#include "rtc_base/boringssl_identity.h" +#else +#include "rtc_base/openssl_identity.h" +#endif +#include "api/task_queue/pending_task_safety_flag.h" +#include "rtc_base/ssl_identity.h" +#include "rtc_base/ssl_stream_adapter.h" +#include "rtc_base/stream.h" +#include "rtc_base/system/rtc_export.h" +#include "rtc_base/task_utils/repeating_task.h" +#include "rtc_base/third_party/sigslot/sigslot.h" + +namespace rtc { + +// This class was written with OpenSSLAdapter (a socket adapter) as a +// starting point. It has similar structure and functionality, but uses a +// "peer-to-peer" mode, verifying the peer's certificate using a digest +// sent over a secure signaling channel. +// +// Static methods to initialize and deinit the SSL library are in +// OpenSSLAdapter. These should probably be moved out to a neutral class. +// +// In a few cases I have factored out some OpenSSLAdapter code into static +// methods so it can be reused from this class. Eventually that code should +// probably be moved to a common support class. Unfortunately there remain a +// few duplicated sections of code. I have not done more restructuring because +// I did not want to affect existing code that uses OpenSSLAdapter. +// +// This class does not support the SSL connection restart feature present in +// OpenSSLAdapter. I am not entirely sure how the feature is useful and I am +// not convinced that it works properly. +// +// This implementation is careful to disallow data exchange after an SSL error, +// and it has an explicit SSL_CLOSED state. It should not be possible to send +// any data in clear after one of the StartSSL methods has been called. + +// Look in sslstreamadapter.h for documentation of the methods. + +class SSLCertChain; + +/////////////////////////////////////////////////////////////////////////////// + +// If `allow` has a value, its value determines if legacy TLS protocols are +// allowed, overriding the default configuration. +// If `allow` has no value, any previous override is removed and the default +// configuration is restored. +RTC_EXPORT void SetAllowLegacyTLSProtocols(const absl::optional<bool>& allow); + +class OpenSSLStreamAdapter final : public SSLStreamAdapter, + public sigslot::has_slots<> { + public: + OpenSSLStreamAdapter( + std::unique_ptr<StreamInterface> stream, + absl::AnyInvocable<void(SSLHandshakeError)> handshake_error); + ~OpenSSLStreamAdapter() override; + + void SetIdentity(std::unique_ptr<SSLIdentity> identity) override; + SSLIdentity* GetIdentityForTesting() const override; + + // Default argument is for compatibility + void SetServerRole(SSLRole role = SSL_SERVER) override; + bool SetPeerCertificateDigest( + absl::string_view digest_alg, + const unsigned char* digest_val, + size_t digest_len, + SSLPeerCertificateDigestError* error = nullptr) override; + + std::unique_ptr<SSLCertChain> GetPeerSSLCertChain() const override; + + // Goes from state SSL_NONE to either SSL_CONNECTING or SSL_WAIT, depending + // on whether the underlying stream is already open or not. + int StartSSL() override; + void SetMode(SSLMode mode) override; + void SetMaxProtocolVersion(SSLProtocolVersion version) override; + void SetInitialRetransmissionTimeout(int timeout_ms) override; + + StreamResult Read(rtc::ArrayView<uint8_t> data, + size_t& read, + int& error) override; + StreamResult Write(rtc::ArrayView<const uint8_t> data, + size_t& written, + int& error) override; + void Close() override; + StreamState GetState() const override; + + // TODO(guoweis): Move this away from a static class method. + static std::string SslCipherSuiteToName(int crypto_suite); + + bool GetSslCipherSuite(int* cipher) override; + + SSLProtocolVersion GetSslVersion() const override; + bool GetSslVersionBytes(int* version) const override; + // Key Extractor interface + bool ExportKeyingMaterial(absl::string_view label, + const uint8_t* context, + size_t context_len, + bool use_context, + uint8_t* result, + size_t result_len) override; + + uint16_t GetPeerSignatureAlgorithm() const override; + + // DTLS-SRTP interface + bool SetDtlsSrtpCryptoSuites(const std::vector<int>& crypto_suites) override; + bool GetDtlsSrtpCryptoSuite(int* crypto_suite) override; + + bool IsTlsConnected() override; + + // Capabilities interfaces. + static bool IsBoringSsl(); + + static bool IsAcceptableCipher(int cipher, KeyType key_type); + static bool IsAcceptableCipher(absl::string_view cipher, KeyType key_type); + + // Use our timeutils.h source of timing in BoringSSL, allowing us to test + // using a fake clock. + static void EnableTimeCallbackForTesting(); + + private: + enum SSLState { + // Before calling one of the StartSSL methods, data flows + // in clear text. + SSL_NONE, + SSL_WAIT, // waiting for the stream to open to start SSL negotiation + SSL_CONNECTING, // SSL negotiation in progress + SSL_CONNECTED, // SSL stream successfully established + SSL_ERROR, // some SSL error occurred, stream is closed + SSL_CLOSED // Clean close + }; + + void OnEvent(StreamInterface* stream, int events, int err); + + void PostEvent(int events, int err); + void SetTimeout(int delay_ms); + + // The following three methods return 0 on success and a negative + // error code on failure. The error code may be from OpenSSL or -1 + // on some other error cases, so it can't really be interpreted + // unfortunately. + + // Prepare SSL library, state is SSL_CONNECTING. + int BeginSSL(); + // Perform SSL negotiation steps. + int ContinueSSL(); + + // Error handler helper. signal is given as true for errors in + // asynchronous contexts (when an error method was not returned + // through some other method), and in that case an SE_CLOSE event is + // raised on the stream with the specified error. + // A 0 error means a graceful close, otherwise there is not really enough + // context to interpret the error code. + // `alert` indicates an alert description (one of the SSL_AD constants) to + // send to the remote endpoint when closing the association. If 0, a normal + // shutdown will be performed. + void Error(absl::string_view context, int err, uint8_t alert, bool signal); + void Cleanup(uint8_t alert); + + // Flush the input buffers by reading left bytes (for DTLS) + void FlushInput(unsigned int left); + + // SSL library configuration + SSL_CTX* SetupSSLContext(); + // Verify the peer certificate matches the signaled digest. + bool VerifyPeerCertificate(); + +#ifdef OPENSSL_IS_BORINGSSL + // SSL certificate verification callback. See SSL_CTX_set_custom_verify. + static enum ssl_verify_result_t SSLVerifyCallback(SSL* ssl, + uint8_t* out_alert); +#else + // SSL certificate verification callback. See + // SSL_CTX_set_cert_verify_callback. + static int SSLVerifyCallback(X509_STORE_CTX* store, void* arg); +#endif + + bool WaitingToVerifyPeerCertificate() const { + return GetClientAuthEnabled() && !peer_certificate_verified_; + } + + bool HasPeerCertificateDigest() const { + return !peer_certificate_digest_algorithm_.empty() && + !peer_certificate_digest_value_.empty(); + } + + const std::unique_ptr<StreamInterface> stream_; + absl::AnyInvocable<void(SSLHandshakeError)> handshake_error_; + + rtc::Thread* const owner_; + webrtc::ScopedTaskSafety task_safety_; + webrtc::RepeatingTaskHandle timeout_task_; + + SSLState state_; + SSLRole role_; + int ssl_error_code_; // valid when state_ == SSL_ERROR or SSL_CLOSED + // Whether the SSL negotiation is blocked on needing to read or + // write to the wrapped stream. + bool ssl_read_needs_write_; + bool ssl_write_needs_read_; + + SSL* ssl_; + SSL_CTX* ssl_ctx_; + + // Our key and certificate. +#ifdef OPENSSL_IS_BORINGSSL + std::unique_ptr<BoringSSLIdentity> identity_; +#else + std::unique_ptr<OpenSSLIdentity> identity_; +#endif + // The certificate chain that the peer presented. Initially null, until the + // connection is established. + std::unique_ptr<SSLCertChain> peer_cert_chain_; + bool peer_certificate_verified_ = false; + // The digest of the certificate that the peer must present. + Buffer peer_certificate_digest_value_; + std::string peer_certificate_digest_algorithm_; + + // The DtlsSrtp ciphers + std::string srtp_ciphers_; + + // Do DTLS or not + SSLMode ssl_mode_; + + // Max. allowed protocol version + SSLProtocolVersion ssl_max_version_; + + // A 50-ms initial timeout ensures rapid setup on fast connections, but may + // be too aggressive for low bandwidth links. + int dtls_handshake_timeout_ms_ = 50; + + // TODO(https://bugs.webrtc.org/10261): Completely remove this option in M84. + const bool support_legacy_tls_protocols_flag_; +}; + +///////////////////////////////////////////////////////////////////////////// + +} // namespace rtc + +#endif // RTC_BASE_OPENSSL_STREAM_ADAPTER_H_ diff --git a/third_party/libwebrtc/rtc_base/openssl_utility.cc b/third_party/libwebrtc/rtc_base/openssl_utility.cc new file mode 100644 index 0000000000..eba3788a94 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/openssl_utility.cc @@ -0,0 +1,274 @@ +/* + * 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. + */ + +#include "rtc_base/openssl_utility.h" + +#include "absl/strings/string_view.h" +#if defined(WEBRTC_WIN) +// Must be included first before openssl headers. +#include "rtc_base/win32.h" // NOLINT +#endif // WEBRTC_WIN + +#ifdef OPENSSL_IS_BORINGSSL +#include <openssl/pool.h> +#endif +#include <openssl/err.h> +#include <openssl/x509.h> +#include <openssl/x509v3.h> +#include <stddef.h> + +#include "rtc_base/arraysize.h" +#include "rtc_base/logging.h" +#include "rtc_base/numerics/safe_conversions.h" +#include "rtc_base/openssl.h" +#include "rtc_base/ssl_identity.h" +#ifndef WEBRTC_EXCLUDE_BUILT_IN_SSL_ROOT_CERTS +#include "rtc_base/ssl_roots.h" +#endif // WEBRTC_EXCLUDE_BUILT_IN_SSL_ROOT_CERTS + +namespace rtc { +namespace openssl { + +// Holds various helper methods. +namespace { + +// TODO(crbug.com/webrtc/11710): When OS certificate verification is available, +// and we don't need VerifyPeerCertMatchesHost, don't compile this in order to +// avoid a dependency on OpenSSL X509 objects (see crbug.com/webrtc/11410). +void LogCertificates(SSL* ssl, X509* certificate) { +// Logging certificates is extremely verbose. So it is disabled by default. +#ifdef LOG_CERTIFICATES + BIO* mem = BIO_new(BIO_s_mem()); + if (mem == nullptr) { + RTC_DLOG(LS_ERROR) << "BIO_new() failed to allocate memory."; + return; + } + + RTC_DLOG(LS_INFO) << "Certificate from server:"; + X509_print_ex(mem, certificate, XN_FLAG_SEP_CPLUS_SPC, X509_FLAG_NO_HEADER); + BIO_write(mem, "\0", 1); + + char* buffer = nullptr; + BIO_get_mem_data(mem, &buffer); + if (buffer != nullptr) { + RTC_DLOG(LS_INFO) << buffer; + } else { + RTC_DLOG(LS_ERROR) << "BIO_get_mem_data() failed to get buffer."; + } + BIO_free(mem); + + const char* cipher_name = SSL_CIPHER_get_name(SSL_get_current_cipher(ssl)); + if (cipher_name != nullptr) { + RTC_DLOG(LS_INFO) << "Cipher: " << cipher_name; + } else { + RTC_DLOG(LS_ERROR) << "SSL_CIPHER_DESCRIPTION() failed to get cipher_name."; + } +#endif +} +} // namespace + +#ifdef OPENSSL_IS_BORINGSSL +bool ParseCertificate(CRYPTO_BUFFER* cert_buffer, + CBS* signature_algorithm_oid, + int64_t* expiration_time) { + CBS cbs; + CRYPTO_BUFFER_init_CBS(cert_buffer, &cbs); + + // Certificate ::= SEQUENCE { + CBS certificate; + if (!CBS_get_asn1(&cbs, &certificate, CBS_ASN1_SEQUENCE)) { + return false; + } + // tbsCertificate TBSCertificate, + CBS tbs_certificate; + if (!CBS_get_asn1(&certificate, &tbs_certificate, CBS_ASN1_SEQUENCE)) { + return false; + } + // signatureAlgorithm AlgorithmIdentifier, + CBS signature_algorithm; + if (!CBS_get_asn1(&certificate, &signature_algorithm, CBS_ASN1_SEQUENCE)) { + return false; + } + if (!CBS_get_asn1(&signature_algorithm, signature_algorithm_oid, + CBS_ASN1_OBJECT)) { + return false; + } + // signatureValue BIT STRING } + if (!CBS_get_asn1(&certificate, nullptr, CBS_ASN1_BITSTRING)) { + return false; + } + if (CBS_len(&certificate)) { + return false; + } + + // Now parse the inner TBSCertificate. + // version [0] EXPLICIT Version DEFAULT v1, + if (!CBS_get_optional_asn1( + &tbs_certificate, nullptr, nullptr, + CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC)) { + return false; + } + // serialNumber CertificateSerialNumber, + if (!CBS_get_asn1(&tbs_certificate, nullptr, CBS_ASN1_INTEGER)) { + return false; + } + // signature AlgorithmIdentifier + if (!CBS_get_asn1(&tbs_certificate, nullptr, CBS_ASN1_SEQUENCE)) { + return false; + } + // issuer Name, + if (!CBS_get_asn1(&tbs_certificate, nullptr, CBS_ASN1_SEQUENCE)) { + return false; + } + // validity Validity, + CBS validity; + if (!CBS_get_asn1(&tbs_certificate, &validity, CBS_ASN1_SEQUENCE)) { + return false; + } + // Skip over notBefore. + if (!CBS_get_any_asn1_element(&validity, nullptr, nullptr, nullptr)) { + return false; + } + // Parse notAfter. + CBS not_after; + unsigned not_after_tag; + if (!CBS_get_any_asn1(&validity, ¬_after, ¬_after_tag)) { + return false; + } + bool long_format; + if (not_after_tag == CBS_ASN1_UTCTIME) { + long_format = false; + } else if (not_after_tag == CBS_ASN1_GENERALIZEDTIME) { + long_format = true; + } else { + return false; + } + if (expiration_time) { + *expiration_time = + ASN1TimeToSec(CBS_data(¬_after), CBS_len(¬_after), long_format); + } + // subject Name, + if (!CBS_get_asn1_element(&tbs_certificate, nullptr, CBS_ASN1_SEQUENCE)) { + return false; + } + // subjectPublicKeyInfo SubjectPublicKeyInfo, + if (!CBS_get_asn1(&tbs_certificate, nullptr, CBS_ASN1_SEQUENCE)) { + return false; + } + // issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL + if (!CBS_get_optional_asn1(&tbs_certificate, nullptr, nullptr, + 0x01 | CBS_ASN1_CONTEXT_SPECIFIC)) { + return false; + } + // subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL + if (!CBS_get_optional_asn1(&tbs_certificate, nullptr, nullptr, + 0x02 | CBS_ASN1_CONTEXT_SPECIFIC)) { + return false; + } + // extensions [3] EXPLICIT Extensions OPTIONAL + if (!CBS_get_optional_asn1( + &tbs_certificate, nullptr, nullptr, + 0x03 | CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC)) { + return false; + } + if (CBS_len(&tbs_certificate)) { + return false; + } + + return true; +} +#endif // OPENSSL_IS_BORINGSSL + +bool VerifyPeerCertMatchesHost(SSL* ssl, absl::string_view host) { + if (host.empty()) { + RTC_DLOG(LS_ERROR) << "Hostname is empty. Cannot verify peer certificate."; + return false; + } + + if (ssl == nullptr) { + RTC_DLOG(LS_ERROR) << "SSL is nullptr. Cannot verify peer certificate."; + return false; + } + +#ifdef OPENSSL_IS_BORINGSSL + // We can't grab a X509 object directly, as the SSL context may have been + // initialized with TLS_with_buffers_method. + const STACK_OF(CRYPTO_BUFFER)* chain = SSL_get0_peer_certificates(ssl); + if (chain == nullptr || sk_CRYPTO_BUFFER_num(chain) == 0) { + RTC_LOG(LS_ERROR) + << "SSL_get0_peer_certificates failed. This should never happen."; + return false; + } + CRYPTO_BUFFER* leaf = sk_CRYPTO_BUFFER_value(chain, 0); + bssl::UniquePtr<X509> x509(X509_parse_from_buffer(leaf)); + if (!x509) { + RTC_LOG(LS_ERROR) << "Failed to parse certificate to X509 object."; + return false; + } + LogCertificates(ssl, x509.get()); + return X509_check_host(x509.get(), host.data(), host.size(), 0, nullptr) == 1; +#else // OPENSSL_IS_BORINGSSL + X509* certificate = SSL_get_peer_certificate(ssl); + if (certificate == nullptr) { + RTC_LOG(LS_ERROR) + << "SSL_get_peer_certificate failed. This should never happen."; + return false; + } + + LogCertificates(ssl, certificate); + + bool is_valid_cert_name = + X509_check_host(certificate, host.data(), host.size(), 0, nullptr) == 1; + X509_free(certificate); + return is_valid_cert_name; +#endif // !defined(OPENSSL_IS_BORINGSSL) +} + +void LogSSLErrors(absl::string_view prefix) { + char error_buf[200]; + unsigned long err; // NOLINT + + while ((err = ERR_get_error()) != 0) { + ERR_error_string_n(err, error_buf, sizeof(error_buf)); + RTC_LOG(LS_ERROR) << prefix << ": " << error_buf << "\n"; + } +} + +#ifndef WEBRTC_EXCLUDE_BUILT_IN_SSL_ROOT_CERTS +bool LoadBuiltinSSLRootCertificates(SSL_CTX* ctx) { + int count_of_added_certs = 0; + for (size_t i = 0; i < arraysize(kSSLCertCertificateList); i++) { + const unsigned char* cert_buffer = kSSLCertCertificateList[i]; + size_t cert_buffer_len = kSSLCertCertificateSizeList[i]; + X509* cert = d2i_X509(nullptr, &cert_buffer, + checked_cast<long>(cert_buffer_len)); // NOLINT + if (cert) { + int return_value = X509_STORE_add_cert(SSL_CTX_get_cert_store(ctx), cert); + if (return_value == 0) { + RTC_LOG(LS_WARNING) << "Unable to add certificate."; + } else { + count_of_added_certs++; + } + X509_free(cert); + } + } + return count_of_added_certs > 0; +} +#endif // WEBRTC_EXCLUDE_BUILT_IN_SSL_ROOT_CERTS + +#ifdef OPENSSL_IS_BORINGSSL +CRYPTO_BUFFER_POOL* GetBufferPool() { + static CRYPTO_BUFFER_POOL* instance = CRYPTO_BUFFER_POOL_new(); + return instance; +} +#endif + +} // namespace openssl +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/openssl_utility.h b/third_party/libwebrtc/rtc_base/openssl_utility.h new file mode 100644 index 0000000000..dd183c283a --- /dev/null +++ b/third_party/libwebrtc/rtc_base/openssl_utility.h @@ -0,0 +1,60 @@ +/* + * 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 RTC_BASE_OPENSSL_UTILITY_H_ +#define RTC_BASE_OPENSSL_UTILITY_H_ + +#include <openssl/ossl_typ.h> + +#include <string> + +#include "absl/strings/string_view.h" + +namespace rtc { +// The openssl namespace holds static helper methods. All methods related +// to OpenSSL that are commonly used and don't require global state should be +// placed here. +namespace openssl { + +#ifdef OPENSSL_IS_BORINGSSL +// Does minimal parsing of a certificate (only verifying the presence of major +// fields), primarily for the purpose of extracting the relevant out +// parameters. Any that the caller is uninterested in can be null. +bool ParseCertificate(CRYPTO_BUFFER* cert_buffer, + CBS* signature_algorithm_oid, + int64_t* expiration_time); +#endif + +// Verifies that the hostname provided matches that in the peer certificate +// attached to this SSL state. +// TODO(crbug.com/webrtc/11710): When OS certificate verification is available, +// skip compiling this as it adds a dependency on OpenSSL X509 objects, which we +// are trying to avoid in favor of CRYPTO_BUFFERs (see crbug.com/webrtc/11410). +bool VerifyPeerCertMatchesHost(SSL* ssl, absl::string_view host); + +// Logs all the errors in the OpenSSL errror queue from the current thread. A +// prefix can be provided for context. +void LogSSLErrors(absl::string_view prefix); + +#ifndef WEBRTC_EXCLUDE_BUILT_IN_SSL_ROOT_CERTS +// Attempt to add the certificates from the loader into the SSL_CTX. False is +// returned only if there are no certificates returned from the loader or none +// of them can be added to the TrustStore for the provided context. +bool LoadBuiltinSSLRootCertificates(SSL_CTX* ssl_ctx); +#endif // WEBRTC_EXCLUDE_BUILT_IN_SSL_ROOT_CERTS + +#ifdef OPENSSL_IS_BORINGSSL +CRYPTO_BUFFER_POOL* GetBufferPool(); +#endif + +} // namespace openssl +} // namespace rtc + +#endif // RTC_BASE_OPENSSL_UTILITY_H_ diff --git a/third_party/libwebrtc/rtc_base/openssl_utility_unittest.cc b/third_party/libwebrtc/rtc_base/openssl_utility_unittest.cc new file mode 100644 index 0000000000..3302490bd0 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/openssl_utility_unittest.cc @@ -0,0 +1,308 @@ +/* + * 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. + */ + +#include <string> +#include <vector> + +#if defined(WEBRTC_POSIX) +#include <unistd.h> +#endif + +#if defined(WEBRTC_WIN) +// Must be included first before openssl headers. +#include "rtc_base/win32.h" // NOLINT +#endif // WEBRTC_WIN + +#include <openssl/bio.h> +#include <openssl/crypto.h> +#include <openssl/evp.h> +#include <openssl/ssl.h> +#ifdef OPENSSL_IS_BORINGSSL +#include <openssl/pool.h> +#else +#include <openssl/x509.h> +#include <openssl/x509v3.h> +#endif + +#include "rtc_base/arraysize.h" +#include "rtc_base/checks.h" +#include "rtc_base/gunit.h" +#include "rtc_base/numerics/safe_conversions.h" +#include "rtc_base/openssl.h" +#include "rtc_base/openssl_utility.h" +#include "rtc_base/ssl_roots.h" +#include "test/gmock.h" + +namespace rtc { +namespace { +// Fake P-256 key for use with the test certificates below. +const unsigned char kFakeSSLPrivateKey[] = { + 0x30, 0x81, 0x87, 0x02, 0x01, 0x00, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, + 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, + 0x03, 0x01, 0x07, 0x04, 0x6d, 0x30, 0x6b, 0x02, 0x01, 0x01, 0x04, 0x20, + 0x07, 0x0f, 0x08, 0x72, 0x7a, 0xd4, 0xa0, 0x4a, 0x9c, 0xdd, 0x59, 0xc9, + 0x4d, 0x89, 0x68, 0x77, 0x08, 0xb5, 0x6f, 0xc9, 0x5d, 0x30, 0x77, 0x0e, + 0xe8, 0xd1, 0xc9, 0xce, 0x0a, 0x8b, 0xb4, 0x6a, 0xa1, 0x44, 0x03, 0x42, + 0x00, 0x04, 0xe6, 0x2b, 0x69, 0xe2, 0xbf, 0x65, 0x9f, 0x97, 0xbe, 0x2f, + 0x1e, 0x0d, 0x94, 0x8a, 0x4c, 0xd5, 0x97, 0x6b, 0xb7, 0xa9, 0x1e, 0x0d, + 0x46, 0xfb, 0xdd, 0xa9, 0xa9, 0x1e, 0x9d, 0xdc, 0xba, 0x5a, 0x01, 0xe7, + 0xd6, 0x97, 0xa8, 0x0a, 0x18, 0xf9, 0xc3, 0xc4, 0xa3, 0x1e, 0x56, 0xe2, + 0x7c, 0x83, 0x48, 0xdb, 0x16, 0x1a, 0x1c, 0xf5, 0x1d, 0x7e, 0xf1, 0x94, + 0x2d, 0x4b, 0xcf, 0x72, 0x22, 0xc1}; + +// A self-signed certificate with CN *.webrtc.org and SANs foo.test, *.bar.test, +// and test.webrtc.org. +const unsigned char kFakeSSLCertificate[] = { + 0x30, 0x82, 0x02, 0x9e, 0x30, 0x82, 0x02, 0x42, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x09, 0x00, 0xc8, 0x83, 0x59, 0x4d, 0x90, 0xc3, 0x5f, 0xc8, + 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, + 0x05, 0x00, 0x30, 0x81, 0x8d, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, + 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, + 0x55, 0x04, 0x08, 0x0c, 0x02, 0x57, 0x41, 0x31, 0x2c, 0x30, 0x2a, 0x06, + 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x23, 0x46, 0x61, 0x6b, 0x65, 0x20, 0x57, + 0x65, 0x62, 0x52, 0x54, 0x43, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x46, 0x6f, 0x72, 0x20, 0x54, 0x65, + 0x73, 0x74, 0x69, 0x6e, 0x67, 0x31, 0x2c, 0x30, 0x2a, 0x06, 0x03, 0x55, + 0x04, 0x0b, 0x0c, 0x23, 0x46, 0x61, 0x6b, 0x65, 0x20, 0x57, 0x65, 0x62, + 0x52, 0x54, 0x43, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x65, 0x20, 0x46, 0x6f, 0x72, 0x20, 0x54, 0x65, 0x73, 0x74, + 0x69, 0x6e, 0x67, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x03, + 0x0c, 0x0c, 0x2a, 0x2e, 0x77, 0x65, 0x62, 0x72, 0x74, 0x63, 0x2e, 0x6f, + 0x72, 0x67, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x38, 0x30, 0x34, 0x30, 0x33, + 0x32, 0x31, 0x35, 0x34, 0x30, 0x38, 0x5a, 0x17, 0x0d, 0x31, 0x39, 0x30, + 0x34, 0x30, 0x33, 0x32, 0x31, 0x35, 0x34, 0x30, 0x38, 0x5a, 0x30, 0x81, + 0x8d, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, + 0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, + 0x02, 0x57, 0x41, 0x31, 0x2c, 0x30, 0x2a, 0x06, 0x03, 0x55, 0x04, 0x0a, + 0x0c, 0x23, 0x46, 0x61, 0x6b, 0x65, 0x20, 0x57, 0x65, 0x62, 0x52, 0x54, + 0x43, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, + 0x65, 0x20, 0x46, 0x6f, 0x72, 0x20, 0x54, 0x65, 0x73, 0x74, 0x69, 0x6e, + 0x67, 0x31, 0x2c, 0x30, 0x2a, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x23, + 0x46, 0x61, 0x6b, 0x65, 0x20, 0x57, 0x65, 0x62, 0x52, 0x54, 0x43, 0x20, + 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, + 0x46, 0x6f, 0x72, 0x20, 0x54, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x31, + 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x0c, 0x2a, 0x2e, + 0x77, 0x65, 0x62, 0x72, 0x74, 0x63, 0x2e, 0x6f, 0x72, 0x67, 0x30, 0x59, + 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, + 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, + 0x04, 0xe6, 0x2b, 0x69, 0xe2, 0xbf, 0x65, 0x9f, 0x97, 0xbe, 0x2f, 0x1e, + 0x0d, 0x94, 0x8a, 0x4c, 0xd5, 0x97, 0x6b, 0xb7, 0xa9, 0x1e, 0x0d, 0x46, + 0xfb, 0xdd, 0xa9, 0xa9, 0x1e, 0x9d, 0xdc, 0xba, 0x5a, 0x01, 0xe7, 0xd6, + 0x97, 0xa8, 0x0a, 0x18, 0xf9, 0xc3, 0xc4, 0xa3, 0x1e, 0x56, 0xe2, 0x7c, + 0x83, 0x48, 0xdb, 0x16, 0x1a, 0x1c, 0xf5, 0x1d, 0x7e, 0xf1, 0x94, 0x2d, + 0x4b, 0xcf, 0x72, 0x22, 0xc1, 0xa3, 0x81, 0x86, 0x30, 0x81, 0x83, 0x30, + 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xb7, 0xc0, + 0x9a, 0xa7, 0x22, 0xaf, 0xf8, 0x7d, 0xff, 0x68, 0xdb, 0x80, 0xac, 0x0a, + 0xb6, 0xdc, 0x64, 0x89, 0xdb, 0xd4, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, + 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xb7, 0xc0, 0x9a, 0xa7, 0x22, + 0xaf, 0xf8, 0x7d, 0xff, 0x68, 0xdb, 0x80, 0xac, 0x0a, 0xb6, 0xdc, 0x64, + 0x89, 0xdb, 0xd4, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, + 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x30, 0x06, 0x03, + 0x55, 0x1d, 0x11, 0x04, 0x29, 0x30, 0x27, 0x82, 0x08, 0x66, 0x6f, 0x6f, + 0x2e, 0x74, 0x65, 0x73, 0x74, 0x82, 0x0a, 0x2a, 0x2e, 0x62, 0x61, 0x72, + 0x2e, 0x74, 0x65, 0x73, 0x74, 0x82, 0x0f, 0x74, 0x65, 0x73, 0x74, 0x2e, + 0x77, 0x65, 0x62, 0x72, 0x74, 0x63, 0x2e, 0x6f, 0x72, 0x67, 0x30, 0x0c, + 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x05, 0x00, + 0x03, 0x48, 0x00, 0x30, 0x45, 0x02, 0x21, 0x00, 0x81, 0xcb, 0xe2, 0xf9, + 0x04, 0xba, 0xf7, 0xfd, 0x3f, 0x0d, 0x56, 0x37, 0xdb, 0x65, 0x68, 0x07, + 0x28, 0x8d, 0xc5, 0xe1, 0x73, 0xb7, 0xce, 0xa5, 0x20, 0x65, 0x15, 0xb2, + 0xc6, 0x37, 0x8c, 0x5a, 0x02, 0x20, 0x24, 0x62, 0x74, 0xe8, 0xd9, 0x80, + 0x78, 0x2a, 0xbb, 0x87, 0xff, 0x49, 0x99, 0xdb, 0x94, 0xab, 0x06, 0x91, + 0xc0, 0x7a, 0xa4, 0x62, 0x61, 0x98, 0x97, 0x47, 0xb7, 0x64, 0x2b, 0x99, + 0xc3, 0x71}; + +// A self-signed SSL certificate with only the legacy CN field *.webrtc.org. +const unsigned char kFakeSSLCertificateLegacy[] = { + 0x30, 0x82, 0x02, 0x6a, 0x30, 0x82, 0x02, 0x0e, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x09, 0x00, 0xc8, 0x83, 0x59, 0x4d, 0x90, 0xc3, 0x5f, 0xc8, + 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, + 0x05, 0x00, 0x30, 0x81, 0x8d, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, + 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, + 0x55, 0x04, 0x08, 0x0c, 0x02, 0x57, 0x41, 0x31, 0x2c, 0x30, 0x2a, 0x06, + 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x23, 0x46, 0x61, 0x6b, 0x65, 0x20, 0x57, + 0x65, 0x62, 0x52, 0x54, 0x43, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x46, 0x6f, 0x72, 0x20, 0x54, 0x65, + 0x73, 0x74, 0x69, 0x6e, 0x67, 0x31, 0x2c, 0x30, 0x2a, 0x06, 0x03, 0x55, + 0x04, 0x0b, 0x0c, 0x23, 0x46, 0x61, 0x6b, 0x65, 0x20, 0x57, 0x65, 0x62, + 0x52, 0x54, 0x43, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x65, 0x20, 0x46, 0x6f, 0x72, 0x20, 0x54, 0x65, 0x73, 0x74, + 0x69, 0x6e, 0x67, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x03, + 0x0c, 0x0c, 0x2a, 0x2e, 0x77, 0x65, 0x62, 0x72, 0x74, 0x63, 0x2e, 0x6f, + 0x72, 0x67, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x38, 0x30, 0x34, 0x30, 0x33, + 0x32, 0x31, 0x35, 0x34, 0x30, 0x38, 0x5a, 0x17, 0x0d, 0x31, 0x39, 0x30, + 0x34, 0x30, 0x33, 0x32, 0x31, 0x35, 0x34, 0x30, 0x38, 0x5a, 0x30, 0x81, + 0x8d, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, + 0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, + 0x02, 0x57, 0x41, 0x31, 0x2c, 0x30, 0x2a, 0x06, 0x03, 0x55, 0x04, 0x0a, + 0x0c, 0x23, 0x46, 0x61, 0x6b, 0x65, 0x20, 0x57, 0x65, 0x62, 0x52, 0x54, + 0x43, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, + 0x65, 0x20, 0x46, 0x6f, 0x72, 0x20, 0x54, 0x65, 0x73, 0x74, 0x69, 0x6e, + 0x67, 0x31, 0x2c, 0x30, 0x2a, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x23, + 0x46, 0x61, 0x6b, 0x65, 0x20, 0x57, 0x65, 0x62, 0x52, 0x54, 0x43, 0x20, + 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, + 0x46, 0x6f, 0x72, 0x20, 0x54, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x31, + 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x0c, 0x2a, 0x2e, + 0x77, 0x65, 0x62, 0x72, 0x74, 0x63, 0x2e, 0x6f, 0x72, 0x67, 0x30, 0x59, + 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, + 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, + 0x04, 0xe6, 0x2b, 0x69, 0xe2, 0xbf, 0x65, 0x9f, 0x97, 0xbe, 0x2f, 0x1e, + 0x0d, 0x94, 0x8a, 0x4c, 0xd5, 0x97, 0x6b, 0xb7, 0xa9, 0x1e, 0x0d, 0x46, + 0xfb, 0xdd, 0xa9, 0xa9, 0x1e, 0x9d, 0xdc, 0xba, 0x5a, 0x01, 0xe7, 0xd6, + 0x97, 0xa8, 0x0a, 0x18, 0xf9, 0xc3, 0xc4, 0xa3, 0x1e, 0x56, 0xe2, 0x7c, + 0x83, 0x48, 0xdb, 0x16, 0x1a, 0x1c, 0xf5, 0x1d, 0x7e, 0xf1, 0x94, 0x2d, + 0x4b, 0xcf, 0x72, 0x22, 0xc1, 0xa3, 0x53, 0x30, 0x51, 0x30, 0x1d, 0x06, + 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xb7, 0xc0, 0x9a, 0xa7, + 0x22, 0xaf, 0xf8, 0x7d, 0xff, 0x68, 0xdb, 0x80, 0xac, 0x0a, 0xb6, 0xdc, + 0x64, 0x89, 0xdb, 0xd4, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, + 0x18, 0x30, 0x16, 0x80, 0x14, 0xb7, 0xc0, 0x9a, 0xa7, 0x22, 0xaf, 0xf8, + 0x7d, 0xff, 0x68, 0xdb, 0x80, 0xac, 0x0a, 0xb6, 0xdc, 0x64, 0x89, 0xdb, + 0xd4, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, + 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, + 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x05, 0x00, 0x03, 0x48, 0x00, 0x30, + 0x45, 0x02, 0x21, 0x00, 0xae, 0x51, 0xbc, 0x0f, 0x28, 0x29, 0xd9, 0x35, + 0x95, 0xcc, 0x68, 0xf1, 0xc6, 0x3e, 0xfe, 0x56, 0xfd, 0x7f, 0xd2, 0x03, + 0x6d, 0x09, 0xc7, 0x9b, 0x83, 0x93, 0xd6, 0xd0, 0xfe, 0x45, 0x34, 0x7c, + 0x02, 0x20, 0x6b, 0xaa, 0x95, 0x8c, 0xfc, 0x29, 0x5e, 0x5e, 0xc9, 0xf5, + 0x84, 0x0b, 0xc7, 0x15, 0x86, 0xc3, 0xfc, 0x48, 0x55, 0xb5, 0x81, 0x94, + 0x73, 0xbd, 0x18, 0xcd, 0x9d, 0x92, 0x47, 0xaa, 0xfd, 0x18}; + +#ifdef OPENSSL_IS_BORINGSSL +enum ssl_verify_result_t DummyVerifyCallback(SSL* ssl, uint8_t* out_alert) { + return ssl_verify_ok; +} +#endif + +// Creates a client SSL that has completed handshaking with a server that uses +// the specified certificate (which must have private key kFakeSSLPrivateKey). +// The server is deallocated. This client will have a peer certificate available +// and is thus suitable for testing VerifyPeerCertMatchesHost. +SSL* CreateSSLWithPeerCertificate(const unsigned char* cert, size_t cert_len) { + const unsigned char* key_ptr = kFakeSSLPrivateKey; + EVP_PKEY* key = d2i_PrivateKey( + EVP_PKEY_EC, nullptr, &key_ptr, + checked_cast<long>(arraysize(kFakeSSLPrivateKey))); // NOLINT + RTC_CHECK(key); + +#ifdef OPENSSL_IS_BORINGSSL + SSL_CTX* ctx = SSL_CTX_new(TLS_with_buffers_method()); +#else + SSL_CTX* ctx = SSL_CTX_new(TLS_method()); +#endif + SSL* client = SSL_new(ctx); + SSL* server = SSL_new(ctx); + SSL_set_connect_state(client); + SSL_set_accept_state(server); + +#ifdef OPENSSL_IS_BORINGSSL + bssl::UniquePtr<CRYPTO_BUFFER> cert_buffer(CRYPTO_BUFFER_new( + static_cast<const uint8_t*>(cert), cert_len, openssl::GetBufferPool())); + RTC_CHECK(cert_buffer); + std::vector<CRYPTO_BUFFER*> cert_buffers; + cert_buffers.push_back(cert_buffer.get()); + RTC_CHECK(1 == SSL_set_chain_and_key(server, cert_buffers.data(), + cert_buffers.size(), key, nullptr)); + // When using crypto buffers we don't get any built-in verification. + SSL_set_custom_verify(client, SSL_VERIFY_PEER, DummyVerifyCallback); +#else + X509* x509 = + d2i_X509(nullptr, &cert, checked_cast<long>(cert_len)); // NOLINT + RTC_CHECK(x509); + RTC_CHECK(SSL_use_certificate(server, x509)); + RTC_CHECK(SSL_use_PrivateKey(server, key)); +#endif + + BIO* bio1; + BIO* bio2; + BIO_new_bio_pair(&bio1, 0, &bio2, 0); + // SSL_set_bio takes ownership of the BIOs. + SSL_set_bio(client, bio1, bio1); + SSL_set_bio(server, bio2, bio2); + + for (;;) { + int client_ret = SSL_do_handshake(client); + int client_err = SSL_get_error(client, client_ret); + RTC_CHECK(client_err == SSL_ERROR_NONE || + client_err == SSL_ERROR_WANT_READ || + client_err == SSL_ERROR_WANT_WRITE); + + int server_ret = SSL_do_handshake(server); + int server_err = SSL_get_error(server, server_ret); + RTC_CHECK(server_err == SSL_ERROR_NONE || + server_err == SSL_ERROR_WANT_READ || + server_err == SSL_ERROR_WANT_WRITE); + + if (client_ret == 1 && server_ret == 1) { + break; + } + } + + SSL_free(server); + SSL_CTX_free(ctx); + EVP_PKEY_free(key); +#ifndef OPENSSL_IS_BORINGSSL + X509_free(x509); +#endif + return client; +} +} // namespace + +TEST(OpenSSLUtilityTest, VerifyPeerCertMatchesHostFailsOnNoPeerCertificate) { +#ifdef OPENSSL_IS_BORINGSSL + SSL_CTX* ssl_ctx = SSL_CTX_new(DTLS_with_buffers_method()); +#else + SSL_CTX* ssl_ctx = SSL_CTX_new(DTLS_method()); +#endif + SSL* ssl = SSL_new(ssl_ctx); + + EXPECT_FALSE(openssl::VerifyPeerCertMatchesHost(ssl, "webrtc.org")); + + SSL_free(ssl); + SSL_CTX_free(ssl_ctx); +} + +TEST(OpenSSLUtilityTest, VerifyPeerCertMatchesHost) { + SSL* ssl = CreateSSLWithPeerCertificate(kFakeSSLCertificate, + arraysize(kFakeSSLCertificate)); + + // Each of the names in the SAN list is valid. + EXPECT_TRUE(openssl::VerifyPeerCertMatchesHost(ssl, "foo.test")); + EXPECT_TRUE(openssl::VerifyPeerCertMatchesHost(ssl, "a.bar.test")); + EXPECT_TRUE(openssl::VerifyPeerCertMatchesHost(ssl, "b.bar.test")); + EXPECT_TRUE(openssl::VerifyPeerCertMatchesHost(ssl, "test.webrtc.org")); + + // If the SAN list is present, the CN is not checked for hosts. + EXPECT_FALSE(openssl::VerifyPeerCertMatchesHost(ssl, "www.webrtc.org")); + + // Additional cases around wildcards. + EXPECT_FALSE(openssl::VerifyPeerCertMatchesHost(ssl, "a.b.bar.test")); + EXPECT_FALSE(openssl::VerifyPeerCertMatchesHost(ssl, "notbar.test")); + EXPECT_FALSE(openssl::VerifyPeerCertMatchesHost(ssl, "bar.test")); + + SSL_free(ssl); +} + +TEST(OpenSSLUtilityTest, VerifyPeerCertMatchesHostLegacy) { + SSL* ssl = CreateSSLWithPeerCertificate(kFakeSSLCertificateLegacy, + arraysize(kFakeSSLCertificateLegacy)); + + // If there is no SAN list, WebRTC still implements the legacy mechanism which + // checks the CN, no longer supported by modern browsers. + EXPECT_TRUE(openssl::VerifyPeerCertMatchesHost(ssl, "www.webrtc.org")); + EXPECT_TRUE(openssl::VerifyPeerCertMatchesHost(ssl, "alice.webrtc.org")); + EXPECT_TRUE(openssl::VerifyPeerCertMatchesHost(ssl, "bob.webrtc.org")); + + EXPECT_FALSE(openssl::VerifyPeerCertMatchesHost(ssl, "a.b.webrtc.org")); + EXPECT_FALSE(openssl::VerifyPeerCertMatchesHost(ssl, "notwebrtc.org")); + EXPECT_FALSE(openssl::VerifyPeerCertMatchesHost(ssl, "webrtc.org")); + + SSL_free(ssl); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/operations_chain.cc b/third_party/libwebrtc/rtc_base/operations_chain.cc new file mode 100644 index 0000000000..4398bb16c1 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/operations_chain.cc @@ -0,0 +1,88 @@ +/* + * 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 "rtc_base/operations_chain.h" + +#include "api/make_ref_counted.h" +#include "rtc_base/checks.h" + +namespace rtc { + +OperationsChain::CallbackHandle::CallbackHandle( + scoped_refptr<OperationsChain> operations_chain) + : operations_chain_(std::move(operations_chain)) {} + +OperationsChain::CallbackHandle::~CallbackHandle() { +#if RTC_DCHECK_IS_ON + RTC_DCHECK(has_run_); +#endif +} + +void OperationsChain::CallbackHandle::OnOperationComplete() { +#if RTC_DCHECK_IS_ON + RTC_DCHECK(!has_run_); + has_run_ = true; +#endif // RTC_DCHECK_IS_ON + operations_chain_->OnOperationComplete(); + // We have no reason to keep the `operations_chain_` alive through reference + // counting anymore. + operations_chain_ = nullptr; +} + +// static +scoped_refptr<OperationsChain> OperationsChain::Create() { + // Explicit new, to access private constructor. + return rtc::scoped_refptr<OperationsChain>(new OperationsChain()); +} + +OperationsChain::OperationsChain() { + RTC_DCHECK_RUN_ON(&sequence_checker_); +} + +OperationsChain::~OperationsChain() { + // Operations keep the chain alive through reference counting so this should + // not be possible. The fact that the chain is empty makes it safe to + // destroy the OperationsChain on any sequence. + RTC_DCHECK(chained_operations_.empty()); +} + +void OperationsChain::SetOnChainEmptyCallback( + std::function<void()> on_chain_empty_callback) { + RTC_DCHECK_RUN_ON(&sequence_checker_); + on_chain_empty_callback_ = std::move(on_chain_empty_callback); +} + +bool OperationsChain::IsEmpty() const { + RTC_DCHECK_RUN_ON(&sequence_checker_); + return chained_operations_.empty(); +} + +std::function<void()> OperationsChain::CreateOperationsChainCallback() { + return [handle = rtc::make_ref_counted<CallbackHandle>( + rtc::scoped_refptr<OperationsChain>(this))]() { + handle->OnOperationComplete(); + }; +} + +void OperationsChain::OnOperationComplete() { + RTC_DCHECK_RUN_ON(&sequence_checker_); + // The front element is the operation that just completed, remove it. + RTC_DCHECK(!chained_operations_.empty()); + chained_operations_.pop(); + // If there are any other operations chained, execute the next one. Otherwise, + // invoke the "on chain empty" callback if it has been set. + if (!chained_operations_.empty()) { + chained_operations_.front()->Run(); + } else if (on_chain_empty_callback_.has_value()) { + on_chain_empty_callback_.value()(); + } +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/operations_chain.h b/third_party/libwebrtc/rtc_base/operations_chain.h new file mode 100644 index 0000000000..0e8c0681ba --- /dev/null +++ b/third_party/libwebrtc/rtc_base/operations_chain.h @@ -0,0 +1,203 @@ +/* + * 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 RTC_BASE_OPERATIONS_CHAIN_H_ +#define RTC_BASE_OPERATIONS_CHAIN_H_ + +#include <functional> +#include <memory> +#include <queue> +#include <set> +#include <type_traits> +#include <utility> + +#include "absl/types/optional.h" +#include "api/ref_counted_base.h" +#include "api/scoped_refptr.h" +#include "api/sequence_checker.h" +#include "rtc_base/checks.h" +#include "rtc_base/ref_count.h" +#include "rtc_base/ref_counted_object.h" +#include "rtc_base/system/no_unique_address.h" + +namespace rtc { + +namespace rtc_operations_chain_internal { + +// Abstract base class for operations on the OperationsChain. Run() must be +// invoked exactly once during the Operation's lifespan. +class Operation { + public: + virtual ~Operation() {} + + virtual void Run() = 0; +}; + +// FunctorT is the same as in OperationsChain::ChainOperation(). `callback_` is +// passed on to the `functor_` and is used to inform the OperationsChain that +// the operation completed. The functor is responsible for invoking the +// callback when the operation has completed. +template <typename FunctorT> +class OperationWithFunctor final : public Operation { + public: + OperationWithFunctor(FunctorT&& functor, std::function<void()> callback) + : functor_(std::forward<FunctorT>(functor)), + callback_(std::move(callback)) {} + + ~OperationWithFunctor() override { +#if RTC_DCHECK_IS_ON + RTC_DCHECK(has_run_); +#endif // RTC_DCHECK_IS_ON + } + + void Run() override { +#if RTC_DCHECK_IS_ON + RTC_DCHECK(!has_run_); + has_run_ = true; +#endif // RTC_DCHECK_IS_ON + // The functor being executed may invoke the callback synchronously, + // marking the operation as complete. As such, `this` OperationWithFunctor + // object may get deleted here, including destroying `functor_`. To + // protect the functor from self-destruction while running, it is moved to + // a local variable. + auto functor = std::move(functor_); + functor(std::move(callback_)); + // `this` may now be deleted; don't touch any member variables. + } + + private: + typename std::remove_reference<FunctorT>::type functor_; + std::function<void()> callback_; +#if RTC_DCHECK_IS_ON + bool has_run_ = false; +#endif // RTC_DCHECK_IS_ON +}; + +} // namespace rtc_operations_chain_internal + +// An implementation of an operations chain. An operations chain is used to +// ensure that asynchronous tasks are executed in-order with at most one task +// running at a time. The notion of an operation chain is defined in +// https://w3c.github.io/webrtc-pc/#dfn-operations-chain, though unlike this +// implementation, the referenced definition is coupled with a peer connection. +// +// An operation is an asynchronous task. The operation starts when its functor +// is invoked, and completes when the callback that is passed to functor is +// invoked by the operation. The operation must start and complete on the same +// sequence that the operation was "chained" on. As such, the OperationsChain +// operates in a "single-threaded" fashion, but the asynchronous operations may +// use any number of threads to achieve "in parallel" behavior. +// +// When an operation is chained onto the OperationsChain, it is enqueued to be +// executed. Operations are executed in FIFO order, where the next operation +// does not start until the previous operation has completed. OperationsChain +// guarantees that: +// - If the operations chain is empty when an operation is chained, the +// operation starts immediately, inside ChainOperation(). +// - If the operations chain is not empty when an operation is chained, the +// operation starts upon the previous operation completing, inside the +// callback. +// +// An operation is contractually obligated to invoke the completion callback +// exactly once. Cancelling a chained operation is not supported by the +// OperationsChain; an operation that wants to be cancellable is responsible for +// aborting its own steps. The callback must still be invoked. +// +// The OperationsChain is kept-alive through reference counting if there are +// operations pending. This, together with the contract, guarantees that all +// operations that are chained get executed. +class OperationsChain final : public RefCountedNonVirtual<OperationsChain> { + public: + static scoped_refptr<OperationsChain> Create(); + ~OperationsChain(); + + OperationsChain(const OperationsChain&) = delete; + OperationsChain& operator=(const OperationsChain&) = delete; + + void SetOnChainEmptyCallback(std::function<void()> on_chain_empty_callback); + bool IsEmpty() const; + + // Chains an operation. Chained operations are executed in FIFO order. The + // operation starts when `functor` is executed by the OperationsChain and is + // contractually obligated to invoke the callback passed to it when the + // operation is complete. Operations must start and complete on the same + // sequence that this method was invoked on. + // + // If the OperationsChain is empty, the operation starts immediately. + // Otherwise it starts upon the previous operation completing. + // + // Requirements of FunctorT: + // - FunctorT is movable. + // - FunctorT implements "T operator()(std::function<void()> callback)" or + // "T operator()(std::function<void()> callback) const" for some T (if T is + // not void, the return value is discarded in the invoking sequence). The + // operator starts the operation; when the operation is complete, "callback" + // MUST be invoked, and it MUST be so on the sequence that ChainOperation() + // was invoked on. + // + // Lambda expressions are valid functors. + template <typename FunctorT> + void ChainOperation(FunctorT&& functor) { + RTC_DCHECK_RUN_ON(&sequence_checker_); + chained_operations_.push( + std::make_unique< + rtc_operations_chain_internal::OperationWithFunctor<FunctorT>>( + std::forward<FunctorT>(functor), CreateOperationsChainCallback())); + // If this is the only operation in the chain we execute it immediately. + // Otherwise the callback will get invoked when the pending operation + // completes which will trigger the next operation to execute. + if (chained_operations_.size() == 1) { + chained_operations_.front()->Run(); + } + } + + private: + friend class CallbackHandle; + + // The callback that is passed to an operation's functor (that is used to + // inform the OperationsChain that the operation has completed) is of type + // std::function<void()>, which is a copyable type. To allow the callback to + // be copyable, it is backed up by this reference counted handle. See + // CreateOperationsChainCallback(). + class CallbackHandle final : public RefCountedNonVirtual<CallbackHandle> { + public: + explicit CallbackHandle(scoped_refptr<OperationsChain> operations_chain); + ~CallbackHandle(); + + CallbackHandle(const CallbackHandle&) = delete; + CallbackHandle& operator=(const CallbackHandle&) = delete; + + void OnOperationComplete(); + + private: + scoped_refptr<OperationsChain> operations_chain_; +#if RTC_DCHECK_IS_ON + bool has_run_ = false; +#endif // RTC_DCHECK_IS_ON + }; + + OperationsChain(); + + std::function<void()> CreateOperationsChainCallback(); + void OnOperationComplete(); + + RTC_NO_UNIQUE_ADDRESS webrtc::SequenceChecker sequence_checker_; + // FIFO-list of operations that are chained. An operation that is executing + // remains on this list until it has completed by invoking the callback passed + // to it. + std::queue<std::unique_ptr<rtc_operations_chain_internal::Operation>> + chained_operations_ RTC_GUARDED_BY(sequence_checker_); + absl::optional<std::function<void()>> on_chain_empty_callback_ + RTC_GUARDED_BY(sequence_checker_); +}; + +} // namespace rtc + +#endif // RTC_BASE_OPERATIONS_CHAIN_H_ diff --git a/third_party/libwebrtc/rtc_base/operations_chain_unittest.cc b/third_party/libwebrtc/rtc_base/operations_chain_unittest.cc new file mode 100644 index 0000000000..4f44423b19 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/operations_chain_unittest.cc @@ -0,0 +1,502 @@ +/* + * 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 "rtc_base/operations_chain.h" + +#include <atomic> +#include <functional> +#include <memory> +#include <utility> +#include <vector> + +#include "rtc_base/event.h" +#include "rtc_base/gunit.h" +#include "rtc_base/thread.h" +#include "test/gmock.h" +#include "test/gtest.h" + +namespace rtc { + +using ::testing::ElementsAre; + +namespace { + +constexpr int kDefaultTimeout = 3000; + +} // namespace + +class OperationTracker { + public: + OperationTracker() : background_thread_(Thread::Create()) { + background_thread_->Start(); + } + // The caller is responsible for ensuring that no operations are pending. + ~OperationTracker() {} + + // Creates a binding for the synchronous operation (see + // StartSynchronousOperation() below). + std::function<void(std::function<void()>)> BindSynchronousOperation( + Event* operation_complete_event) { + return [this, operation_complete_event](std::function<void()> callback) { + StartSynchronousOperation(operation_complete_event, std::move(callback)); + }; + } + + // Creates a binding for the asynchronous operation (see + // StartAsynchronousOperation() below). + std::function<void(std::function<void()>)> BindAsynchronousOperation( + Event* unblock_operation_event, + Event* operation_complete_event) { + return [this, unblock_operation_event, + operation_complete_event](std::function<void()> callback) { + StartAsynchronousOperation(unblock_operation_event, + operation_complete_event, std::move(callback)); + }; + } + + // When an operation is completed, its associated Event* is added to this + // list, in chronological order. This allows you to verify the order that + // operations are executed. + const std::vector<Event*>& completed_operation_events() const { + return completed_operation_events_; + } + + private: + // This operation is completed synchronously; the callback is invoked before + // the function returns. + void StartSynchronousOperation(Event* operation_complete_event, + std::function<void()> callback) { + completed_operation_events_.push_back(operation_complete_event); + operation_complete_event->Set(); + callback(); + } + + // This operation is completed asynchronously; it pings `background_thread_`, + // blocking that thread until `unblock_operation_event` is signaled and then + // completes upon posting back to the thread that the operation started on. + // Note that this requires the starting thread to be executing tasks (handle + // messages), i.e. must not be blocked. + void StartAsynchronousOperation(Event* unblock_operation_event, + Event* operation_complete_event, + std::function<void()> callback) { + Thread* current_thread = Thread::Current(); + background_thread_->PostTask([this, current_thread, unblock_operation_event, + operation_complete_event, callback]() { + unblock_operation_event->Wait(Event::kForever); + current_thread->PostTask([this, operation_complete_event, callback]() { + completed_operation_events_.push_back(operation_complete_event); + operation_complete_event->Set(); + callback(); + }); + }); + } + + std::unique_ptr<Thread> background_thread_; + std::vector<Event*> completed_operation_events_; +}; + +// The OperationTrackerProxy ensures all operations are chained on a separate +// thread. This allows tests to block while chained operations are posting +// between threads. +class OperationTrackerProxy { + public: + OperationTrackerProxy() + : operations_chain_thread_(Thread::Create()), + operation_tracker_(nullptr), + operations_chain_(nullptr) { + operations_chain_thread_->Start(); + } + + std::unique_ptr<Event> Initialize() { + std::unique_ptr<Event> event = std::make_unique<Event>(); + operations_chain_thread_->PostTask([this, event_ptr = event.get()]() { + operation_tracker_ = std::make_unique<OperationTracker>(); + operations_chain_ = OperationsChain::Create(); + event_ptr->Set(); + }); + return event; + } + + void SetOnChainEmptyCallback(std::function<void()> on_chain_empty_callback) { + Event event; + operations_chain_thread_->PostTask( + [this, &event, + on_chain_empty_callback = std::move(on_chain_empty_callback)]() { + operations_chain_->SetOnChainEmptyCallback( + std::move(on_chain_empty_callback)); + event.Set(); + }); + event.Wait(Event::kForever); + } + + bool IsEmpty() { + Event event; + bool is_empty = false; + operations_chain_thread_->PostTask([this, &event, &is_empty]() { + is_empty = operations_chain_->IsEmpty(); + event.Set(); + }); + event.Wait(Event::kForever); + return is_empty; + } + + std::unique_ptr<Event> ReleaseOperationChain() { + std::unique_ptr<Event> event = std::make_unique<Event>(); + operations_chain_thread_->PostTask([this, event_ptr = event.get()]() { + operations_chain_ = nullptr; + event_ptr->Set(); + }); + return event; + } + + // Chains a synchronous operation on the operation chain's thread. + std::unique_ptr<Event> PostSynchronousOperation() { + std::unique_ptr<Event> operation_complete_event = std::make_unique<Event>(); + operations_chain_thread_->PostTask( + [this, + operation_complete_event_ptr = operation_complete_event.get()]() { + operations_chain_->ChainOperation( + operation_tracker_->BindSynchronousOperation( + operation_complete_event_ptr)); + }); + return operation_complete_event; + } + + // Chains an asynchronous operation on the operation chain's thread. This + // involves the operation chain thread and an additional background thread. + std::unique_ptr<Event> PostAsynchronousOperation( + Event* unblock_operation_event) { + std::unique_ptr<Event> operation_complete_event = std::make_unique<Event>(); + operations_chain_thread_->PostTask( + [this, unblock_operation_event, + operation_complete_event_ptr = operation_complete_event.get()]() { + operations_chain_->ChainOperation( + operation_tracker_->BindAsynchronousOperation( + unblock_operation_event, operation_complete_event_ptr)); + }); + return operation_complete_event; + } + + // The order of completed events. Touches the `operation_tracker_` on the + // calling thread, this is only thread safe if all chained operations have + // completed. + const std::vector<Event*>& completed_operation_events() const { + return operation_tracker_->completed_operation_events(); + } + + private: + std::unique_ptr<Thread> operations_chain_thread_; + std::unique_ptr<OperationTracker> operation_tracker_; + scoped_refptr<OperationsChain> operations_chain_; +}; + +// On destruction, sets a boolean flag to true. +class SignalOnDestruction final { + public: + SignalOnDestruction(bool* destructor_called) + : destructor_called_(destructor_called) { + RTC_DCHECK(destructor_called_); + } + ~SignalOnDestruction() { + // Moved objects will have `destructor_called_` set to null. Destroying a + // moved SignalOnDestruction should not signal. + if (destructor_called_) { + *destructor_called_ = true; + } + } + + SignalOnDestruction(const SignalOnDestruction&) = delete; + SignalOnDestruction& operator=(const SignalOnDestruction&) = delete; + + // Move operators. + SignalOnDestruction(SignalOnDestruction&& other) + : SignalOnDestruction(other.destructor_called_) { + other.destructor_called_ = nullptr; + } + SignalOnDestruction& operator=(SignalOnDestruction&& other) { + destructor_called_ = other.destructor_called_; + other.destructor_called_ = nullptr; + return *this; + } + + private: + bool* destructor_called_; +}; + +TEST(OperationsChainTest, SynchronousOperation) { + OperationTrackerProxy operation_tracker_proxy; + operation_tracker_proxy.Initialize()->Wait(Event::kForever); + + operation_tracker_proxy.PostSynchronousOperation()->Wait(Event::kForever); +} + +TEST(OperationsChainTest, AsynchronousOperation) { + OperationTrackerProxy operation_tracker_proxy; + operation_tracker_proxy.Initialize()->Wait(Event::kForever); + + Event unblock_async_operation_event; + auto async_operation_completed_event = + operation_tracker_proxy.PostAsynchronousOperation( + &unblock_async_operation_event); + // This should not be signaled until we unblock the operation. + EXPECT_FALSE( + async_operation_completed_event->Wait(webrtc::TimeDelta::Zero())); + // Unblock the operation and wait for it to complete. + unblock_async_operation_event.Set(); + async_operation_completed_event->Wait(Event::kForever); +} + +TEST(OperationsChainTest, + SynchronousOperationsAreExecutedImmediatelyWhenChainIsEmpty) { + // Testing synchonicity must be done without the OperationTrackerProxy to + // ensure messages are not processed in parallel. This test has no background + // threads. + scoped_refptr<OperationsChain> operations_chain = OperationsChain::Create(); + OperationTracker operation_tracker; + Event event0; + operations_chain->ChainOperation( + operation_tracker.BindSynchronousOperation(&event0)); + // This should already be signaled. (If it wasn't, waiting wouldn't help, + // because we'd be blocking the only thread that exists.) + EXPECT_TRUE(event0.Wait(webrtc::TimeDelta::Zero())); + // Chaining another operation should also execute immediately because the + // chain should already be empty. + Event event1; + operations_chain->ChainOperation( + operation_tracker.BindSynchronousOperation(&event1)); + EXPECT_TRUE(event1.Wait(webrtc::TimeDelta::Zero())); +} + +TEST(OperationsChainTest, AsynchronousOperationBlocksSynchronousOperation) { + OperationTrackerProxy operation_tracker_proxy; + operation_tracker_proxy.Initialize()->Wait(Event::kForever); + + Event unblock_async_operation_event; + auto async_operation_completed_event = + operation_tracker_proxy.PostAsynchronousOperation( + &unblock_async_operation_event); + + auto sync_operation_completed_event = + operation_tracker_proxy.PostSynchronousOperation(); + + unblock_async_operation_event.Set(); + + sync_operation_completed_event->Wait(Event::kForever); + // The asynchronous avent should have blocked the synchronous event, meaning + // this should already be signaled. + EXPECT_TRUE(async_operation_completed_event->Wait(webrtc::TimeDelta::Zero())); +} + +TEST(OperationsChainTest, OperationsAreExecutedInOrder) { + OperationTrackerProxy operation_tracker_proxy; + operation_tracker_proxy.Initialize()->Wait(Event::kForever); + + // Chain a mix of asynchronous and synchronous operations. + Event operation0_unblock_event; + auto operation0_completed_event = + operation_tracker_proxy.PostAsynchronousOperation( + &operation0_unblock_event); + + Event operation1_unblock_event; + auto operation1_completed_event = + operation_tracker_proxy.PostAsynchronousOperation( + &operation1_unblock_event); + + auto operation2_completed_event = + operation_tracker_proxy.PostSynchronousOperation(); + + auto operation3_completed_event = + operation_tracker_proxy.PostSynchronousOperation(); + + Event operation4_unblock_event; + auto operation4_completed_event = + operation_tracker_proxy.PostAsynchronousOperation( + &operation4_unblock_event); + + auto operation5_completed_event = + operation_tracker_proxy.PostSynchronousOperation(); + + Event operation6_unblock_event; + auto operation6_completed_event = + operation_tracker_proxy.PostAsynchronousOperation( + &operation6_unblock_event); + + // Unblock events in reverse order. Operations 5, 3 and 2 are synchronous and + // don't need to be unblocked. + operation6_unblock_event.Set(); + operation4_unblock_event.Set(); + operation1_unblock_event.Set(); + operation0_unblock_event.Set(); + // Await all operations. The await-order shouldn't matter since they all get + // executed eventually. + operation0_completed_event->Wait(Event::kForever); + operation1_completed_event->Wait(Event::kForever); + operation2_completed_event->Wait(Event::kForever); + operation3_completed_event->Wait(Event::kForever); + operation4_completed_event->Wait(Event::kForever); + operation5_completed_event->Wait(Event::kForever); + operation6_completed_event->Wait(Event::kForever); + + EXPECT_THAT( + operation_tracker_proxy.completed_operation_events(), + ElementsAre( + operation0_completed_event.get(), operation1_completed_event.get(), + operation2_completed_event.get(), operation3_completed_event.get(), + operation4_completed_event.get(), operation5_completed_event.get(), + operation6_completed_event.get())); +} + +TEST(OperationsChainTest, IsEmpty) { + OperationTrackerProxy operation_tracker_proxy; + operation_tracker_proxy.Initialize()->Wait(Event::kForever); + + // The chain is initially empty. + EXPECT_TRUE(operation_tracker_proxy.IsEmpty()); + // Chain a single event. + Event unblock_async_operation_event0; + auto async_operation_completed_event0 = + operation_tracker_proxy.PostAsynchronousOperation( + &unblock_async_operation_event0); + // The chain is not empty while an event is pending. + EXPECT_FALSE(operation_tracker_proxy.IsEmpty()); + // Completing the operation empties the chain. + unblock_async_operation_event0.Set(); + async_operation_completed_event0->Wait(Event::kForever); + EXPECT_TRUE(operation_tracker_proxy.IsEmpty()); + + // Chain multiple events. + Event unblock_async_operation_event1; + auto async_operation_completed_event1 = + operation_tracker_proxy.PostAsynchronousOperation( + &unblock_async_operation_event1); + Event unblock_async_operation_event2; + auto async_operation_completed_event2 = + operation_tracker_proxy.PostAsynchronousOperation( + &unblock_async_operation_event2); + // Again, the chain is not empty while an event is pending. + EXPECT_FALSE(operation_tracker_proxy.IsEmpty()); + // Upon completing the first event, the chain is still not empty. + unblock_async_operation_event1.Set(); + async_operation_completed_event1->Wait(Event::kForever); + EXPECT_FALSE(operation_tracker_proxy.IsEmpty()); + // Completing the last evenet empties the chain. + unblock_async_operation_event2.Set(); + async_operation_completed_event2->Wait(Event::kForever); + EXPECT_TRUE(operation_tracker_proxy.IsEmpty()); +} + +TEST(OperationsChainTest, OnChainEmptyCallback) { + rtc::AutoThread main_thread; + OperationTrackerProxy operation_tracker_proxy; + operation_tracker_proxy.Initialize()->Wait(Event::kForever); + + std::atomic<size_t> on_empty_callback_counter(0u); + operation_tracker_proxy.SetOnChainEmptyCallback( + [&on_empty_callback_counter] { ++on_empty_callback_counter; }); + + // Chain a single event. + Event unblock_async_operation_event0; + auto async_operation_completed_event0 = + operation_tracker_proxy.PostAsynchronousOperation( + &unblock_async_operation_event0); + // The callback is not invoked until the operation has completed. + EXPECT_EQ(0u, on_empty_callback_counter); + // Completing the operation empties the chain, invoking the callback. + unblock_async_operation_event0.Set(); + async_operation_completed_event0->Wait(Event::kForever); + EXPECT_TRUE_WAIT(1u == on_empty_callback_counter, kDefaultTimeout); + + // Chain multiple events. + Event unblock_async_operation_event1; + auto async_operation_completed_event1 = + operation_tracker_proxy.PostAsynchronousOperation( + &unblock_async_operation_event1); + Event unblock_async_operation_event2; + auto async_operation_completed_event2 = + operation_tracker_proxy.PostAsynchronousOperation( + &unblock_async_operation_event2); + // Again, the callback is not invoked until the operation has completed. + EXPECT_TRUE_WAIT(1u == on_empty_callback_counter, kDefaultTimeout); + // Upon completing the first event, the chain is still not empty, so the + // callback must not be invoked yet. + unblock_async_operation_event1.Set(); + async_operation_completed_event1->Wait(Event::kForever); + EXPECT_TRUE_WAIT(1u == on_empty_callback_counter, kDefaultTimeout); + // Completing the last evenet empties the chain, invoking the callback. + unblock_async_operation_event2.Set(); + async_operation_completed_event2->Wait(Event::kForever); + EXPECT_TRUE_WAIT(2u == on_empty_callback_counter, kDefaultTimeout); +} + +TEST(OperationsChainTest, + SafeToReleaseReferenceToOperationChainWhileOperationIsPending) { + OperationTrackerProxy operation_tracker_proxy; + operation_tracker_proxy.Initialize()->Wait(Event::kForever); + + Event unblock_async_operation_event; + auto async_operation_completed_event = + operation_tracker_proxy.PostAsynchronousOperation( + &unblock_async_operation_event); + + // Pending operations keep the OperationChain alive, making it safe for the + // test to release any references before unblocking the async operation. + operation_tracker_proxy.ReleaseOperationChain()->Wait(Event::kForever); + + unblock_async_operation_event.Set(); + async_operation_completed_event->Wait(Event::kForever); +} + +TEST(OperationsChainTest, FunctorIsNotDestroyedWhileExecuting) { + scoped_refptr<OperationsChain> operations_chain = OperationsChain::Create(); + + bool destructor_called = false; + SignalOnDestruction signal_on_destruction(&destructor_called); + + operations_chain->ChainOperation( + [signal_on_destruction = std::move(signal_on_destruction), + &destructor_called](std::function<void()> callback) { + EXPECT_FALSE(destructor_called); + // Invoking the callback marks the operation as complete, popping the + // Operation object from the OperationsChain internal queue. + callback(); + // Even though the internal Operation object has been destroyed, + // variables captured by this lambda expression must still be valid (the + // associated functor must not be deleted while executing). + EXPECT_FALSE(destructor_called); + }); + // The lambda having executed synchronously and completed, its captured + // variables should now have been deleted. + EXPECT_TRUE(destructor_called); +} + +#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID) + +TEST(OperationsChainDeathTest, OperationNotInvokingCallbackShouldCrash) { + scoped_refptr<OperationsChain> operations_chain = OperationsChain::Create(); + EXPECT_DEATH( + operations_chain->ChainOperation([](std::function<void()> callback) {}), + ""); +} + +TEST(OperationsChainDeathTest, + OperationInvokingCallbackMultipleTimesShouldCrash) { + scoped_refptr<OperationsChain> operations_chain = OperationsChain::Create(); + EXPECT_DEATH( + operations_chain->ChainOperation([](std::function<void()> callback) { + // Signal that the operation has completed multiple times. + callback(); + callback(); + }), + ""); +} + +#endif // RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID) + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/physical_socket_server.cc b/third_party/libwebrtc/rtc_base/physical_socket_server.cc new file mode 100644 index 0000000000..95ba130e91 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/physical_socket_server.cc @@ -0,0 +1,1953 @@ +/* + * 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 "rtc_base/physical_socket_server.h" + +#include <cstdint> +#include <utility> + +#if defined(_MSC_VER) && _MSC_VER < 1300 +#pragma warning(disable : 4786) +#endif + +#ifdef MEMORY_SANITIZER +#include <sanitizer/msan_interface.h> +#endif + +#if defined(WEBRTC_POSIX) +#include <fcntl.h> +#if defined(WEBRTC_USE_EPOLL) +// "poll" will be used to wait for the signal dispatcher. +#include <poll.h> +#elif defined(WEBRTC_USE_POLL) +#include <poll.h> +#endif +#include <sys/ioctl.h> +#include <sys/select.h> +#include <unistd.h> +#endif + +#if defined(WEBRTC_WIN) +#include <windows.h> +#include <winsock2.h> +#include <ws2tcpip.h> + +#undef SetPort +#endif + +#include <errno.h> + +#include "rtc_base/async_dns_resolver.h" +#include "rtc_base/checks.h" +#include "rtc_base/event.h" +#include "rtc_base/ip_address.h" +#include "rtc_base/logging.h" +#include "rtc_base/network_monitor.h" +#include "rtc_base/synchronization/mutex.h" +#include "rtc_base/time_utils.h" +#include "system_wrappers/include/field_trial.h" + +#if defined(WEBRTC_LINUX) +#include <linux/sockios.h> +#endif + +#if defined(WEBRTC_WIN) +#define LAST_SYSTEM_ERROR (::GetLastError()) +#elif defined(__native_client__) && __native_client__ +#define LAST_SYSTEM_ERROR (0) +#elif defined(WEBRTC_POSIX) +#define LAST_SYSTEM_ERROR (errno) +#endif // WEBRTC_WIN + +#if defined(WEBRTC_POSIX) +#include <netinet/tcp.h> // for TCP_NODELAY + +#define IP_MTU 14 // Until this is integrated from linux/in.h to netinet/in.h +typedef void* SockOptArg; + +#endif // WEBRTC_POSIX + +#if defined(WEBRTC_POSIX) && !defined(WEBRTC_MAC) && !defined(WEBRTC_BSD) && !defined(__native_client__) +#if defined(WEBRTC_LINUX) +#include <linux/sockios.h> +#endif + +int64_t GetSocketRecvTimestamp(int socket) { + struct timeval tv_ioctl; + int ret = ioctl(socket, SIOCGSTAMP, &tv_ioctl); + if (ret != 0) + return -1; + int64_t timestamp = + rtc::kNumMicrosecsPerSec * static_cast<int64_t>(tv_ioctl.tv_sec) + + static_cast<int64_t>(tv_ioctl.tv_usec); + return timestamp; +} + +#else + +int64_t GetSocketRecvTimestamp(int socket) { + return -1; +} +#endif + +#if defined(WEBRTC_WIN) +typedef char* SockOptArg; +#endif + +#if defined(WEBRTC_USE_EPOLL) +// POLLRDHUP / EPOLLRDHUP are only defined starting with Linux 2.6.17. +#if !defined(POLLRDHUP) +#define POLLRDHUP 0x2000 +#endif +#if !defined(EPOLLRDHUP) +#define EPOLLRDHUP 0x2000 +#endif +#endif + +namespace { +class ScopedSetTrue { + public: + ScopedSetTrue(bool* value) : value_(value) { + RTC_DCHECK(!*value_); + *value_ = true; + } + ~ScopedSetTrue() { *value_ = false; } + + private: + bool* value_; +}; + +// Returns true if the experiement "WebRTC-SCM-Timestamp" is explicitly +// disabled. +bool IsScmTimeStampExperimentDisabled() { + return webrtc::field_trial::IsDisabled("WebRTC-SCM-Timestamp"); +} +} // namespace + +namespace rtc { + +PhysicalSocket::PhysicalSocket(PhysicalSocketServer* ss, SOCKET s) + : ss_(ss), + s_(s), + error_(0), + state_((s == INVALID_SOCKET) ? CS_CLOSED : CS_CONNECTED), + resolver_(nullptr), + read_scm_timestamp_experiment_(!IsScmTimeStampExperimentDisabled()) { + if (s_ != INVALID_SOCKET) { + SetEnabledEvents(DE_READ | DE_WRITE); + + int type = SOCK_STREAM; + socklen_t len = sizeof(type); + const int res = + getsockopt(s_, SOL_SOCKET, SO_TYPE, (SockOptArg)&type, &len); + RTC_DCHECK_EQ(0, res); + udp_ = (SOCK_DGRAM == type); + } +} + +PhysicalSocket::~PhysicalSocket() { + Close(); +} + +bool PhysicalSocket::Create(int family, int type) { + Close(); + s_ = ::socket(family, type, 0); + udp_ = (SOCK_DGRAM == type); + family_ = family; + UpdateLastError(); + if (udp_) { + SetEnabledEvents(DE_READ | DE_WRITE); + } + return s_ != INVALID_SOCKET; +} + +SocketAddress PhysicalSocket::GetLocalAddress() const { + sockaddr_storage addr_storage = {}; + socklen_t addrlen = sizeof(addr_storage); + sockaddr* addr = reinterpret_cast<sockaddr*>(&addr_storage); + int result = ::getsockname(s_, addr, &addrlen); + SocketAddress address; + if (result >= 0) { + SocketAddressFromSockAddrStorage(addr_storage, &address); + } else { + RTC_LOG(LS_WARNING) << "GetLocalAddress: unable to get local addr, socket=" + << s_; + } + return address; +} + +SocketAddress PhysicalSocket::GetRemoteAddress() const { + sockaddr_storage addr_storage = {}; + socklen_t addrlen = sizeof(addr_storage); + sockaddr* addr = reinterpret_cast<sockaddr*>(&addr_storage); + int result = ::getpeername(s_, addr, &addrlen); + SocketAddress address; + if (result >= 0) { + SocketAddressFromSockAddrStorage(addr_storage, &address); + } else { + RTC_LOG(LS_WARNING) + << "GetRemoteAddress: unable to get remote addr, socket=" << s_; + } + return address; +} + +int PhysicalSocket::Bind(const SocketAddress& bind_addr) { + SocketAddress copied_bind_addr = bind_addr; + // If a network binder is available, use it to bind a socket to an interface + // instead of bind(), since this is more reliable on an OS with a weak host + // model. + if (ss_->network_binder() && !bind_addr.IsAnyIP()) { + NetworkBindingResult result = + ss_->network_binder()->BindSocketToNetwork(s_, bind_addr.ipaddr()); + if (result == NetworkBindingResult::SUCCESS) { + // Since the network binder handled binding the socket to the desired + // network interface, we don't need to (and shouldn't) include an IP in + // the bind() call; bind() just needs to assign a port. + copied_bind_addr.SetIP(GetAnyIP(copied_bind_addr.ipaddr().family())); + } else if (result == NetworkBindingResult::NOT_IMPLEMENTED) { + RTC_LOG(LS_INFO) << "Can't bind socket to network because " + "network binding is not implemented for this OS."; + } else { + if (bind_addr.IsLoopbackIP()) { + // If we couldn't bind to a loopback IP (which should only happen in + // test scenarios), continue on. This may be expected behavior. + RTC_LOG(LS_VERBOSE) << "Binding socket to loopback address" + << " failed; result: " << static_cast<int>(result); + } else { + RTC_LOG(LS_WARNING) << "Binding socket to network address" + << " failed; result: " << static_cast<int>(result); + // If a network binding was attempted and failed, we should stop here + // and not try to use the socket. Otherwise, we may end up sending + // packets with an invalid source address. + // See: https://bugs.chromium.org/p/webrtc/issues/detail?id=7026 + return -1; + } + } + } + sockaddr_storage addr_storage; + size_t len = copied_bind_addr.ToSockAddrStorage(&addr_storage); + sockaddr* addr = reinterpret_cast<sockaddr*>(&addr_storage); + int err = ::bind(s_, addr, static_cast<int>(len)); + UpdateLastError(); +#if !defined(NDEBUG) + if (0 == err) { + dbg_addr_ = "Bound @ "; + dbg_addr_.append(GetLocalAddress().ToString()); + } +#endif + return err; +} + +int PhysicalSocket::Connect(const SocketAddress& addr) { + // TODO(pthatcher): Implicit creation is required to reconnect... + // ...but should we make it more explicit? + if (state_ != CS_CLOSED) { + SetError(EALREADY); + return SOCKET_ERROR; + } + if (addr.IsUnresolvedIP()) { + RTC_LOG(LS_VERBOSE) << "Resolving addr in PhysicalSocket::Connect"; + resolver_ = std::make_unique<webrtc::AsyncDnsResolver>(); + resolver_->Start(addr, [this] { OnResolveResult(resolver_->result()); }); + state_ = CS_CONNECTING; + return 0; + } + + return DoConnect(addr); +} + +int PhysicalSocket::DoConnect(const SocketAddress& connect_addr) { + if ((s_ == INVALID_SOCKET) && !Create(connect_addr.family(), SOCK_STREAM)) { + return SOCKET_ERROR; + } + sockaddr_storage addr_storage; + size_t len = connect_addr.ToSockAddrStorage(&addr_storage); + sockaddr* addr = reinterpret_cast<sockaddr*>(&addr_storage); + int err = ::connect(s_, addr, static_cast<int>(len)); + UpdateLastError(); + uint8_t events = DE_READ | DE_WRITE; + if (err == 0) { + state_ = CS_CONNECTED; + } else if (IsBlockingError(GetError())) { + state_ = CS_CONNECTING; + events |= DE_CONNECT; + } else { + return SOCKET_ERROR; + } + + EnableEvents(events); + return 0; +} + +int PhysicalSocket::GetError() const { + webrtc::MutexLock lock(&mutex_); + return error_; +} + +void PhysicalSocket::SetError(int error) { + webrtc::MutexLock lock(&mutex_); + error_ = error; +} + +Socket::ConnState PhysicalSocket::GetState() const { + return state_; +} + +int PhysicalSocket::GetOption(Option opt, int* value) { + int slevel; + int sopt; + if (TranslateOption(opt, &slevel, &sopt) == -1) + return -1; + socklen_t optlen = sizeof(*value); + int ret = ::getsockopt(s_, slevel, sopt, (SockOptArg)value, &optlen); + if (ret == -1) { + return -1; + } + if (opt == OPT_DONTFRAGMENT) { +#if defined(WEBRTC_LINUX) && !defined(WEBRTC_ANDROID) + *value = (*value != IP_PMTUDISC_DONT) ? 1 : 0; +#endif + } else if (opt == OPT_DSCP) { +#if defined(WEBRTC_POSIX) + // unshift DSCP value to get six most significant bits of IP DiffServ field + *value >>= 2; +#endif + } + return ret; +} + +int PhysicalSocket::SetOption(Option opt, int value) { + int slevel; + int sopt; + if (TranslateOption(opt, &slevel, &sopt) == -1) + return -1; + if (opt == OPT_DONTFRAGMENT) { +#if defined(WEBRTC_LINUX) && !defined(WEBRTC_ANDROID) + value = (value) ? IP_PMTUDISC_DO : IP_PMTUDISC_DONT; +#endif + } else if (opt == OPT_DSCP) { +#if defined(WEBRTC_POSIX) + // shift DSCP value to fit six most significant bits of IP DiffServ field + value <<= 2; +#endif + } +#if defined(WEBRTC_POSIX) + if (sopt == IPV6_TCLASS) { + // Set the IPv4 option in all cases to support dual-stack sockets. + // Don't bother checking the return code, as this is expected to fail if + // it's not actually dual-stack. + ::setsockopt(s_, IPPROTO_IP, IP_TOS, (SockOptArg)&value, sizeof(value)); + } +#endif + int result = + ::setsockopt(s_, slevel, sopt, (SockOptArg)&value, sizeof(value)); + if (result != 0) { + UpdateLastError(); + } + return result; +} + +int PhysicalSocket::Send(const void* pv, size_t cb) { + int sent = DoSend( + s_, reinterpret_cast<const char*>(pv), static_cast<int>(cb), +#if defined(WEBRTC_LINUX) && !defined(WEBRTC_ANDROID) + // Suppress SIGPIPE. Without this, attempting to send on a socket whose + // other end is closed will result in a SIGPIPE signal being raised to + // our process, which by default will terminate the process, which we + // don't want. By specifying this flag, we'll just get the error EPIPE + // instead and can handle the error gracefully. + MSG_NOSIGNAL +#else + 0 +#endif + ); + UpdateLastError(); + MaybeRemapSendError(); + // We have seen minidumps where this may be false. + RTC_DCHECK(sent <= static_cast<int>(cb)); + if ((sent > 0 && sent < static_cast<int>(cb)) || + (sent < 0 && IsBlockingError(GetError()))) { + EnableEvents(DE_WRITE); + } + return sent; +} + +int PhysicalSocket::SendTo(const void* buffer, + size_t length, + const SocketAddress& addr) { + sockaddr_storage saddr; + size_t len = addr.ToSockAddrStorage(&saddr); + int sent = + DoSendTo(s_, static_cast<const char*>(buffer), static_cast<int>(length), +#if defined(WEBRTC_LINUX) && !defined(WEBRTC_ANDROID) + // Suppress SIGPIPE. See above for explanation. + MSG_NOSIGNAL, +#else + 0, +#endif + reinterpret_cast<sockaddr*>(&saddr), static_cast<int>(len)); + UpdateLastError(); + MaybeRemapSendError(); + // We have seen minidumps where this may be false. + RTC_DCHECK(sent <= static_cast<int>(length)); + if ((sent > 0 && sent < static_cast<int>(length)) || + (sent < 0 && IsBlockingError(GetError()))) { + EnableEvents(DE_WRITE); + } + return sent; +} + +int PhysicalSocket::Recv(void* buffer, size_t length, int64_t* timestamp) { + int received = + DoReadFromSocket(buffer, length, /*out_addr*/ nullptr, timestamp); + if ((received == 0) && (length != 0)) { + // Note: on graceful shutdown, recv can return 0. In this case, we + // pretend it is blocking, and then signal close, so that simplifying + // assumptions can be made about Recv. + RTC_LOG(LS_WARNING) << "EOF from socket; deferring close event"; + // Must turn this back on so that the select() loop will notice the close + // event. + EnableEvents(DE_READ); + SetError(EWOULDBLOCK); + return SOCKET_ERROR; + } + + UpdateLastError(); + int error = GetError(); + bool success = (received >= 0) || IsBlockingError(error); + if (udp_ || success) { + EnableEvents(DE_READ); + } + if (!success) { + RTC_LOG_F(LS_VERBOSE) << "Error = " << error; + } + return received; +} + +int PhysicalSocket::RecvFrom(void* buffer, + size_t length, + SocketAddress* out_addr, + int64_t* timestamp) { + int received = DoReadFromSocket(buffer, length, out_addr, timestamp); + UpdateLastError(); + int error = GetError(); + bool success = (received >= 0) || IsBlockingError(error); + if (udp_ || success) { + EnableEvents(DE_READ); + } + if (!success) { + RTC_LOG_F(LS_VERBOSE) << "Error = " << error; + } + return received; +} + +int PhysicalSocket::DoReadFromSocket(void* buffer, + size_t length, + SocketAddress* out_addr, + int64_t* timestamp) { + sockaddr_storage addr_storage; + socklen_t addr_len = sizeof(addr_storage); + sockaddr* addr = reinterpret_cast<sockaddr*>(&addr_storage); + +#if defined(WEBRTC_POSIX) + int received = 0; + if (read_scm_timestamp_experiment_) { + iovec iov = {.iov_base = buffer, .iov_len = length}; + msghdr msg = {.msg_name = nullptr, .msg_namelen = 0, .msg_iov = &iov, .msg_iovlen = 1}; + if (out_addr) { + out_addr->Clear(); + msg.msg_name = addr; + msg.msg_namelen = addr_len; + } + char control[CMSG_SPACE(sizeof(struct timeval))] = {}; + if (timestamp) { + *timestamp = -1; + msg.msg_control = &control; + msg.msg_controllen = sizeof(control); + } + received = ::recvmsg(s_, &msg, 0); + if (received <= 0) { + // An error occured or shut down. + return received; + } + if (timestamp) { + struct cmsghdr* cmsg; + for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { + if (cmsg->cmsg_level != SOL_SOCKET) + continue; + if (cmsg->cmsg_type == SCM_TIMESTAMP) { + timeval* ts = reinterpret_cast<timeval*>(CMSG_DATA(cmsg)); + *timestamp = + rtc::kNumMicrosecsPerSec * static_cast<int64_t>(ts->tv_sec) + + static_cast<int64_t>(ts->tv_usec); + break; + } + } + } + if (out_addr) { + SocketAddressFromSockAddrStorage(addr_storage, out_addr); + } + } else { // !read_scm_timestamp_experiment_ + if (out_addr) { + received = ::recvfrom(s_, static_cast<char*>(buffer), + static_cast<int>(length), 0, addr, &addr_len); + SocketAddressFromSockAddrStorage(addr_storage, out_addr); + } else { + received = + ::recv(s_, static_cast<char*>(buffer), static_cast<int>(length), 0); + } + if (timestamp) { + *timestamp = GetSocketRecvTimestamp(s_); + } + } + return received; + +#else + int received = 0; + if (out_addr) { + received = ::recvfrom(s_, static_cast<char*>(buffer), + static_cast<int>(length), 0, addr, &addr_len); + SocketAddressFromSockAddrStorage(addr_storage, out_addr); + } else { + received = + ::recv(s_, static_cast<char*>(buffer), static_cast<int>(length), 0); + } + if (timestamp) { + *timestamp = -1; + } + return received; +#endif +} + +int PhysicalSocket::Listen(int backlog) { + int err = ::listen(s_, backlog); + UpdateLastError(); + if (err == 0) { + state_ = CS_CONNECTING; + EnableEvents(DE_ACCEPT); +#if !defined(NDEBUG) + dbg_addr_ = "Listening @ "; + dbg_addr_.append(GetLocalAddress().ToString()); +#endif + } + return err; +} + +Socket* PhysicalSocket::Accept(SocketAddress* out_addr) { + // Always re-subscribe DE_ACCEPT to make sure new incoming connections will + // trigger an event even if DoAccept returns an error here. + EnableEvents(DE_ACCEPT); + sockaddr_storage addr_storage; + socklen_t addr_len = sizeof(addr_storage); + sockaddr* addr = reinterpret_cast<sockaddr*>(&addr_storage); + SOCKET s = DoAccept(s_, addr, &addr_len); + UpdateLastError(); + if (s == INVALID_SOCKET) + return nullptr; + if (out_addr != nullptr) + SocketAddressFromSockAddrStorage(addr_storage, out_addr); + return ss_->WrapSocket(s); +} + +int PhysicalSocket::Close() { + if (s_ == INVALID_SOCKET) + return 0; + int err = ::closesocket(s_); + UpdateLastError(); + s_ = INVALID_SOCKET; + state_ = CS_CLOSED; + SetEnabledEvents(0); + if (resolver_) { + resolver_.reset(); + } + return err; +} + +SOCKET PhysicalSocket::DoAccept(SOCKET socket, + sockaddr* addr, + socklen_t* addrlen) { + return ::accept(socket, addr, addrlen); +} + +int PhysicalSocket::DoSend(SOCKET socket, const char* buf, int len, int flags) { + return ::send(socket, buf, len, flags); +} + +int PhysicalSocket::DoSendTo(SOCKET socket, + const char* buf, + int len, + int flags, + const struct sockaddr* dest_addr, + socklen_t addrlen) { + return ::sendto(socket, buf, len, flags, dest_addr, addrlen); +} + +void PhysicalSocket::OnResolveResult( + const webrtc::AsyncDnsResolverResult& result) { + int error = result.GetError(); + if (error == 0) { + SocketAddress address; + if (result.GetResolvedAddress(AF_INET, &address)) { + error = DoConnect(address); + } else { + Close(); + } + } else { + Close(); + } + + if (error) { + SetError(error); + SignalCloseEvent(this, error); + } +} + +void PhysicalSocket::UpdateLastError() { + SetError(LAST_SYSTEM_ERROR); +} + +void PhysicalSocket::MaybeRemapSendError() { +#if defined(WEBRTC_MAC) + // https://developer.apple.com/library/mac/documentation/Darwin/ + // Reference/ManPages/man2/sendto.2.html + // ENOBUFS - The output queue for a network interface is full. + // This generally indicates that the interface has stopped sending, + // but may be caused by transient congestion. + if (GetError() == ENOBUFS) { + SetError(EWOULDBLOCK); + } +#endif +} + +void PhysicalSocket::SetEnabledEvents(uint8_t events) { + enabled_events_ = events; +} + +void PhysicalSocket::EnableEvents(uint8_t events) { + enabled_events_ |= events; +} + +void PhysicalSocket::DisableEvents(uint8_t events) { + enabled_events_ &= ~events; +} + +int PhysicalSocket::TranslateOption(Option opt, int* slevel, int* sopt) { + switch (opt) { + case OPT_DONTFRAGMENT: +#if defined(WEBRTC_WIN) + *slevel = IPPROTO_IP; + *sopt = IP_DONTFRAGMENT; + break; +#elif defined(WEBRTC_MAC) || defined(WEBRTC_BSD) || defined(__native_client__) + RTC_LOG(LS_WARNING) << "Socket::OPT_DONTFRAGMENT not supported."; + return -1; +#elif defined(WEBRTC_POSIX) + *slevel = IPPROTO_IP; + *sopt = IP_MTU_DISCOVER; + break; +#endif + case OPT_RCVBUF: + *slevel = SOL_SOCKET; + *sopt = SO_RCVBUF; + break; + case OPT_SNDBUF: + *slevel = SOL_SOCKET; + *sopt = SO_SNDBUF; + break; + case OPT_NODELAY: + *slevel = IPPROTO_TCP; + *sopt = TCP_NODELAY; + break; + case OPT_DSCP: +#if defined(WEBRTC_POSIX) + if (family_ == AF_INET6) { + *slevel = IPPROTO_IPV6; + *sopt = IPV6_TCLASS; + } else { + *slevel = IPPROTO_IP; + *sopt = IP_TOS; + } + break; +#else + RTC_LOG(LS_WARNING) << "Socket::OPT_DSCP not supported."; + return -1; +#endif + case OPT_RTP_SENDTIME_EXTN_ID: + return -1; // No logging is necessary as this not a OS socket option. + default: + RTC_DCHECK_NOTREACHED(); + return -1; + } + return 0; +} + +SocketDispatcher::SocketDispatcher(PhysicalSocketServer* ss) +#if defined(WEBRTC_WIN) + : PhysicalSocket(ss), + id_(0), + signal_close_(false) +#else + : PhysicalSocket(ss) +#endif +{ +} + +SocketDispatcher::SocketDispatcher(SOCKET s, PhysicalSocketServer* ss) +#if defined(WEBRTC_WIN) + : PhysicalSocket(ss, s), + id_(0), + signal_close_(false) +#else + : PhysicalSocket(ss, s) +#endif +{ +} + +SocketDispatcher::~SocketDispatcher() { + Close(); +} + +bool SocketDispatcher::Initialize() { + RTC_DCHECK(s_ != INVALID_SOCKET); +// Must be a non-blocking +#if defined(WEBRTC_WIN) + u_long argp = 1; + ioctlsocket(s_, FIONBIO, &argp); +#elif defined(WEBRTC_POSIX) + fcntl(s_, F_SETFL, fcntl(s_, F_GETFL, 0) | O_NONBLOCK); + if (!IsScmTimeStampExperimentDisabled()) { + int value = 1; + // Attempt to get receive packet timestamp from the socket. + if (::setsockopt(s_, SOL_SOCKET, SO_TIMESTAMP, &value, sizeof(value)) != + 0) { + RTC_DLOG(LS_ERROR) << "::setsockopt failed. errno: " << LAST_SYSTEM_ERROR; + } + } +#endif + +#if defined(WEBRTC_IOS) + // iOS may kill sockets when the app is moved to the background + // (specifically, if the app doesn't use the "voip" UIBackgroundMode). When + // we attempt to write to such a socket, SIGPIPE will be raised, which by + // default will terminate the process, which we don't want. By specifying + // this socket option, SIGPIPE will be disabled for the socket. + int value = 1; + if (::setsockopt(s_, SOL_SOCKET, SO_NOSIGPIPE, &value, sizeof(value)) != 0) { + RTC_DLOG(LS_ERROR) << "::setsockopt failed. errno: " << LAST_SYSTEM_ERROR; + } +#endif + ss_->Add(this); + return true; +} + +bool SocketDispatcher::Create(int type) { + return Create(AF_INET, type); +} + +bool SocketDispatcher::Create(int family, int type) { + // Change the socket to be non-blocking. + if (!PhysicalSocket::Create(family, type)) + return false; + + if (!Initialize()) + return false; + +#if defined(WEBRTC_WIN) + do { + id_ = ++next_id_; + } while (id_ == 0); +#endif + return true; +} + +#if defined(WEBRTC_WIN) + +WSAEVENT SocketDispatcher::GetWSAEvent() { + return WSA_INVALID_EVENT; +} + +SOCKET SocketDispatcher::GetSocket() { + return s_; +} + +bool SocketDispatcher::CheckSignalClose() { + if (!signal_close_) + return false; + + char ch; + if (recv(s_, &ch, 1, MSG_PEEK) > 0) + return false; + + state_ = CS_CLOSED; + signal_close_ = false; + SignalCloseEvent(this, signal_err_); + return true; +} + +int SocketDispatcher::next_id_ = 0; + +#elif defined(WEBRTC_POSIX) + +int SocketDispatcher::GetDescriptor() { + return s_; +} + +bool SocketDispatcher::IsDescriptorClosed() { + if (udp_) { + // The MSG_PEEK trick doesn't work for UDP, since (at least in some + // circumstances) it requires reading an entire UDP packet, which would be + // bad for performance here. So, just check whether `s_` has been closed, + // which should be sufficient. + return s_ == INVALID_SOCKET; + } + // We don't have a reliable way of distinguishing end-of-stream + // from readability. So test on each readable call. Is this + // inefficient? Probably. + char ch; + ssize_t res; + // Retry if the system call was interrupted. + do { + res = ::recv(s_, &ch, 1, MSG_PEEK); + } while (res < 0 && errno == EINTR); + if (res > 0) { + // Data available, so not closed. + return false; + } else if (res == 0) { + // EOF, so closed. + return true; + } else { // error + switch (errno) { + // Returned if we've already closed s_. + case EBADF: + // This is dangerous: if we keep attempting to access a FD after close, + // it could be reopened by something else making us think it's still + // open. Note that this is only a DCHECK. + RTC_DCHECK_NOTREACHED(); + return true; + // Returned during ungraceful peer shutdown. + case ECONNRESET: + return true; + case ECONNABORTED: + return true; + case EPIPE: + return true; + // The normal blocking error; don't log anything. + case EWOULDBLOCK: + return false; + default: + // Assume that all other errors are just blocking errors, meaning the + // connection is still good but we just can't read from it right now. + // This should only happen when connecting (and at most once), because + // in all other cases this function is only called if the file + // descriptor is already known to be in the readable state. However, + // it's not necessary a problem if we spuriously interpret a + // "connection lost"-type error as a blocking error, because typically + // the next recv() will get EOF, so we'll still eventually notice that + // the socket is closed. + RTC_LOG_ERR(LS_WARNING) << "Assuming benign blocking error"; + return false; + } + } +} + +#endif // WEBRTC_POSIX + +uint32_t SocketDispatcher::GetRequestedEvents() { + return enabled_events(); +} + +#if defined(WEBRTC_WIN) + +void SocketDispatcher::OnEvent(uint32_t ff, int err) { + if ((ff & DE_CONNECT) != 0) + state_ = CS_CONNECTED; + + // We set CS_CLOSED from CheckSignalClose. + + int cache_id = id_; + // Make sure we deliver connect/accept first. Otherwise, consumers may see + // something like a READ followed by a CONNECT, which would be odd. + if (((ff & DE_CONNECT) != 0) && (id_ == cache_id)) { + if (ff != DE_CONNECT) + RTC_LOG(LS_VERBOSE) << "Signalled with DE_CONNECT: " << ff; + DisableEvents(DE_CONNECT); +#if !defined(NDEBUG) + dbg_addr_ = "Connected @ "; + dbg_addr_.append(GetRemoteAddress().ToString()); +#endif + SignalConnectEvent(this); + } + if (((ff & DE_ACCEPT) != 0) && (id_ == cache_id)) { + DisableEvents(DE_ACCEPT); + SignalReadEvent(this); + } + if ((ff & DE_READ) != 0) { + DisableEvents(DE_READ); + SignalReadEvent(this); + } + if (((ff & DE_WRITE) != 0) && (id_ == cache_id)) { + DisableEvents(DE_WRITE); + SignalWriteEvent(this); + } + if (((ff & DE_CLOSE) != 0) && (id_ == cache_id)) { + signal_close_ = true; + signal_err_ = err; + } +} + +#elif defined(WEBRTC_POSIX) + +void SocketDispatcher::OnEvent(uint32_t ff, int err) { + if ((ff & DE_CONNECT) != 0) + state_ = CS_CONNECTED; + + if ((ff & DE_CLOSE) != 0) + state_ = CS_CLOSED; + +#if defined(WEBRTC_USE_EPOLL) + // Remember currently enabled events so we can combine multiple changes + // into one update call later. + // The signal handlers might re-enable events disabled here, so we can't + // keep a list of events to disable at the end of the method. This list + // would not be updated with the events enabled by the signal handlers. + StartBatchedEventUpdates(); +#endif + // Make sure we deliver connect/accept first. Otherwise, consumers may see + // something like a READ followed by a CONNECT, which would be odd. + if ((ff & DE_CONNECT) != 0) { + DisableEvents(DE_CONNECT); + SignalConnectEvent(this); + } + if ((ff & DE_ACCEPT) != 0) { + DisableEvents(DE_ACCEPT); + SignalReadEvent(this); + } + if ((ff & DE_READ) != 0) { + DisableEvents(DE_READ); + SignalReadEvent(this); + } + if ((ff & DE_WRITE) != 0) { + DisableEvents(DE_WRITE); + SignalWriteEvent(this); + } + if ((ff & DE_CLOSE) != 0) { + // The socket is now dead to us, so stop checking it. + SetEnabledEvents(0); + SignalCloseEvent(this, err); + } +#if defined(WEBRTC_USE_EPOLL) + FinishBatchedEventUpdates(); +#endif +} + +#endif // WEBRTC_POSIX + +#if defined(WEBRTC_USE_EPOLL) + +inline static int GetEpollEvents(uint32_t ff) { + int events = 0; + if (ff & (DE_READ | DE_ACCEPT)) { + events |= EPOLLIN; + } + if (ff & (DE_WRITE | DE_CONNECT)) { + events |= EPOLLOUT; + } + return events; +} + +void SocketDispatcher::StartBatchedEventUpdates() { + RTC_DCHECK_EQ(saved_enabled_events_, -1); + saved_enabled_events_ = enabled_events(); +} + +void SocketDispatcher::FinishBatchedEventUpdates() { + RTC_DCHECK_NE(saved_enabled_events_, -1); + uint8_t old_events = static_cast<uint8_t>(saved_enabled_events_); + saved_enabled_events_ = -1; + MaybeUpdateDispatcher(old_events); +} + +void SocketDispatcher::MaybeUpdateDispatcher(uint8_t old_events) { + if (GetEpollEvents(enabled_events()) != GetEpollEvents(old_events) && + saved_enabled_events_ == -1) { + ss_->Update(this); + } +} + +void SocketDispatcher::SetEnabledEvents(uint8_t events) { + uint8_t old_events = enabled_events(); + PhysicalSocket::SetEnabledEvents(events); + MaybeUpdateDispatcher(old_events); +} + +void SocketDispatcher::EnableEvents(uint8_t events) { + uint8_t old_events = enabled_events(); + PhysicalSocket::EnableEvents(events); + MaybeUpdateDispatcher(old_events); +} + +void SocketDispatcher::DisableEvents(uint8_t events) { + uint8_t old_events = enabled_events(); + PhysicalSocket::DisableEvents(events); + MaybeUpdateDispatcher(old_events); +} + +#endif // WEBRTC_USE_EPOLL + +int SocketDispatcher::Close() { + if (s_ == INVALID_SOCKET) + return 0; + +#if defined(WEBRTC_WIN) + id_ = 0; + signal_close_ = false; +#endif +#if defined(WEBRTC_USE_EPOLL) + // If we're batching events, the socket can be closed and reopened + // during the batch. Set saved_enabled_events_ to 0 here so the new + // socket, if any, has the correct old events bitfield + if (saved_enabled_events_ != -1) { + saved_enabled_events_ = 0; + } +#endif + ss_->Remove(this); + return PhysicalSocket::Close(); +} + +#if defined(WEBRTC_POSIX) +// Sets the value of a boolean value to false when signaled. +class Signaler : public Dispatcher { + public: + Signaler(PhysicalSocketServer* ss, bool& flag_to_clear) + : ss_(ss), + afd_([] { + std::array<int, 2> afd = {-1, -1}; + + if (pipe(afd.data()) < 0) { + RTC_LOG(LS_ERROR) << "pipe failed"; + } + return afd; + }()), + fSignaled_(false), + flag_to_clear_(flag_to_clear) { + ss_->Add(this); + } + + ~Signaler() override { + ss_->Remove(this); + close(afd_[0]); + close(afd_[1]); + } + + virtual void Signal() { + webrtc::MutexLock lock(&mutex_); + if (!fSignaled_) { + const uint8_t b[1] = {0}; + const ssize_t res = write(afd_[1], b, sizeof(b)); + RTC_DCHECK_EQ(1, res); + fSignaled_ = true; + } + } + + uint32_t GetRequestedEvents() override { return DE_READ; } + + void OnEvent(uint32_t ff, int err) override { + // It is not possible to perfectly emulate an auto-resetting event with + // pipes. This simulates it by resetting before the event is handled. + + webrtc::MutexLock lock(&mutex_); + if (fSignaled_) { + uint8_t b[4]; // Allow for reading more than 1 byte, but expect 1. + const ssize_t res = read(afd_[0], b, sizeof(b)); + RTC_DCHECK_EQ(1, res); + fSignaled_ = false; + } + flag_to_clear_ = false; + } + + int GetDescriptor() override { return afd_[0]; } + + bool IsDescriptorClosed() override { return false; } + + private: + PhysicalSocketServer* const ss_; + const std::array<int, 2> afd_; + bool fSignaled_ RTC_GUARDED_BY(mutex_); + webrtc::Mutex mutex_; + bool& flag_to_clear_; +}; + +#endif // WEBRTC_POSIX + +#if defined(WEBRTC_WIN) +static uint32_t FlagsToEvents(uint32_t events) { + uint32_t ffFD = FD_CLOSE; + if (events & DE_READ) + ffFD |= FD_READ; + if (events & DE_WRITE) + ffFD |= FD_WRITE; + if (events & DE_CONNECT) + ffFD |= FD_CONNECT; + if (events & DE_ACCEPT) + ffFD |= FD_ACCEPT; + return ffFD; +} + +// Sets the value of a boolean value to false when signaled. +class Signaler : public Dispatcher { + public: + Signaler(PhysicalSocketServer* ss, bool& flag_to_clear) + : ss_(ss), flag_to_clear_(flag_to_clear) { + hev_ = WSACreateEvent(); + if (hev_) { + ss_->Add(this); + } + } + + ~Signaler() override { + if (hev_ != nullptr) { + ss_->Remove(this); + WSACloseEvent(hev_); + hev_ = nullptr; + } + } + + virtual void Signal() { + if (hev_ != nullptr) + WSASetEvent(hev_); + } + + uint32_t GetRequestedEvents() override { return 0; } + + void OnEvent(uint32_t ff, int err) override { + WSAResetEvent(hev_); + flag_to_clear_ = false; + } + + WSAEVENT GetWSAEvent() override { return hev_; } + + SOCKET GetSocket() override { return INVALID_SOCKET; } + + bool CheckSignalClose() override { return false; } + + private: + PhysicalSocketServer* ss_; + WSAEVENT hev_; + bool& flag_to_clear_; +}; +#endif // WEBRTC_WIN + +PhysicalSocketServer::PhysicalSocketServer() + : +#if defined(WEBRTC_USE_EPOLL) + // Since Linux 2.6.8, the size argument is ignored, but must be greater + // than zero. Before that the size served as hint to the kernel for the + // amount of space to initially allocate in internal data structures. + epoll_fd_(epoll_create(FD_SETSIZE)), +#endif +#if defined(WEBRTC_WIN) + socket_ev_(WSACreateEvent()), +#endif + fWait_(false) { +#if defined(WEBRTC_USE_EPOLL) + if (epoll_fd_ == -1) { + // Not an error, will fall back to "select" below. + RTC_LOG_E(LS_WARNING, EN, errno) << "epoll_create"; + // Note that -1 == INVALID_SOCKET, the alias used by later checks. + } +#endif + // The `fWait_` flag to be cleared by the Signaler. + signal_wakeup_ = new Signaler(this, fWait_); +} + +PhysicalSocketServer::~PhysicalSocketServer() { +#if defined(WEBRTC_WIN) + WSACloseEvent(socket_ev_); +#endif + delete signal_wakeup_; +#if defined(WEBRTC_USE_EPOLL) + if (epoll_fd_ != INVALID_SOCKET) { + close(epoll_fd_); + } +#endif + RTC_DCHECK(dispatcher_by_key_.empty()); + RTC_DCHECK(key_by_dispatcher_.empty()); +} + +void PhysicalSocketServer::WakeUp() { + signal_wakeup_->Signal(); +} + +Socket* PhysicalSocketServer::CreateSocket(int family, int type) { + SocketDispatcher* dispatcher = new SocketDispatcher(this); + if (dispatcher->Create(family, type)) { + return dispatcher; + } else { + delete dispatcher; + return nullptr; + } +} + +Socket* PhysicalSocketServer::WrapSocket(SOCKET s) { + SocketDispatcher* dispatcher = new SocketDispatcher(s, this); + if (dispatcher->Initialize()) { + return dispatcher; + } else { + delete dispatcher; + return nullptr; + } +} + +void PhysicalSocketServer::Add(Dispatcher* pdispatcher) { + CritScope cs(&crit_); + if (key_by_dispatcher_.count(pdispatcher)) { + RTC_LOG(LS_WARNING) + << "PhysicalSocketServer asked to add a duplicate dispatcher."; + return; + } + uint64_t key = next_dispatcher_key_++; + dispatcher_by_key_.emplace(key, pdispatcher); + key_by_dispatcher_.emplace(pdispatcher, key); +#if defined(WEBRTC_USE_EPOLL) + if (epoll_fd_ != INVALID_SOCKET) { + AddEpoll(pdispatcher, key); + } +#endif // WEBRTC_USE_EPOLL +} + +void PhysicalSocketServer::Remove(Dispatcher* pdispatcher) { + CritScope cs(&crit_); + if (!key_by_dispatcher_.count(pdispatcher)) { + RTC_LOG(LS_WARNING) + << "PhysicalSocketServer asked to remove a unknown " + "dispatcher, potentially from a duplicate call to Add."; + return; + } + uint64_t key = key_by_dispatcher_.at(pdispatcher); + key_by_dispatcher_.erase(pdispatcher); + dispatcher_by_key_.erase(key); +#if defined(WEBRTC_USE_EPOLL) + if (epoll_fd_ != INVALID_SOCKET) { + RemoveEpoll(pdispatcher); + } +#endif // WEBRTC_USE_EPOLL +} + +void PhysicalSocketServer::Update(Dispatcher* pdispatcher) { +#if defined(WEBRTC_USE_EPOLL) + if (epoll_fd_ == INVALID_SOCKET) { + return; + } + + // Don't update dispatchers that haven't yet been added. + CritScope cs(&crit_); + if (!key_by_dispatcher_.count(pdispatcher)) { + return; + } + + UpdateEpoll(pdispatcher, key_by_dispatcher_.at(pdispatcher)); +#endif +} + +int PhysicalSocketServer::ToCmsWait(webrtc::TimeDelta max_wait_duration) { + return max_wait_duration == Event::kForever + ? kForeverMs + : max_wait_duration.RoundUpTo(webrtc::TimeDelta::Millis(1)).ms(); +} + +#if defined(WEBRTC_POSIX) + +bool PhysicalSocketServer::Wait(webrtc::TimeDelta max_wait_duration, + bool process_io) { + // We don't support reentrant waiting. + RTC_DCHECK(!waiting_); + ScopedSetTrue s(&waiting_); + const int cmsWait = ToCmsWait(max_wait_duration); + +#if defined(WEBRTC_USE_POLL) + return WaitPoll(cmsWait, process_io); +#else +#if defined(WEBRTC_USE_EPOLL) + // We don't keep a dedicated "epoll" descriptor containing only the non-IO + // (i.e. signaling) dispatcher, so "poll" will be used instead of the default + // "select" to support sockets larger than FD_SETSIZE. + if (!process_io) { + return WaitPollOneDispatcher(cmsWait, signal_wakeup_); + } else if (epoll_fd_ != INVALID_SOCKET) { + return WaitEpoll(cmsWait); + } +#endif + return WaitSelect(cmsWait, process_io); +#endif +} + +// `error_event` is true if we are responding to an event where we know an +// error has occurred, which is possible with the poll/epoll implementations +// but not the select implementation. +// +// `check_error` is true if there is the possibility of an error. +static void ProcessEvents(Dispatcher* dispatcher, + bool readable, + bool writable, + bool error_event, + bool check_error) { + RTC_DCHECK(!(error_event && !check_error)); + int errcode = 0; + if (check_error) { + socklen_t len = sizeof(errcode); + int res = ::getsockopt(dispatcher->GetDescriptor(), SOL_SOCKET, SO_ERROR, + &errcode, &len); + if (res < 0) { + // If we are sure an error has occurred, or if getsockopt failed for a + // socket descriptor, make sure we set the error code to a nonzero value. + if (error_event || errno != ENOTSOCK) { + errcode = EBADF; + } + } + } + + // Most often the socket is writable or readable or both, so make a single + // virtual call to get requested events + const uint32_t requested_events = dispatcher->GetRequestedEvents(); + uint32_t ff = 0; + + // Check readable descriptors. If we're waiting on an accept, signal + // that. Otherwise we're waiting for data, check to see if we're + // readable or really closed. + // TODO(pthatcher): Only peek at TCP descriptors. + if (readable) { + if (errcode || dispatcher->IsDescriptorClosed()) { + ff |= DE_CLOSE; + } else if (requested_events & DE_ACCEPT) { + ff |= DE_ACCEPT; + } else { + ff |= DE_READ; + } + } + + // Check writable descriptors. If we're waiting on a connect, detect + // success versus failure by the reaped error code. + if (writable) { + if (requested_events & DE_CONNECT) { + if (!errcode) { + ff |= DE_CONNECT; + } + } else { + ff |= DE_WRITE; + } + } + + // Make sure we report any errors regardless of whether readable or writable. + if (errcode) { + ff |= DE_CLOSE; + } + + // Tell the descriptor about the event. + if (ff != 0) { + dispatcher->OnEvent(ff, errcode); + } +} + +#if defined(WEBRTC_USE_POLL) || defined(WEBRTC_USE_EPOLL) +static void ProcessPollEvents(Dispatcher* dispatcher, const pollfd& pfd) { + bool readable = (pfd.revents & (POLLIN | POLLPRI)); + bool writable = (pfd.revents & POLLOUT); + bool error = (pfd.revents & (POLLRDHUP | POLLERR | POLLHUP)); + + ProcessEvents(dispatcher, readable, writable, error, error); +} + +static pollfd DispatcherToPollfd(Dispatcher* dispatcher) { + pollfd fd{ + .fd = dispatcher->GetDescriptor(), + .events = 0, + .revents = 0, + }; + + uint32_t ff = dispatcher->GetRequestedEvents(); + if (ff & (DE_READ | DE_ACCEPT)) { + fd.events |= POLLIN; + } + if (ff & (DE_WRITE | DE_CONNECT)) { + fd.events |= POLLOUT; + } + + return fd; +} +#endif // WEBRTC_USE_POLL || WEBRTC_USE_EPOLL + +bool PhysicalSocketServer::WaitSelect(int cmsWait, bool process_io) { + // Calculate timing information + + struct timeval* ptvWait = nullptr; + struct timeval tvWait; + int64_t stop_us; + if (cmsWait != kForeverMs) { + // Calculate wait timeval + tvWait.tv_sec = cmsWait / 1000; + tvWait.tv_usec = (cmsWait % 1000) * 1000; + ptvWait = &tvWait; + + // Calculate when to return + stop_us = rtc::TimeMicros() + cmsWait * 1000; + } + + fd_set fdsRead; + fd_set fdsWrite; +// Explicitly unpoison these FDs on MemorySanitizer which doesn't handle the +// inline assembly in FD_ZERO. +// http://crbug.com/344505 +#ifdef MEMORY_SANITIZER + __msan_unpoison(&fdsRead, sizeof(fdsRead)); + __msan_unpoison(&fdsWrite, sizeof(fdsWrite)); +#endif + + fWait_ = true; + + while (fWait_) { + // Zero all fd_sets. Although select() zeros the descriptors not signaled, + // we may need to do this for dispatchers that were deleted while + // iterating. + FD_ZERO(&fdsRead); + FD_ZERO(&fdsWrite); + int fdmax = -1; + { + CritScope cr(&crit_); + current_dispatcher_keys_.clear(); + for (auto const& kv : dispatcher_by_key_) { + uint64_t key = kv.first; + Dispatcher* pdispatcher = kv.second; + if (!process_io && (pdispatcher != signal_wakeup_)) + continue; + current_dispatcher_keys_.push_back(key); + int fd = pdispatcher->GetDescriptor(); + // "select"ing a file descriptor that is equal to or larger than + // FD_SETSIZE will result in undefined behavior. + RTC_CHECK_LT(fd, FD_SETSIZE); + if (fd > fdmax) + fdmax = fd; + + uint32_t ff = pdispatcher->GetRequestedEvents(); + if (ff & (DE_READ | DE_ACCEPT)) + FD_SET(fd, &fdsRead); + if (ff & (DE_WRITE | DE_CONNECT)) + FD_SET(fd, &fdsWrite); + } + } + + // Wait then call handlers as appropriate + // < 0 means error + // 0 means timeout + // > 0 means count of descriptors ready + int n = select(fdmax + 1, &fdsRead, &fdsWrite, nullptr, ptvWait); + + // If error, return error. + if (n < 0) { + if (errno != EINTR) { + RTC_LOG_E(LS_ERROR, EN, errno) << "select"; + return false; + } + // Else ignore the error and keep going. If this EINTR was for one of the + // signals managed by this PhysicalSocketServer, the + // PosixSignalDeliveryDispatcher will be in the signaled state in the next + // iteration. + } else if (n == 0) { + // If timeout, return success + return true; + } else { + // We have signaled descriptors + CritScope cr(&crit_); + // Iterate only on the dispatchers whose file descriptors were passed into + // select; this avoids the ABA problem (a socket being destroyed and a new + // one created with the same file descriptor). + for (uint64_t key : current_dispatcher_keys_) { + if (!dispatcher_by_key_.count(key)) + continue; + Dispatcher* pdispatcher = dispatcher_by_key_.at(key); + + int fd = pdispatcher->GetDescriptor(); + + bool readable = FD_ISSET(fd, &fdsRead); + if (readable) { + FD_CLR(fd, &fdsRead); + } + + bool writable = FD_ISSET(fd, &fdsWrite); + if (writable) { + FD_CLR(fd, &fdsWrite); + } + + // The error code can be signaled through reads or writes. + ProcessEvents(pdispatcher, readable, writable, /*error_event=*/false, + readable || writable); + } + } + + // Recalc the time remaining to wait. Doing it here means it doesn't get + // calced twice the first time through the loop + if (ptvWait) { + ptvWait->tv_sec = 0; + ptvWait->tv_usec = 0; + int64_t time_left_us = stop_us - rtc::TimeMicros(); + if (time_left_us > 0) { + ptvWait->tv_sec = time_left_us / rtc::kNumMicrosecsPerSec; + ptvWait->tv_usec = time_left_us % rtc::kNumMicrosecsPerSec; + } + } + } + + return true; +} + +#if defined(WEBRTC_USE_EPOLL) + +void PhysicalSocketServer::AddEpoll(Dispatcher* pdispatcher, uint64_t key) { + RTC_DCHECK(epoll_fd_ != INVALID_SOCKET); + int fd = pdispatcher->GetDescriptor(); + RTC_DCHECK(fd != INVALID_SOCKET); + if (fd == INVALID_SOCKET) { + return; + } + + struct epoll_event event = {0}; + event.events = GetEpollEvents(pdispatcher->GetRequestedEvents()); + if (event.events == 0u) { + // Don't add at all if we don't have any requested events. Could indicate a + // closed socket. + return; + } + event.data.u64 = key; + int err = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, fd, &event); + RTC_DCHECK_EQ(err, 0); + if (err == -1) { + RTC_LOG_E(LS_ERROR, EN, errno) << "epoll_ctl EPOLL_CTL_ADD"; + } +} + +void PhysicalSocketServer::RemoveEpoll(Dispatcher* pdispatcher) { + RTC_DCHECK(epoll_fd_ != INVALID_SOCKET); + int fd = pdispatcher->GetDescriptor(); + RTC_DCHECK(fd != INVALID_SOCKET); + if (fd == INVALID_SOCKET) { + return; + } + + struct epoll_event event = {0}; + int err = epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, fd, &event); + RTC_DCHECK(err == 0 || errno == ENOENT); + // Ignore ENOENT, which could occur if this descriptor wasn't added due to + // having no requested events. + if (err == -1 && errno != ENOENT) { + RTC_LOG_E(LS_ERROR, EN, errno) << "epoll_ctl EPOLL_CTL_DEL"; + } +} + +void PhysicalSocketServer::UpdateEpoll(Dispatcher* pdispatcher, uint64_t key) { + RTC_DCHECK(epoll_fd_ != INVALID_SOCKET); + int fd = pdispatcher->GetDescriptor(); + RTC_DCHECK(fd != INVALID_SOCKET); + if (fd == INVALID_SOCKET) { + return; + } + + struct epoll_event event = {0}; + event.events = GetEpollEvents(pdispatcher->GetRequestedEvents()); + event.data.u64 = key; + // Remove if we don't have any requested events. Could indicate a closed + // socket. + if (event.events == 0u) { + epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, fd, &event); + } else { + int err = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, fd, &event); + RTC_DCHECK(err == 0 || errno == ENOENT); + if (err == -1) { + // Could have been removed earlier due to no requested events. + if (errno == ENOENT) { + err = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, fd, &event); + if (err == -1) { + RTC_LOG_E(LS_ERROR, EN, errno) << "epoll_ctl EPOLL_CTL_ADD"; + } + } else { + RTC_LOG_E(LS_ERROR, EN, errno) << "epoll_ctl EPOLL_CTL_MOD"; + } + } + } +} + +bool PhysicalSocketServer::WaitEpoll(int cmsWait) { + RTC_DCHECK(epoll_fd_ != INVALID_SOCKET); + int64_t msWait = -1; + int64_t msStop = -1; + if (cmsWait != kForeverMs) { + msWait = cmsWait; + msStop = TimeAfter(cmsWait); + } + + fWait_ = true; + while (fWait_) { + // Wait then call handlers as appropriate + // < 0 means error + // 0 means timeout + // > 0 means count of descriptors ready + int n = epoll_wait(epoll_fd_, epoll_events_.data(), epoll_events_.size(), + static_cast<int>(msWait)); + if (n < 0) { + if (errno != EINTR) { + RTC_LOG_E(LS_ERROR, EN, errno) << "epoll"; + return false; + } + // Else ignore the error and keep going. If this EINTR was for one of the + // signals managed by this PhysicalSocketServer, the + // PosixSignalDeliveryDispatcher will be in the signaled state in the next + // iteration. + } else if (n == 0) { + // If timeout, return success + return true; + } else { + // We have signaled descriptors + CritScope cr(&crit_); + for (int i = 0; i < n; ++i) { + const epoll_event& event = epoll_events_[i]; + uint64_t key = event.data.u64; + if (!dispatcher_by_key_.count(key)) { + // The dispatcher for this socket no longer exists. + continue; + } + Dispatcher* pdispatcher = dispatcher_by_key_.at(key); + + bool readable = (event.events & (EPOLLIN | EPOLLPRI)); + bool writable = (event.events & EPOLLOUT); + bool error = (event.events & (EPOLLRDHUP | EPOLLERR | EPOLLHUP)); + + ProcessEvents(pdispatcher, readable, writable, error, error); + } + } + + if (cmsWait != kForeverMs) { + msWait = TimeDiff(msStop, TimeMillis()); + if (msWait <= 0) { + // Return success on timeout. + return true; + } + } + } + + return true; +} + +bool PhysicalSocketServer::WaitPollOneDispatcher(int cmsWait, + Dispatcher* dispatcher) { + RTC_DCHECK(dispatcher); + int64_t msWait = -1; + int64_t msStop = -1; + if (cmsWait != kForeverMs) { + msWait = cmsWait; + msStop = TimeAfter(cmsWait); + } + + fWait_ = true; + const int fd = dispatcher->GetDescriptor(); + + while (fWait_) { + auto fds = DispatcherToPollfd(dispatcher); + + // Wait then call handlers as appropriate + // < 0 means error + // 0 means timeout + // > 0 means count of descriptors ready + int n = poll(&fds, 1, static_cast<int>(msWait)); + if (n < 0) { + if (errno != EINTR) { + RTC_LOG_E(LS_ERROR, EN, errno) << "poll"; + return false; + } + // Else ignore the error and keep going. If this EINTR was for one of the + // signals managed by this PhysicalSocketServer, the + // PosixSignalDeliveryDispatcher will be in the signaled state in the next + // iteration. + } else if (n == 0) { + // If timeout, return success + return true; + } else { + // We have signaled descriptors (should only be the passed dispatcher). + RTC_DCHECK_EQ(n, 1); + RTC_DCHECK_EQ(fds.fd, fd); + ProcessPollEvents(dispatcher, fds); + } + + if (cmsWait != kForeverMs) { + msWait = TimeDiff(msStop, TimeMillis()); + if (msWait < 0) { + // Return success on timeout. + return true; + } + } + } + + return true; +} + +#elif defined(WEBRTC_USE_POLL) + +bool PhysicalSocketServer::WaitPoll(int cmsWait, bool process_io) { + int64_t msWait = -1; + int64_t msStop = -1; + if (cmsWait != kForeverMs) { + msWait = cmsWait; + msStop = TimeAfter(cmsWait); + } + + std::vector<pollfd> pollfds; + fWait_ = true; + + while (fWait_) { + { + CritScope cr(&crit_); + current_dispatcher_keys_.clear(); + pollfds.clear(); + pollfds.reserve(dispatcher_by_key_.size()); + + for (auto const& kv : dispatcher_by_key_) { + uint64_t key = kv.first; + Dispatcher* pdispatcher = kv.second; + if (!process_io && (pdispatcher != signal_wakeup_)) + continue; + current_dispatcher_keys_.push_back(key); + pollfds.push_back(DispatcherToPollfd(pdispatcher)); + } + } + + // Wait then call handlers as appropriate + // < 0 means error + // 0 means timeout + // > 0 means count of descriptors ready + int n = poll(pollfds.data(), pollfds.size(), static_cast<int>(msWait)); + if (n < 0) { + if (errno != EINTR) { + RTC_LOG_E(LS_ERROR, EN, errno) << "poll"; + return false; + } + // Else ignore the error and keep going. If this EINTR was for one of the + // signals managed by this PhysicalSocketServer, the + // PosixSignalDeliveryDispatcher will be in the signaled state in the next + // iteration. + } else if (n == 0) { + // If timeout, return success + return true; + } else { + // We have signaled descriptors + CritScope cr(&crit_); + // Iterate only on the dispatchers whose file descriptors were passed into + // poll; this avoids the ABA problem (a socket being destroyed and a new + // one created with the same file descriptor). + for (size_t i = 0; i < current_dispatcher_keys_.size(); ++i) { + uint64_t key = current_dispatcher_keys_[i]; + if (!dispatcher_by_key_.count(key)) + continue; + ProcessPollEvents(dispatcher_by_key_.at(key), pollfds[i]); + } + } + + if (cmsWait != kForeverMs) { + msWait = TimeDiff(msStop, TimeMillis()); + if (msWait < 0) { + // Return success on timeout. + return true; + } + } + } + + return true; +} + +#endif // WEBRTC_USE_EPOLL, WEBRTC_USE_POLL + +#endif // WEBRTC_POSIX + +#if defined(WEBRTC_WIN) +bool PhysicalSocketServer::Wait(webrtc::TimeDelta max_wait_duration, + bool process_io) { + // We don't support reentrant waiting. + RTC_DCHECK(!waiting_); + ScopedSetTrue s(&waiting_); + + int cmsWait = ToCmsWait(max_wait_duration); + int64_t cmsTotal = cmsWait; + int64_t cmsElapsed = 0; + int64_t msStart = Time(); + + fWait_ = true; + while (fWait_) { + std::vector<WSAEVENT> events; + std::vector<uint64_t> event_owners; + + events.push_back(socket_ev_); + + { + CritScope cr(&crit_); + // Get a snapshot of all current dispatchers; this is used to avoid the + // ABA problem (see later comment) and avoids the dispatcher_by_key_ + // iterator being invalidated by calling CheckSignalClose, which may + // remove the dispatcher from the list. + current_dispatcher_keys_.clear(); + for (auto const& kv : dispatcher_by_key_) { + current_dispatcher_keys_.push_back(kv.first); + } + for (uint64_t key : current_dispatcher_keys_) { + if (!dispatcher_by_key_.count(key)) { + continue; + } + Dispatcher* disp = dispatcher_by_key_.at(key); + if (!disp) + continue; + if (!process_io && (disp != signal_wakeup_)) + continue; + SOCKET s = disp->GetSocket(); + if (disp->CheckSignalClose()) { + // We just signalled close, don't poll this socket. + } else if (s != INVALID_SOCKET) { + WSAEventSelect(s, events[0], + FlagsToEvents(disp->GetRequestedEvents())); + } else { + events.push_back(disp->GetWSAEvent()); + event_owners.push_back(key); + } + } + } + + // Which is shorter, the delay wait or the asked wait? + + int64_t cmsNext; + if (cmsWait == kForeverMs) { + cmsNext = cmsWait; + } else { + cmsNext = std::max<int64_t>(0, cmsTotal - cmsElapsed); + } + + // Wait for one of the events to signal + DWORD dw = + WSAWaitForMultipleEvents(static_cast<DWORD>(events.size()), &events[0], + false, static_cast<DWORD>(cmsNext), false); + + if (dw == WSA_WAIT_FAILED) { + // Failed? + // TODO(pthatcher): need a better strategy than this! + WSAGetLastError(); + RTC_DCHECK_NOTREACHED(); + return false; + } else if (dw == WSA_WAIT_TIMEOUT) { + // Timeout? + return true; + } else { + // Figure out which one it is and call it + CritScope cr(&crit_); + int index = dw - WSA_WAIT_EVENT_0; + if (index > 0) { + --index; // The first event is the socket event + uint64_t key = event_owners[index]; + if (!dispatcher_by_key_.count(key)) { + // The dispatcher could have been removed while waiting for events. + continue; + } + Dispatcher* disp = dispatcher_by_key_.at(key); + disp->OnEvent(0, 0); + } else if (process_io) { + // Iterate only on the dispatchers whose sockets were passed into + // WSAEventSelect; this avoids the ABA problem (a socket being + // destroyed and a new one created with the same SOCKET handle). + for (uint64_t key : current_dispatcher_keys_) { + if (!dispatcher_by_key_.count(key)) { + continue; + } + Dispatcher* disp = dispatcher_by_key_.at(key); + SOCKET s = disp->GetSocket(); + if (s == INVALID_SOCKET) + continue; + + WSANETWORKEVENTS wsaEvents; + int err = WSAEnumNetworkEvents(s, events[0], &wsaEvents); + if (err == 0) { + { + if ((wsaEvents.lNetworkEvents & FD_READ) && + wsaEvents.iErrorCode[FD_READ_BIT] != 0) { + RTC_LOG(LS_WARNING) + << "PhysicalSocketServer got FD_READ_BIT error " + << wsaEvents.iErrorCode[FD_READ_BIT]; + } + if ((wsaEvents.lNetworkEvents & FD_WRITE) && + wsaEvents.iErrorCode[FD_WRITE_BIT] != 0) { + RTC_LOG(LS_WARNING) + << "PhysicalSocketServer got FD_WRITE_BIT error " + << wsaEvents.iErrorCode[FD_WRITE_BIT]; + } + if ((wsaEvents.lNetworkEvents & FD_CONNECT) && + wsaEvents.iErrorCode[FD_CONNECT_BIT] != 0) { + RTC_LOG(LS_WARNING) + << "PhysicalSocketServer got FD_CONNECT_BIT error " + << wsaEvents.iErrorCode[FD_CONNECT_BIT]; + } + if ((wsaEvents.lNetworkEvents & FD_ACCEPT) && + wsaEvents.iErrorCode[FD_ACCEPT_BIT] != 0) { + RTC_LOG(LS_WARNING) + << "PhysicalSocketServer got FD_ACCEPT_BIT error " + << wsaEvents.iErrorCode[FD_ACCEPT_BIT]; + } + if ((wsaEvents.lNetworkEvents & FD_CLOSE) && + wsaEvents.iErrorCode[FD_CLOSE_BIT] != 0) { + RTC_LOG(LS_WARNING) + << "PhysicalSocketServer got FD_CLOSE_BIT error " + << wsaEvents.iErrorCode[FD_CLOSE_BIT]; + } + } + uint32_t ff = 0; + int errcode = 0; + if (wsaEvents.lNetworkEvents & FD_READ) + ff |= DE_READ; + if (wsaEvents.lNetworkEvents & FD_WRITE) + ff |= DE_WRITE; + if (wsaEvents.lNetworkEvents & FD_CONNECT) { + if (wsaEvents.iErrorCode[FD_CONNECT_BIT] == 0) { + ff |= DE_CONNECT; + } else { + ff |= DE_CLOSE; + errcode = wsaEvents.iErrorCode[FD_CONNECT_BIT]; + } + } + if (wsaEvents.lNetworkEvents & FD_ACCEPT) + ff |= DE_ACCEPT; + if (wsaEvents.lNetworkEvents & FD_CLOSE) { + ff |= DE_CLOSE; + errcode = wsaEvents.iErrorCode[FD_CLOSE_BIT]; + } + if (ff != 0) { + disp->OnEvent(ff, errcode); + } + } + } + } + + // Reset the network event until new activity occurs + WSAResetEvent(socket_ev_); + } + + // Break? + if (!fWait_) + break; + cmsElapsed = TimeSince(msStart); + if ((cmsWait != kForeverMs) && (cmsElapsed >= cmsWait)) { + break; + } + } + + // Done + return true; +} +#endif // WEBRTC_WIN + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/physical_socket_server.h b/third_party/libwebrtc/rtc_base/physical_socket_server.h new file mode 100644 index 0000000000..ea449ff121 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/physical_socket_server.h @@ -0,0 +1,310 @@ +/* + * 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 RTC_BASE_PHYSICAL_SOCKET_SERVER_H_ +#define RTC_BASE_PHYSICAL_SOCKET_SERVER_H_ + +#include "api/async_dns_resolver.h" +#include "api/units/time_delta.h" +#include "rtc_base/socket.h" +#include "rtc_base/socket_address.h" +#include "rtc_base/third_party/sigslot/sigslot.h" + +#if defined(WEBRTC_POSIX) +#if defined(WEBRTC_LINUX) +// On Linux, use epoll. +#include <sys/epoll.h> + +#define WEBRTC_USE_EPOLL 1 +#elif defined(WEBRTC_FUCHSIA) +// Fuchsia implements select and poll but not epoll, and testing shows that poll +// is faster than select. +#include <poll.h> + +#define WEBRTC_USE_POLL 1 +#else +// On other POSIX systems, use select by default. +#endif // WEBRTC_LINUX, WEBRTC_FUCHSIA +#endif // WEBRTC_POSIX + +#include <array> +#include <cstdint> +#include <memory> +#include <string> +#include <unordered_map> +#include <vector> + +#include "rtc_base/async_resolver.h" +#include "rtc_base/async_resolver_interface.h" +#include "rtc_base/deprecated/recursive_critical_section.h" +#include "rtc_base/socket_server.h" +#include "rtc_base/synchronization/mutex.h" +#include "rtc_base/system/rtc_export.h" +#include "rtc_base/thread_annotations.h" + +#if defined(WEBRTC_POSIX) +typedef int SOCKET; +#endif // WEBRTC_POSIX + +namespace rtc { + +// Event constants for the Dispatcher class. +enum DispatcherEvent { + DE_READ = 0x0001, + DE_WRITE = 0x0002, + DE_CONNECT = 0x0004, + DE_CLOSE = 0x0008, + DE_ACCEPT = 0x0010, +}; + +class Signaler; + +class Dispatcher { + public: + virtual ~Dispatcher() {} + virtual uint32_t GetRequestedEvents() = 0; + virtual void OnEvent(uint32_t ff, int err) = 0; +#if defined(WEBRTC_WIN) + virtual WSAEVENT GetWSAEvent() = 0; + virtual SOCKET GetSocket() = 0; + virtual bool CheckSignalClose() = 0; +#elif defined(WEBRTC_POSIX) + virtual int GetDescriptor() = 0; + virtual bool IsDescriptorClosed() = 0; +#endif +}; + +// A socket server that provides the real sockets of the underlying OS. +class RTC_EXPORT PhysicalSocketServer : public SocketServer { + public: + PhysicalSocketServer(); + ~PhysicalSocketServer() override; + + // SocketFactory: + Socket* CreateSocket(int family, int type) override; + + // Internal Factory for Accept (virtual so it can be overwritten in tests). + virtual Socket* WrapSocket(SOCKET s); + + // SocketServer: + bool Wait(webrtc::TimeDelta max_wait_duration, bool process_io) override; + void WakeUp() override; + + void Add(Dispatcher* dispatcher); + void Remove(Dispatcher* dispatcher); + void Update(Dispatcher* dispatcher); + + private: + // The number of events to process with one call to "epoll_wait". + static constexpr size_t kNumEpollEvents = 128; + // A local historical definition of "foreverness", in milliseconds. + static constexpr int kForeverMs = -1; + + static int ToCmsWait(webrtc::TimeDelta max_wait_duration); + +#if defined(WEBRTC_POSIX) + bool WaitSelect(int cmsWait, bool process_io); + +#if defined(WEBRTC_USE_EPOLL) + void AddEpoll(Dispatcher* dispatcher, uint64_t key); + void RemoveEpoll(Dispatcher* dispatcher); + void UpdateEpoll(Dispatcher* dispatcher, uint64_t key); + bool WaitEpoll(int cmsWait); + bool WaitPollOneDispatcher(int cmsWait, Dispatcher* dispatcher); + + // This array is accessed in isolation by a thread calling into Wait(). + // It's useless to use a SequenceChecker to guard it because a socket + // server can outlive the thread it's bound to, forcing the Wait call + // to have to reset the sequence checker on Wait calls. + std::array<epoll_event, kNumEpollEvents> epoll_events_; + const int epoll_fd_ = INVALID_SOCKET; + +#elif defined(WEBRTC_USE_POLL) + void AddPoll(Dispatcher* dispatcher, uint64_t key); + void RemovePoll(Dispatcher* dispatcher); + void UpdatePoll(Dispatcher* dispatcher, uint64_t key); + bool WaitPoll(int cmsWait, bool process_io); + +#endif // WEBRTC_USE_EPOLL, WEBRTC_USE_POLL +#endif // WEBRTC_POSIX + + // uint64_t keys are used to uniquely identify a dispatcher in order to avoid + // the ABA problem during the epoll loop (a dispatcher being destroyed and + // replaced by one with the same address). + uint64_t next_dispatcher_key_ RTC_GUARDED_BY(crit_) = 0; + std::unordered_map<uint64_t, Dispatcher*> dispatcher_by_key_ + RTC_GUARDED_BY(crit_); + // Reverse lookup necessary for removals/updates. + std::unordered_map<Dispatcher*, uint64_t> key_by_dispatcher_ + RTC_GUARDED_BY(crit_); + // A list of dispatcher keys that we're interested in for the current + // select(), poll(), or WSAWaitForMultipleEvents() loop. Again, used to avoid + // the ABA problem (a socket being destroyed and a new one created with the + // same handle, erroneously receiving the events from the destroyed socket). + // + // Kept as a member variable just for efficiency. + std::vector<uint64_t> current_dispatcher_keys_; + Signaler* signal_wakeup_; // Assigned in constructor only + RecursiveCriticalSection crit_; +#if defined(WEBRTC_WIN) + const WSAEVENT socket_ev_; +#endif + bool fWait_; + // Are we currently in a select()/epoll()/WSAWaitForMultipleEvents loop? + // Used for a DCHECK, because we don't support reentrant waiting. + bool waiting_ = false; +}; + +class PhysicalSocket : public Socket, public sigslot::has_slots<> { + public: + PhysicalSocket(PhysicalSocketServer* ss, SOCKET s = INVALID_SOCKET); + ~PhysicalSocket() override; + + // Creates the underlying OS socket (same as the "socket" function). + virtual bool Create(int family, int type); + + SocketAddress GetLocalAddress() const override; + SocketAddress GetRemoteAddress() const override; + + int Bind(const SocketAddress& bind_addr) override; + int Connect(const SocketAddress& addr) override; + + int GetError() const override; + void SetError(int error) override; + + ConnState GetState() const override; + + int GetOption(Option opt, int* value) override; + int SetOption(Option opt, int value) override; + + int Send(const void* pv, size_t cb) override; + int SendTo(const void* buffer, + size_t length, + const SocketAddress& addr) override; + + int Recv(void* buffer, size_t length, int64_t* timestamp) override; + int RecvFrom(void* buffer, + size_t length, + SocketAddress* out_addr, + int64_t* timestamp) override; + + int Listen(int backlog) override; + Socket* Accept(SocketAddress* out_addr) override; + + int Close() override; + + SocketServer* socketserver() { return ss_; } + + SOCKET GetSocketFD() const { return s_; } + + protected: + int DoConnect(const SocketAddress& connect_addr); + + // Make virtual so ::accept can be overwritten in tests. + virtual SOCKET DoAccept(SOCKET socket, sockaddr* addr, socklen_t* addrlen); + + // Make virtual so ::send can be overwritten in tests. + virtual int DoSend(SOCKET socket, const char* buf, int len, int flags); + + // Make virtual so ::sendto can be overwritten in tests. + virtual int DoSendTo(SOCKET socket, + const char* buf, + int len, + int flags, + const struct sockaddr* dest_addr, + socklen_t addrlen); + + int DoReadFromSocket(void* buffer, + size_t length, + SocketAddress* out_addr, + int64_t* timestamp); + + void OnResolveResult(const webrtc::AsyncDnsResolverResult& resolver); + + void UpdateLastError(); + void MaybeRemapSendError(); + + uint8_t enabled_events() const { return enabled_events_; } + virtual void SetEnabledEvents(uint8_t events); + virtual void EnableEvents(uint8_t events); + virtual void DisableEvents(uint8_t events); + + int TranslateOption(Option opt, int* slevel, int* sopt); + + PhysicalSocketServer* ss_; + SOCKET s_; + bool udp_; + int family_ = 0; + mutable webrtc::Mutex mutex_; + int error_ RTC_GUARDED_BY(mutex_); + ConnState state_; + std::unique_ptr<webrtc::AsyncDnsResolverInterface> resolver_; + +#if !defined(NDEBUG) + std::string dbg_addr_; +#endif + + private: + const bool read_scm_timestamp_experiment_; + uint8_t enabled_events_ = 0; +}; + +class SocketDispatcher : public Dispatcher, public PhysicalSocket { + public: + explicit SocketDispatcher(PhysicalSocketServer* ss); + SocketDispatcher(SOCKET s, PhysicalSocketServer* ss); + ~SocketDispatcher() override; + + bool Initialize(); + + virtual bool Create(int type); + bool Create(int family, int type) override; + +#if defined(WEBRTC_WIN) + WSAEVENT GetWSAEvent() override; + SOCKET GetSocket() override; + bool CheckSignalClose() override; +#elif defined(WEBRTC_POSIX) + int GetDescriptor() override; + bool IsDescriptorClosed() override; +#endif + + uint32_t GetRequestedEvents() override; + void OnEvent(uint32_t ff, int err) override; + + int Close() override; + +#if defined(WEBRTC_USE_EPOLL) + protected: + void StartBatchedEventUpdates(); + void FinishBatchedEventUpdates(); + + void SetEnabledEvents(uint8_t events) override; + void EnableEvents(uint8_t events) override; + void DisableEvents(uint8_t events) override; +#endif + + private: +#if defined(WEBRTC_WIN) + static int next_id_; + int id_; + bool signal_close_; + int signal_err_; +#endif // WEBRTC_WIN +#if defined(WEBRTC_USE_EPOLL) + void MaybeUpdateDispatcher(uint8_t old_events); + + int saved_enabled_events_ = -1; +#endif +}; + +} // namespace rtc + +#endif // RTC_BASE_PHYSICAL_SOCKET_SERVER_H_ diff --git a/third_party/libwebrtc/rtc_base/physical_socket_server_unittest.cc b/third_party/libwebrtc/rtc_base/physical_socket_server_unittest.cc new file mode 100644 index 0000000000..de64a31812 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/physical_socket_server_unittest.cc @@ -0,0 +1,535 @@ +/* + * 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 "rtc_base/physical_socket_server.h" + +#include <signal.h> + +#include <algorithm> +#include <memory> + +#include "rtc_base/gunit.h" +#include "rtc_base/ip_address.h" +#include "rtc_base/logging.h" +#include "rtc_base/net_helpers.h" +#include "rtc_base/net_test_helpers.h" +#include "rtc_base/network_monitor.h" +#include "rtc_base/socket_unittest.h" +#include "rtc_base/test_utils.h" +#include "rtc_base/thread.h" +#include "test/field_trial.h" +#include "test/gtest.h" + +namespace rtc { + +#define MAYBE_SKIP_IPV4 \ + if (!HasIPv4Enabled()) { \ + RTC_LOG(LS_INFO) << "No IPv4... skipping"; \ + return; \ + } + +#define MAYBE_SKIP_IPV6 \ + if (!HasIPv6Enabled()) { \ + RTC_LOG(LS_INFO) << "No IPv6... skipping"; \ + return; \ + } + +class PhysicalSocketTest; + +class FakeSocketDispatcher : public SocketDispatcher { + public: + explicit FakeSocketDispatcher(PhysicalSocketServer* ss) + : SocketDispatcher(ss) {} + + FakeSocketDispatcher(SOCKET s, PhysicalSocketServer* ss) + : SocketDispatcher(s, ss) {} + + protected: + SOCKET DoAccept(SOCKET socket, sockaddr* addr, socklen_t* addrlen) override; + int DoSend(SOCKET socket, const char* buf, int len, int flags) override; + int DoSendTo(SOCKET socket, + const char* buf, + int len, + int flags, + const struct sockaddr* dest_addr, + socklen_t addrlen) override; +}; + +class FakePhysicalSocketServer : public PhysicalSocketServer { + public: + explicit FakePhysicalSocketServer(PhysicalSocketTest* test) : test_(test) {} + + Socket* CreateSocket(int family, int type) override { + SocketDispatcher* dispatcher = new FakeSocketDispatcher(this); + if (!dispatcher->Create(family, type)) { + delete dispatcher; + return nullptr; + } + return dispatcher; + } + + Socket* WrapSocket(SOCKET s) override { + SocketDispatcher* dispatcher = new FakeSocketDispatcher(s, this); + if (!dispatcher->Initialize()) { + delete dispatcher; + return nullptr; + } + return dispatcher; + } + + PhysicalSocketTest* GetTest() const { return test_; } + + private: + PhysicalSocketTest* test_; +}; + +class FakeNetworkBinder : public NetworkBinderInterface { + public: + NetworkBindingResult BindSocketToNetwork(int, const IPAddress&) override { + ++num_binds_; + return result_; + } + + void set_result(NetworkBindingResult result) { result_ = result; } + + int num_binds() { return num_binds_; } + + private: + NetworkBindingResult result_ = NetworkBindingResult::SUCCESS; + int num_binds_ = 0; +}; + +class PhysicalSocketTest : public SocketTest { + public: + // Set flag to simluate failures when calling "::accept" on a Socket. + void SetFailAccept(bool fail) { fail_accept_ = fail; } + bool FailAccept() const { return fail_accept_; } + + // Maximum size to ::send to a socket. Set to < 0 to disable limiting. + void SetMaxSendSize(int max_size) { max_send_size_ = max_size; } + int MaxSendSize() const { return max_send_size_; } + + protected: + PhysicalSocketTest() + : SocketTest(&server_), + server_(this), + thread_(&server_), + fail_accept_(false), + max_send_size_(-1) {} + + void ConnectInternalAcceptError(const IPAddress& loopback); + void WritableAfterPartialWrite(const IPAddress& loopback); + + FakePhysicalSocketServer server_; + rtc::AutoSocketServerThread thread_; + bool fail_accept_; + int max_send_size_; +}; + +SOCKET FakeSocketDispatcher::DoAccept(SOCKET socket, + sockaddr* addr, + socklen_t* addrlen) { + FakePhysicalSocketServer* ss = + static_cast<FakePhysicalSocketServer*>(socketserver()); + if (ss->GetTest()->FailAccept()) { + return INVALID_SOCKET; + } + + return SocketDispatcher::DoAccept(socket, addr, addrlen); +} + +int FakeSocketDispatcher::DoSend(SOCKET socket, + const char* buf, + int len, + int flags) { + FakePhysicalSocketServer* ss = + static_cast<FakePhysicalSocketServer*>(socketserver()); + if (ss->GetTest()->MaxSendSize() >= 0) { + len = std::min(len, ss->GetTest()->MaxSendSize()); + } + + return SocketDispatcher::DoSend(socket, buf, len, flags); +} + +int FakeSocketDispatcher::DoSendTo(SOCKET socket, + const char* buf, + int len, + int flags, + const struct sockaddr* dest_addr, + socklen_t addrlen) { + FakePhysicalSocketServer* ss = + static_cast<FakePhysicalSocketServer*>(socketserver()); + if (ss->GetTest()->MaxSendSize() >= 0) { + len = std::min(len, ss->GetTest()->MaxSendSize()); + } + + return SocketDispatcher::DoSendTo(socket, buf, len, flags, dest_addr, + addrlen); +} + +TEST_F(PhysicalSocketTest, TestConnectIPv4) { + MAYBE_SKIP_IPV4; + SocketTest::TestConnectIPv4(); +} + +TEST_F(PhysicalSocketTest, TestConnectIPv6) { + SocketTest::TestConnectIPv6(); +} + +TEST_F(PhysicalSocketTest, TestConnectWithDnsLookupIPv4) { + MAYBE_SKIP_IPV4; + SocketTest::TestConnectWithDnsLookupIPv4(); +} + +TEST_F(PhysicalSocketTest, TestConnectWithDnsLookupIPv6) { + SocketTest::TestConnectWithDnsLookupIPv6(); +} + +TEST_F(PhysicalSocketTest, TestConnectFailIPv4) { + MAYBE_SKIP_IPV4; + SocketTest::TestConnectFailIPv4(); +} + +void PhysicalSocketTest::ConnectInternalAcceptError(const IPAddress& loopback) { + webrtc::testing::StreamSink sink; + SocketAddress accept_addr; + + // Create two clients. + std::unique_ptr<Socket> client1( + server_.CreateSocket(loopback.family(), SOCK_STREAM)); + sink.Monitor(client1.get()); + EXPECT_EQ(Socket::CS_CLOSED, client1->GetState()); + EXPECT_TRUE(IsUnspecOrEmptyIP(client1->GetLocalAddress().ipaddr())); + + std::unique_ptr<Socket> client2( + server_.CreateSocket(loopback.family(), SOCK_STREAM)); + sink.Monitor(client2.get()); + EXPECT_EQ(Socket::CS_CLOSED, client2->GetState()); + EXPECT_TRUE(IsUnspecOrEmptyIP(client2->GetLocalAddress().ipaddr())); + + // Create server and listen. + std::unique_ptr<Socket> server( + server_.CreateSocket(loopback.family(), SOCK_STREAM)); + sink.Monitor(server.get()); + EXPECT_EQ(0, server->Bind(SocketAddress(loopback, 0))); + EXPECT_EQ(0, server->Listen(5)); + EXPECT_EQ(Socket::CS_CONNECTING, server->GetState()); + + // Ensure no pending server connections, since we haven't done anything yet. + EXPECT_FALSE(sink.Check(server.get(), webrtc::testing::SSE_READ)); + EXPECT_TRUE(nullptr == server->Accept(&accept_addr)); + EXPECT_TRUE(accept_addr.IsNil()); + + // Attempt first connect to listening socket. + EXPECT_EQ(0, client1->Connect(server->GetLocalAddress())); + EXPECT_FALSE(client1->GetLocalAddress().IsNil()); + EXPECT_NE(server->GetLocalAddress(), client1->GetLocalAddress()); + + // Client is connecting, outcome not yet determined. + EXPECT_EQ(Socket::CS_CONNECTING, client1->GetState()); + EXPECT_FALSE(sink.Check(client1.get(), webrtc::testing::SSE_OPEN)); + EXPECT_FALSE(sink.Check(client1.get(), webrtc::testing::SSE_CLOSE)); + + // Server has pending connection, try to accept it (will fail). + EXPECT_TRUE_WAIT((sink.Check(server.get(), webrtc::testing::SSE_READ)), + kTimeout); + // Simulate "::accept" returning an error. + SetFailAccept(true); + std::unique_ptr<Socket> accepted(server->Accept(&accept_addr)); + EXPECT_FALSE(accepted); + ASSERT_TRUE(accept_addr.IsNil()); + + // Ensure no more pending server connections. + EXPECT_FALSE(sink.Check(server.get(), webrtc::testing::SSE_READ)); + EXPECT_TRUE(nullptr == server->Accept(&accept_addr)); + EXPECT_TRUE(accept_addr.IsNil()); + + // Attempt second connect to listening socket. + EXPECT_EQ(0, client2->Connect(server->GetLocalAddress())); + EXPECT_FALSE(client2->GetLocalAddress().IsNil()); + EXPECT_NE(server->GetLocalAddress(), client2->GetLocalAddress()); + + // Client is connecting, outcome not yet determined. + EXPECT_EQ(Socket::CS_CONNECTING, client2->GetState()); + EXPECT_FALSE(sink.Check(client2.get(), webrtc::testing::SSE_OPEN)); + EXPECT_FALSE(sink.Check(client2.get(), webrtc::testing::SSE_CLOSE)); + + // Server has pending connection, try to accept it (will succeed). + EXPECT_TRUE_WAIT((sink.Check(server.get(), webrtc::testing::SSE_READ)), + kTimeout); + SetFailAccept(false); + std::unique_ptr<Socket> accepted2(server->Accept(&accept_addr)); + ASSERT_TRUE(accepted2); + EXPECT_FALSE(accept_addr.IsNil()); + EXPECT_EQ(accepted2->GetRemoteAddress(), accept_addr); +} + +TEST_F(PhysicalSocketTest, TestConnectAcceptErrorIPv4) { + MAYBE_SKIP_IPV4; + ConnectInternalAcceptError(kIPv4Loopback); +} + +TEST_F(PhysicalSocketTest, TestConnectAcceptErrorIPv6) { + MAYBE_SKIP_IPV6; + ConnectInternalAcceptError(kIPv6Loopback); +} + +void PhysicalSocketTest::WritableAfterPartialWrite(const IPAddress& loopback) { + // Simulate a really small maximum send size. + const int kMaxSendSize = 128; + SetMaxSendSize(kMaxSendSize); + + // Run the default send/receive socket tests with a smaller amount of data + // to avoid long running times due to the small maximum send size. + const size_t kDataSize = 128 * 1024; + TcpInternal(loopback, kDataSize, kMaxSendSize); +} + +// https://bugs.chromium.org/p/webrtc/issues/detail?id=6167 +#if defined(WEBRTC_WIN) +#define MAYBE_TestWritableAfterPartialWriteIPv4 \ + DISABLED_TestWritableAfterPartialWriteIPv4 +#else +#define MAYBE_TestWritableAfterPartialWriteIPv4 \ + TestWritableAfterPartialWriteIPv4 +#endif +TEST_F(PhysicalSocketTest, MAYBE_TestWritableAfterPartialWriteIPv4) { + MAYBE_SKIP_IPV4; + WritableAfterPartialWrite(kIPv4Loopback); +} + +// https://bugs.chromium.org/p/webrtc/issues/detail?id=6167 +#if defined(WEBRTC_WIN) +#define MAYBE_TestWritableAfterPartialWriteIPv6 \ + DISABLED_TestWritableAfterPartialWriteIPv6 +#else +#define MAYBE_TestWritableAfterPartialWriteIPv6 \ + TestWritableAfterPartialWriteIPv6 +#endif +TEST_F(PhysicalSocketTest, MAYBE_TestWritableAfterPartialWriteIPv6) { + MAYBE_SKIP_IPV6; + WritableAfterPartialWrite(kIPv6Loopback); +} + +TEST_F(PhysicalSocketTest, TestConnectFailIPv6) { + SocketTest::TestConnectFailIPv6(); +} + +TEST_F(PhysicalSocketTest, TestConnectWithDnsLookupFailIPv4) { + MAYBE_SKIP_IPV4; + SocketTest::TestConnectWithDnsLookupFailIPv4(); +} + +TEST_F(PhysicalSocketTest, TestConnectWithDnsLookupFailIPv6) { + SocketTest::TestConnectWithDnsLookupFailIPv6(); +} + +TEST_F(PhysicalSocketTest, TestConnectWithClosedSocketIPv4) { + MAYBE_SKIP_IPV4; + SocketTest::TestConnectWithClosedSocketIPv4(); +} + +TEST_F(PhysicalSocketTest, TestConnectWithClosedSocketIPv6) { + SocketTest::TestConnectWithClosedSocketIPv6(); +} + +TEST_F(PhysicalSocketTest, TestConnectWhileNotClosedIPv4) { + MAYBE_SKIP_IPV4; + SocketTest::TestConnectWhileNotClosedIPv4(); +} + +TEST_F(PhysicalSocketTest, TestConnectWhileNotClosedIPv6) { + SocketTest::TestConnectWhileNotClosedIPv6(); +} + +TEST_F(PhysicalSocketTest, TestServerCloseDuringConnectIPv4) { + MAYBE_SKIP_IPV4; + SocketTest::TestServerCloseDuringConnectIPv4(); +} + +TEST_F(PhysicalSocketTest, TestServerCloseDuringConnectIPv6) { + SocketTest::TestServerCloseDuringConnectIPv6(); +} + +TEST_F(PhysicalSocketTest, TestClientCloseDuringConnectIPv4) { + MAYBE_SKIP_IPV4; + SocketTest::TestClientCloseDuringConnectIPv4(); +} + +TEST_F(PhysicalSocketTest, TestClientCloseDuringConnectIPv6) { + SocketTest::TestClientCloseDuringConnectIPv6(); +} + +TEST_F(PhysicalSocketTest, TestServerCloseIPv4) { + MAYBE_SKIP_IPV4; + SocketTest::TestServerCloseIPv4(); +} + +TEST_F(PhysicalSocketTest, TestServerCloseIPv6) { + SocketTest::TestServerCloseIPv6(); +} + +TEST_F(PhysicalSocketTest, TestCloseInClosedCallbackIPv4) { + MAYBE_SKIP_IPV4; + SocketTest::TestCloseInClosedCallbackIPv4(); +} + +TEST_F(PhysicalSocketTest, TestCloseInClosedCallbackIPv6) { + SocketTest::TestCloseInClosedCallbackIPv6(); +} + +TEST_F(PhysicalSocketTest, TestDeleteInReadCallbackIPv4) { + MAYBE_SKIP_IPV4; + SocketTest::TestDeleteInReadCallbackIPv4(); +} + +TEST_F(PhysicalSocketTest, TestDeleteInReadCallbackIPv6) { + SocketTest::TestDeleteInReadCallbackIPv6(); +} + +TEST_F(PhysicalSocketTest, TestSocketServerWaitIPv4) { + MAYBE_SKIP_IPV4; + SocketTest::TestSocketServerWaitIPv4(); +} + +TEST_F(PhysicalSocketTest, TestSocketServerWaitIPv6) { + SocketTest::TestSocketServerWaitIPv6(); +} + +TEST_F(PhysicalSocketTest, TestTcpIPv4) { + MAYBE_SKIP_IPV4; + SocketTest::TestTcpIPv4(); +} + +TEST_F(PhysicalSocketTest, TestTcpIPv6) { + SocketTest::TestTcpIPv6(); +} + +TEST_F(PhysicalSocketTest, TestUdpIPv4) { + MAYBE_SKIP_IPV4; + SocketTest::TestUdpIPv4(); +} + +TEST_F(PhysicalSocketTest, TestUdpIPv6) { + SocketTest::TestUdpIPv6(); +} + +// Disable for TSan v2, see +// https://code.google.com/p/webrtc/issues/detail?id=3498 for details. +// Also disable for MSan, see: +// https://code.google.com/p/webrtc/issues/detail?id=4958 +// TODO(deadbeef): Enable again once test is reimplemented to be unflaky. +// Also disable for ASan. +// Disabled on Android: https://code.google.com/p/webrtc/issues/detail?id=4364 +// Disabled on Linux: https://bugs.chromium.org/p/webrtc/issues/detail?id=5233 +#if defined(THREAD_SANITIZER) || defined(MEMORY_SANITIZER) || \ + defined(ADDRESS_SANITIZER) || defined(WEBRTC_ANDROID) || \ + defined(WEBRTC_LINUX) +#define MAYBE_TestUdpReadyToSendIPv4 DISABLED_TestUdpReadyToSendIPv4 +#else +#define MAYBE_TestUdpReadyToSendIPv4 TestUdpReadyToSendIPv4 +#endif +TEST_F(PhysicalSocketTest, MAYBE_TestUdpReadyToSendIPv4) { + MAYBE_SKIP_IPV4; + SocketTest::TestUdpReadyToSendIPv4(); +} + +// https://bugs.chromium.org/p/webrtc/issues/detail?id=6167 +#if defined(WEBRTC_WIN) +#define MAYBE_TestUdpReadyToSendIPv6 DISABLED_TestUdpReadyToSendIPv6 +#else +#define MAYBE_TestUdpReadyToSendIPv6 TestUdpReadyToSendIPv6 +#endif +TEST_F(PhysicalSocketTest, MAYBE_TestUdpReadyToSendIPv6) { + SocketTest::TestUdpReadyToSendIPv6(); +} + +TEST_F(PhysicalSocketTest, TestGetSetOptionsIPv4) { + MAYBE_SKIP_IPV4; + SocketTest::TestGetSetOptionsIPv4(); +} + +TEST_F(PhysicalSocketTest, TestGetSetOptionsIPv6) { + SocketTest::TestGetSetOptionsIPv6(); +} + +#if defined(WEBRTC_POSIX) + +TEST_F(PhysicalSocketTest, TestSocketRecvTimestampIPv4) { + MAYBE_SKIP_IPV4; + SocketTest::TestSocketRecvTimestampIPv4(); +} + +TEST_F(PhysicalSocketTest, TestSocketRecvTimestampIPv6) { + SocketTest::TestSocketRecvTimestampIPv6(); +} + +#if !defined(WEBRTC_MAC) +TEST_F(PhysicalSocketTest, TestSocketRecvTimestampIPv4ScmExperimentDisabled) { + MAYBE_SKIP_IPV4; + webrtc::test::ScopedFieldTrials trial("WebRTC-SCM-Timestamp/Disabled/"); + SocketTest::TestSocketRecvTimestampIPv4(); +} + +TEST_F(PhysicalSocketTest, TestSocketRecvTimestampIPv6ScmExperimentDisabled) { + webrtc::test::ScopedFieldTrials trial("WebRTC-SCM-Timestamp/Disabled/"); + SocketTest::TestSocketRecvTimestampIPv6(); +} +#endif + +// Verify that if the socket was unable to be bound to a real network interface +// (not loopback), Bind will return an error. +TEST_F(PhysicalSocketTest, + BindFailsIfNetworkBinderFailsForNonLoopbackInterface) { + MAYBE_SKIP_IPV4; + FakeNetworkBinder fake_network_binder; + server_.set_network_binder(&fake_network_binder); + std::unique_ptr<Socket> socket(server_.CreateSocket(AF_INET, SOCK_DGRAM)); + fake_network_binder.set_result(NetworkBindingResult::FAILURE); + EXPECT_EQ(-1, socket->Bind(SocketAddress("192.168.0.1", 0))); + server_.set_network_binder(nullptr); +} + +// Network binder shouldn't be used if the socket is bound to the "any" IP. +TEST_F(PhysicalSocketTest, NetworkBinderIsNotUsedForAnyIp) { + MAYBE_SKIP_IPV4; + FakeNetworkBinder fake_network_binder; + server_.set_network_binder(&fake_network_binder); + std::unique_ptr<Socket> socket(server_.CreateSocket(AF_INET, SOCK_DGRAM)); + EXPECT_EQ(0, socket->Bind(SocketAddress("0.0.0.0", 0))); + EXPECT_EQ(0, fake_network_binder.num_binds()); + server_.set_network_binder(nullptr); +} + +// For a loopback interface, failures to bind to the interface should be +// tolerated. +TEST_F(PhysicalSocketTest, + BindSucceedsIfNetworkBinderFailsForLoopbackInterface) { + MAYBE_SKIP_IPV4; + FakeNetworkBinder fake_network_binder; + server_.set_network_binder(&fake_network_binder); + std::unique_ptr<Socket> socket(server_.CreateSocket(AF_INET, SOCK_DGRAM)); + fake_network_binder.set_result(NetworkBindingResult::FAILURE); + EXPECT_EQ(0, socket->Bind(SocketAddress(kIPv4Loopback, 0))); + server_.set_network_binder(nullptr); +} + +#endif + +TEST_F(PhysicalSocketTest, UdpSocketRecvTimestampUseRtcEpochIPv4) { + MAYBE_SKIP_IPV4; + SocketTest::TestUdpSocketRecvTimestampUseRtcEpochIPv4(); +} + +TEST_F(PhysicalSocketTest, UdpSocketRecvTimestampUseRtcEpochIPv6) { + SocketTest::TestUdpSocketRecvTimestampUseRtcEpochIPv6(); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/platform_thread.cc b/third_party/libwebrtc/rtc_base/platform_thread.cc new file mode 100644 index 0000000000..bcbb784b97 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/platform_thread.cc @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2015 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 "rtc_base/platform_thread.h" + +#include <algorithm> +#include <memory> + +#if !defined(WEBRTC_WIN) +#include <sched.h> +#endif + +#include "rtc_base/checks.h" + +#include "MicroGeckoProfiler.h" + +namespace rtc { +namespace { + +#if defined(WEBRTC_WIN) +int Win32PriorityFromThreadPriority(ThreadPriority priority) { + switch (priority) { + case ThreadPriority::kLow: + return THREAD_PRIORITY_BELOW_NORMAL; + case ThreadPriority::kNormal: + return THREAD_PRIORITY_NORMAL; + case ThreadPriority::kHigh: + return THREAD_PRIORITY_ABOVE_NORMAL; + case ThreadPriority::kRealtime: + return THREAD_PRIORITY_TIME_CRITICAL; + } +} +#endif + +bool SetPriority(ThreadPriority priority) { +#if defined(WEBRTC_WIN) + return SetThreadPriority(GetCurrentThread(), + Win32PriorityFromThreadPriority(priority)) != FALSE; +#elif defined(__native_client__) || defined(WEBRTC_FUCHSIA) + // Setting thread priorities is not supported in NaCl or Fuchsia. + return true; +#elif defined(WEBRTC_CHROMIUM_BUILD) && defined(WEBRTC_LINUX) + // TODO(tommi): Switch to the same mechanism as Chromium uses for changing + // thread priorities. + return true; +#elif defined(WEBRTC_MOZILLA_BUILD) && defined(WEBRTC_LINUX) + // Only realtime audio uses realtime scheduling in Firefox. + return true; +#else + const int policy = SCHED_FIFO; + const int min_prio = sched_get_priority_min(policy); + const int max_prio = sched_get_priority_max(policy); + if (min_prio == -1 || max_prio == -1) { + return false; + } + + if (max_prio - min_prio <= 2) + return false; + + // Convert webrtc priority to system priorities: + sched_param param; + const int top_prio = max_prio - 1; + const int low_prio = min_prio + 1; + switch (priority) { + case ThreadPriority::kLow: + param.sched_priority = low_prio; + break; + case ThreadPriority::kNormal: + // The -1 ensures that the kHighPriority is always greater or equal to + // kNormalPriority. + param.sched_priority = (low_prio + top_prio - 1) / 2; + break; + case ThreadPriority::kHigh: + param.sched_priority = std::max(top_prio - 2, low_prio); + break; + case ThreadPriority::kRealtime: + param.sched_priority = top_prio; + break; + } + return pthread_setschedparam(pthread_self(), policy, ¶m) == 0; +#endif // defined(WEBRTC_WIN) +} + +#if defined(WEBRTC_WIN) +DWORD WINAPI RunPlatformThread(void* param) { + // The GetLastError() function only returns valid results when it is called + // after a Win32 API function that returns a "failed" result. A crash dump + // contains the result from GetLastError() and to make sure it does not + // falsely report a Windows error we call SetLastError here. + ::SetLastError(ERROR_SUCCESS); + auto function = static_cast<std::function<void()>*>(param); + (*function)(); + delete function; + return 0; +} +#else +void* RunPlatformThread(void* param) { + auto function = static_cast<std::function<void()>*>(param); + (*function)(); + delete function; + return 0; +} +#endif // defined(WEBRTC_WIN) + +} // namespace + +PlatformThread::PlatformThread(Handle handle, bool joinable) + : handle_(handle), joinable_(joinable) {} + +PlatformThread::PlatformThread(PlatformThread&& rhs) + : handle_(rhs.handle_), joinable_(rhs.joinable_) { + rhs.handle_ = absl::nullopt; +} + +PlatformThread& PlatformThread::operator=(PlatformThread&& rhs) { + Finalize(); + handle_ = rhs.handle_; + joinable_ = rhs.joinable_; + rhs.handle_ = absl::nullopt; + return *this; +} + +PlatformThread::~PlatformThread() { + Finalize(); +} + +PlatformThread PlatformThread::SpawnJoinable( + std::function<void()> thread_function, + absl::string_view name, + ThreadAttributes attributes) { + return SpawnThread(std::move(thread_function), name, attributes, + /*joinable=*/true); +} + +PlatformThread PlatformThread::SpawnDetached( + std::function<void()> thread_function, + absl::string_view name, + ThreadAttributes attributes) { + return SpawnThread(std::move(thread_function), name, attributes, + /*joinable=*/false); +} + +absl::optional<PlatformThread::Handle> PlatformThread::GetHandle() const { + return handle_; +} + +#if defined(WEBRTC_WIN) +bool PlatformThread::QueueAPC(PAPCFUNC function, ULONG_PTR data) { + RTC_DCHECK(handle_.has_value()); + return handle_.has_value() ? QueueUserAPC(function, *handle_, data) != FALSE + : false; +} +#endif + +void PlatformThread::Finalize() { + if (!handle_.has_value()) + return; +#if defined(WEBRTC_WIN) + if (joinable_) + WaitForSingleObject(*handle_, INFINITE); + CloseHandle(*handle_); +#else + if (joinable_) + RTC_CHECK_EQ(0, pthread_join(*handle_, nullptr)); +#endif + handle_ = absl::nullopt; +} + +PlatformThread PlatformThread::SpawnThread( + std::function<void()> thread_function, + absl::string_view name, + ThreadAttributes attributes, + bool joinable) { + RTC_DCHECK(thread_function); + RTC_DCHECK(!name.empty()); + // TODO(tommi): Consider lowering the limit to 15 (limit on Linux). + RTC_DCHECK(name.length() < 64); + auto start_thread_function_ptr = + new std::function<void()>([thread_function = std::move(thread_function), + name = std::string(name), attributes] { + rtc::SetCurrentThreadName(name.c_str()); + + char stacktop; + AutoRegisterProfiler profiler(name.c_str(), &stacktop); + + SetPriority(attributes.priority); + thread_function(); + }); +#if defined(WEBRTC_WIN) + // See bug 2902 for background on STACK_SIZE_PARAM_IS_A_RESERVATION. + // Set the reserved stack stack size to 1M, which is the default on Windows + // and Linux. + DWORD thread_id = 0; + // Mozilla: Set to 256kb for consistency with nsIThreadManager.idl + PlatformThread::Handle handle = ::CreateThread( + nullptr, 256 * 1024, &RunPlatformThread, start_thread_function_ptr, + STACK_SIZE_PARAM_IS_A_RESERVATION, &thread_id); + RTC_CHECK(handle) << "CreateThread failed"; +#else + pthread_attr_t attr; + pthread_attr_init(&attr); + // Set the stack stack size to 1M. + // Mozilla: Set to 256kb for consistency with nsIThreadManager.idl + pthread_attr_setstacksize(&attr, 256 * 1024); + pthread_attr_setdetachstate( + &attr, joinable ? PTHREAD_CREATE_JOINABLE : PTHREAD_CREATE_DETACHED); + PlatformThread::Handle handle; + RTC_CHECK_EQ(0, pthread_create(&handle, &attr, &RunPlatformThread, + start_thread_function_ptr)); + pthread_attr_destroy(&attr); +#endif // defined(WEBRTC_WIN) + return PlatformThread(handle, joinable); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/platform_thread.h b/third_party/libwebrtc/rtc_base/platform_thread.h new file mode 100644 index 0000000000..5b7c6884fe --- /dev/null +++ b/third_party/libwebrtc/rtc_base/platform_thread.h @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2015 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 RTC_BASE_PLATFORM_THREAD_H_ +#define RTC_BASE_PLATFORM_THREAD_H_ + +#include <functional> +#include <string> +#if !defined(WEBRTC_WIN) +#include <pthread.h> +#endif + +#include "absl/strings/string_view.h" +#include "absl/types/optional.h" +#include "rtc_base/platform_thread_types.h" + +#include "rtc_base/deprecated/recursive_critical_section.h" + +namespace rtc { + +// Bug 1691641 +class PlatformUIThread; + +enum class ThreadPriority { + kLow = 1, + kNormal, + kHigh, + kRealtime, +}; + +struct ThreadAttributes { + ThreadPriority priority = ThreadPriority::kNormal; + ThreadAttributes& SetPriority(ThreadPriority priority_param) { + priority = priority_param; + return *this; + } +}; + +// Represents a simple worker thread. +class PlatformThread final { + public: + // Handle is the base platform thread handle. +#if defined(WEBRTC_WIN) + using Handle = HANDLE; +#else + using Handle = pthread_t; +#endif // defined(WEBRTC_WIN) + // This ctor creates the PlatformThread with an unset handle (returning true + // in empty()) and is provided for convenience. + // TODO(bugs.webrtc.org/12727) Look into if default and move support can be + // removed. + PlatformThread() = default; + + // Moves `rhs` into this, storing an empty state in `rhs`. + // TODO(bugs.webrtc.org/12727) Look into if default and move support can be + // removed. + PlatformThread(PlatformThread&& rhs); + + // Copies won't work since we'd have problems with joinable threads. + PlatformThread(const PlatformThread&) = delete; + PlatformThread& operator=(const PlatformThread&) = delete; + + // Moves `rhs` into this, storing an empty state in `rhs`. + // TODO(bugs.webrtc.org/12727) Look into if default and move support can be + // removed. + PlatformThread& operator=(PlatformThread&& rhs); + + // For a PlatformThread that's been spawned joinable, the destructor suspends + // the calling thread until the created thread exits unless the thread has + // already exited. + virtual ~PlatformThread(); + + // Finalizes any allocated resources. + // For a PlatformThread that's been spawned joinable, Finalize() suspends + // the calling thread until the created thread exits unless the thread has + // already exited. + // empty() returns true after completion. + void Finalize(); + + // Returns true if default constructed, moved from, or Finalize()ed. + bool empty() const { return !handle_.has_value(); } + + // Creates a started joinable thread which will be joined when the returned + // PlatformThread destructs or Finalize() is called. + static PlatformThread SpawnJoinable( + std::function<void()> thread_function, + absl::string_view name, + ThreadAttributes attributes = ThreadAttributes()); + + // Creates a started detached thread. The caller has to use external + // synchronization as nothing is provided by the PlatformThread construct. + static PlatformThread SpawnDetached( + std::function<void()> thread_function, + absl::string_view name, + ThreadAttributes attributes = ThreadAttributes()); + + // Returns the base platform thread handle of this thread. + absl::optional<Handle> GetHandle() const; + +#if defined(WEBRTC_WIN) + // Queue a Windows APC function that runs when the thread is alertable. + bool QueueAPC(PAPCFUNC apc_function, ULONG_PTR data); +#endif + + private: + PlatformThread(Handle handle, bool joinable); + static PlatformThread SpawnThread(std::function<void()> thread_function, + absl::string_view name, + ThreadAttributes attributes, + bool joinable); + + absl::optional<Handle> handle_; + bool joinable_ = false; + // Bug 1691641 + friend PlatformUIThread; +}; + +} // namespace rtc + +#endif // RTC_BASE_PLATFORM_THREAD_H_ diff --git a/third_party/libwebrtc/rtc_base/platform_thread_gn/moz.build b/third_party/libwebrtc/rtc_base/platform_thread_gn/moz.build new file mode 100644 index 0000000000..6e962e3280 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/platform_thread_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/rtc_base/platform_thread.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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("platform_thread_gn") diff --git a/third_party/libwebrtc/rtc_base/platform_thread_types.cc b/third_party/libwebrtc/rtc_base/platform_thread_types.cc new file mode 100644 index 0000000000..c3c6955a7b --- /dev/null +++ b/third_party/libwebrtc/rtc_base/platform_thread_types.cc @@ -0,0 +1,128 @@ +/* + * 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 "rtc_base/platform_thread_types.h" + +#if defined(WEBRTC_LINUX) +#include <sys/prctl.h> +#include <sys/syscall.h> +#endif + +#if defined(WEBRTC_WIN) +#include "rtc_base/arraysize.h" + +// The SetThreadDescription API was brought in version 1607 of Windows 10. +// For compatibility with various versions of winuser and avoid clashing with +// a potentially defined type, we use the RTC_ prefix. +typedef HRESULT(WINAPI* RTC_SetThreadDescription)(HANDLE hThread, + PCWSTR lpThreadDescription); +#endif + +#if defined(WEBRTC_FUCHSIA) +#include <string.h> +#include <zircon/syscalls.h> + +#include "rtc_base/checks.h" +#endif + +namespace rtc { + +PlatformThreadId CurrentThreadId() { +#if defined(WEBRTC_WIN) + return GetCurrentThreadId(); +#elif defined(WEBRTC_POSIX) +#if defined(WEBRTC_MAC) || defined(WEBRTC_IOS) + return pthread_mach_thread_np(pthread_self()); +#elif defined(WEBRTC_ANDROID) + return gettid(); +#elif defined(WEBRTC_FUCHSIA) + return zx_thread_self(); +#elif defined(WEBRTC_LINUX) + return syscall(__NR_gettid); +#elif defined(__EMSCRIPTEN__) + return static_cast<PlatformThreadId>(pthread_self()); +#else + // Default implementation for nacl and solaris. + // WEBRTC_BSD: pthread_t is a pointer, so cannot be casted to pid_t + // (aka int32_t) on 64-bit archs. Required on OpenBSD. + return reinterpret_cast<long>(pthread_self()); +#endif +#endif // defined(WEBRTC_POSIX) +} + +PlatformThreadRef CurrentThreadRef() { +#if defined(WEBRTC_WIN) + return GetCurrentThreadId(); +#elif defined(WEBRTC_FUCHSIA) + return zx_thread_self(); +#elif defined(WEBRTC_POSIX) + return pthread_self(); +#endif +} + +bool IsThreadRefEqual(const PlatformThreadRef& a, const PlatformThreadRef& b) { +#if defined(WEBRTC_WIN) || defined(WEBRTC_FUCHSIA) + return a == b; +#elif defined(WEBRTC_POSIX) + return pthread_equal(a, b); +#endif +} + +void SetCurrentThreadName(const char* name) { +#if defined(WEBRTC_WIN) + // The SetThreadDescription API works even if no debugger is attached. + // The names set with this API also show up in ETW traces. Very handy. + static auto set_thread_description_func = + reinterpret_cast<RTC_SetThreadDescription>(::GetProcAddress( + ::GetModuleHandleA("Kernel32.dll"), "SetThreadDescription")); + if (set_thread_description_func) { + // Convert from ASCII to UTF-16. + wchar_t wide_thread_name[64]; + for (size_t i = 0; i < arraysize(wide_thread_name) - 1; ++i) { + wide_thread_name[i] = name[i]; + if (wide_thread_name[i] == L'\0') + break; + } + // Guarantee null-termination. + wide_thread_name[arraysize(wide_thread_name) - 1] = L'\0'; + set_thread_description_func(::GetCurrentThread(), wide_thread_name); + } + + // For details see: + // https://docs.microsoft.com/en-us/visualstudio/debugger/how-to-set-a-thread-name-in-native-code +#pragma pack(push, 8) + struct { + DWORD dwType; + LPCSTR szName; + DWORD dwThreadID; + DWORD dwFlags; + } threadname_info = {0x1000, name, static_cast<DWORD>(-1), 0}; +#pragma pack(pop) + +#pragma warning(push) +#pragma warning(disable : 6320 6322) + __try { + ::RaiseException(0x406D1388, 0, sizeof(threadname_info) / sizeof(ULONG_PTR), + reinterpret_cast<ULONG_PTR*>(&threadname_info)); + } __except (EXCEPTION_EXECUTE_HANDLER) { // NOLINT + } +#pragma warning(pop) +#elif defined(WEBRTC_LINUX) || defined(WEBRTC_ANDROID) + prctl(PR_SET_NAME, reinterpret_cast<unsigned long>(name)); // NOLINT +#elif defined(WEBRTC_MAC) || defined(WEBRTC_IOS) + pthread_setname_np(name); +#elif defined(WEBRTC_FUCHSIA) + zx_status_t status = zx_object_set_property(zx_thread_self(), ZX_PROP_NAME, + name, strlen(name)); + RTC_DCHECK_EQ(status, ZX_OK); +#endif +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/platform_thread_types.h b/third_party/libwebrtc/rtc_base/platform_thread_types.h new file mode 100644 index 0000000000..6b9101eec0 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/platform_thread_types.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2015 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 RTC_BASE_PLATFORM_THREAD_TYPES_H_ +#define RTC_BASE_PLATFORM_THREAD_TYPES_H_ + +// clang-format off +// clang formating would change include order. +#if defined(WEBRTC_WIN) +// Include winsock2.h before including <windows.h> to maintain consistency with +// win32.h. To include win32.h directly, it must be broken out into its own +// build target. +#include <winsock2.h> +#include <windows.h> +#elif defined(WEBRTC_FUCHSIA) +#include <zircon/types.h> +#include <zircon/process.h> +#elif defined(WEBRTC_POSIX) +#include <pthread.h> +#include <unistd.h> +#if defined(WEBRTC_MAC) +#include <pthread_spis.h> +#endif +#endif +// clang-format on + +namespace rtc { +#if defined(WEBRTC_WIN) +typedef DWORD PlatformThreadId; +typedef DWORD PlatformThreadRef; +#elif defined(WEBRTC_FUCHSIA) +typedef zx_handle_t PlatformThreadId; +typedef zx_handle_t PlatformThreadRef; +#elif defined(WEBRTC_POSIX) +typedef pid_t PlatformThreadId; +typedef pthread_t PlatformThreadRef; +#endif + +// Retrieve the ID of the current thread. +PlatformThreadId CurrentThreadId(); + +// Retrieves a reference to the current thread. On Windows, this is the same +// as CurrentThreadId. On other platforms it's the pthread_t returned by +// pthread_self(). +PlatformThreadRef CurrentThreadRef(); + +// Compares two thread identifiers for equality. +bool IsThreadRefEqual(const PlatformThreadRef& a, const PlatformThreadRef& b); + +// Sets the current thread name. +void SetCurrentThreadName(const char* name); + +} // namespace rtc + +#endif // RTC_BASE_PLATFORM_THREAD_TYPES_H_ diff --git a/third_party/libwebrtc/rtc_base/platform_thread_types_gn/moz.build b/third_party/libwebrtc/rtc_base/platform_thread_types_gn/moz.build new file mode 100644 index 0000000000..0e817e6eb9 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/platform_thread_types_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/rtc_base/platform_thread_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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("platform_thread_types_gn") diff --git a/third_party/libwebrtc/rtc_base/platform_thread_unittest.cc b/third_party/libwebrtc/rtc_base/platform_thread_unittest.cc new file mode 100644 index 0000000000..97b25e02e2 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/platform_thread_unittest.cc @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2012 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 "rtc_base/platform_thread.h" + +#include "absl/types/optional.h" +#include "rtc_base/event.h" +#include "system_wrappers/include/sleep.h" +#include "test/gmock.h" + +namespace rtc { + +TEST(PlatformThreadTest, DefaultConstructedIsEmpty) { + PlatformThread thread; + EXPECT_EQ(thread.GetHandle(), absl::nullopt); + EXPECT_TRUE(thread.empty()); +} + +TEST(PlatformThreadTest, StartFinalize) { + PlatformThread thread = PlatformThread::SpawnJoinable([] {}, "1"); + EXPECT_NE(thread.GetHandle(), absl::nullopt); + EXPECT_FALSE(thread.empty()); + thread.Finalize(); + EXPECT_TRUE(thread.empty()); + rtc::Event done; + thread = PlatformThread::SpawnDetached([&] { done.Set(); }, "2"); + EXPECT_FALSE(thread.empty()); + thread.Finalize(); + EXPECT_TRUE(thread.empty()); + done.Wait(webrtc::TimeDelta::Seconds(30)); +} + +TEST(PlatformThreadTest, MovesEmpty) { + PlatformThread thread1; + PlatformThread thread2 = std::move(thread1); + EXPECT_TRUE(thread1.empty()); + EXPECT_TRUE(thread2.empty()); +} + +TEST(PlatformThreadTest, MovesHandles) { + PlatformThread thread1 = PlatformThread::SpawnJoinable([] {}, "1"); + PlatformThread thread2 = std::move(thread1); + EXPECT_TRUE(thread1.empty()); + EXPECT_FALSE(thread2.empty()); + rtc::Event done; + thread1 = PlatformThread::SpawnDetached([&] { done.Set(); }, "2"); + thread2 = std::move(thread1); + EXPECT_TRUE(thread1.empty()); + EXPECT_FALSE(thread2.empty()); + done.Wait(webrtc::TimeDelta::Seconds(30)); +} + +TEST(PlatformThreadTest, + TwoThreadHandlesAreDifferentWhenStartedAndEqualWhenJoined) { + PlatformThread thread1 = PlatformThread(); + PlatformThread thread2 = PlatformThread(); + EXPECT_EQ(thread1.GetHandle(), thread2.GetHandle()); + thread1 = PlatformThread::SpawnJoinable([] {}, "1"); + thread2 = PlatformThread::SpawnJoinable([] {}, "2"); + EXPECT_NE(thread1.GetHandle(), thread2.GetHandle()); + thread1.Finalize(); + EXPECT_NE(thread1.GetHandle(), thread2.GetHandle()); + thread2.Finalize(); + EXPECT_EQ(thread1.GetHandle(), thread2.GetHandle()); +} + +TEST(PlatformThreadTest, RunFunctionIsCalled) { + bool flag = false; + PlatformThread::SpawnJoinable([&] { flag = true; }, "T"); + EXPECT_TRUE(flag); +} + +TEST(PlatformThreadTest, JoinsThread) { + // This test flakes if there are problems with the join implementation. + rtc::Event event; + PlatformThread::SpawnJoinable([&] { event.Set(); }, "T"); + EXPECT_TRUE(event.Wait(/*give_up_after=*/webrtc::TimeDelta::Zero())); +} + +TEST(PlatformThreadTest, StopsBeforeDetachedThreadExits) { + // This test flakes if there are problems with the detached thread + // implementation. + bool flag = false; + rtc::Event thread_started; + rtc::Event thread_continue; + rtc::Event thread_exiting; + PlatformThread::SpawnDetached( + [&] { + thread_started.Set(); + thread_continue.Wait(Event::kForever); + flag = true; + thread_exiting.Set(); + }, + "T"); + thread_started.Wait(Event::kForever); + EXPECT_FALSE(flag); + thread_continue.Set(); + thread_exiting.Wait(Event::kForever); + EXPECT_TRUE(flag); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/protobuf_utils.h b/third_party/libwebrtc/rtc_base/protobuf_utils.h new file mode 100644 index 0000000000..497b7f488f --- /dev/null +++ b/third_party/libwebrtc/rtc_base/protobuf_utils.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2017 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 <string> + +#ifndef RTC_BASE_PROTOBUF_UTILS_H_ +#define RTC_BASE_PROTOBUF_UTILS_H_ + +#if WEBRTC_ENABLE_PROTOBUF + +#include "third_party/protobuf/src/google/protobuf/message_lite.h" // nogncheck +#include "third_party/protobuf/src/google/protobuf/repeated_field.h" // nogncheck + +namespace webrtc { + +using google::protobuf::MessageLite; +using google::protobuf::RepeatedPtrField; + +} // namespace webrtc + +#endif // WEBRTC_ENABLE_PROTOBUF + +#endif // RTC_BASE_PROTOBUF_UTILS_H_ diff --git a/third_party/libwebrtc/rtc_base/protobuf_utils_gn/moz.build b/third_party/libwebrtc/rtc_base/protobuf_utils_gn/moz.build new file mode 100644 index 0000000000..7f1e533b39 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/protobuf_utils_gn/moz.build @@ -0,0 +1,205 @@ +# 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("protobuf_utils_gn") diff --git a/third_party/libwebrtc/rtc_base/proxy_info.cc b/third_party/libwebrtc/rtc_base/proxy_info.cc new file mode 100644 index 0000000000..23d60afa74 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/proxy_info.cc @@ -0,0 +1,23 @@ +/* + * 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 "rtc_base/proxy_info.h" + +namespace rtc { + +const char* ProxyToString(ProxyType proxy) { + const char* const PROXY_NAMES[] = {"none", "https", "socks5", "unknown"}; + return PROXY_NAMES[proxy]; +} + +ProxyInfo::ProxyInfo() : type(PROXY_NONE), autodetect(false) {} +ProxyInfo::~ProxyInfo() = default; + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/proxy_info.h b/third_party/libwebrtc/rtc_base/proxy_info.h new file mode 100644 index 0000000000..e614692025 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/proxy_info.h @@ -0,0 +1,39 @@ +/* + * 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 RTC_BASE_PROXY_INFO_H_ +#define RTC_BASE_PROXY_INFO_H_ + +#include <string> + +#include "rtc_base/crypt_string.h" +#include "rtc_base/socket_address.h" + +namespace rtc { + +enum ProxyType { PROXY_NONE, PROXY_HTTPS, PROXY_SOCKS5, PROXY_UNKNOWN }; +const char* ProxyToString(ProxyType proxy); + +struct ProxyInfo { + ProxyType type; + SocketAddress address; + std::string autoconfig_url; + bool autodetect; + std::string bypass_list; + std::string username; + CryptString password; + + ProxyInfo(); + ~ProxyInfo(); +}; + +} // namespace rtc + +#endif // RTC_BASE_PROXY_INFO_H_ diff --git a/third_party/libwebrtc/rtc_base/proxy_server.cc b/third_party/libwebrtc/rtc_base/proxy_server.cc new file mode 100644 index 0000000000..84c96213c3 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/proxy_server.cc @@ -0,0 +1,156 @@ +/* + * 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 "rtc_base/proxy_server.h" + +#include <stddef.h> + +#include <memory> + +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" +#include "rtc_base/socket_factory.h" + +namespace rtc { + +// ProxyServer +ProxyServer::ProxyServer(SocketFactory* int_factory, + const SocketAddress& int_addr, + SocketFactory* ext_factory, + const SocketAddress& ext_ip) + : ext_factory_(ext_factory), + ext_ip_(ext_ip.ipaddr(), 0), // strip off port + server_socket_( + int_factory->CreateSocket(int_addr.family(), SOCK_STREAM)) { + RTC_DCHECK(server_socket_.get() != nullptr); + RTC_DCHECK(int_addr.family() == AF_INET || int_addr.family() == AF_INET6); + server_socket_->Bind(int_addr); + server_socket_->Listen(5); + server_socket_->SignalReadEvent.connect(this, &ProxyServer::OnAcceptEvent); +} + +ProxyServer::~ProxyServer() = default; + +SocketAddress ProxyServer::GetServerAddress() { + return server_socket_->GetLocalAddress(); +} + +void ProxyServer::OnAcceptEvent(Socket* socket) { + RTC_DCHECK(socket); + RTC_DCHECK_EQ(socket, server_socket_.get()); + Socket* int_socket = socket->Accept(nullptr); + AsyncProxyServerSocket* wrapped_socket = WrapSocket(int_socket); + Socket* ext_socket = + ext_factory_->CreateSocket(ext_ip_.family(), SOCK_STREAM); + if (ext_socket) { + ext_socket->Bind(ext_ip_); + bindings_.emplace_back( + std::make_unique<ProxyBinding>(wrapped_socket, ext_socket)); + } else { + RTC_LOG(LS_ERROR) + << "Unable to create external socket on proxy accept event"; + } +} + +// ProxyBinding +ProxyBinding::ProxyBinding(AsyncProxyServerSocket* int_socket, + Socket* ext_socket) + : int_socket_(int_socket), + ext_socket_(ext_socket), + connected_(false), + out_buffer_(kBufferSize), + in_buffer_(kBufferSize) { + int_socket_->SignalConnectRequest.connect(this, + &ProxyBinding::OnConnectRequest); + int_socket_->SignalReadEvent.connect(this, &ProxyBinding::OnInternalRead); + int_socket_->SignalWriteEvent.connect(this, &ProxyBinding::OnInternalWrite); + int_socket_->SignalCloseEvent.connect(this, &ProxyBinding::OnInternalClose); + ext_socket_->SignalConnectEvent.connect(this, + &ProxyBinding::OnExternalConnect); + ext_socket_->SignalReadEvent.connect(this, &ProxyBinding::OnExternalRead); + ext_socket_->SignalWriteEvent.connect(this, &ProxyBinding::OnExternalWrite); + ext_socket_->SignalCloseEvent.connect(this, &ProxyBinding::OnExternalClose); +} + +ProxyBinding::~ProxyBinding() = default; + +void ProxyBinding::OnConnectRequest(AsyncProxyServerSocket* socket, + const SocketAddress& addr) { + RTC_DCHECK(!connected_); + RTC_DCHECK(ext_socket_); + ext_socket_->Connect(addr); + // TODO: handle errors here +} + +void ProxyBinding::OnInternalRead(Socket* socket) { + Read(int_socket_.get(), &out_buffer_); + Write(ext_socket_.get(), &out_buffer_); +} + +void ProxyBinding::OnInternalWrite(Socket* socket) { + Write(int_socket_.get(), &in_buffer_); +} + +void ProxyBinding::OnInternalClose(Socket* socket, int err) { + Destroy(); +} + +void ProxyBinding::OnExternalConnect(Socket* socket) { + RTC_DCHECK(socket != nullptr); + connected_ = true; + int_socket_->SendConnectResult(0, socket->GetRemoteAddress()); +} + +void ProxyBinding::OnExternalRead(Socket* socket) { + Read(ext_socket_.get(), &in_buffer_); + Write(int_socket_.get(), &in_buffer_); +} + +void ProxyBinding::OnExternalWrite(Socket* socket) { + Write(ext_socket_.get(), &out_buffer_); +} + +void ProxyBinding::OnExternalClose(Socket* socket, int err) { + if (!connected_) { + int_socket_->SendConnectResult(err, SocketAddress()); + } + Destroy(); +} + +void ProxyBinding::Read(Socket* socket, FifoBuffer* buffer) { + // Only read if the buffer is empty. + RTC_DCHECK(socket != nullptr); + size_t size; + int read; + if (buffer->GetBuffered(&size) && size == 0) { + void* p = buffer->GetWriteBuffer(&size); + read = socket->Recv(p, size, nullptr); + buffer->ConsumeWriteBuffer(std::max(read, 0)); + } +} + +void ProxyBinding::Write(Socket* socket, FifoBuffer* buffer) { + RTC_DCHECK(socket != nullptr); + size_t size; + int written; + const void* p = buffer->GetReadData(&size); + written = socket->Send(p, size); + buffer->ConsumeReadData(std::max(written, 0)); +} + +void ProxyBinding::Destroy() { + SignalDestroyed(this); +} + +AsyncProxyServerSocket* SocksProxyServer::WrapSocket(Socket* socket) { + return new AsyncSocksProxyServerSocket(socket); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/proxy_server.h b/third_party/libwebrtc/rtc_base/proxy_server.h new file mode 100644 index 0000000000..0b9b655a5e --- /dev/null +++ b/third_party/libwebrtc/rtc_base/proxy_server.h @@ -0,0 +1,110 @@ +/* + * 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 RTC_BASE_PROXY_SERVER_H_ +#define RTC_BASE_PROXY_SERVER_H_ + +#include <memory> +#include <vector> + +#include "absl/memory/memory.h" +#include "rtc_base/memory/fifo_buffer.h" +#include "rtc_base/server_socket_adapters.h" +#include "rtc_base/socket.h" +#include "rtc_base/socket_address.h" + +namespace rtc { + +class SocketFactory; + +// ProxyServer is a base class that allows for easy construction of proxy +// servers. With its helper class ProxyBinding, it contains all the necessary +// logic for receiving and bridging connections. The specific client-server +// proxy protocol is implemented by an instance of the AsyncProxyServerSocket +// class; children of ProxyServer implement WrapSocket appropriately to return +// the correct protocol handler. + +class ProxyBinding : public sigslot::has_slots<> { + public: + ProxyBinding(AsyncProxyServerSocket* in_socket, Socket* out_socket); + ~ProxyBinding() override; + + ProxyBinding(const ProxyBinding&) = delete; + ProxyBinding& operator=(const ProxyBinding&) = delete; + + sigslot::signal1<ProxyBinding*> SignalDestroyed; + + private: + void OnConnectRequest(AsyncProxyServerSocket* socket, + const SocketAddress& addr); + void OnInternalRead(Socket* socket); + void OnInternalWrite(Socket* socket); + void OnInternalClose(Socket* socket, int err); + void OnExternalConnect(Socket* socket); + void OnExternalRead(Socket* socket); + void OnExternalWrite(Socket* socket); + void OnExternalClose(Socket* socket, int err); + + static void Read(Socket* socket, FifoBuffer* buffer); + static void Write(Socket* socket, FifoBuffer* buffer); + void Destroy(); + + static const int kBufferSize = 4096; + std::unique_ptr<AsyncProxyServerSocket> int_socket_; + std::unique_ptr<Socket> ext_socket_; + bool connected_; + FifoBuffer out_buffer_; + FifoBuffer in_buffer_; +}; + +class ProxyServer : public sigslot::has_slots<> { + public: + ProxyServer(SocketFactory* int_factory, + const SocketAddress& int_addr, + SocketFactory* ext_factory, + const SocketAddress& ext_ip); + ~ProxyServer() override; + + ProxyServer(const ProxyServer&) = delete; + ProxyServer& operator=(const ProxyServer&) = delete; + + // Returns the address to which the proxy server is bound + SocketAddress GetServerAddress(); + + protected: + void OnAcceptEvent(Socket* socket); + virtual AsyncProxyServerSocket* WrapSocket(Socket* socket) = 0; + + private: + SocketFactory* ext_factory_; + SocketAddress ext_ip_; + std::unique_ptr<Socket> server_socket_; + std::vector<std::unique_ptr<ProxyBinding>> bindings_; +}; + +// SocksProxyServer is a simple extension of ProxyServer to implement SOCKS. +class SocksProxyServer : public ProxyServer { + public: + SocksProxyServer(SocketFactory* int_factory, + const SocketAddress& int_addr, + SocketFactory* ext_factory, + const SocketAddress& ext_ip) + : ProxyServer(int_factory, int_addr, ext_factory, ext_ip) {} + + SocksProxyServer(const SocksProxyServer&) = delete; + SocksProxyServer& operator=(const SocksProxyServer&) = delete; + + protected: + AsyncProxyServerSocket* WrapSocket(Socket* socket) override; +}; + +} // namespace rtc + +#endif // RTC_BASE_PROXY_SERVER_H_ diff --git a/third_party/libwebrtc/rtc_base/proxy_unittest.cc b/third_party/libwebrtc/rtc_base/proxy_unittest.cc new file mode 100644 index 0000000000..9e3898e430 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/proxy_unittest.cc @@ -0,0 +1,68 @@ +/* + * Copyright 2009 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 <memory> +#include <string> + +#include "rtc_base/gunit.h" +#include "rtc_base/proxy_server.h" +#include "rtc_base/socket_adapters.h" +#include "rtc_base/test_client.h" +#include "rtc_base/test_echo_server.h" +#include "rtc_base/virtual_socket_server.h" + +using rtc::Socket; +using rtc::SocketAddress; + +static const SocketAddress kSocksProxyIntAddr("1.2.3.4", 1080); +static const SocketAddress kSocksProxyExtAddr("1.2.3.5", 0); +static const SocketAddress kBogusProxyIntAddr("1.2.3.4", 999); + +// Sets up a virtual socket server and a SOCKS5 proxy server. +class ProxyTest : public ::testing::Test { + public: + ProxyTest() : ss_(new rtc::VirtualSocketServer()), thread_(ss_.get()) { + socks_.reset(new rtc::SocksProxyServer(ss_.get(), kSocksProxyIntAddr, + ss_.get(), kSocksProxyExtAddr)); + } + + rtc::SocketServer* ss() { return ss_.get(); } + + private: + std::unique_ptr<rtc::SocketServer> ss_; + rtc::AutoSocketServerThread thread_; + std::unique_ptr<rtc::SocksProxyServer> socks_; +}; + +// Tests whether we can use a SOCKS5 proxy to connect to a server. +TEST_F(ProxyTest, TestSocks5Connect) { + rtc::Socket* socket = + ss()->CreateSocket(kSocksProxyIntAddr.family(), SOCK_STREAM); + rtc::AsyncSocksProxySocket* proxy_socket = new rtc::AsyncSocksProxySocket( + socket, kSocksProxyIntAddr, "", rtc::CryptString()); + // TODO: IPv6-ize these tests when proxy supports IPv6. + + rtc::TestEchoServer server(rtc::Thread::Current(), + SocketAddress(INADDR_ANY, 0)); + + std::unique_ptr<rtc::AsyncTCPSocket> packet_socket( + rtc::AsyncTCPSocket::Create(proxy_socket, SocketAddress(INADDR_ANY, 0), + server.address())); + EXPECT_TRUE(packet_socket != nullptr); + rtc::TestClient client(std::move(packet_socket)); + + EXPECT_EQ(Socket::CS_CONNECTING, proxy_socket->GetState()); + EXPECT_TRUE(client.CheckConnected()); + EXPECT_EQ(Socket::CS_CONNECTED, proxy_socket->GetState()); + EXPECT_EQ(server.address(), client.remote_address()); + client.Send("foo", 3); + EXPECT_TRUE(client.CheckNextPacket("foo", 3, nullptr)); + EXPECT_TRUE(client.CheckNoPacket()); +} diff --git a/third_party/libwebrtc/rtc_base/race_checker.cc b/third_party/libwebrtc/rtc_base/race_checker.cc new file mode 100644 index 0000000000..f0d4e868c2 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/race_checker.cc @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2016 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 "rtc_base/race_checker.h" + +namespace rtc { + +RaceChecker::RaceChecker() {} + +// Note that the implementation here is in itself racy, but we pretend it does +// not matter because we want this useful in release builds without having to +// pay the cost of using atomics. A race hitting the race checker is likely to +// cause access_count_ to diverge from zero and therefore cause the ThreadRef +// comparison to fail, signaling a race, although it may not be in the exact +// spot where a race *first* appeared in the code we're trying to protect. There +// is also a chance that an actual race is missed, however the probability of +// that has been considered small enough to be an acceptable trade off. +bool RaceChecker::Acquire() const { + const PlatformThreadRef current_thread = CurrentThreadRef(); + // Set new accessing thread if this is a new use. + const int current_access_count = access_count_; + access_count_ = access_count_ + 1; + if (current_access_count == 0) + accessing_thread_ = current_thread; + // If this is being used concurrently this check will fail for the second + // thread entering since it won't set the thread. Recursive use of checked + // methods are OK since the accessing thread remains the same. + const PlatformThreadRef accessing_thread = accessing_thread_; + return IsThreadRefEqual(accessing_thread, current_thread); +} + +void RaceChecker::Release() const { + access_count_ = access_count_ - 1; +} + +namespace internal { +RaceCheckerScope::RaceCheckerScope(const RaceChecker* race_checker) + : race_checker_(race_checker), race_check_ok_(race_checker->Acquire()) {} + +bool RaceCheckerScope::RaceDetected() const { + return !race_check_ok_; +} + +RaceCheckerScope::~RaceCheckerScope() { + race_checker_->Release(); +} + +} // namespace internal +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/race_checker.h b/third_party/libwebrtc/rtc_base/race_checker.h new file mode 100644 index 0000000000..00bab52f33 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/race_checker.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2016 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 RTC_BASE_RACE_CHECKER_H_ +#define RTC_BASE_RACE_CHECKER_H_ + +#include "rtc_base/checks.h" +#include "rtc_base/platform_thread_types.h" +#include "rtc_base/thread_annotations.h" + +namespace rtc { + +namespace internal { +class RaceCheckerScope; +} // namespace internal + +// Best-effort race-checking implementation. This primitive uses no +// synchronization at all to be as-fast-as-possible in the non-racy case. +class RTC_LOCKABLE RaceChecker { + public: + friend class internal::RaceCheckerScope; + RaceChecker(); + + private: + bool Acquire() const RTC_EXCLUSIVE_LOCK_FUNCTION(); + void Release() const RTC_UNLOCK_FUNCTION(); + + // Volatile to prevent code being optimized away in Acquire()/Release(). + mutable volatile int access_count_ = 0; + mutable volatile PlatformThreadRef accessing_thread_; +}; + +namespace internal { +class RTC_SCOPED_LOCKABLE RaceCheckerScope { + public: + explicit RaceCheckerScope(const RaceChecker* race_checker) + RTC_EXCLUSIVE_LOCK_FUNCTION(race_checker); + + bool RaceDetected() const; + ~RaceCheckerScope() RTC_UNLOCK_FUNCTION(); + + private: + const RaceChecker* const race_checker_; + const bool race_check_ok_; +}; + +class RTC_SCOPED_LOCKABLE RaceCheckerScopeDoNothing { + public: + explicit RaceCheckerScopeDoNothing(const RaceChecker* race_checker) + RTC_EXCLUSIVE_LOCK_FUNCTION(race_checker) {} + + ~RaceCheckerScopeDoNothing() RTC_UNLOCK_FUNCTION() {} +}; + +} // namespace internal +} // namespace rtc + +#define RTC_CHECK_RUNS_SERIALIZED(x) RTC_CHECK_RUNS_SERIALIZED_NEXT(x, __LINE__) + +#define RTC_CHECK_RUNS_SERIALIZED_NEXT(x, suffix) \ + RTC_CHECK_RUNS_SERIALIZED_IMPL(x, suffix) + +#define RTC_CHECK_RUNS_SERIALIZED_IMPL(x, suffix) \ + rtc::internal::RaceCheckerScope race_checker##suffix(x); \ + RTC_CHECK(!race_checker##suffix.RaceDetected()) + +#if RTC_DCHECK_IS_ON +#define RTC_DCHECK_RUNS_SERIALIZED(x) \ + rtc::internal::RaceCheckerScope race_checker(x); \ + RTC_DCHECK(!race_checker.RaceDetected()) +#else +#define RTC_DCHECK_RUNS_SERIALIZED(x) \ + rtc::internal::RaceCheckerScopeDoNothing race_checker(x) +#endif + +#endif // RTC_BASE_RACE_CHECKER_H_ diff --git a/third_party/libwebrtc/rtc_base/race_checker_gn/moz.build b/third_party/libwebrtc/rtc_base/race_checker_gn/moz.build new file mode 100644 index 0000000000..2fab623156 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/race_checker_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/rtc_base/race_checker.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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("race_checker_gn") diff --git a/third_party/libwebrtc/rtc_base/random.cc b/third_party/libwebrtc/rtc_base/random.cc new file mode 100644 index 0000000000..5206b817f3 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/random.cc @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2015 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 "rtc_base/random.h" + +#include <math.h> + +#include "rtc_base/checks.h" +#include "rtc_base/numerics/safe_conversions.h" + +namespace webrtc { + +Random::Random(uint64_t seed) { + RTC_DCHECK(seed != 0x0ull); + state_ = seed; +} + +uint32_t Random::Rand(uint32_t t) { + // Casting the output to 32 bits will give an almost uniform number. + // Pr[x=0] = (2^32-1) / (2^64-1) + // Pr[x=k] = 2^32 / (2^64-1) for k!=0 + // Uniform would be Pr[x=k] = 2^32 / 2^64 for all 32-bit integers k. + uint32_t x = NextOutput(); + // If x / 2^32 is uniform on [0,1), then x / 2^32 * (t+1) is uniform on + // the interval [0,t+1), so the integer part is uniform on [0,t]. + uint64_t result = x * (static_cast<uint64_t>(t) + 1); + result >>= 32; + return result; +} + +uint32_t Random::Rand(uint32_t low, uint32_t high) { + RTC_DCHECK(low <= high); + return Rand(high - low) + low; +} + +int32_t Random::Rand(int32_t low, int32_t high) { + RTC_DCHECK(low <= high); + const int64_t low_i64{low}; + return rtc::dchecked_cast<int32_t>( + Rand(rtc::dchecked_cast<uint32_t>(high - low_i64)) + low_i64); +} + +template <> +float Random::Rand<float>() { + double result = NextOutput() - 1; + result = result / static_cast<double>(0xFFFFFFFFFFFFFFFFull); + return static_cast<float>(result); +} + +template <> +double Random::Rand<double>() { + double result = NextOutput() - 1; + result = result / static_cast<double>(0xFFFFFFFFFFFFFFFFull); + return result; +} + +template <> +bool Random::Rand<bool>() { + return Rand(0, 1) == 1; +} + +double Random::Gaussian(double mean, double standard_deviation) { + // Creating a Normal distribution variable from two independent uniform + // variables based on the Box-Muller transform, which is defined on the + // interval (0, 1]. Note that we rely on NextOutput to generate integers + // in the range [1, 2^64-1]. Normally this behavior is a bit frustrating, + // but here it is exactly what we need. + const double kPi = 3.14159265358979323846; + double u1 = static_cast<double>(NextOutput()) / + static_cast<double>(0xFFFFFFFFFFFFFFFFull); + double u2 = static_cast<double>(NextOutput()) / + static_cast<double>(0xFFFFFFFFFFFFFFFFull); + return mean + standard_deviation * sqrt(-2 * log(u1)) * cos(2 * kPi * u2); +} + +double Random::Exponential(double lambda) { + double uniform = Rand<double>(); + return -log(uniform) / lambda; +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/random.h b/third_party/libwebrtc/rtc_base/random.h new file mode 100644 index 0000000000..b3b9fd1608 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/random.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2015 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 RTC_BASE_RANDOM_H_ +#define RTC_BASE_RANDOM_H_ + +#include <stdint.h> + +#include <limits> + +#include "rtc_base/checks.h" + +namespace webrtc { + +class Random { + public: + // TODO(tommi): Change this so that the seed can be initialized internally, + // e.g. by offering two ways of constructing or offer a static method that + // returns a seed that's suitable for initialization. + // The problem now is that callers are calling clock_->TimeInMicroseconds() + // which calls TickTime::Now().Ticks(), which can return a very low value on + // Mac and can result in a seed of 0 after conversion to microseconds. + // Besides the quality of the random seed being poor, this also requires + // the client to take on extra dependencies to generate a seed. + // If we go for a static seed generator in Random, we can use something from + // webrtc/rtc_base and make sure that it works the same way across platforms. + // See also discussion here: https://codereview.webrtc.org/1623543002/ + explicit Random(uint64_t seed); + + Random() = delete; + Random(const Random&) = delete; + Random& operator=(const Random&) = delete; + + // Return pseudo-random integer of the specified type. + // We need to limit the size to 32 bits to keep the output close to uniform. + template <typename T> + T Rand() { + static_assert(std::numeric_limits<T>::is_integer && + std::numeric_limits<T>::radix == 2 && + std::numeric_limits<T>::digits <= 32, + "Rand is only supported for built-in integer types that are " + "32 bits or smaller."); + return static_cast<T>(NextOutput()); + } + + // Uniformly distributed pseudo-random number in the interval [0, t]. + uint32_t Rand(uint32_t t); + + // Uniformly distributed pseudo-random number in the interval [low, high]. + uint32_t Rand(uint32_t low, uint32_t high); + + // Uniformly distributed pseudo-random number in the interval [low, high]. + int32_t Rand(int32_t low, int32_t high); + + // Normal Distribution. + double Gaussian(double mean, double standard_deviation); + + // Exponential Distribution. + double Exponential(double lambda); + + private: + // Outputs a nonzero 64-bit random number using Xorshift algorithm. + // https://en.wikipedia.org/wiki/Xorshift + uint64_t NextOutput() { + state_ ^= state_ >> 12; + state_ ^= state_ << 25; + state_ ^= state_ >> 27; + RTC_DCHECK(state_ != 0x0ULL); + return state_ * 2685821657736338717ull; + } + + uint64_t state_; +}; + +// Return pseudo-random number in the interval [0.0, 1.0). +template <> +float Random::Rand<float>(); + +// Return pseudo-random number in the interval [0.0, 1.0). +template <> +double Random::Rand<double>(); + +// Return pseudo-random boolean value. +template <> +bool Random::Rand<bool>(); + +} // namespace webrtc + +#endif // RTC_BASE_RANDOM_H_ diff --git a/third_party/libwebrtc/rtc_base/random_gn/moz.build b/third_party/libwebrtc/rtc_base/random_gn/moz.build new file mode 100644 index 0000000000..394eefde59 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/random_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/rtc_base/random.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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("random_gn") diff --git a/third_party/libwebrtc/rtc_base/random_unittest.cc b/third_party/libwebrtc/rtc_base/random_unittest.cc new file mode 100644 index 0000000000..4eb6f754eb --- /dev/null +++ b/third_party/libwebrtc/rtc_base/random_unittest.cc @@ -0,0 +1,305 @@ +/* + * Copyright (c) 2015 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 "rtc_base/random.h" + +#include <math.h> + +#include <limits> +#include <vector> + +#include "rtc_base/numerics/math_utils.h" // unsigned difference +#include "test/gtest.h" + +namespace webrtc { + +namespace { +// Computes the positive remainder of x/n. +template <typename T> +T fdiv_remainder(T x, T n) { + RTC_CHECK_GE(n, 0); + T remainder = x % n; + if (remainder < 0) + remainder += n; + return remainder; +} +} // namespace + +// Sample a number of random integers of type T. Divide them into buckets +// based on the remainder when dividing by bucket_count and check that each +// bucket gets roughly the expected number of elements. +template <typename T> +void UniformBucketTest(T bucket_count, int samples, Random* prng) { + std::vector<int> buckets(bucket_count, 0); + + uint64_t total_values = 1ull << (std::numeric_limits<T>::digits + + std::numeric_limits<T>::is_signed); + T upper_limit = + std::numeric_limits<T>::max() - + static_cast<T>(total_values % static_cast<uint64_t>(bucket_count)); + ASSERT_GT(upper_limit, std::numeric_limits<T>::max() / 2); + + for (int i = 0; i < samples; i++) { + T sample; + do { + // We exclude a few numbers from the range so that it is divisible by + // the number of buckets. If we are unlucky and hit one of the excluded + // numbers we just resample. Note that if the number of buckets is a + // power of 2, then we don't have to exclude anything. + sample = prng->Rand<T>(); + } while (sample > upper_limit); + buckets[fdiv_remainder(sample, bucket_count)]++; + } + + for (T i = 0; i < bucket_count; i++) { + // Expect the result to be within 3 standard deviations of the mean. + EXPECT_NEAR(buckets[i], samples / bucket_count, + 3 * sqrt(samples / bucket_count)); + } +} + +TEST(RandomNumberGeneratorTest, BucketTestSignedChar) { + Random prng(7297352569824ull); + UniformBucketTest<signed char>(64, 640000, &prng); + UniformBucketTest<signed char>(11, 440000, &prng); + UniformBucketTest<signed char>(3, 270000, &prng); +} + +TEST(RandomNumberGeneratorTest, BucketTestUnsignedChar) { + Random prng(7297352569824ull); + UniformBucketTest<unsigned char>(64, 640000, &prng); + UniformBucketTest<unsigned char>(11, 440000, &prng); + UniformBucketTest<unsigned char>(3, 270000, &prng); +} + +TEST(RandomNumberGeneratorTest, BucketTestSignedShort) { + Random prng(7297352569824ull); + UniformBucketTest<int16_t>(64, 640000, &prng); + UniformBucketTest<int16_t>(11, 440000, &prng); + UniformBucketTest<int16_t>(3, 270000, &prng); +} + +TEST(RandomNumberGeneratorTest, BucketTestUnsignedShort) { + Random prng(7297352569824ull); + UniformBucketTest<uint16_t>(64, 640000, &prng); + UniformBucketTest<uint16_t>(11, 440000, &prng); + UniformBucketTest<uint16_t>(3, 270000, &prng); +} + +TEST(RandomNumberGeneratorTest, BucketTestSignedInt) { + Random prng(7297352569824ull); + UniformBucketTest<signed int>(64, 640000, &prng); + UniformBucketTest<signed int>(11, 440000, &prng); + UniformBucketTest<signed int>(3, 270000, &prng); +} + +TEST(RandomNumberGeneratorTest, BucketTestUnsignedInt) { + Random prng(7297352569824ull); + UniformBucketTest<unsigned int>(64, 640000, &prng); + UniformBucketTest<unsigned int>(11, 440000, &prng); + UniformBucketTest<unsigned int>(3, 270000, &prng); +} + +// The range of the random numbers is divided into bucket_count intervals +// of consecutive numbers. Check that approximately equally many numbers +// from each inteval are generated. +void BucketTestSignedInterval(unsigned int bucket_count, + unsigned int samples, + int32_t low, + int32_t high, + int sigma_level, + Random* prng) { + std::vector<unsigned int> buckets(bucket_count, 0); + + ASSERT_GE(high, low); + ASSERT_GE(bucket_count, 2u); + uint32_t interval = webrtc_impl::unsigned_difference<int32_t>(high, low) + 1; + uint32_t numbers_per_bucket; + if (interval == 0) { + // The computation high - low + 1 should be 2^32 but overflowed + // Hence, bucket_count must be a power of 2 + ASSERT_EQ(bucket_count & (bucket_count - 1), 0u); + numbers_per_bucket = (0x80000000u / bucket_count) * 2; + } else { + ASSERT_EQ(interval % bucket_count, 0u); + numbers_per_bucket = interval / bucket_count; + } + + for (unsigned int i = 0; i < samples; i++) { + int32_t sample = prng->Rand(low, high); + EXPECT_LE(low, sample); + EXPECT_GE(high, sample); + buckets[webrtc_impl::unsigned_difference<int32_t>(sample, low) / + numbers_per_bucket]++; + } + + for (unsigned int i = 0; i < bucket_count; i++) { + // Expect the result to be within 3 standard deviations of the mean, + // or more generally, within sigma_level standard deviations of the mean. + double mean = static_cast<double>(samples) / bucket_count; + EXPECT_NEAR(buckets[i], mean, sigma_level * sqrt(mean)); + } +} + +// The range of the random numbers is divided into bucket_count intervals +// of consecutive numbers. Check that approximately equally many numbers +// from each inteval are generated. +void BucketTestUnsignedInterval(unsigned int bucket_count, + unsigned int samples, + uint32_t low, + uint32_t high, + int sigma_level, + Random* prng) { + std::vector<unsigned int> buckets(bucket_count, 0); + + ASSERT_GE(high, low); + ASSERT_GE(bucket_count, 2u); + uint32_t interval = high - low + 1; + uint32_t numbers_per_bucket; + if (interval == 0) { + // The computation high - low + 1 should be 2^32 but overflowed + // Hence, bucket_count must be a power of 2 + ASSERT_EQ(bucket_count & (bucket_count - 1), 0u); + numbers_per_bucket = (0x80000000u / bucket_count) * 2; + } else { + ASSERT_EQ(interval % bucket_count, 0u); + numbers_per_bucket = interval / bucket_count; + } + + for (unsigned int i = 0; i < samples; i++) { + uint32_t sample = prng->Rand(low, high); + EXPECT_LE(low, sample); + EXPECT_GE(high, sample); + buckets[(sample - low) / numbers_per_bucket]++; + } + + for (unsigned int i = 0; i < bucket_count; i++) { + // Expect the result to be within 3 standard deviations of the mean, + // or more generally, within sigma_level standard deviations of the mean. + double mean = static_cast<double>(samples) / bucket_count; + EXPECT_NEAR(buckets[i], mean, sigma_level * sqrt(mean)); + } +} + +TEST(RandomNumberGeneratorTest, UniformUnsignedInterval) { + Random prng(299792458ull); + BucketTestUnsignedInterval(2, 100000, 0, 1, 3, &prng); + BucketTestUnsignedInterval(7, 100000, 1, 14, 3, &prng); + BucketTestUnsignedInterval(11, 100000, 1000, 1010, 3, &prng); + BucketTestUnsignedInterval(100, 100000, 0, 99, 3, &prng); + BucketTestUnsignedInterval(2, 100000, 0, 4294967295, 3, &prng); + BucketTestUnsignedInterval(17, 100000, 455, 2147484110, 3, &prng); + // 99.7% of all samples will be within 3 standard deviations of the mean, + // but since we test 1000 buckets we allow an interval of 4 sigma. + BucketTestUnsignedInterval(1000, 1000000, 0, 2147483999, 4, &prng); +} + +TEST(RandomNumberGeneratorTest, UniformSignedInterval) { + Random prng(66260695729ull); + BucketTestSignedInterval(2, 100000, 0, 1, 3, &prng); + BucketTestSignedInterval(7, 100000, -2, 4, 3, &prng); + BucketTestSignedInterval(11, 100000, 1000, 1010, 3, &prng); + BucketTestSignedInterval(100, 100000, 0, 99, 3, &prng); + BucketTestSignedInterval(2, 100000, std::numeric_limits<int32_t>::min(), + std::numeric_limits<int32_t>::max(), 3, &prng); + BucketTestSignedInterval(17, 100000, -1073741826, 1073741829, 3, &prng); + // 99.7% of all samples will be within 3 standard deviations of the mean, + // but since we test 1000 buckets we allow an interval of 4 sigma. + BucketTestSignedInterval(1000, 1000000, -352, 2147483647, 4, &prng); +} + +// The range of the random numbers is divided into bucket_count intervals +// of consecutive numbers. Check that approximately equally many numbers +// from each inteval are generated. +void BucketTestFloat(unsigned int bucket_count, + unsigned int samples, + int sigma_level, + Random* prng) { + ASSERT_GE(bucket_count, 2u); + std::vector<unsigned int> buckets(bucket_count, 0); + + for (unsigned int i = 0; i < samples; i++) { + uint32_t sample = bucket_count * prng->Rand<float>(); + EXPECT_LE(0u, sample); + EXPECT_GE(bucket_count - 1, sample); + buckets[sample]++; + } + + for (unsigned int i = 0; i < bucket_count; i++) { + // Expect the result to be within 3 standard deviations of the mean, + // or more generally, within sigma_level standard deviations of the mean. + double mean = static_cast<double>(samples) / bucket_count; + EXPECT_NEAR(buckets[i], mean, sigma_level * sqrt(mean)); + } +} + +TEST(RandomNumberGeneratorTest, UniformFloatInterval) { + Random prng(1380648813ull); + BucketTestFloat(100, 100000, 3, &prng); + // 99.7% of all samples will be within 3 standard deviations of the mean, + // but since we test 1000 buckets we allow an interval of 4 sigma. + // BucketTestSignedInterval(1000, 1000000, -352, 2147483647, 4, &prng); +} + +TEST(RandomNumberGeneratorTest, SignedHasSameBitPattern) { + Random prng_signed(66738480ull), prng_unsigned(66738480ull); + + for (int i = 0; i < 1000; i++) { + signed int s = prng_signed.Rand<signed int>(); + unsigned int u = prng_unsigned.Rand<unsigned int>(); + EXPECT_EQ(u, static_cast<unsigned int>(s)); + } + + for (int i = 0; i < 1000; i++) { + int16_t s = prng_signed.Rand<int16_t>(); + uint16_t u = prng_unsigned.Rand<uint16_t>(); + EXPECT_EQ(u, static_cast<uint16_t>(s)); + } + + for (int i = 0; i < 1000; i++) { + signed char s = prng_signed.Rand<signed char>(); + unsigned char u = prng_unsigned.Rand<unsigned char>(); + EXPECT_EQ(u, static_cast<unsigned char>(s)); + } +} + +TEST(RandomNumberGeneratorTest, Gaussian) { + const int kN = 100000; + const int kBuckets = 100; + const double kMean = 49; + const double kStddev = 10; + + Random prng(1256637061); + + std::vector<unsigned int> buckets(kBuckets, 0); + for (int i = 0; i < kN; i++) { + int index = prng.Gaussian(kMean, kStddev) + 0.5; + if (index >= 0 && index < kBuckets) { + buckets[index]++; + } + } + + const double kPi = 3.14159265358979323846; + const double kScale = 1 / (kStddev * sqrt(2.0 * kPi)); + const double kDiv = -2.0 * kStddev * kStddev; + for (int n = 0; n < kBuckets; ++n) { + // Use Simpsons rule to estimate the probability that a random gaussian + // sample is in the interval [n-0.5, n+0.5]. + double f_left = kScale * exp((n - kMean - 0.5) * (n - kMean - 0.5) / kDiv); + double f_mid = kScale * exp((n - kMean) * (n - kMean) / kDiv); + double f_right = kScale * exp((n - kMean + 0.5) * (n - kMean + 0.5) / kDiv); + double normal_dist = (f_left + 4 * f_mid + f_right) / 6; + // Expect the number of samples to be within 3 standard deviations + // (rounded up) of the expected number of samples in the bucket. + EXPECT_NEAR(buckets[n], kN * normal_dist, 3 * sqrt(kN * normal_dist) + 1); + } +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/rate_limiter.cc b/third_party/libwebrtc/rtc_base/rate_limiter.cc new file mode 100644 index 0000000000..0f3f343aed --- /dev/null +++ b/third_party/libwebrtc/rtc_base/rate_limiter.cc @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2016 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 "rtc_base/rate_limiter.h" + +#include <limits> + +#include "absl/types/optional.h" +#include "system_wrappers/include/clock.h" + +namespace webrtc { + +RateLimiter::RateLimiter(Clock* clock, int64_t max_window_ms) + : clock_(clock), + current_rate_(max_window_ms, RateStatistics::kBpsScale), + window_size_ms_(max_window_ms), + max_rate_bps_(std::numeric_limits<uint32_t>::max()) {} + +RateLimiter::~RateLimiter() {} + +// Usage note: This class is intended be usable in a scenario where different +// threads may call each of the the different method. For instance, a network +// thread trying to send data calling TryUseRate(), the bandwidth estimator +// calling SetMaxRate() and a timed maintenance thread periodically updating +// the RTT. +bool RateLimiter::TryUseRate(size_t packet_size_bytes) { + MutexLock lock(&lock_); + int64_t now_ms = clock_->TimeInMilliseconds(); + absl::optional<uint32_t> current_rate = current_rate_.Rate(now_ms); + if (current_rate) { + // If there is a current rate, check if adding bytes would cause maximum + // bitrate target to be exceeded. If there is NOT a valid current rate, + // allow allocating rate even if target is exceeded. This prevents + // problems + // at very low rates, where for instance retransmissions would never be + // allowed due to too high bitrate caused by a single packet. + + size_t bitrate_addition_bps = + (packet_size_bytes * 8 * 1000) / window_size_ms_; + if (*current_rate + bitrate_addition_bps > max_rate_bps_) + return false; + } + + current_rate_.Update(packet_size_bytes, now_ms); + return true; +} + +void RateLimiter::SetMaxRate(uint32_t max_rate_bps) { + MutexLock lock(&lock_); + max_rate_bps_ = max_rate_bps; +} + +// Set the window size over which to measure the current bitrate. +// For retransmissions, this is typically the RTT. +bool RateLimiter::SetWindowSize(int64_t window_size_ms) { + MutexLock lock(&lock_); + window_size_ms_ = window_size_ms; + return current_rate_.SetWindowSize(window_size_ms, + clock_->TimeInMilliseconds()); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/rate_limiter.h b/third_party/libwebrtc/rtc_base/rate_limiter.h new file mode 100644 index 0000000000..9bbe21f9ca --- /dev/null +++ b/third_party/libwebrtc/rtc_base/rate_limiter.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2016 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 RTC_BASE_RATE_LIMITER_H_ +#define RTC_BASE_RATE_LIMITER_H_ + +#include <stddef.h> +#include <stdint.h> + +#include "rtc_base/rate_statistics.h" +#include "rtc_base/synchronization/mutex.h" +#include "rtc_base/thread_annotations.h" + +namespace webrtc { + +class Clock; + +// Class used to limit a bitrate, making sure the average does not exceed a +// maximum as measured over a sliding window. This class is thread safe; all +// methods will acquire (the same) lock befeore executing. +class RateLimiter { + public: + RateLimiter(Clock* clock, int64_t max_window_ms); + + RateLimiter() = delete; + RateLimiter(const RateLimiter&) = delete; + RateLimiter& operator=(const RateLimiter&) = delete; + + ~RateLimiter(); + + // Try to use rate to send bytes. Returns true on success and if so updates + // current rate. + bool TryUseRate(size_t packet_size_bytes); + + // Set the maximum bitrate, in bps, that this limiter allows to send. + void SetMaxRate(uint32_t max_rate_bps); + + // Set the window size over which to measure the current bitrate. + // For example, irt retransmissions, this is typically the RTT. + // Returns true on success and false if window_size_ms is out of range. + bool SetWindowSize(int64_t window_size_ms); + + private: + Clock* const clock_; + Mutex lock_; + RateStatistics current_rate_ RTC_GUARDED_BY(lock_); + int64_t window_size_ms_ RTC_GUARDED_BY(lock_); + uint32_t max_rate_bps_ RTC_GUARDED_BY(lock_); +}; + +} // namespace webrtc + +#endif // RTC_BASE_RATE_LIMITER_H_ diff --git a/third_party/libwebrtc/rtc_base/rate_limiter_gn/moz.build b/third_party/libwebrtc/rtc_base/rate_limiter_gn/moz.build new file mode 100644 index 0000000000..cf10767d72 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/rate_limiter_gn/moz.build @@ -0,0 +1,236 @@ +# 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/rtc_base/rate_limiter.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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("rate_limiter_gn") diff --git a/third_party/libwebrtc/rtc_base/rate_limiter_unittest.cc b/third_party/libwebrtc/rtc_base/rate_limiter_unittest.cc new file mode 100644 index 0000000000..07dda5609e --- /dev/null +++ b/third_party/libwebrtc/rtc_base/rate_limiter_unittest.cc @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2016 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 "rtc_base/rate_limiter.h" + +#include <memory> + +#include "rtc_base/event.h" +#include "rtc_base/platform_thread.h" +#include "system_wrappers/include/clock.h" +#include "test/gtest.h" + +namespace webrtc { + +class RateLimitTest : public ::testing::Test { + public: + RateLimitTest() + : clock_(0), rate_limiter(new RateLimiter(&clock_, kWindowSizeMs)) {} + ~RateLimitTest() override {} + + void SetUp() override { rate_limiter->SetMaxRate(kMaxRateBps); } + + protected: + static constexpr int64_t kWindowSizeMs = 1000; + static constexpr uint32_t kMaxRateBps = 100000; + // Bytes needed to completely saturate the rate limiter. + static constexpr size_t kRateFillingBytes = + (kMaxRateBps * kWindowSizeMs) / (8 * 1000); + SimulatedClock clock_; + std::unique_ptr<RateLimiter> rate_limiter; +}; + +TEST_F(RateLimitTest, IncreasingMaxRate) { + // Fill rate, extend window to full size. + EXPECT_TRUE(rate_limiter->TryUseRate(kRateFillingBytes / 2)); + clock_.AdvanceTimeMilliseconds(kWindowSizeMs - 1); + EXPECT_TRUE(rate_limiter->TryUseRate(kRateFillingBytes / 2)); + + // All rate consumed. + EXPECT_FALSE(rate_limiter->TryUseRate(1)); + + // Double the available rate and fill that too. + rate_limiter->SetMaxRate(kMaxRateBps * 2); + EXPECT_TRUE(rate_limiter->TryUseRate(kRateFillingBytes)); + + // All rate consumed again. + EXPECT_FALSE(rate_limiter->TryUseRate(1)); +} + +TEST_F(RateLimitTest, DecreasingMaxRate) { + // Fill rate, extend window to full size. + EXPECT_TRUE(rate_limiter->TryUseRate(kRateFillingBytes / 2)); + clock_.AdvanceTimeMilliseconds(kWindowSizeMs - 1); + EXPECT_TRUE(rate_limiter->TryUseRate(kRateFillingBytes / 2)); + + // All rate consumed. + EXPECT_FALSE(rate_limiter->TryUseRate(1)); + + // Halve the available rate and move window so half of the data falls out. + rate_limiter->SetMaxRate(kMaxRateBps / 2); + clock_.AdvanceTimeMilliseconds(1); + + // All rate still consumed. + EXPECT_FALSE(rate_limiter->TryUseRate(1)); +} + +TEST_F(RateLimitTest, ChangingWindowSize) { + // Fill rate, extend window to full size. + EXPECT_TRUE(rate_limiter->TryUseRate(kRateFillingBytes / 2)); + clock_.AdvanceTimeMilliseconds(kWindowSizeMs - 1); + EXPECT_TRUE(rate_limiter->TryUseRate(kRateFillingBytes / 2)); + + // All rate consumed. + EXPECT_FALSE(rate_limiter->TryUseRate(1)); + + // Decrease window size so half of the data falls out. + rate_limiter->SetWindowSize(kWindowSizeMs / 2); + // Average rate should still be the same, so rate is still all consumed. + EXPECT_FALSE(rate_limiter->TryUseRate(1)); + + // Increase window size again. Now the rate is only half used (removed data + // points don't come back to life). + rate_limiter->SetWindowSize(kWindowSizeMs); + EXPECT_TRUE(rate_limiter->TryUseRate(kRateFillingBytes / 2)); + + // All rate consumed again. + EXPECT_FALSE(rate_limiter->TryUseRate(1)); +} + +TEST_F(RateLimitTest, SingleUsageAlwaysOk) { + // Using more bytes than can fit in a window is OK for a single packet. + EXPECT_TRUE(rate_limiter->TryUseRate(kRateFillingBytes + 1)); +} + +TEST_F(RateLimitTest, WindowSizeLimits) { + EXPECT_TRUE(rate_limiter->SetWindowSize(1)); + EXPECT_FALSE(rate_limiter->SetWindowSize(0)); + EXPECT_TRUE(rate_limiter->SetWindowSize(kWindowSizeMs)); + EXPECT_FALSE(rate_limiter->SetWindowSize(kWindowSizeMs + 1)); +} + +static constexpr TimeDelta kMaxTimeout = TimeDelta::Seconds(30); + +class ThreadTask { + public: + explicit ThreadTask(RateLimiter* rate_limiter) + : rate_limiter_(rate_limiter) {} + virtual ~ThreadTask() {} + + void Run() { + start_signal_.Wait(kMaxTimeout); + DoRun(); + end_signal_.Set(); + } + + virtual void DoRun() = 0; + + RateLimiter* const rate_limiter_; + rtc::Event start_signal_; + rtc::Event end_signal_; +}; + +TEST_F(RateLimitTest, MultiThreadedUsage) { + // Simple sanity test, with different threads calling the various methods. + // Runs a few simple tasks, each on its own thread, but coordinated with + // events so that they run in a serialized order. Intended to catch data + // races when run with tsan et al. + + // Half window size, double rate -> same amount of bytes needed to fill rate. + + class SetWindowSizeTask : public ThreadTask { + public: + explicit SetWindowSizeTask(RateLimiter* rate_limiter) + : ThreadTask(rate_limiter) {} + ~SetWindowSizeTask() override {} + + void DoRun() override { + EXPECT_TRUE(rate_limiter_->SetWindowSize(kWindowSizeMs / 2)); + } + } set_window_size_task(rate_limiter.get()); + auto thread1 = rtc::PlatformThread::SpawnJoinable( + [&set_window_size_task] { set_window_size_task.Run(); }, "Thread1"); + + class SetMaxRateTask : public ThreadTask { + public: + explicit SetMaxRateTask(RateLimiter* rate_limiter) + : ThreadTask(rate_limiter) {} + ~SetMaxRateTask() override {} + + void DoRun() override { rate_limiter_->SetMaxRate(kMaxRateBps * 2); } + } set_max_rate_task(rate_limiter.get()); + auto thread2 = rtc::PlatformThread::SpawnJoinable( + [&set_max_rate_task] { set_max_rate_task.Run(); }, "Thread2"); + + class UseRateTask : public ThreadTask { + public: + UseRateTask(RateLimiter* rate_limiter, SimulatedClock* clock) + : ThreadTask(rate_limiter), clock_(clock) {} + ~UseRateTask() override {} + + void DoRun() override { + EXPECT_TRUE(rate_limiter_->TryUseRate(kRateFillingBytes / 2)); + clock_->AdvanceTimeMilliseconds((kWindowSizeMs / 2) - 1); + EXPECT_TRUE(rate_limiter_->TryUseRate(kRateFillingBytes / 2)); + } + + SimulatedClock* const clock_; + } use_rate_task(rate_limiter.get(), &clock_); + auto thread3 = rtc::PlatformThread::SpawnJoinable( + [&use_rate_task] { use_rate_task.Run(); }, "Thread3"); + + set_window_size_task.start_signal_.Set(); + EXPECT_TRUE(set_window_size_task.end_signal_.Wait(kMaxTimeout)); + + set_max_rate_task.start_signal_.Set(); + EXPECT_TRUE(set_max_rate_task.end_signal_.Wait(kMaxTimeout)); + + use_rate_task.start_signal_.Set(); + EXPECT_TRUE(use_rate_task.end_signal_.Wait(kMaxTimeout)); + + // All rate consumed. + EXPECT_FALSE(rate_limiter->TryUseRate(1)); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/rate_statistics.cc b/third_party/libwebrtc/rtc_base/rate_statistics.cc new file mode 100644 index 0000000000..5c83796471 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/rate_statistics.cc @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2013 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 "rtc_base/rate_statistics.h" + +#include <algorithm> +#include <limits> +#include <memory> + +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" +#include "rtc_base/numerics/safe_conversions.h" + +namespace webrtc { + +RateStatistics::Bucket::Bucket(int64_t timestamp) + : sum(0), num_samples(0), timestamp(timestamp) {} + +RateStatistics::RateStatistics(int64_t window_size_ms, float scale) + : accumulated_count_(0), + first_timestamp_(-1), + num_samples_(0), + scale_(scale), + max_window_size_ms_(window_size_ms), + current_window_size_ms_(max_window_size_ms_) {} + +RateStatistics::RateStatistics(const RateStatistics& other) + : buckets_(other.buckets_), + accumulated_count_(other.accumulated_count_), + first_timestamp_(other.first_timestamp_), + overflow_(other.overflow_), + num_samples_(other.num_samples_), + scale_(other.scale_), + max_window_size_ms_(other.max_window_size_ms_), + current_window_size_ms_(other.current_window_size_ms_) {} + +RateStatistics::RateStatistics(RateStatistics&& other) = default; + +RateStatistics::~RateStatistics() {} + +void RateStatistics::Reset() { + accumulated_count_ = 0; + overflow_ = false; + num_samples_ = 0; + first_timestamp_ = -1; + current_window_size_ms_ = max_window_size_ms_; + buckets_.clear(); +} + +void RateStatistics::Update(int64_t count, int64_t now_ms) { + RTC_DCHECK_GE(count, 0); + + EraseOld(now_ms); + if (first_timestamp_ == -1 || num_samples_ == 0) { + first_timestamp_ = now_ms; + } + + if (buckets_.empty() || now_ms != buckets_.back().timestamp) { + if (!buckets_.empty() && now_ms < buckets_.back().timestamp) { + RTC_LOG(LS_WARNING) << "Timestamp " << now_ms + << " is before the last added " + "timestamp in the rate window: " + << buckets_.back().timestamp << ", aligning to that."; + now_ms = buckets_.back().timestamp; + } + buckets_.emplace_back(now_ms); + } + Bucket& last_bucket = buckets_.back(); + last_bucket.sum += count; + ++last_bucket.num_samples; + + if (std::numeric_limits<int64_t>::max() - accumulated_count_ > count) { + accumulated_count_ += count; + } else { + overflow_ = true; + } + ++num_samples_; +} + +absl::optional<int64_t> RateStatistics::Rate(int64_t now_ms) const { + // Yeah, this const_cast ain't pretty, but the alternative is to declare most + // of the members as mutable... + const_cast<RateStatistics*>(this)->EraseOld(now_ms); + + int active_window_size = 0; + if (first_timestamp_ != -1) { + if (first_timestamp_ <= now_ms - current_window_size_ms_) { + // Count window as full even if no data points currently in view, if the + // data stream started before the window. + active_window_size = current_window_size_ms_; + } else { + // Size of a single bucket is 1ms, so even if now_ms == first_timestmap_ + // the window size should be 1. + active_window_size = now_ms - first_timestamp_ + 1; + } + } + + // If window is a single bucket or there is only one sample in a data set that + // has not grown to the full window size, or if the accumulator has + // overflowed, treat this as rate unavailable. + if (num_samples_ == 0 || active_window_size <= 1 || + (num_samples_ <= 1 && + rtc::SafeLt(active_window_size, current_window_size_ms_)) || + overflow_) { + return absl::nullopt; + } + + float scale = static_cast<float>(scale_) / active_window_size; + float result = accumulated_count_ * scale + 0.5f; + + // Better return unavailable rate than garbage value (undefined behavior). + if (result > static_cast<float>(std::numeric_limits<int64_t>::max())) { + return absl::nullopt; + } + return rtc::dchecked_cast<int64_t>(result); +} + +void RateStatistics::EraseOld(int64_t now_ms) { + // New oldest time that is included in data set. + const int64_t new_oldest_time = now_ms - current_window_size_ms_ + 1; + + // Loop over buckets and remove too old data points. + while (!buckets_.empty() && buckets_.front().timestamp < new_oldest_time) { + const Bucket& oldest_bucket = buckets_.front(); + RTC_DCHECK_GE(accumulated_count_, oldest_bucket.sum); + RTC_DCHECK_GE(num_samples_, oldest_bucket.num_samples); + accumulated_count_ -= oldest_bucket.sum; + num_samples_ -= oldest_bucket.num_samples; + buckets_.pop_front(); + // This does not clear overflow_ even when counter is empty. + // TODO(https://bugs.webrtc.org/11247): Consider if overflow_ can be reset. + } +} + +bool RateStatistics::SetWindowSize(int64_t window_size_ms, int64_t now_ms) { + if (window_size_ms <= 0 || window_size_ms > max_window_size_ms_) + return false; + if (first_timestamp_ != -1) { + // If the window changes (e.g. decreases - removing data point, then + // increases again) we need to update the first timestamp mark as + // otherwise it indicates the window coveres a region of zeros, suddenly + // under-estimating the rate. + first_timestamp_ = std::max(first_timestamp_, now_ms - window_size_ms + 1); + } + current_window_size_ms_ = window_size_ms; + EraseOld(now_ms); + return true; +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/rate_statistics.h b/third_party/libwebrtc/rtc_base/rate_statistics.h new file mode 100644 index 0000000000..e7ce8ad5ed --- /dev/null +++ b/third_party/libwebrtc/rtc_base/rate_statistics.h @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2013 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 RTC_BASE_RATE_STATISTICS_H_ +#define RTC_BASE_RATE_STATISTICS_H_ + +#include <stddef.h> +#include <stdint.h> + +#include <deque> +#include <memory> + +#include "absl/types/optional.h" +#include "rtc_base/system/rtc_export.h" + +namespace webrtc { + +// Class to estimate rates based on counts in a sequence of 1-millisecond +// intervals. + +// This class uses int64 for all its numbers because some rates can be very +// high; for instance, a 20 Mbit/sec video stream can wrap a 32-bit byte +// counter in 14 minutes. + +// Note that timestamps used in Update(), Rate() and SetWindowSize() must never +// decrease for two consecutive calls. +// TODO(bugs.webrtc.org/11600): Migrate from int64_t to Timestamp. + +class RTC_EXPORT RateStatistics { + public: + static constexpr float kBpsScale = 8000.0f; + + // max_window_size_ms = Maximum window size in ms for the rate estimation. + // Initial window size is set to this, but may be changed + // to something lower by calling SetWindowSize(). + // scale = coefficient to convert counts/ms to desired unit + // ex: kBpsScale (8000) for bits/s if count represents bytes. + RateStatistics(int64_t max_window_size_ms, float scale); + + RateStatistics(const RateStatistics& other); + + RateStatistics(RateStatistics&& other); + + ~RateStatistics(); + + // Reset instance to original state. + void Reset(); + + // Update rate with a new data point, moving averaging window as needed. + void Update(int64_t count, int64_t now_ms); + + // Note that despite this being a const method, it still updates the internal + // state (moves averaging window), but it doesn't make any alterations that + // are observable from the other methods, as long as supplied timestamps are + // from a monotonic clock. Ie, it doesn't matter if this call moves the + // window, since any subsequent call to Update or Rate would still have moved + // the window as much or more. + absl::optional<int64_t> Rate(int64_t now_ms) const; + + // Update the size of the averaging window. The maximum allowed value for + // window_size_ms is max_window_size_ms as supplied in the constructor. + bool SetWindowSize(int64_t window_size_ms, int64_t now_ms); + + private: + void EraseOld(int64_t now_ms); + + struct Bucket { + explicit Bucket(int64_t timestamp); + int64_t sum; // Sum of all samples in this bucket. + int num_samples; // Number of samples in this bucket. + const int64_t timestamp; // Timestamp this bucket corresponds to. + }; + // All buckets within the time window, ordered by time. + std::deque<Bucket> buckets_; + + // Total count recorded in all buckets. + int64_t accumulated_count_; + + // Timestamp of the first data point seen, or -1 of none seen. + int64_t first_timestamp_; + + // True if accumulated_count_ has ever grown too large to be + // contained in its integer type. + bool overflow_ = false; + + // The total number of samples in the buckets. + int num_samples_; + + // To convert counts/ms to desired units + const float scale_; + + // The window sizes, in ms, over which the rate is calculated. + const int64_t max_window_size_ms_; + int64_t current_window_size_ms_; +}; +} // namespace webrtc + +#endif // RTC_BASE_RATE_STATISTICS_H_ diff --git a/third_party/libwebrtc/rtc_base/rate_statistics_gn/moz.build b/third_party/libwebrtc/rtc_base/rate_statistics_gn/moz.build new file mode 100644 index 0000000000..657f0a6597 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/rate_statistics_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/rtc_base/rate_statistics.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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("rate_statistics_gn") diff --git a/third_party/libwebrtc/rtc_base/rate_statistics_unittest.cc b/third_party/libwebrtc/rtc_base/rate_statistics_unittest.cc new file mode 100644 index 0000000000..8f1a8384cf --- /dev/null +++ b/third_party/libwebrtc/rtc_base/rate_statistics_unittest.cc @@ -0,0 +1,318 @@ +/* + * Copyright (c) 2012 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 "rtc_base/rate_statistics.h" + +#include <cstdlib> + +#include "test/gtest.h" + +namespace { + +using webrtc::RateStatistics; + +const int64_t kWindowMs = 500; + +class RateStatisticsTest : public ::testing::Test { + protected: + RateStatisticsTest() : stats_(kWindowMs, 8000) {} + RateStatistics stats_; +}; + +TEST_F(RateStatisticsTest, TestStrictMode) { + int64_t now_ms = 0; + EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms))); + + const uint32_t kPacketSize = 1500u; + const uint32_t kExpectedRateBps = kPacketSize * 1000 * 8; + + // Single data point is not enough for valid estimate. + stats_.Update(kPacketSize, now_ms++); + EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms))); + + // Expecting 1200 kbps since the window is initially kept small and grows as + // we have more data. + stats_.Update(kPacketSize, now_ms); + EXPECT_EQ(kExpectedRateBps, *stats_.Rate(now_ms)); + + stats_.Reset(); + // Expecting 0 after init. + EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms))); + + const int kInterval = 10; + for (int i = 0; i < 100000; ++i) { + if (i % kInterval == 0) + stats_.Update(kPacketSize, now_ms); + + // Approximately 1200 kbps expected. Not exact since when packets + // are removed we will jump 10 ms to the next packet. + if (i > kInterval) { + absl::optional<uint32_t> rate = stats_.Rate(now_ms); + EXPECT_TRUE(static_cast<bool>(rate)); + uint32_t samples = i / kInterval + 1; + uint64_t total_bits = samples * kPacketSize * 8; + uint32_t rate_bps = static_cast<uint32_t>((1000 * total_bits) / (i + 1)); + EXPECT_NEAR(rate_bps, *rate, 22000u); + } + now_ms += 1; + } + now_ms += kWindowMs; + // The window is 2 seconds. If nothing has been received for that time + // the estimate should be 0. + EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms))); +} + +TEST_F(RateStatisticsTest, IncreasingThenDecreasingBitrate) { + int64_t now_ms = 0; + stats_.Reset(); + // Expecting 0 after init. + EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms))); + + stats_.Update(1000, ++now_ms); + const uint32_t kExpectedBitrate = 8000000; + // 1000 bytes per millisecond until plateau is reached. + int prev_error = kExpectedBitrate; + absl::optional<uint32_t> bitrate; + while (++now_ms < 10000) { + stats_.Update(1000, now_ms); + bitrate = stats_.Rate(now_ms); + EXPECT_TRUE(static_cast<bool>(bitrate)); + int error = kExpectedBitrate - *bitrate; + error = std::abs(error); + // Expect the estimation error to decrease as the window is extended. + EXPECT_LE(error, prev_error + 1); + prev_error = error; + } + // Window filled, expect to be close to 8000000. + EXPECT_EQ(kExpectedBitrate, *bitrate); + + // 1000 bytes per millisecond until 10-second mark, 8000 kbps expected. + while (++now_ms < 10000) { + stats_.Update(1000, now_ms); + bitrate = stats_.Rate(now_ms); + EXPECT_EQ(kExpectedBitrate, *bitrate); + } + + // Zero bytes per millisecond until 0 is reached. + while (++now_ms < 20000) { + stats_.Update(0, now_ms); + absl::optional<uint32_t> new_bitrate = stats_.Rate(now_ms); + if (static_cast<bool>(new_bitrate) && *new_bitrate != *bitrate) { + // New bitrate must be lower than previous one. + EXPECT_LT(*new_bitrate, *bitrate); + } else { + // 0 kbps expected. + EXPECT_EQ(0u, *new_bitrate); + break; + } + bitrate = new_bitrate; + } + + // Zero bytes per millisecond until 20-second mark, 0 kbps expected. + while (++now_ms < 20000) { + stats_.Update(0, now_ms); + EXPECT_EQ(0u, *stats_.Rate(now_ms)); + } +} + +TEST_F(RateStatisticsTest, ResetAfterSilence) { + int64_t now_ms = 0; + stats_.Reset(); + // Expecting 0 after init. + EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms))); + + const uint32_t kExpectedBitrate = 8000000; + // 1000 bytes per millisecond until the window has been filled. + int prev_error = kExpectedBitrate; + absl::optional<uint32_t> bitrate; + while (++now_ms < 10000) { + stats_.Update(1000, now_ms); + bitrate = stats_.Rate(now_ms); + if (bitrate) { + int error = kExpectedBitrate - *bitrate; + error = std::abs(error); + // Expect the estimation error to decrease as the window is extended. + EXPECT_LE(error, prev_error + 1); + prev_error = error; + } + } + // Window filled, expect to be close to 8000000. + EXPECT_EQ(kExpectedBitrate, *bitrate); + + now_ms += kWindowMs + 1; + EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms))); + // Silence over window size should trigger auto reset for coming sample. + stats_.Update(1000, now_ms); + ++now_ms; + stats_.Update(1000, now_ms); + // We expect two samples of 1000 bytes, and that the bitrate is measured over + // active window instead of full window, which is now_ms - first_timestamp + 1 + EXPECT_EQ(kExpectedBitrate, *stats_.Rate(now_ms)); + + // Manual reset, add the same samples again. + stats_.Reset(); + EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms))); + stats_.Update(1000, now_ms); + ++now_ms; + stats_.Update(1000, now_ms); + // We expect two samples of 1000 bytes, and that the bitrate is measured over + // 2 ms (window size has been reset) i.e. 2 * 8 * 1000 / 0.002 = 8000000. + EXPECT_EQ(kExpectedBitrate, *stats_.Rate(now_ms)); +} + +TEST_F(RateStatisticsTest, HandlesChangingWindowSize) { + int64_t now_ms = 0; + stats_.Reset(); + + // Sanity test window size. + EXPECT_TRUE(stats_.SetWindowSize(kWindowMs, now_ms)); + EXPECT_FALSE(stats_.SetWindowSize(kWindowMs + 1, now_ms)); + EXPECT_FALSE(stats_.SetWindowSize(0, now_ms)); + EXPECT_TRUE(stats_.SetWindowSize(1, now_ms)); + EXPECT_TRUE(stats_.SetWindowSize(kWindowMs, now_ms)); + + // Fill the buffer at a rate of 1 byte / millisecond (8 kbps). + const int kBatchSize = 10; + for (int i = 0; i <= kWindowMs; i += kBatchSize) + stats_.Update(kBatchSize, now_ms += kBatchSize); + EXPECT_EQ(static_cast<uint32_t>(8000), *stats_.Rate(now_ms)); + + // Halve the window size, rate should stay the same. + EXPECT_TRUE(stats_.SetWindowSize(kWindowMs / 2, now_ms)); + EXPECT_EQ(static_cast<uint32_t>(8000), *stats_.Rate(now_ms)); + + // Double the window size again, rate should stay the same. (As the window + // won't actually expand until new bit and bobs fall into it. + EXPECT_TRUE(stats_.SetWindowSize(kWindowMs, now_ms)); + EXPECT_EQ(static_cast<uint32_t>(8000), *stats_.Rate(now_ms)); + + // Fill the now empty half with bits it twice the rate. + for (int i = 0; i < kWindowMs / 2; i += kBatchSize) + stats_.Update(kBatchSize * 2, now_ms += kBatchSize); + + // Rate should have increase be 50%. + EXPECT_EQ(static_cast<uint32_t>((8000 * 3) / 2), *stats_.Rate(now_ms)); +} + +TEST_F(RateStatisticsTest, RespectsWindowSizeEdges) { + int64_t now_ms = 0; + stats_.Reset(); + // Expecting 0 after init. + EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms))); + + // One byte per ms, using one big sample. + stats_.Update(kWindowMs, now_ms); + now_ms += kWindowMs - 2; + // Shouldn't work! (Only one sample, not full window size.) + EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms))); + + // Window size should be full, and the single data point should be accepted. + ++now_ms; + absl::optional<uint32_t> bitrate = stats_.Rate(now_ms); + EXPECT_TRUE(static_cast<bool>(bitrate)); + EXPECT_EQ(1000 * 8u, *bitrate); + + // Add another, now we have twice the bitrate. + stats_.Update(kWindowMs, now_ms); + bitrate = stats_.Rate(now_ms); + EXPECT_TRUE(static_cast<bool>(bitrate)); + EXPECT_EQ(2 * 1000 * 8u, *bitrate); + + // Now that first sample should drop out... + now_ms += 1; + bitrate = stats_.Rate(now_ms); + EXPECT_TRUE(static_cast<bool>(bitrate)); + EXPECT_EQ(1000 * 8u, *bitrate); +} + +TEST_F(RateStatisticsTest, HandlesZeroCounts) { + int64_t now_ms = 0; + stats_.Reset(); + // Expecting 0 after init. + EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms))); + + stats_.Update(kWindowMs, now_ms); + now_ms += kWindowMs - 1; + stats_.Update(0, now_ms); + absl::optional<uint32_t> bitrate = stats_.Rate(now_ms); + EXPECT_TRUE(static_cast<bool>(bitrate)); + EXPECT_EQ(1000 * 8u, *bitrate); + + // Move window along so first data point falls out. + ++now_ms; + bitrate = stats_.Rate(now_ms); + EXPECT_TRUE(static_cast<bool>(bitrate)); + EXPECT_EQ(0u, *bitrate); + + // Move window so last data point falls out. + now_ms += kWindowMs; + EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms))); +} + +TEST_F(RateStatisticsTest, HandlesQuietPeriods) { + int64_t now_ms = 0; + stats_.Reset(); + // Expecting 0 after init. + EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms))); + + stats_.Update(0, now_ms); + now_ms += kWindowMs - 1; + absl::optional<uint32_t> bitrate = stats_.Rate(now_ms); + EXPECT_TRUE(static_cast<bool>(bitrate)); + EXPECT_EQ(0u, *bitrate); + + // Move window along so first data point falls out. + ++now_ms; + EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms))); + + // Move window a long way out. + // This will cause an automatic reset of the window + // First data point won't give a valid result + now_ms += 2 * kWindowMs; + stats_.Update(0, now_ms); + bitrate = stats_.Rate(now_ms); + EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms))); + // Second data point gives valid result + ++now_ms; + stats_.Update(0, now_ms); + bitrate = stats_.Rate(now_ms); + EXPECT_TRUE(static_cast<bool>(bitrate)); + EXPECT_EQ(0u, *bitrate); +} + +TEST_F(RateStatisticsTest, HandlesBigNumbers) { + int64_t large_number = 0x100000000u; + int64_t now_ms = 0; + stats_.Update(large_number, now_ms++); + stats_.Update(large_number, now_ms); + EXPECT_TRUE(stats_.Rate(now_ms)); + EXPECT_EQ(large_number * RateStatistics::kBpsScale, *stats_.Rate(now_ms)); +} + +TEST_F(RateStatisticsTest, HandlesTooLargeNumbers) { + int64_t very_large_number = std::numeric_limits<int64_t>::max(); + int64_t now_ms = 0; + stats_.Update(very_large_number, now_ms++); + stats_.Update(very_large_number, now_ms); + // This should overflow the internal accumulator. + EXPECT_FALSE(stats_.Rate(now_ms)); +} + +TEST_F(RateStatisticsTest, HandlesSomewhatLargeNumbers) { + int64_t very_large_number = std::numeric_limits<int64_t>::max(); + int64_t now_ms = 0; + stats_.Update(very_large_number / 4, now_ms++); + stats_.Update(very_large_number / 4, now_ms); + // This should generate a rate of more than int64_t max, but still + // accumulate less than int64_t overflow. + EXPECT_FALSE(stats_.Rate(now_ms)); +} + +} // namespace diff --git a/third_party/libwebrtc/rtc_base/rate_tracker.cc b/third_party/libwebrtc/rtc_base/rate_tracker.cc new file mode 100644 index 0000000000..e39dadb988 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/rate_tracker.cc @@ -0,0 +1,158 @@ +/* + * Copyright 2015 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 "rtc_base/rate_tracker.h" + +#include <algorithm> + +#include "rtc_base/checks.h" +#include "rtc_base/time_utils.h" + +namespace rtc { + +static const int64_t kTimeUnset = -1; + +RateTracker::RateTracker(int64_t bucket_milliseconds, size_t bucket_count) + : bucket_milliseconds_(bucket_milliseconds), + bucket_count_(bucket_count), + sample_buckets_(new int64_t[bucket_count + 1]), + total_sample_count_(0u), + bucket_start_time_milliseconds_(kTimeUnset) { + RTC_CHECK(bucket_milliseconds > 0); + RTC_CHECK(bucket_count > 0); +} + +RateTracker::~RateTracker() { + delete[] sample_buckets_; +} + +double RateTracker::ComputeRateForInterval( + int64_t interval_milliseconds) const { + if (bucket_start_time_milliseconds_ == kTimeUnset) { + return 0.0; + } + int64_t current_time = Time(); + // Calculate which buckets to sum up given the current time. If the time + // has passed to a new bucket then we have to skip some of the oldest buckets. + int64_t available_interval_milliseconds = + std::min(interval_milliseconds, + bucket_milliseconds_ * static_cast<int64_t>(bucket_count_)); + // number of old buckets (i.e. after the current bucket in the ring buffer) + // that are expired given our current time interval. + size_t buckets_to_skip; + // Number of milliseconds of the first bucket that are not a portion of the + // current interval. + int64_t milliseconds_to_skip; + if (current_time > + initialization_time_milliseconds_ + available_interval_milliseconds) { + int64_t time_to_skip = + current_time - bucket_start_time_milliseconds_ + + static_cast<int64_t>(bucket_count_) * bucket_milliseconds_ - + available_interval_milliseconds; + buckets_to_skip = time_to_skip / bucket_milliseconds_; + milliseconds_to_skip = time_to_skip % bucket_milliseconds_; + } else { + buckets_to_skip = bucket_count_ - current_bucket_; + milliseconds_to_skip = 0; + available_interval_milliseconds = + TimeDiff(current_time, initialization_time_milliseconds_); + // Let one bucket interval pass after initialization before reporting. + if (available_interval_milliseconds < bucket_milliseconds_) { + return 0.0; + } + } + // If we're skipping all buckets that means that there have been no samples + // within the sampling interval so report 0. + if (buckets_to_skip > bucket_count_ || available_interval_milliseconds == 0) { + return 0.0; + } + size_t start_bucket = NextBucketIndex(current_bucket_ + buckets_to_skip); + // Only count a portion of the first bucket according to how much of the + // first bucket is within the current interval. + int64_t total_samples = ((sample_buckets_[start_bucket] * + (bucket_milliseconds_ - milliseconds_to_skip)) + + (bucket_milliseconds_ >> 1)) / + bucket_milliseconds_; + // All other buckets in the interval are counted in their entirety. + for (size_t i = NextBucketIndex(start_bucket); + i != NextBucketIndex(current_bucket_); i = NextBucketIndex(i)) { + total_samples += sample_buckets_[i]; + } + // Convert to samples per second. + return static_cast<double>(total_samples * 1000) / + static_cast<double>(available_interval_milliseconds); +} + +double RateTracker::ComputeTotalRate() const { + if (bucket_start_time_milliseconds_ == kTimeUnset) { + return 0.0; + } + int64_t current_time = Time(); + if (current_time <= initialization_time_milliseconds_) { + return 0.0; + } + return static_cast<double>(total_sample_count_ * 1000) / + static_cast<double>( + TimeDiff(current_time, initialization_time_milliseconds_)); +} + +int64_t RateTracker::TotalSampleCount() const { + return total_sample_count_; +} + +void RateTracker::AddSamples(int64_t sample_count) { + AddSamplesAtTime(Time(), sample_count); +} + +void RateTracker::AddSamplesAtTime(int64_t current_time_ms, + int64_t sample_count) { + RTC_DCHECK_LE(0, sample_count); + EnsureInitialized(); + // Advance the current bucket as needed for the current time, and reset + // bucket counts as we advance. + for (size_t i = 0; i <= bucket_count_ && + current_time_ms >= + bucket_start_time_milliseconds_ + bucket_milliseconds_; + ++i) { + bucket_start_time_milliseconds_ += bucket_milliseconds_; + current_bucket_ = NextBucketIndex(current_bucket_); + sample_buckets_[current_bucket_] = 0; + } + // Ensure that bucket_start_time_milliseconds_ is updated appropriately if + // the entire buffer of samples has been expired. + bucket_start_time_milliseconds_ += + bucket_milliseconds_ * + ((current_time_ms - bucket_start_time_milliseconds_) / + bucket_milliseconds_); + // Add all samples in the bucket that includes the current time. + sample_buckets_[current_bucket_] += sample_count; + total_sample_count_ += sample_count; +} + +int64_t RateTracker::Time() const { + return rtc::TimeMillis(); +} + +void RateTracker::EnsureInitialized() { + if (bucket_start_time_milliseconds_ == kTimeUnset) { + initialization_time_milliseconds_ = Time(); + bucket_start_time_milliseconds_ = initialization_time_milliseconds_; + current_bucket_ = 0; + // We only need to initialize the first bucket because we reset buckets when + // current_bucket_ increments. + sample_buckets_[current_bucket_] = 0; + } +} + +size_t RateTracker::NextBucketIndex(size_t bucket_index) const { + return (bucket_index + 1u) % (bucket_count_ + 1u); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/rate_tracker.h b/third_party/libwebrtc/rtc_base/rate_tracker.h new file mode 100644 index 0000000000..d706569ecd --- /dev/null +++ b/third_party/libwebrtc/rtc_base/rate_tracker.h @@ -0,0 +1,72 @@ +/* + * Copyright 2015 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 RTC_BASE_RATE_TRACKER_H_ +#define RTC_BASE_RATE_TRACKER_H_ + +#include <stdint.h> +#include <stdlib.h> + +namespace rtc { + +// Computes units per second over a given interval by tracking the units over +// each bucket of a given size and calculating the instantaneous rate assuming +// that over each bucket the rate was constant. +class RateTracker { + public: + RateTracker(int64_t bucket_milliseconds, size_t bucket_count); + virtual ~RateTracker(); + + // Computes the average rate over the most recent interval_milliseconds, + // or if the first sample was added within this period, computes the rate + // since the first sample was added. + double ComputeRateForInterval(int64_t interval_milliseconds) const; + + // Computes the average rate over the rate tracker's recording interval + // of bucket_milliseconds * bucket_count. + double ComputeRate() const { + return ComputeRateForInterval(bucket_milliseconds_ * + static_cast<int64_t>(bucket_count_)); + } + + // Computes the average rate since the first sample was added to the + // rate tracker. + double ComputeTotalRate() const; + + // The total number of samples added. + int64_t TotalSampleCount() const; + + // Reads the current time in order to determine the appropriate bucket for + // these samples, and increments the count for that bucket by sample_count. + void AddSamples(int64_t sample_count); + + // Increment count for bucket at `current_time_ms`. + void AddSamplesAtTime(int64_t current_time_ms, int64_t sample_count); + + protected: + // overrideable for tests + virtual int64_t Time() const; + + private: + void EnsureInitialized(); + size_t NextBucketIndex(size_t bucket_index) const; + + const int64_t bucket_milliseconds_; + const size_t bucket_count_; + int64_t* sample_buckets_; + size_t total_sample_count_; + size_t current_bucket_; + int64_t bucket_start_time_milliseconds_; + int64_t initialization_time_milliseconds_; +}; + +} // namespace rtc + +#endif // RTC_BASE_RATE_TRACKER_H_ diff --git a/third_party/libwebrtc/rtc_base/rate_tracker_gn/moz.build b/third_party/libwebrtc/rtc_base/rate_tracker_gn/moz.build new file mode 100644 index 0000000000..f8ebf228f1 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/rate_tracker_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/rtc_base/rate_tracker.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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("rate_tracker_gn") diff --git a/third_party/libwebrtc/rtc_base/rate_tracker_unittest.cc b/third_party/libwebrtc/rtc_base/rate_tracker_unittest.cc new file mode 100644 index 0000000000..22ae2c07e7 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/rate_tracker_unittest.cc @@ -0,0 +1,178 @@ +/* + * Copyright 2015 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 "rtc_base/rate_tracker.h" + +#include "test/gtest.h" + +namespace rtc { +namespace { +const uint32_t kBucketIntervalMs = 100; +} // namespace + +class RateTrackerForTest : public RateTracker { + public: + RateTrackerForTest() : RateTracker(kBucketIntervalMs, 10u), time_(0) {} + int64_t Time() const override { return time_; } + void AdvanceTime(int delta) { time_ += delta; } + + private: + int64_t time_; +}; + +TEST(RateTrackerTest, Test30FPS) { + RateTrackerForTest tracker; + + for (int i = 0; i < 300; ++i) { + tracker.AddSamples(1); + tracker.AdvanceTime(33); + if (i % 3 == 0) { + tracker.AdvanceTime(1); + } + } + EXPECT_DOUBLE_EQ(30.0, tracker.ComputeRateForInterval(50000)); +} + +TEST(RateTrackerTest, Test60FPS) { + RateTrackerForTest tracker; + + for (int i = 0; i < 300; ++i) { + tracker.AddSamples(1); + tracker.AdvanceTime(16); + if (i % 3 != 0) { + tracker.AdvanceTime(1); + } + } + EXPECT_DOUBLE_EQ(60.0, tracker.ComputeRateForInterval(1000)); +} + +TEST(RateTrackerTest, TestRateTrackerBasics) { + RateTrackerForTest tracker; + EXPECT_DOUBLE_EQ(0.0, tracker.ComputeRateForInterval(1000)); + + // Add a sample. + tracker.AddSamples(1234); + // Advance the clock by less than one bucket interval (no rate returned). + tracker.AdvanceTime(kBucketIntervalMs - 1); + EXPECT_DOUBLE_EQ(0.0, tracker.ComputeRate()); + // Advance the clock by 100 ms (one bucket interval). + tracker.AdvanceTime(1); + EXPECT_DOUBLE_EQ(12340.0, tracker.ComputeRateForInterval(1000)); + EXPECT_DOUBLE_EQ(12340.0, tracker.ComputeRate()); + EXPECT_EQ(1234U, tracker.TotalSampleCount()); + EXPECT_DOUBLE_EQ(12340.0, tracker.ComputeTotalRate()); + + // Repeat. + tracker.AddSamples(1234); + tracker.AdvanceTime(100); + EXPECT_DOUBLE_EQ(12340.0, tracker.ComputeRateForInterval(1000)); + EXPECT_DOUBLE_EQ(12340.0, tracker.ComputeRate()); + EXPECT_EQ(1234U * 2, tracker.TotalSampleCount()); + EXPECT_DOUBLE_EQ(12340.0, tracker.ComputeTotalRate()); + + // Advance the clock by 800 ms, so we've elapsed a full second. + // units_second should now be filled in properly. + tracker.AdvanceTime(800); + EXPECT_DOUBLE_EQ(1234.0 * 2.0, tracker.ComputeRateForInterval(1000)); + EXPECT_DOUBLE_EQ(1234.0 * 2.0, tracker.ComputeRate()); + EXPECT_EQ(1234U * 2, tracker.TotalSampleCount()); + EXPECT_DOUBLE_EQ(1234.0 * 2.0, tracker.ComputeTotalRate()); + + // Poll the tracker again immediately. The reported rate should stay the same. + EXPECT_DOUBLE_EQ(1234.0 * 2.0, tracker.ComputeRateForInterval(1000)); + EXPECT_DOUBLE_EQ(1234.0 * 2.0, tracker.ComputeRate()); + EXPECT_EQ(1234U * 2, tracker.TotalSampleCount()); + EXPECT_DOUBLE_EQ(1234.0 * 2.0, tracker.ComputeTotalRate()); + + // Do nothing and advance by a second. We should drop down to zero. + tracker.AdvanceTime(1000); + EXPECT_DOUBLE_EQ(0.0, tracker.ComputeRateForInterval(1000)); + EXPECT_DOUBLE_EQ(0.0, tracker.ComputeRate()); + EXPECT_EQ(1234U * 2, tracker.TotalSampleCount()); + EXPECT_DOUBLE_EQ(1234.0, tracker.ComputeTotalRate()); + + // Send a bunch of data at a constant rate for 5.5 "seconds". + // We should report the rate properly. + for (int i = 0; i < 5500; i += 100) { + tracker.AddSamples(9876U); + tracker.AdvanceTime(100); + } + EXPECT_DOUBLE_EQ(9876.0 * 10.0, tracker.ComputeRateForInterval(1000)); + EXPECT_DOUBLE_EQ(9876.0 * 10.0, tracker.ComputeRate()); + EXPECT_EQ(1234U * 2 + 9876U * 55, tracker.TotalSampleCount()); + EXPECT_DOUBLE_EQ((1234.0 * 2.0 + 9876.0 * 55.0) / 7.5, + tracker.ComputeTotalRate()); + + // Advance the clock by 500 ms. Since we sent nothing over this half-second, + // the reported rate should be reduced by half. + tracker.AdvanceTime(500); + EXPECT_DOUBLE_EQ(9876.0 * 5.0, tracker.ComputeRateForInterval(1000)); + EXPECT_DOUBLE_EQ(9876.0 * 5.0, tracker.ComputeRate()); + EXPECT_EQ(1234U * 2 + 9876U * 55, tracker.TotalSampleCount()); + EXPECT_DOUBLE_EQ((1234.0 * 2.0 + 9876.0 * 55.0) / 8.0, + tracker.ComputeTotalRate()); + + // Rate over the last half second should be zero. + EXPECT_DOUBLE_EQ(0.0, tracker.ComputeRateForInterval(500)); +} + +TEST(RateTrackerTest, TestLongPeriodBetweenSamples) { + RateTrackerForTest tracker; + tracker.AddSamples(1); + tracker.AdvanceTime(1000); + EXPECT_DOUBLE_EQ(1.0, tracker.ComputeRate()); + + tracker.AdvanceTime(2000); + EXPECT_DOUBLE_EQ(0.0, tracker.ComputeRate()); + + tracker.AdvanceTime(2000); + tracker.AddSamples(1); + EXPECT_DOUBLE_EQ(1.0, tracker.ComputeRate()); +} + +TEST(RateTrackerTest, TestRolloff) { + RateTrackerForTest tracker; + for (int i = 0; i < 10; ++i) { + tracker.AddSamples(1U); + tracker.AdvanceTime(100); + } + EXPECT_DOUBLE_EQ(10.0, tracker.ComputeRate()); + + for (int i = 0; i < 10; ++i) { + tracker.AddSamples(1U); + tracker.AdvanceTime(50); + } + EXPECT_DOUBLE_EQ(15.0, tracker.ComputeRate()); + EXPECT_DOUBLE_EQ(20.0, tracker.ComputeRateForInterval(500)); + + for (int i = 0; i < 10; ++i) { + tracker.AddSamples(1U); + tracker.AdvanceTime(50); + } + EXPECT_DOUBLE_EQ(20.0, tracker.ComputeRate()); +} + +TEST(RateTrackerTest, TestGetUnitSecondsAfterInitialValue) { + RateTrackerForTest tracker; + tracker.AddSamples(1234); + tracker.AdvanceTime(1000); + EXPECT_DOUBLE_EQ(1234.0, tracker.ComputeRateForInterval(1000)); +} + +TEST(RateTrackerTest, TestLargeNumbers) { + RateTrackerForTest tracker; + const uint64_t large_number = 0x100000000; + tracker.AddSamples(large_number); + tracker.AdvanceTime(1000); + tracker.AddSamples(large_number); + EXPECT_DOUBLE_EQ(large_number * 2, tracker.ComputeRate()); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/ref_count.h b/third_party/libwebrtc/rtc_base/ref_count.h new file mode 100644 index 0000000000..d8d652abd8 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/ref_count.h @@ -0,0 +1,67 @@ +/* + * Copyright 2011 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 RTC_BASE_REF_COUNT_H_ +#define RTC_BASE_REF_COUNT_H_ + +namespace rtc { + +// Refcounted objects should implement the following informal interface: +// +// void AddRef() const ; +// RefCountReleaseStatus Release() const; +// +// You may access members of a reference-counted object, including the AddRef() +// and Release() methods, only if you already own a reference to it, or if +// you're borrowing someone else's reference. (A newly created object is a +// special case: the reference count is zero on construction, and the code that +// creates the object should immediately call AddRef(), bringing the reference +// count from zero to one, e.g., by constructing an rtc::scoped_refptr). +// +// AddRef() creates a new reference to the object. +// +// Release() releases a reference to the object; the caller now has one less +// reference than before the call. Returns kDroppedLastRef if the number of +// references dropped to zero because of this (in which case the object destroys +// itself). Otherwise, returns kOtherRefsRemained, to signal that at the precise +// time the caller's reference was dropped, other references still remained (but +// if other threads own references, this may of course have changed by the time +// Release() returns). +// +// The caller of Release() must treat it in the same way as a delete operation: +// Regardless of the return value from Release(), the caller mustn't access the +// object. The object might still be alive, due to references held by other +// users of the object, but the object can go away at any time, e.g., as the +// result of another thread calling Release(). +// +// Calling AddRef() and Release() manually is discouraged. It's recommended to +// use rtc::scoped_refptr to manage all pointers to reference counted objects. +// Note that rtc::scoped_refptr depends on compile-time duck-typing; formally +// implementing the below RefCountInterface is not required. + +enum class RefCountReleaseStatus { kDroppedLastRef, kOtherRefsRemained }; + +// Interfaces where refcounting is part of the public api should +// inherit this abstract interface. The implementation of these +// methods is usually provided by the RefCountedObject template class, +// applied as a leaf in the inheritance tree. +class RefCountInterface { + public: + virtual void AddRef() const = 0; + virtual RefCountReleaseStatus Release() const = 0; + + // Non-public destructor, because Release() has exclusive responsibility for + // destroying the object. + protected: + virtual ~RefCountInterface() {} +}; + +} // namespace rtc + +#endif // RTC_BASE_REF_COUNT_H_ diff --git a/third_party/libwebrtc/rtc_base/ref_counted_object.h b/third_party/libwebrtc/rtc_base/ref_counted_object.h new file mode 100644 index 0000000000..418c3d80cc --- /dev/null +++ b/third_party/libwebrtc/rtc_base/ref_counted_object.h @@ -0,0 +1,89 @@ +/* + * Copyright 2016 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 RTC_BASE_REF_COUNTED_OBJECT_H_ +#define RTC_BASE_REF_COUNTED_OBJECT_H_ + +#include "api/scoped_refptr.h" +#include "rtc_base/ref_count.h" +#include "rtc_base/ref_counter.h" + +namespace rtc { + +template <class T> +class RefCountedObject : public T { + public: + RefCountedObject() {} + + RefCountedObject(const RefCountedObject&) = delete; + RefCountedObject& operator=(const RefCountedObject&) = delete; + + template <class P0> + explicit RefCountedObject(P0&& p0) : T(std::forward<P0>(p0)) {} + + template <class P0, class P1, class... Args> + RefCountedObject(P0&& p0, P1&& p1, Args&&... args) + : T(std::forward<P0>(p0), + std::forward<P1>(p1), + std::forward<Args>(args)...) {} + + void AddRef() const override { ref_count_.IncRef(); } + + RefCountReleaseStatus Release() const override { + const auto status = ref_count_.DecRef(); + if (status == RefCountReleaseStatus::kDroppedLastRef) { + delete this; + } + return status; + } + + // Return whether the reference count is one. If the reference count is used + // in the conventional way, a reference count of 1 implies that the current + // thread owns the reference and no other thread shares it. This call + // performs the test for a reference count of one, and performs the memory + // barrier needed for the owning thread to act on the object, knowing that it + // has exclusive access to the object. + virtual bool HasOneRef() const { return ref_count_.HasOneRef(); } + + protected: + ~RefCountedObject() override {} + + mutable webrtc::webrtc_impl::RefCounter ref_count_{0}; +}; + +template <class T> +class FinalRefCountedObject final : public T { + public: + using T::T; + // Above using declaration propagates a default move constructor + // FinalRefCountedObject(FinalRefCountedObject&& other), but we also need + // move construction from T. + explicit FinalRefCountedObject(T&& other) : T(std::move(other)) {} + FinalRefCountedObject(const FinalRefCountedObject&) = delete; + FinalRefCountedObject& operator=(const FinalRefCountedObject&) = delete; + + void AddRef() const { ref_count_.IncRef(); } + RefCountReleaseStatus Release() const { + const auto status = ref_count_.DecRef(); + if (status == RefCountReleaseStatus::kDroppedLastRef) { + delete this; + } + return status; + } + bool HasOneRef() const { return ref_count_.HasOneRef(); } + + private: + ~FinalRefCountedObject() = default; + + mutable webrtc::webrtc_impl::RefCounter ref_count_{0}; +}; + +} // namespace rtc + +#endif // RTC_BASE_REF_COUNTED_OBJECT_H_ diff --git a/third_party/libwebrtc/rtc_base/ref_counted_object_unittest.cc b/third_party/libwebrtc/rtc_base/ref_counted_object_unittest.cc new file mode 100644 index 0000000000..abeb1e9e67 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/ref_counted_object_unittest.cc @@ -0,0 +1,175 @@ +/* + * Copyright 2016 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 "rtc_base/ref_counted_object.h" + +#include <memory> +#include <string> +#include <type_traits> +#include <utility> + +#include "absl/strings/string_view.h" +#include "api/make_ref_counted.h" +#include "api/scoped_refptr.h" +#include "rtc_base/ref_count.h" +#include "test/gtest.h" + +namespace rtc { + +namespace { + +class A { + public: + A() {} + + A(const A&) = delete; + A& operator=(const A&) = delete; +}; + +class RefClass : public RefCountInterface { + public: + RefClass() {} + + protected: + ~RefClass() override {} +}; + +class RefClassWithRvalue : public RefCountInterface { + public: + explicit RefClassWithRvalue(std::unique_ptr<A> a) : a_(std::move(a)) {} + + protected: + ~RefClassWithRvalue() override {} + + public: + std::unique_ptr<A> a_; +}; + +class RefClassWithMixedValues : public RefCountInterface { + public: + RefClassWithMixedValues(std::unique_ptr<A> a, int b, absl::string_view c) + : a_(std::move(a)), b_(b), c_(c) {} + + protected: + ~RefClassWithMixedValues() override {} + + public: + std::unique_ptr<A> a_; + int b_; + std::string c_; +}; + +class Foo { + public: + Foo() {} + Foo(int i, int j) : foo_(i + j) {} + int foo_ = 0; +}; + +class FooItf : public RefCountInterface { + public: + FooItf() {} + FooItf(int i, int j) : foo_(i + j) {} + int foo_ = 0; +}; + +} // namespace + +TEST(RefCountedObject, HasOneRef) { + scoped_refptr<RefCountedObject<RefClass>> aref( + new RefCountedObject<RefClass>()); + EXPECT_TRUE(aref->HasOneRef()); + aref->AddRef(); + EXPECT_FALSE(aref->HasOneRef()); + EXPECT_EQ(aref->Release(), RefCountReleaseStatus::kOtherRefsRemained); + EXPECT_TRUE(aref->HasOneRef()); +} + +TEST(RefCountedObject, SupportRValuesInCtor) { + std::unique_ptr<A> a(new A()); + scoped_refptr<RefClassWithRvalue> ref( + new RefCountedObject<RefClassWithRvalue>(std::move(a))); + EXPECT_TRUE(ref->a_.get() != nullptr); + EXPECT_TRUE(a.get() == nullptr); +} + +TEST(RefCountedObject, SupportMixedTypesInCtor) { + std::unique_ptr<A> a(new A()); + int b = 9; + std::string c = "hello"; + scoped_refptr<RefClassWithMixedValues> ref( + new RefCountedObject<RefClassWithMixedValues>(std::move(a), b, c)); + EXPECT_TRUE(ref->a_.get() != nullptr); + EXPECT_TRUE(a.get() == nullptr); + EXPECT_EQ(b, ref->b_); + EXPECT_EQ(c, ref->c_); +} + +TEST(FinalRefCountedObject, CanWrapIntoScopedRefptr) { + using WrappedTyped = FinalRefCountedObject<A>; + static_assert(!std::is_polymorphic<WrappedTyped>::value, ""); + scoped_refptr<WrappedTyped> ref(new WrappedTyped()); + EXPECT_TRUE(ref.get()); + EXPECT_TRUE(ref->HasOneRef()); + // Test reference counter is updated on some simple operations. + scoped_refptr<WrappedTyped> ref2 = ref; + EXPECT_FALSE(ref->HasOneRef()); + EXPECT_FALSE(ref2->HasOneRef()); + + ref = nullptr; + EXPECT_TRUE(ref2->HasOneRef()); +} + +TEST(FinalRefCountedObject, CanCreateFromMovedType) { + class MoveOnly { + public: + MoveOnly(int a) : a_(a) {} + MoveOnly(MoveOnly&&) = default; + + int a() { return a_; } + + private: + int a_; + }; + MoveOnly foo(5); + auto ref = make_ref_counted<MoveOnly>(std::move(foo)); + EXPECT_EQ(ref->a(), 5); +} + +// This test is mostly a compile-time test for scoped_refptr compatibility. +TEST(RefCounted, SmartPointers) { + // Sanity compile-time tests. FooItf is virtual, Foo is not, FooItf inherits + // from RefCountInterface, Foo does not. + static_assert(std::is_base_of<RefCountInterface, FooItf>::value, ""); + static_assert(!std::is_base_of<RefCountInterface, Foo>::value, ""); + static_assert(std::is_polymorphic<FooItf>::value, ""); + static_assert(!std::is_polymorphic<Foo>::value, ""); + + { + // Test with FooItf, a class that inherits from RefCountInterface. + // Check that we get a valid FooItf reference counted object. + auto p = make_ref_counted<FooItf>(2, 3); + EXPECT_NE(p.get(), nullptr); + EXPECT_EQ(p->foo_, 5); // the FooItf ctor just stores 2+3 in foo_. + + // Declaring what should result in the same type as `p` is of. + scoped_refptr<FooItf> p2 = p; + } + + { + // Same for `Foo` + auto p = make_ref_counted<Foo>(2, 3); + EXPECT_NE(p.get(), nullptr); + EXPECT_EQ(p->foo_, 5); + scoped_refptr<FinalRefCountedObject<Foo>> p2 = p; + } +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/ref_counter.h b/third_party/libwebrtc/rtc_base/ref_counter.h new file mode 100644 index 0000000000..6ffeda8ced --- /dev/null +++ b/third_party/libwebrtc/rtc_base/ref_counter.h @@ -0,0 +1,75 @@ +/* + * Copyright 2017 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 RTC_BASE_REF_COUNTER_H_ +#define RTC_BASE_REF_COUNTER_H_ + +#include <atomic> + +#include "rtc_base/ref_count.h" + +namespace webrtc { +namespace webrtc_impl { + +class RefCounter { + public: + explicit RefCounter(int ref_count) : ref_count_(ref_count) {} + RefCounter() = delete; + + void IncRef() { + // Relaxed memory order: The current thread is allowed to act on the + // resource protected by the reference counter both before and after the + // atomic op, so this function doesn't prevent memory access reordering. + ref_count_.fetch_add(1, std::memory_order_relaxed); + } + + // Returns kDroppedLastRef if this call dropped the last reference; the caller + // should therefore free the resource protected by the reference counter. + // Otherwise, returns kOtherRefsRemained (note that in case of multithreading, + // some other caller may have dropped the last reference by the time this call + // returns; all we know is that we didn't do it). + rtc::RefCountReleaseStatus DecRef() { + // Use release-acquire barrier to ensure all actions on the protected + // resource are finished before the resource can be freed. + // When ref_count_after_subtract > 0, this function require + // std::memory_order_release part of the barrier. + // When ref_count_after_subtract == 0, this function require + // std::memory_order_acquire part of the barrier. + // In addition std::memory_order_release is used for synchronization with + // the HasOneRef function to make sure all actions on the protected resource + // are finished before the resource is assumed to have exclusive access. + int ref_count_after_subtract = + ref_count_.fetch_sub(1, std::memory_order_acq_rel) - 1; + return ref_count_after_subtract == 0 + ? rtc::RefCountReleaseStatus::kDroppedLastRef + : rtc::RefCountReleaseStatus::kOtherRefsRemained; + } + + // Return whether the reference count is one. If the reference count is used + // in the conventional way, a reference count of 1 implies that the current + // thread owns the reference and no other thread shares it. This call performs + // the test for a reference count of one, and performs the memory barrier + // needed for the owning thread to act on the resource protected by the + // reference counter, knowing that it has exclusive access. + bool HasOneRef() const { + // To ensure resource protected by the reference counter has exclusive + // access, all changes to the resource before it was released by other + // threads must be visible by current thread. That is provided by release + // (in DecRef) and acquire (in this function) ordering. + return ref_count_.load(std::memory_order_acquire) == 1; + } + + private: + std::atomic<int> ref_count_; +}; + +} // namespace webrtc_impl +} // namespace webrtc + +#endif // RTC_BASE_REF_COUNTER_H_ diff --git a/third_party/libwebrtc/rtc_base/refcount_gn/moz.build b/third_party/libwebrtc/rtc_base/refcount_gn/moz.build new file mode 100644 index 0000000000..a1b2bcfecc --- /dev/null +++ b/third_party/libwebrtc/rtc_base/refcount_gn/moz.build @@ -0,0 +1,205 @@ +# 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("refcount_gn") diff --git a/third_party/libwebrtc/rtc_base/rolling_accumulator.h b/third_party/libwebrtc/rtc_base/rolling_accumulator.h new file mode 100644 index 0000000000..84d791edd1 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/rolling_accumulator.h @@ -0,0 +1,145 @@ +/* + * Copyright 2011 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 RTC_BASE_ROLLING_ACCUMULATOR_H_ +#define RTC_BASE_ROLLING_ACCUMULATOR_H_ + +#include <stddef.h> + +#include <algorithm> +#include <vector> + +#include "rtc_base/checks.h" +#include "rtc_base/numerics/running_statistics.h" + +namespace rtc { + +// RollingAccumulator stores and reports statistics +// over N most recent samples. +// +// T is assumed to be an int, long, double or float. +template <typename T> +class RollingAccumulator { + public: + explicit RollingAccumulator(size_t max_count) : samples_(max_count) { + RTC_DCHECK(max_count > 0); + Reset(); + } + ~RollingAccumulator() {} + + RollingAccumulator(const RollingAccumulator&) = delete; + RollingAccumulator& operator=(const RollingAccumulator&) = delete; + + size_t max_count() const { return samples_.size(); } + + size_t count() const { return static_cast<size_t>(stats_.Size()); } + + void Reset() { + stats_ = webrtc::webrtc_impl::RunningStatistics<T>(); + next_index_ = 0U; + max_ = T(); + max_stale_ = false; + min_ = T(); + min_stale_ = false; + } + + void AddSample(T sample) { + if (count() == max_count()) { + // Remove oldest sample. + T sample_to_remove = samples_[next_index_]; + stats_.RemoveSample(sample_to_remove); + if (sample_to_remove >= max_) { + max_stale_ = true; + } + if (sample_to_remove <= min_) { + min_stale_ = true; + } + } + // Add new sample. + samples_[next_index_] = sample; + if (count() == 0 || sample >= max_) { + max_ = sample; + max_stale_ = false; + } + if (count() == 0 || sample <= min_) { + min_ = sample; + min_stale_ = false; + } + stats_.AddSample(sample); + // Update next_index_. + next_index_ = (next_index_ + 1) % max_count(); + } + + double ComputeMean() const { return stats_.GetMean().value_or(0); } + + T ComputeMax() const { + if (max_stale_) { + RTC_DCHECK(count() > 0) + << "It shouldn't be possible for max_stale_ && count() == 0"; + max_ = samples_[next_index_]; + for (size_t i = 1u; i < count(); i++) { + max_ = std::max(max_, samples_[(next_index_ + i) % max_count()]); + } + max_stale_ = false; + } + return max_; + } + + T ComputeMin() const { + if (min_stale_) { + RTC_DCHECK(count() > 0) + << "It shouldn't be possible for min_stale_ && count() == 0"; + min_ = samples_[next_index_]; + for (size_t i = 1u; i < count(); i++) { + min_ = std::min(min_, samples_[(next_index_ + i) % max_count()]); + } + min_stale_ = false; + } + return min_; + } + + // O(n) time complexity. + // Weights nth sample with weight (learning_rate)^n. Learning_rate should be + // between (0.0, 1.0], otherwise the non-weighted mean is returned. + double ComputeWeightedMean(double learning_rate) const { + if (count() < 1 || learning_rate <= 0.0 || learning_rate >= 1.0) { + return ComputeMean(); + } + double weighted_mean = 0.0; + double current_weight = 1.0; + double weight_sum = 0.0; + const size_t max_size = max_count(); + for (size_t i = 0; i < count(); ++i) { + current_weight *= learning_rate; + weight_sum += current_weight; + // Add max_size to prevent underflow. + size_t index = (next_index_ + max_size - i - 1) % max_size; + weighted_mean += current_weight * samples_[index]; + } + return weighted_mean / weight_sum; + } + + // Compute estimated variance. Estimation is more accurate + // as the number of samples grows. + double ComputeVariance() const { return stats_.GetVariance().value_or(0); } + + private: + webrtc::webrtc_impl::RunningStatistics<T> stats_; + size_t next_index_; + mutable T max_; + mutable bool max_stale_; + mutable T min_; + mutable bool min_stale_; + std::vector<T> samples_; +}; + +} // namespace rtc + +#endif // RTC_BASE_ROLLING_ACCUMULATOR_H_ diff --git a/third_party/libwebrtc/rtc_base/rolling_accumulator_gn/moz.build b/third_party/libwebrtc/rtc_base/rolling_accumulator_gn/moz.build new file mode 100644 index 0000000000..c5cbc0cb54 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/rolling_accumulator_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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("rolling_accumulator_gn") diff --git a/third_party/libwebrtc/rtc_base/rolling_accumulator_unittest.cc b/third_party/libwebrtc/rtc_base/rolling_accumulator_unittest.cc new file mode 100644 index 0000000000..3a26f9e42f --- /dev/null +++ b/third_party/libwebrtc/rtc_base/rolling_accumulator_unittest.cc @@ -0,0 +1,150 @@ +/* + * Copyright 2011 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 "rtc_base/rolling_accumulator.h" + +#include <random> + +#include "test/gtest.h" + +namespace rtc { + +namespace { + +const double kLearningRate = 0.5; + +// Add `n` samples drawn from uniform distribution in [a;b]. +void FillStatsFromUniformDistribution(RollingAccumulator<double>& stats, + int n, + double a, + double b) { + std::mt19937 gen{std::random_device()()}; + std::uniform_real_distribution<> dis(a, b); + + for (int i = 1; i <= n; i++) { + stats.AddSample(dis(gen)); + } +} +} // namespace + +TEST(RollingAccumulatorTest, ZeroSamples) { + RollingAccumulator<int> accum(10); + + EXPECT_EQ(0U, accum.count()); + EXPECT_DOUBLE_EQ(0.0, accum.ComputeMean()); + EXPECT_DOUBLE_EQ(0.0, accum.ComputeVariance()); + EXPECT_EQ(0, accum.ComputeMin()); + EXPECT_EQ(0, accum.ComputeMax()); +} + +TEST(RollingAccumulatorTest, SomeSamples) { + RollingAccumulator<int> accum(10); + for (int i = 0; i < 4; ++i) { + accum.AddSample(i); + } + + EXPECT_EQ(4U, accum.count()); + EXPECT_DOUBLE_EQ(1.5, accum.ComputeMean()); + EXPECT_NEAR(2.26666, accum.ComputeWeightedMean(kLearningRate), 0.01); + EXPECT_DOUBLE_EQ(1.25, accum.ComputeVariance()); + EXPECT_EQ(0, accum.ComputeMin()); + EXPECT_EQ(3, accum.ComputeMax()); +} + +TEST(RollingAccumulatorTest, RollingSamples) { + RollingAccumulator<int> accum(10); + for (int i = 0; i < 12; ++i) { + accum.AddSample(i); + } + + EXPECT_EQ(10U, accum.count()); + EXPECT_DOUBLE_EQ(6.5, accum.ComputeMean()); + EXPECT_NEAR(10.0, accum.ComputeWeightedMean(kLearningRate), 0.01); + EXPECT_NEAR(9.0, accum.ComputeVariance(), 1.0); + EXPECT_EQ(2, accum.ComputeMin()); + EXPECT_EQ(11, accum.ComputeMax()); +} + +TEST(RollingAccumulatorTest, ResetSamples) { + RollingAccumulator<int> accum(10); + + for (int i = 0; i < 10; ++i) { + accum.AddSample(100); + } + EXPECT_EQ(10U, accum.count()); + EXPECT_DOUBLE_EQ(100.0, accum.ComputeMean()); + EXPECT_EQ(100, accum.ComputeMin()); + EXPECT_EQ(100, accum.ComputeMax()); + + accum.Reset(); + EXPECT_EQ(0U, accum.count()); + + for (int i = 0; i < 5; ++i) { + accum.AddSample(i); + } + + EXPECT_EQ(5U, accum.count()); + EXPECT_DOUBLE_EQ(2.0, accum.ComputeMean()); + EXPECT_EQ(0, accum.ComputeMin()); + EXPECT_EQ(4, accum.ComputeMax()); +} + +TEST(RollingAccumulatorTest, RollingSamplesDouble) { + RollingAccumulator<double> accum(10); + for (int i = 0; i < 23; ++i) { + accum.AddSample(5 * i); + } + + EXPECT_EQ(10u, accum.count()); + EXPECT_DOUBLE_EQ(87.5, accum.ComputeMean()); + EXPECT_NEAR(105.049, accum.ComputeWeightedMean(kLearningRate), 0.1); + EXPECT_NEAR(229.166667, accum.ComputeVariance(), 25); + EXPECT_DOUBLE_EQ(65.0, accum.ComputeMin()); + EXPECT_DOUBLE_EQ(110.0, accum.ComputeMax()); +} + +TEST(RollingAccumulatorTest, ComputeWeightedMeanCornerCases) { + RollingAccumulator<int> accum(10); + EXPECT_DOUBLE_EQ(0.0, accum.ComputeWeightedMean(kLearningRate)); + EXPECT_DOUBLE_EQ(0.0, accum.ComputeWeightedMean(0.0)); + EXPECT_DOUBLE_EQ(0.0, accum.ComputeWeightedMean(1.1)); + + for (int i = 0; i < 8; ++i) { + accum.AddSample(i); + } + + EXPECT_DOUBLE_EQ(3.5, accum.ComputeMean()); + EXPECT_DOUBLE_EQ(3.5, accum.ComputeWeightedMean(0)); + EXPECT_DOUBLE_EQ(3.5, accum.ComputeWeightedMean(1.1)); + EXPECT_NEAR(6.0, accum.ComputeWeightedMean(kLearningRate), 0.1); +} + +TEST(RollingAccumulatorTest, VarianceFromUniformDistribution) { + // Check variance converge to 1/12 for [0;1) uniform distribution. + // Acts as a sanity check for NumericStabilityForVariance test. + RollingAccumulator<double> stats(/*max_count=*/0.5e6); + FillStatsFromUniformDistribution(stats, 1e6, 0, 1); + + EXPECT_NEAR(stats.ComputeVariance(), 1. / 12, 1e-3); +} + +TEST(RollingAccumulatorTest, NumericStabilityForVariance) { + // Same test as VarianceFromUniformDistribution, + // except the range is shifted to [1e9;1e9+1). + // Variance should also converge to 1/12. + // NB: Although we lose precision for the samples themselves, the fractional + // part still enjoys 22 bits of mantissa and errors should even out, + // so that couldn't explain a mismatch. + RollingAccumulator<double> stats(/*max_count=*/0.5e6); + FillStatsFromUniformDistribution(stats, 1e6, 1e9, 1e9 + 1); + + EXPECT_NEAR(stats.ComputeVariance(), 1. / 12, 1e-3); +} +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/rtc_certificate.cc b/third_party/libwebrtc/rtc_base/rtc_certificate.cc new file mode 100644 index 0000000000..e0b6b3258e --- /dev/null +++ b/third_party/libwebrtc/rtc_base/rtc_certificate.cc @@ -0,0 +1,77 @@ +/* + * Copyright 2015 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 "rtc_base/rtc_certificate.h" + +#include <memory> + +#include "rtc_base/checks.h" +#include "rtc_base/ssl_certificate.h" +#include "rtc_base/ssl_identity.h" +#include "rtc_base/time_utils.h" + +namespace rtc { + +scoped_refptr<RTCCertificate> RTCCertificate::Create( + std::unique_ptr<SSLIdentity> identity) { + // Explicit new to access proteced constructor. + return rtc::scoped_refptr<RTCCertificate>( + new RTCCertificate(identity.release())); +} + +RTCCertificate::RTCCertificate(SSLIdentity* identity) : identity_(identity) { + RTC_DCHECK(identity_); +} + +RTCCertificate::~RTCCertificate() = default; + +uint64_t RTCCertificate::Expires() const { + int64_t expires = GetSSLCertificate().CertificateExpirationTime(); + if (expires != -1) + return static_cast<uint64_t>(expires) * kNumMillisecsPerSec; + // If the expiration time could not be retrieved return an expired timestamp. + return 0; // = 1970-01-01 +} + +bool RTCCertificate::HasExpired(uint64_t now) const { + return Expires() <= now; +} + +const SSLCertificate& RTCCertificate::GetSSLCertificate() const { + return identity_->certificate(); +} + +const SSLCertChain& RTCCertificate::GetSSLCertificateChain() const { + return identity_->cert_chain(); +} + +RTCCertificatePEM RTCCertificate::ToPEM() const { + return RTCCertificatePEM(identity_->PrivateKeyToPEMString(), + GetSSLCertificate().ToPEMString()); +} + +scoped_refptr<RTCCertificate> RTCCertificate::FromPEM( + const RTCCertificatePEM& pem) { + std::unique_ptr<SSLIdentity> identity( + SSLIdentity::CreateFromPEMStrings(pem.private_key(), pem.certificate())); + if (!identity) + return nullptr; + return RTCCertificate::Create(std::move(identity)); +} + +bool RTCCertificate::operator==(const RTCCertificate& certificate) const { + return *this->identity_ == *certificate.identity_; +} + +bool RTCCertificate::operator!=(const RTCCertificate& certificate) const { + return !(*this == certificate); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/rtc_certificate.h b/third_party/libwebrtc/rtc_base/rtc_certificate.h new file mode 100644 index 0000000000..67c5c29a89 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/rtc_certificate.h @@ -0,0 +1,97 @@ +/* + * Copyright 2015 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 RTC_BASE_RTC_CERTIFICATE_H_ +#define RTC_BASE_RTC_CERTIFICATE_H_ + +#include <stdint.h> + +#include <memory> +#include <string> + +#include "absl/base/attributes.h" +#include "absl/strings/string_view.h" +#include "api/ref_counted_base.h" +#include "api/scoped_refptr.h" +#include "rtc_base/system/rtc_export.h" + +namespace rtc { + +class SSLCertChain; +class SSLCertificate; +class SSLIdentity; + +// This class contains PEM strings of an RTCCertificate's private key and +// certificate and acts as a text representation of RTCCertificate. Certificates +// can be serialized and deserialized to and from this format, which allows for +// cloning and storing of certificates to disk. The PEM format is that of +// `SSLIdentity::PrivateKeyToPEMString` and `SSLCertificate::ToPEMString`, e.g. +// the string representations used by OpenSSL. +class RTCCertificatePEM { + public: + RTCCertificatePEM(absl::string_view private_key, + absl::string_view certificate) + : private_key_(private_key), certificate_(certificate) {} + + const std::string& private_key() const { return private_key_; } + const std::string& certificate() const { return certificate_; } + + private: + std::string private_key_; + std::string certificate_; +}; + +// A thin abstraction layer between "lower level crypto stuff" like +// SSLCertificate and WebRTC usage. Takes ownership of some lower level objects, +// reference counting protects these from premature destruction. +class RTC_EXPORT RTCCertificate final + : public RefCountedNonVirtual<RTCCertificate> { + public: + // Takes ownership of `identity`. + static scoped_refptr<RTCCertificate> Create( + std::unique_ptr<SSLIdentity> identity); + + // Returns the expiration time in ms relative to epoch, 1970-01-01T00:00:00Z. + uint64_t Expires() const; + // Checks if the certificate has expired, where `now` is expressed in ms + // relative to epoch, 1970-01-01T00:00:00Z. + bool HasExpired(uint64_t now) const; + + const SSLCertificate& GetSSLCertificate() const; + const SSLCertChain& GetSSLCertificateChain() const; + + // TODO(hbos): If possible, remove once RTCCertificate and its + // GetSSLCertificate() is used in all relevant places. Should not pass around + // raw SSLIdentity* for the sake of accessing SSLIdentity::certificate(). + // However, some places might need SSLIdentity* for its public/private key... + SSLIdentity* identity() const { return identity_.get(); } + + // To/from PEM, a text representation of the RTCCertificate. + RTCCertificatePEM ToPEM() const; + // Can return nullptr if the certificate is invalid. + static scoped_refptr<RTCCertificate> FromPEM(const RTCCertificatePEM& pem); + bool operator==(const RTCCertificate& certificate) const; + bool operator!=(const RTCCertificate& certificate) const; + + protected: + explicit RTCCertificate(SSLIdentity* identity); + + friend class RefCountedNonVirtual<RTCCertificate>; + ~RTCCertificate(); + + private: + // The SSLIdentity is the owner of the SSLCertificate. To protect our + // GetSSLCertificate() we take ownership of `identity_`. + const std::unique_ptr<SSLIdentity> identity_; +}; + +} // namespace rtc + +#endif // RTC_BASE_RTC_CERTIFICATE_H_ diff --git a/third_party/libwebrtc/rtc_base/rtc_certificate_generator.cc b/third_party/libwebrtc/rtc_base/rtc_certificate_generator.cc new file mode 100644 index 0000000000..ffc51aa8da --- /dev/null +++ b/third_party/libwebrtc/rtc_base/rtc_certificate_generator.cc @@ -0,0 +1,88 @@ +/* + * Copyright 2016 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 "rtc_base/rtc_certificate_generator.h" + +#include <time.h> + +#include <algorithm> +#include <memory> +#include <utility> + +#include "rtc_base/checks.h" +#include "rtc_base/ssl_identity.h" + +namespace rtc { + +namespace { + +// A certificates' subject and issuer name. +const char kIdentityName[] = "WebRTC"; +const uint64_t kYearInSeconds = 365 * 24 * 60 * 60; + +} // namespace + +// static +scoped_refptr<RTCCertificate> RTCCertificateGenerator::GenerateCertificate( + const KeyParams& key_params, + const absl::optional<uint64_t>& expires_ms) { + if (!key_params.IsValid()) { + return nullptr; + } + + std::unique_ptr<SSLIdentity> identity; + if (!expires_ms) { + identity = SSLIdentity::Create(kIdentityName, key_params); + } else { + uint64_t expires_s = *expires_ms / 1000; + // Limit the expiration time to something reasonable (a year). This was + // somewhat arbitrarily chosen. It also ensures that the value is not too + // large for the unspecified `time_t`. + expires_s = std::min(expires_s, kYearInSeconds); + // TODO(torbjorng): Stop using `time_t`, its type is unspecified. It it safe + // to assume it can hold up to a year's worth of seconds (and more), but + // `SSLIdentity::Create` should stop relying on `time_t`. + // See bugs.webrtc.org/5720. + time_t cert_lifetime_s = static_cast<time_t>(expires_s); + identity = SSLIdentity::Create(kIdentityName, key_params, cert_lifetime_s); + } + if (!identity) { + return nullptr; + } + return RTCCertificate::Create(std::move(identity)); +} + +RTCCertificateGenerator::RTCCertificateGenerator(Thread* signaling_thread, + Thread* worker_thread) + : signaling_thread_(signaling_thread), worker_thread_(worker_thread) { + RTC_DCHECK(signaling_thread_); + RTC_DCHECK(worker_thread_); +} + +void RTCCertificateGenerator::GenerateCertificateAsync( + const KeyParams& key_params, + const absl::optional<uint64_t>& expires_ms, + RTCCertificateGenerator::Callback callback) { + RTC_DCHECK(signaling_thread_->IsCurrent()); + RTC_DCHECK(callback); + + worker_thread_->PostTask([key_params, expires_ms, + signaling_thread = signaling_thread_, + cb = std::move(callback)]() mutable { + scoped_refptr<RTCCertificate> certificate = + RTCCertificateGenerator::GenerateCertificate(key_params, expires_ms); + signaling_thread->PostTask( + [cert = std::move(certificate), cb = std::move(cb)]() mutable { + std::move(cb)(std::move(cert)); + }); + }); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/rtc_certificate_generator.h b/third_party/libwebrtc/rtc_base/rtc_certificate_generator.h new file mode 100644 index 0000000000..a881f1a369 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/rtc_certificate_generator.h @@ -0,0 +1,82 @@ +/* + * Copyright 2016 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 RTC_BASE_RTC_CERTIFICATE_GENERATOR_H_ +#define RTC_BASE_RTC_CERTIFICATE_GENERATOR_H_ + +#include <stdint.h> + +#include "absl/functional/any_invocable.h" +#include "absl/types/optional.h" +#include "api/scoped_refptr.h" +#include "rtc_base/rtc_certificate.h" +#include "rtc_base/ssl_identity.h" +#include "rtc_base/system/rtc_export.h" +#include "rtc_base/thread.h" + +namespace rtc { + +// Generates `RTCCertificate`s. +// See `RTCCertificateGenerator` for the WebRTC repo's implementation. +class RTCCertificateGeneratorInterface { + public: + // Functor that will be called when certificate is generated asynchroniosly. + // Called with nullptr as the parameter on failure. + using Callback = absl::AnyInvocable<void(scoped_refptr<RTCCertificate>) &&>; + + virtual ~RTCCertificateGeneratorInterface() = default; + + // Generates a certificate asynchronously on the worker thread. + // Must be called on the signaling thread. The `callback` is invoked with the + // result on the signaling thread. `exipres_ms` optionally specifies for how + // long we want the certificate to be valid, but the implementation may choose + // its own restrictions on the expiration time. + virtual void GenerateCertificateAsync( + const KeyParams& key_params, + const absl::optional<uint64_t>& expires_ms, + Callback callback) = 0; +}; + +// Standard implementation of `RTCCertificateGeneratorInterface`. +// The static function `GenerateCertificate` generates a certificate on the +// current thread. The `RTCCertificateGenerator` instance generates certificates +// asynchronously on the worker thread with `GenerateCertificateAsync`. +class RTC_EXPORT RTCCertificateGenerator + : public RTCCertificateGeneratorInterface { + public: + // Generates a certificate on the current thread. Returns null on failure. + // If `expires_ms` is specified, the certificate will expire in approximately + // that many milliseconds from now. `expires_ms` is limited to a year, a + // larger value than that is clamped down to a year. If `expires_ms` is not + // specified, a default expiration time is used. + static scoped_refptr<RTCCertificate> GenerateCertificate( + const KeyParams& key_params, + const absl::optional<uint64_t>& expires_ms); + + RTCCertificateGenerator(Thread* signaling_thread, Thread* worker_thread); + ~RTCCertificateGenerator() override {} + + // `RTCCertificateGeneratorInterface` overrides. + // If `expires_ms` is specified, the certificate will expire in approximately + // that many milliseconds from now. `expires_ms` is limited to a year, a + // larger value than that is clamped down to a year. If `expires_ms` is not + // specified, a default expiration time is used. + void GenerateCertificateAsync(const KeyParams& key_params, + const absl::optional<uint64_t>& expires_ms, + Callback callback) override; + + private: + Thread* const signaling_thread_; + Thread* const worker_thread_; +}; + +} // namespace rtc + +#endif // RTC_BASE_RTC_CERTIFICATE_GENERATOR_H_ diff --git a/third_party/libwebrtc/rtc_base/rtc_certificate_generator_unittest.cc b/third_party/libwebrtc/rtc_base/rtc_certificate_generator_unittest.cc new file mode 100644 index 0000000000..fb7ec913e5 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/rtc_certificate_generator_unittest.cc @@ -0,0 +1,137 @@ +/* + * Copyright 2016 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 "rtc_base/rtc_certificate_generator.h" + +#include <memory> + +#include "absl/types/optional.h" +#include "api/make_ref_counted.h" +#include "rtc_base/checks.h" +#include "rtc_base/gunit.h" +#include "rtc_base/thread.h" +#include "test/gtest.h" + +namespace rtc { + +class RTCCertificateGeneratorFixture { + public: + RTCCertificateGeneratorFixture() + : signaling_thread_(Thread::Current()), + worker_thread_(Thread::Create()), + generate_async_completed_(false) { + RTC_CHECK(signaling_thread_); + RTC_CHECK(worker_thread_->Start()); + generator_.reset( + new RTCCertificateGenerator(signaling_thread_, worker_thread_.get())); + } + + RTCCertificateGenerator* generator() const { return generator_.get(); } + RTCCertificate* certificate() const { return certificate_.get(); } + + RTCCertificateGeneratorInterface::Callback OnGenerated() { + return [this](scoped_refptr<RTCCertificate> certificate) mutable { + RTC_CHECK(signaling_thread_->IsCurrent()); + certificate_ = std::move(certificate); + generate_async_completed_ = true; + }; + } + + bool GenerateAsyncCompleted() { + RTC_CHECK(signaling_thread_->IsCurrent()); + if (generate_async_completed_) { + // Reset flag so that future generation requests are not considered done. + generate_async_completed_ = false; + return true; + } + return false; + } + + protected: + Thread* const signaling_thread_; + std::unique_ptr<Thread> worker_thread_; + std::unique_ptr<RTCCertificateGenerator> generator_; + scoped_refptr<RTCCertificate> certificate_; + bool generate_async_completed_; +}; + +class RTCCertificateGeneratorTest : public ::testing::Test { + public: + protected: + static constexpr int kGenerationTimeoutMs = 10000; + + rtc::AutoThread main_thread_; + RTCCertificateGeneratorFixture fixture_; +}; + +TEST_F(RTCCertificateGeneratorTest, GenerateECDSA) { + EXPECT_TRUE(RTCCertificateGenerator::GenerateCertificate(KeyParams::ECDSA(), + absl::nullopt)); +} + +TEST_F(RTCCertificateGeneratorTest, GenerateRSA) { + EXPECT_TRUE(RTCCertificateGenerator::GenerateCertificate(KeyParams::RSA(), + absl::nullopt)); +} + +TEST_F(RTCCertificateGeneratorTest, GenerateAsyncECDSA) { + EXPECT_FALSE(fixture_.certificate()); + fixture_.generator()->GenerateCertificateAsync( + KeyParams::ECDSA(), absl::nullopt, fixture_.OnGenerated()); + // Until generation has completed, the certificate is null. Since this is an + // async call, generation must not have completed until we process messages + // posted to this thread (which is done by `EXPECT_TRUE_WAIT`). + EXPECT_FALSE(fixture_.GenerateAsyncCompleted()); + EXPECT_FALSE(fixture_.certificate()); + EXPECT_TRUE_WAIT(fixture_.GenerateAsyncCompleted(), kGenerationTimeoutMs); + EXPECT_TRUE(fixture_.certificate()); +} + +TEST_F(RTCCertificateGeneratorTest, GenerateWithExpires) { + // By generating two certificates with different expiration we can compare the + // two expiration times relative to each other without knowing the current + // time relative to epoch, 1970-01-01T00:00:00Z. This verifies that the + // expiration parameter is correctly used relative to the generator's clock, + // but does not verify that this clock is relative to epoch. + + // Generate a certificate that expires immediately. + scoped_refptr<RTCCertificate> cert_a = + RTCCertificateGenerator::GenerateCertificate(KeyParams::ECDSA(), 0); + EXPECT_TRUE(cert_a); + + // Generate a certificate that expires in one minute. + const uint64_t kExpiresMs = 60000; + scoped_refptr<RTCCertificate> cert_b = + RTCCertificateGenerator::GenerateCertificate(KeyParams::ECDSA(), + kExpiresMs); + EXPECT_TRUE(cert_b); + + // Verify that `cert_b` expires approximately `kExpiresMs` after `cert_a` + // (allowing a +/- 1 second plus maximum generation time difference). + EXPECT_GT(cert_b->Expires(), cert_a->Expires()); + uint64_t expires_diff = cert_b->Expires() - cert_a->Expires(); + EXPECT_GE(expires_diff, kExpiresMs); + EXPECT_LE(expires_diff, kExpiresMs + 2 * kGenerationTimeoutMs + 1000); +} + +TEST_F(RTCCertificateGeneratorTest, GenerateWithInvalidParamsShouldFail) { + KeyParams invalid_params = KeyParams::RSA(0, 0); + EXPECT_FALSE(invalid_params.IsValid()); + + EXPECT_FALSE(RTCCertificateGenerator::GenerateCertificate(invalid_params, + absl::nullopt)); + + fixture_.generator()->GenerateCertificateAsync(invalid_params, absl::nullopt, + fixture_.OnGenerated()); + EXPECT_TRUE_WAIT(fixture_.GenerateAsyncCompleted(), kGenerationTimeoutMs); + EXPECT_FALSE(fixture_.certificate()); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/rtc_certificate_unittest.cc b/third_party/libwebrtc/rtc_base/rtc_certificate_unittest.cc new file mode 100644 index 0000000000..63183883b3 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/rtc_certificate_unittest.cc @@ -0,0 +1,140 @@ +/* + * Copyright 2015 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 "rtc_base/rtc_certificate.h" + +#include <time.h> + +#include <memory> +#include <utility> + +#include "rtc_base/checks.h" +#include "rtc_base/numerics/safe_conversions.h" +#include "rtc_base/ssl_identity.h" +#include "rtc_base/time_utils.h" +#include "test/gtest.h" + +namespace rtc { + +namespace { + +static const char* kTestCertCommonName = "RTCCertificateTest's certificate"; + +} // namespace + +class RTCCertificateTest : public ::testing::Test { + protected: + scoped_refptr<RTCCertificate> GenerateECDSA() { + std::unique_ptr<SSLIdentity> identity( + SSLIdentity::Create(kTestCertCommonName, KeyParams::ECDSA())); + RTC_CHECK(identity); + return RTCCertificate::Create(std::move(identity)); + } + + // Timestamp note: + // All timestamps in this unittest are expressed in number of seconds since + // epoch, 1970-01-01T00:00:00Z (UTC). The RTCCertificate interface uses ms, + // but only seconds-precision is supported by SSLCertificate. To make the + // tests clearer we convert everything to seconds since the precision matters + // when generating certificates or comparing timestamps. + // As a result, ExpiresSeconds and HasExpiredSeconds are used instead of + // RTCCertificate::Expires and ::HasExpired for ms -> s conversion. + + uint64_t NowSeconds() const { return TimeNanos() / kNumNanosecsPerSec; } + + uint64_t ExpiresSeconds(const scoped_refptr<RTCCertificate>& cert) const { + uint64_t exp_ms = cert->Expires(); + uint64_t exp_s = exp_ms / kNumMillisecsPerSec; + // Make sure this did not result in loss of precision. + RTC_CHECK_EQ(exp_s * kNumMillisecsPerSec, exp_ms); + return exp_s; + } + + bool HasExpiredSeconds(const scoped_refptr<RTCCertificate>& cert, + uint64_t now_s) const { + return cert->HasExpired(now_s * kNumMillisecsPerSec); + } + + // An RTC_CHECK ensures that `expires_s` this is in valid range of time_t as + // is required by SSLIdentityParams. On some 32-bit systems time_t is limited + // to < 2^31. On such systems this will fail for expiration times of year 2038 + // or later. + scoped_refptr<RTCCertificate> GenerateCertificateWithExpires( + uint64_t expires_s) const { + RTC_CHECK(IsValueInRangeForNumericType<time_t>(expires_s)); + + SSLIdentityParams params; + params.common_name = kTestCertCommonName; + params.not_before = 0; + params.not_after = static_cast<time_t>(expires_s); + // Certificate type does not matter for our purposes, using ECDSA because it + // is fast to generate. + params.key_params = KeyParams::ECDSA(); + + std::unique_ptr<SSLIdentity> identity(SSLIdentity::CreateForTest(params)); + return RTCCertificate::Create(std::move(identity)); + } +}; + +TEST_F(RTCCertificateTest, NewCertificateNotExpired) { + // Generate a real certificate without specifying the expiration time. + // Certificate type doesn't matter, using ECDSA because it's fast to generate. + scoped_refptr<RTCCertificate> certificate = GenerateECDSA(); + + uint64_t now = NowSeconds(); + EXPECT_FALSE(HasExpiredSeconds(certificate, now)); + // Even without specifying the expiration time we would expect it to be valid + // for at least half an hour. + EXPECT_FALSE(HasExpiredSeconds(certificate, now + 30 * 60)); +} + +TEST_F(RTCCertificateTest, UsesExpiresAskedFor) { + uint64_t now = NowSeconds(); + scoped_refptr<RTCCertificate> certificate = + GenerateCertificateWithExpires(now); + EXPECT_EQ(now, ExpiresSeconds(certificate)); +} + +TEST_F(RTCCertificateTest, ExpiresInOneSecond) { + // Generate a certificate that expires in 1s. + uint64_t now = NowSeconds(); + scoped_refptr<RTCCertificate> certificate = + GenerateCertificateWithExpires(now + 1); + // Now it should not have expired. + EXPECT_FALSE(HasExpiredSeconds(certificate, now)); + // In 2s it should have expired. + EXPECT_TRUE(HasExpiredSeconds(certificate, now + 2)); +} + +TEST_F(RTCCertificateTest, DifferentCertificatesNotEqual) { + scoped_refptr<RTCCertificate> a = GenerateECDSA(); + scoped_refptr<RTCCertificate> b = GenerateECDSA(); + EXPECT_TRUE(*a != *b); +} + +TEST_F(RTCCertificateTest, CloneWithPEMSerialization) { + scoped_refptr<RTCCertificate> orig = GenerateECDSA(); + + // To PEM. + RTCCertificatePEM orig_pem = orig->ToPEM(); + // Clone from PEM. + scoped_refptr<RTCCertificate> clone = RTCCertificate::FromPEM(orig_pem); + EXPECT_TRUE(clone); + EXPECT_TRUE(*orig == *clone); + EXPECT_EQ(orig->Expires(), clone->Expires()); +} + +TEST_F(RTCCertificateTest, FromPEMWithInvalidPEM) { + RTCCertificatePEM pem("not a valid PEM", "not a valid PEM"); + scoped_refptr<RTCCertificate> certificate = RTCCertificate::FromPEM(pem); + EXPECT_FALSE(certificate); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/rtc_event_gn/moz.build b/third_party/libwebrtc/rtc_base/rtc_event_gn/moz.build new file mode 100644 index 0000000000..a3bb657070 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/rtc_event_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/rtc_base/event.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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("rtc_event_gn") diff --git a/third_party/libwebrtc/rtc_base/rtc_numerics_gn/moz.build b/third_party/libwebrtc/rtc_base/rtc_numerics_gn/moz.build new file mode 100644 index 0000000000..1c0d84013b --- /dev/null +++ b/third_party/libwebrtc/rtc_base/rtc_numerics_gn/moz.build @@ -0,0 +1,227 @@ +# 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/rtc_base/numerics/event_based_exponential_moving_average.cc", + "/third_party/libwebrtc/rtc_base/numerics/exp_filter.cc", + "/third_party/libwebrtc/rtc_base/numerics/moving_average.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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("rtc_numerics_gn") diff --git a/third_party/libwebrtc/rtc_base/rtc_task_queue_gn/moz.build b/third_party/libwebrtc/rtc_base/rtc_task_queue_gn/moz.build new file mode 100644 index 0000000000..21635e570b --- /dev/null +++ b/third_party/libwebrtc/rtc_base/rtc_task_queue_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/rtc_base/task_queue.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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("rtc_task_queue_gn") diff --git a/third_party/libwebrtc/rtc_base/safe_compare_gn/moz.build b/third_party/libwebrtc/rtc_base/safe_compare_gn/moz.build new file mode 100644 index 0000000000..fdcf248573 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/safe_compare_gn/moz.build @@ -0,0 +1,205 @@ +# 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("safe_compare_gn") diff --git a/third_party/libwebrtc/rtc_base/safe_conversions_gn/moz.build b/third_party/libwebrtc/rtc_base/safe_conversions_gn/moz.build new file mode 100644 index 0000000000..5901f174a6 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/safe_conversions_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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("safe_conversions_gn") diff --git a/third_party/libwebrtc/rtc_base/safe_minmax_gn/moz.build b/third_party/libwebrtc/rtc_base/safe_minmax_gn/moz.build new file mode 100644 index 0000000000..c01e7c799b --- /dev/null +++ b/third_party/libwebrtc/rtc_base/safe_minmax_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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("safe_minmax_gn") diff --git a/third_party/libwebrtc/rtc_base/sample_counter_gn/moz.build b/third_party/libwebrtc/rtc_base/sample_counter_gn/moz.build new file mode 100644 index 0000000000..99c6eb8f53 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/sample_counter_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/rtc_base/numerics/sample_counter.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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("sample_counter_gn") diff --git a/third_party/libwebrtc/rtc_base/sanitizer.h b/third_party/libwebrtc/rtc_base/sanitizer.h new file mode 100644 index 0000000000..8af0824b67 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/sanitizer.h @@ -0,0 +1,144 @@ +/* + * Copyright 2016 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 RTC_BASE_SANITIZER_H_ +#define RTC_BASE_SANITIZER_H_ + +#include <stddef.h> // For size_t. + +#ifdef __cplusplus +#include "absl/meta/type_traits.h" +#endif + +#if defined(__has_feature) +#if __has_feature(address_sanitizer) +#define RTC_HAS_ASAN 1 +#endif +#if __has_feature(memory_sanitizer) +#define RTC_HAS_MSAN 1 +#endif +#endif +#ifndef RTC_HAS_ASAN +#define RTC_HAS_ASAN 0 +#endif +#ifndef RTC_HAS_MSAN +#define RTC_HAS_MSAN 0 +#endif + +#if RTC_HAS_ASAN +#include <sanitizer/asan_interface.h> +#endif +#if RTC_HAS_MSAN +#include <sanitizer/msan_interface.h> +#endif + +#ifdef __has_attribute +#if __has_attribute(no_sanitize) +#define RTC_NO_SANITIZE(what) __attribute__((no_sanitize(what))) +#endif +#endif +#ifndef RTC_NO_SANITIZE +#define RTC_NO_SANITIZE(what) +#endif + +// Ask ASan to mark the memory range [ptr, ptr + element_size * num_elements) +// as being unaddressable, so that reads and writes are not allowed. ASan may +// narrow the range to the nearest alignment boundaries. +static inline void rtc_AsanPoison(const volatile void* ptr, + size_t element_size, + size_t num_elements) { +#if RTC_HAS_ASAN + ASAN_POISON_MEMORY_REGION(ptr, element_size * num_elements); +#endif +} + +// Ask ASan to mark the memory range [ptr, ptr + element_size * num_elements) +// as being addressable, so that reads and writes are allowed. ASan may widen +// the range to the nearest alignment boundaries. +static inline void rtc_AsanUnpoison(const volatile void* ptr, + size_t element_size, + size_t num_elements) { +#if RTC_HAS_ASAN + ASAN_UNPOISON_MEMORY_REGION(ptr, element_size * num_elements); +#endif +} + +// Ask MSan to mark the memory range [ptr, ptr + element_size * num_elements) +// as being uninitialized. +static inline void rtc_MsanMarkUninitialized(const volatile void* ptr, + size_t element_size, + size_t num_elements) { +#if RTC_HAS_MSAN + __msan_poison(ptr, element_size * num_elements); +#endif +} + +// Force an MSan check (if any bits in the memory range [ptr, ptr + +// element_size * num_elements) are uninitialized the call will crash with an +// MSan report). +static inline void rtc_MsanCheckInitialized(const volatile void* ptr, + size_t element_size, + size_t num_elements) { +#if RTC_HAS_MSAN + __msan_check_mem_is_initialized(ptr, element_size * num_elements); +#endif +} + +#ifdef __cplusplus + +namespace rtc { +namespace sanitizer_impl { + +template <typename T> +constexpr bool IsTriviallyCopyable() { + return static_cast<bool>(absl::is_trivially_copy_constructible<T>::value && + (absl::is_trivially_copy_assignable<T>::value || + !std::is_copy_assignable<T>::value) && + absl::is_trivially_destructible<T>::value); +} + +} // namespace sanitizer_impl + +template <typename T> +inline void AsanPoison(const T& mem) { + rtc_AsanPoison(mem.data(), sizeof(mem.data()[0]), mem.size()); +} + +template <typename T> +inline void AsanUnpoison(const T& mem) { + rtc_AsanUnpoison(mem.data(), sizeof(mem.data()[0]), mem.size()); +} + +template <typename T> +inline void MsanMarkUninitialized(const T& mem) { + rtc_MsanMarkUninitialized(mem.data(), sizeof(mem.data()[0]), mem.size()); +} + +template <typename T> +inline T MsanUninitialized(T t) { +#if RTC_HAS_MSAN + // TODO(bugs.webrtc.org/8762): Switch to std::is_trivially_copyable when it + // becomes available in downstream projects. + static_assert(sanitizer_impl::IsTriviallyCopyable<T>(), ""); +#endif + rtc_MsanMarkUninitialized(&t, sizeof(T), 1); + return t; +} + +template <typename T> +inline void MsanCheckInitialized(const T& mem) { + rtc_MsanCheckInitialized(mem.data(), sizeof(mem.data()[0]), mem.size()); +} + +} // namespace rtc + +#endif // __cplusplus + +#endif // RTC_BASE_SANITIZER_H_ diff --git a/third_party/libwebrtc/rtc_base/sanitizer_gn/moz.build b/third_party/libwebrtc/rtc_base/sanitizer_gn/moz.build new file mode 100644 index 0000000000..43e96ee810 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/sanitizer_gn/moz.build @@ -0,0 +1,205 @@ +# 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("sanitizer_gn") diff --git a/third_party/libwebrtc/rtc_base/sanitizer_unittest.cc b/third_party/libwebrtc/rtc_base/sanitizer_unittest.cc new file mode 100644 index 0000000000..ffbfed7d22 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/sanitizer_unittest.cc @@ -0,0 +1,152 @@ +/* + * 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. + */ + +#include "rtc_base/sanitizer.h" + +#include <stdint.h> + +#include "rtc_base/logging.h" +#include "test/gtest.h" + +#if RTC_HAS_MSAN +#include <sanitizer/msan_interface.h> +#endif + +namespace rtc { +namespace { + +// Test sanitizer_impl::IsTriviallyCopyable (at compile time). + +// Trivially copyable. + +struct TrTrTr { + TrTrTr(const TrTrTr&) = default; + TrTrTr& operator=(const TrTrTr&) = default; + ~TrTrTr() = default; +}; +static_assert(sanitizer_impl::IsTriviallyCopyable<TrTrTr>(), ""); + +struct TrDeTr { + TrDeTr(const TrDeTr&) = default; + TrDeTr& operator=(const TrDeTr&) = delete; + ~TrDeTr() = default; +}; +static_assert(sanitizer_impl::IsTriviallyCopyable<TrDeTr>(), ""); + +// Non trivially copyable. + +struct TrTrNt { + TrTrNt(const TrTrNt&) = default; + TrTrNt& operator=(const TrTrNt&) = default; + ~TrTrNt(); +}; +static_assert(!sanitizer_impl::IsTriviallyCopyable<TrTrNt>(), ""); + +struct TrNtTr { + TrNtTr(const TrNtTr&) = default; + TrNtTr& operator=(const TrNtTr&); + ~TrNtTr() = default; +}; +static_assert(!sanitizer_impl::IsTriviallyCopyable<TrNtTr>(), ""); + +struct TrNtNt { + TrNtNt(const TrNtNt&) = default; + TrNtNt& operator=(const TrNtNt&); + ~TrNtNt(); +}; +static_assert(!sanitizer_impl::IsTriviallyCopyable<TrNtNt>(), ""); + +struct TrDeNt { + TrDeNt(const TrDeNt&) = default; + TrDeNt& operator=(const TrDeNt&) = delete; + ~TrDeNt(); +}; +static_assert(!sanitizer_impl::IsTriviallyCopyable<TrDeNt>(), ""); + +struct NtTrTr { + NtTrTr(const NtTrTr&); + NtTrTr& operator=(const NtTrTr&) = default; + ~NtTrTr() = default; +}; +static_assert(!sanitizer_impl::IsTriviallyCopyable<NtTrTr>(), ""); + +struct NtTrNt { + NtTrNt(const NtTrNt&); + NtTrNt& operator=(const NtTrNt&) = default; + ~NtTrNt(); +}; +static_assert(!sanitizer_impl::IsTriviallyCopyable<NtTrNt>(), ""); + +struct NtNtTr { + NtNtTr(const NtNtTr&); + NtNtTr& operator=(const NtNtTr&); + ~NtNtTr() = default; +}; +static_assert(!sanitizer_impl::IsTriviallyCopyable<NtNtTr>(), ""); + +struct NtNtNt { + NtNtNt(const NtNtNt&); + NtNtNt& operator=(const NtNtNt&); + ~NtNtNt(); +}; +static_assert(!sanitizer_impl::IsTriviallyCopyable<NtNtNt>(), ""); + +struct NtDeTr { + NtDeTr(const NtDeTr&); + NtDeTr& operator=(const NtDeTr&) = delete; + ~NtDeTr() = default; +}; +static_assert(!sanitizer_impl::IsTriviallyCopyable<NtDeTr>(), ""); + +struct NtDeNt { + NtDeNt(const NtDeNt&); + NtDeNt& operator=(const NtDeNt&) = delete; + ~NtDeNt(); +}; +static_assert(!sanitizer_impl::IsTriviallyCopyable<NtDeNt>(), ""); + +// Trivially copyable types. + +struct Foo { + uint32_t field1; + uint16_t field2; +}; + +struct Bar { + uint32_t ID; + Foo foo; +}; + +// Run the callback, and expect a crash if it *doesn't* make an uninitialized +// memory read. If MSan isn't on, just run the callback. +template <typename F> +void MsanExpectUninitializedRead(F&& f) { +#if RTC_HAS_MSAN + EXPECT_DEATH(f(), ""); +#else + f(); +#endif +} + +} // namespace + +TEST(SanitizerTest, MsanUninitialized) { + Bar bar = MsanUninitialized<Bar>({}); + // Check that a read after initialization is OK. + bar.ID = 1; + EXPECT_EQ(1u, bar.ID); + RTC_LOG(LS_INFO) << "read after init passed"; + // Check that other fields are uninitialized and equal to zero. + MsanExpectUninitializedRead([&] { EXPECT_EQ(0u, bar.foo.field1); }); + MsanExpectUninitializedRead([&] { EXPECT_EQ(0u, bar.foo.field2); }); + RTC_LOG(LS_INFO) << "read with no init passed"; +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/server_socket_adapters.cc b/third_party/libwebrtc/rtc_base/server_socket_adapters.cc new file mode 100644 index 0000000000..673083c7cd --- /dev/null +++ b/third_party/libwebrtc/rtc_base/server_socket_adapters.cc @@ -0,0 +1,186 @@ +/* + * 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 "rtc_base/server_socket_adapters.h" + +#include <string> + +#include "rtc_base/byte_buffer.h" + +namespace rtc { + +AsyncProxyServerSocket::AsyncProxyServerSocket(Socket* socket, + size_t buffer_size) + : BufferedReadAdapter(socket, buffer_size) {} + +AsyncProxyServerSocket::~AsyncProxyServerSocket() = default; + +AsyncSSLServerSocket::AsyncSSLServerSocket(Socket* socket) + : BufferedReadAdapter(socket, 1024) { + BufferInput(true); +} + +void AsyncSSLServerSocket::ProcessInput(char* data, size_t* len) { + // We only accept client hello messages. + const ArrayView<const uint8_t> client_hello = + AsyncSSLSocket::SslClientHello(); + if (*len < client_hello.size()) { + return; + } + + if (memcmp(client_hello.data(), data, client_hello.size()) != 0) { + Close(); + SignalCloseEvent(this, 0); + return; + } + + *len -= client_hello.size(); + + // Clients should not send more data until the handshake is completed. + RTC_DCHECK(*len == 0); + + const ArrayView<const uint8_t> server_hello = + AsyncSSLSocket::SslServerHello(); + // Send a server hello back to the client. + DirectSend(server_hello.data(), server_hello.size()); + + // Handshake completed for us, redirect input to our parent. + BufferInput(false); +} + +AsyncSocksProxyServerSocket::AsyncSocksProxyServerSocket(Socket* socket) + : AsyncProxyServerSocket(socket, kBufferSize), state_(SS_HELLO) { + BufferInput(true); +} + +void AsyncSocksProxyServerSocket::ProcessInput(char* data, size_t* len) { + RTC_DCHECK(state_ < SS_CONNECT_PENDING); + + ByteBufferReader response(data, *len); + if (state_ == SS_HELLO) { + HandleHello(&response); + } else if (state_ == SS_AUTH) { + HandleAuth(&response); + } else if (state_ == SS_CONNECT) { + HandleConnect(&response); + } + + // Consume parsed data + *len = response.Length(); + memmove(data, response.Data(), *len); +} + +void AsyncSocksProxyServerSocket::DirectSend(const ByteBufferWriter& buf) { + BufferedReadAdapter::DirectSend(buf.Data(), buf.Length()); +} + +void AsyncSocksProxyServerSocket::HandleHello(ByteBufferReader* request) { + uint8_t ver, num_methods; + if (!request->ReadUInt8(&ver) || !request->ReadUInt8(&num_methods)) { + Error(0); + return; + } + + if (ver != 5) { + Error(0); + return; + } + + // Handle either no-auth (0) or user/pass auth (2) + uint8_t method = 0xFF; + if (num_methods > 0 && !request->ReadUInt8(&method)) { + Error(0); + return; + } + + SendHelloReply(method); + if (method == 0) { + state_ = SS_CONNECT; + } else if (method == 2) { + state_ = SS_AUTH; + } else { + state_ = SS_ERROR; + } +} + +void AsyncSocksProxyServerSocket::SendHelloReply(uint8_t method) { + ByteBufferWriter response; + response.WriteUInt8(5); // Socks Version + response.WriteUInt8(method); // Auth method + DirectSend(response); +} + +void AsyncSocksProxyServerSocket::HandleAuth(ByteBufferReader* request) { + uint8_t ver, user_len, pass_len; + std::string user, pass; + if (!request->ReadUInt8(&ver) || !request->ReadUInt8(&user_len) || + !request->ReadString(&user, user_len) || !request->ReadUInt8(&pass_len) || + !request->ReadString(&pass, pass_len)) { + Error(0); + return; + } + + SendAuthReply(0); + state_ = SS_CONNECT; +} + +void AsyncSocksProxyServerSocket::SendAuthReply(uint8_t result) { + ByteBufferWriter response; + response.WriteUInt8(1); // Negotiation Version + response.WriteUInt8(result); + DirectSend(response); +} + +void AsyncSocksProxyServerSocket::HandleConnect(ByteBufferReader* request) { + uint8_t ver, command, reserved, addr_type; + uint32_t ip; + uint16_t port; + if (!request->ReadUInt8(&ver) || !request->ReadUInt8(&command) || + !request->ReadUInt8(&reserved) || !request->ReadUInt8(&addr_type) || + !request->ReadUInt32(&ip) || !request->ReadUInt16(&port)) { + Error(0); + return; + } + + if (ver != 5 || command != 1 || reserved != 0 || addr_type != 1) { + Error(0); + return; + } + + SignalConnectRequest(this, SocketAddress(ip, port)); + state_ = SS_CONNECT_PENDING; +} + +void AsyncSocksProxyServerSocket::SendConnectResult(int result, + const SocketAddress& addr) { + if (state_ != SS_CONNECT_PENDING) + return; + + ByteBufferWriter response; + response.WriteUInt8(5); // Socks version + response.WriteUInt8((result != 0)); // 0x01 is generic error + response.WriteUInt8(0); // reserved + response.WriteUInt8(1); // IPv4 address + response.WriteUInt32(addr.ip()); + response.WriteUInt16(addr.port()); + DirectSend(response); + BufferInput(false); + state_ = SS_TUNNEL; +} + +void AsyncSocksProxyServerSocket::Error(int error) { + state_ = SS_ERROR; + BufferInput(false); + Close(); + SetError(SOCKET_EACCES); + SignalCloseEvent(this, error); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/server_socket_adapters.h b/third_party/libwebrtc/rtc_base/server_socket_adapters.h new file mode 100644 index 0000000000..b18c7a6a65 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/server_socket_adapters.h @@ -0,0 +1,77 @@ +/* + * 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 RTC_BASE_SERVER_SOCKET_ADAPTERS_H_ +#define RTC_BASE_SERVER_SOCKET_ADAPTERS_H_ + +#include "rtc_base/socket_adapters.h" + +namespace rtc { + +// Interface for implementing proxy server sockets. +class AsyncProxyServerSocket : public BufferedReadAdapter { + public: + AsyncProxyServerSocket(Socket* socket, size_t buffer_size); + ~AsyncProxyServerSocket() override; + sigslot::signal2<AsyncProxyServerSocket*, const SocketAddress&> + SignalConnectRequest; + virtual void SendConnectResult(int err, const SocketAddress& addr) = 0; +}; + +// Implements a socket adapter that performs the server side of a +// fake SSL handshake. Used when implementing a relay server that does "ssltcp". +class AsyncSSLServerSocket : public BufferedReadAdapter { + public: + explicit AsyncSSLServerSocket(Socket* socket); + + AsyncSSLServerSocket(const AsyncSSLServerSocket&) = delete; + AsyncSSLServerSocket& operator=(const AsyncSSLServerSocket&) = delete; + + protected: + void ProcessInput(char* data, size_t* len) override; +}; + +// Implements a proxy server socket for the SOCKS protocol. +class AsyncSocksProxyServerSocket : public AsyncProxyServerSocket { + public: + explicit AsyncSocksProxyServerSocket(Socket* socket); + + AsyncSocksProxyServerSocket(const AsyncSocksProxyServerSocket&) = delete; + AsyncSocksProxyServerSocket& operator=(const AsyncSocksProxyServerSocket&) = + delete; + + private: + void ProcessInput(char* data, size_t* len) override; + void DirectSend(const ByteBufferWriter& buf); + + void HandleHello(ByteBufferReader* request); + void SendHelloReply(uint8_t method); + void HandleAuth(ByteBufferReader* request); + void SendAuthReply(uint8_t result); + void HandleConnect(ByteBufferReader* request); + void SendConnectResult(int result, const SocketAddress& addr) override; + + void Error(int error); + + static const int kBufferSize = 1024; + enum State { + SS_HELLO, + SS_AUTH, + SS_CONNECT, + SS_CONNECT_PENDING, + SS_TUNNEL, + SS_ERROR + }; + State state_; +}; + +} // namespace rtc + +#endif // RTC_BASE_SERVER_SOCKET_ADAPTERS_H_ diff --git a/third_party/libwebrtc/rtc_base/sigslot_tester.h b/third_party/libwebrtc/rtc_base/sigslot_tester.h new file mode 100644 index 0000000000..92483c0b8d --- /dev/null +++ b/third_party/libwebrtc/rtc_base/sigslot_tester.h @@ -0,0 +1,245 @@ +// This file was GENERATED by command: +// pump.py sigslottester.h.pump +// DO NOT EDIT BY HAND!!! + +/* + * Copyright 2014 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 RTC_BASE_SIGSLOT_TESTER_H_ +#define RTC_BASE_SIGSLOT_TESTER_H_ + +// To generate sigslottester.h from sigslottester.h.pump, execute: +// /home/build/google3/third_party/gtest/scripts/pump.py sigslottester.h.pump + +// SigslotTester(s) are utility classes to check if signals owned by an +// object are being invoked at the right time and with the right arguments. +// They are meant to be used in tests. Tests must provide "capture" pointers +// (i.e. address of variables) where the arguments from the signal callback +// can be stored. +// +// Example: +// /* Some signal */ +// sigslot::signal1<const std::string&> foo; +// +// /* We want to monitor foo in some test. Note how signal argument is +// const std::string&, but capture-type is std::string. Capture type +// must be type that can be assigned to. */ +// std::string capture; +// SigslotTester1<const std::string&, std::string> slot(&foo, &capture); +// foo.emit("hello"); +// EXPECT_EQ(1, slot.callback_count()); +// EXPECT_EQ("hello", capture); +// /* See unit-tests for more examples */ + +#include "rtc_base/third_party/sigslot/sigslot.h" + +namespace rtc { + +// Base version for testing signals that passes no arguments. +class SigslotTester0 : public sigslot::has_slots<> { + public: + explicit SigslotTester0(sigslot::signal0<>* signal) : callback_count_(0) { + signal->connect(this, &SigslotTester0::OnSignalCallback); + } + + SigslotTester0(const SigslotTester0&) = delete; + SigslotTester0& operator=(const SigslotTester0&) = delete; + + int callback_count() const { return callback_count_; } + + private: + void OnSignalCallback() { callback_count_++; } + int callback_count_; +}; + +// Versions below are for testing signals that pass arguments. For all the +// templates below: +// - A1-A5 is the type of the argument i in the callback. Signals may and often +// do use const-references here for efficiency. +// - C1-C5 is the type of the variable to capture argument i. These should be +// non-const value types suitable for use as lvalues. + +template <class A1, class C1> +class SigslotTester1 : public sigslot::has_slots<> { + public: + SigslotTester1(sigslot::signal1<A1>* signal, C1* capture1) + : callback_count_(0), capture1_(capture1) { + signal->connect(this, &SigslotTester1::OnSignalCallback); + } + + SigslotTester1(const SigslotTester1&) = delete; + SigslotTester1& operator=(const SigslotTester1&) = delete; + + int callback_count() const { return callback_count_; } + + private: + void OnSignalCallback(A1 arg1) { + callback_count_++; + *capture1_ = arg1; + } + + int callback_count_; + C1* capture1_; +}; + +template <class A1, class A2, class C1, class C2> +class SigslotTester2 : public sigslot::has_slots<> { + public: + SigslotTester2(sigslot::signal2<A1, A2>* signal, C1* capture1, C2* capture2) + : callback_count_(0), capture1_(capture1), capture2_(capture2) { + signal->connect(this, &SigslotTester2::OnSignalCallback); + } + + SigslotTester2(const SigslotTester2&) = delete; + SigslotTester2& operator=(const SigslotTester2&) = delete; + + int callback_count() const { return callback_count_; } + + private: + void OnSignalCallback(A1 arg1, A2 arg2) { + callback_count_++; + *capture1_ = arg1; + *capture2_ = arg2; + } + + int callback_count_; + C1* capture1_; + C2* capture2_; +}; + +template <class A1, class A2, class A3, class C1, class C2, class C3> +class SigslotTester3 : public sigslot::has_slots<> { + public: + SigslotTester3(sigslot::signal3<A1, A2, A3>* signal, + C1* capture1, + C2* capture2, + C3* capture3) + : callback_count_(0), + capture1_(capture1), + capture2_(capture2), + capture3_(capture3) { + signal->connect(this, &SigslotTester3::OnSignalCallback); + } + + SigslotTester3(const SigslotTester3&) = delete; + SigslotTester3& operator=(const SigslotTester3&) = delete; + + int callback_count() const { return callback_count_; } + + private: + void OnSignalCallback(A1 arg1, A2 arg2, A3 arg3) { + callback_count_++; + *capture1_ = arg1; + *capture2_ = arg2; + *capture3_ = arg3; + } + + int callback_count_; + C1* capture1_; + C2* capture2_; + C3* capture3_; +}; + +template <class A1, + class A2, + class A3, + class A4, + class C1, + class C2, + class C3, + class C4> +class SigslotTester4 : public sigslot::has_slots<> { + public: + SigslotTester4(sigslot::signal4<A1, A2, A3, A4>* signal, + C1* capture1, + C2* capture2, + C3* capture3, + C4* capture4) + : callback_count_(0), + capture1_(capture1), + capture2_(capture2), + capture3_(capture3), + capture4_(capture4) { + signal->connect(this, &SigslotTester4::OnSignalCallback); + } + + SigslotTester4(const SigslotTester4&) = delete; + SigslotTester4& operator=(const SigslotTester4&) = delete; + + int callback_count() const { return callback_count_; } + + private: + void OnSignalCallback(A1 arg1, A2 arg2, A3 arg3, A4 arg4) { + callback_count_++; + *capture1_ = arg1; + *capture2_ = arg2; + *capture3_ = arg3; + *capture4_ = arg4; + } + + int callback_count_; + C1* capture1_; + C2* capture2_; + C3* capture3_; + C4* capture4_; +}; + +template <class A1, + class A2, + class A3, + class A4, + class A5, + class C1, + class C2, + class C3, + class C4, + class C5> +class SigslotTester5 : public sigslot::has_slots<> { + public: + SigslotTester5(sigslot::signal5<A1, A2, A3, A4, A5>* signal, + C1* capture1, + C2* capture2, + C3* capture3, + C4* capture4, + C5* capture5) + : callback_count_(0), + capture1_(capture1), + capture2_(capture2), + capture3_(capture3), + capture4_(capture4), + capture5_(capture5) { + signal->connect(this, &SigslotTester5::OnSignalCallback); + } + + SigslotTester5(const SigslotTester5&) = delete; + SigslotTester5& operator=(const SigslotTester5&) = delete; + + int callback_count() const { return callback_count_; } + + private: + void OnSignalCallback(A1 arg1, A2 arg2, A3 arg3, A4 arg4, A5 arg5) { + callback_count_++; + *capture1_ = arg1; + *capture2_ = arg2; + *capture3_ = arg3; + *capture4_ = arg4; + *capture5_ = arg5; + } + + int callback_count_; + C1* capture1_; + C2* capture2_; + C3* capture3_; + C4* capture4_; + C5* capture5_; +}; +} // namespace rtc + +#endif // RTC_BASE_SIGSLOT_TESTER_H_ diff --git a/third_party/libwebrtc/rtc_base/sigslot_tester_unittest.cc b/third_party/libwebrtc/rtc_base/sigslot_tester_unittest.cc new file mode 100644 index 0000000000..6c5b12ec5f --- /dev/null +++ b/third_party/libwebrtc/rtc_base/sigslot_tester_unittest.cc @@ -0,0 +1,86 @@ +/* + * Copyright 2014 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 "rtc_base/sigslot_tester.h" + +#include <string> + +#include "rtc_base/third_party/sigslot/sigslot.h" +#include "test/gtest.h" + +namespace rtc { + +TEST(SigslotTester, TestSignal1Arg) { + sigslot::signal1<int> source1; + int capture1; + SigslotTester1<int, int> slot1(&source1, &capture1); + EXPECT_EQ(0, slot1.callback_count()); + + source1.emit(10); + EXPECT_EQ(1, slot1.callback_count()); + EXPECT_EQ(10, capture1); + + source1.emit(20); + EXPECT_EQ(2, slot1.callback_count()); + EXPECT_EQ(20, capture1); +} + +TEST(SigslotTester, TestSignal2Args) { + sigslot::signal2<int, char> source2; + int capture1; + char capture2; + SigslotTester2<int, char, int, char> slot2(&source2, &capture1, &capture2); + EXPECT_EQ(0, slot2.callback_count()); + + source2.emit(10, 'x'); + EXPECT_EQ(1, slot2.callback_count()); + EXPECT_EQ(10, capture1); + EXPECT_EQ('x', capture2); + + source2.emit(20, 'y'); + EXPECT_EQ(2, slot2.callback_count()); + EXPECT_EQ(20, capture1); + EXPECT_EQ('y', capture2); +} + +// Since it applies for 1 and 2 args, we assume it will work for up to 5 args. + +TEST(SigslotTester, TestSignalWithConstReferenceArgs) { + sigslot::signal1<const std::string&> source1; + std::string capture1; + SigslotTester1<const std::string&, std::string> slot1(&source1, &capture1); + EXPECT_EQ(0, slot1.callback_count()); + source1.emit("hello"); + EXPECT_EQ(1, slot1.callback_count()); + EXPECT_EQ("hello", capture1); +} + +TEST(SigslotTester, TestSignalWithPointerToConstArgs) { + sigslot::signal1<const std::string*> source1; + const std::string* capture1; + SigslotTester1<const std::string*, const std::string*> slot1(&source1, + &capture1); + EXPECT_EQ(0, slot1.callback_count()); + source1.emit(nullptr); + EXPECT_EQ(1, slot1.callback_count()); + EXPECT_EQ(nullptr, capture1); +} + +TEST(SigslotTester, TestSignalWithConstPointerArgs) { + sigslot::signal1<std::string* const> source1; + std::string* capture1; + SigslotTester1<std::string* const, std::string*> slot1(&source1, &capture1); + EXPECT_EQ(0, slot1.callback_count()); + source1.emit(nullptr); + EXPECT_EQ(1, slot1.callback_count()); + EXPECT_EQ(nullptr, capture1); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/sigslot_unittest.cc b/third_party/libwebrtc/rtc_base/sigslot_unittest.cc new file mode 100644 index 0000000000..e9fdba503c --- /dev/null +++ b/third_party/libwebrtc/rtc_base/sigslot_unittest.cc @@ -0,0 +1,350 @@ +/* + * Copyright 2012 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 "rtc_base/third_party/sigslot/sigslot.h" + +#include "test/gtest.h" + +// This function, when passed a has_slots or signalx, will break the build if +// its threading requirement is not single threaded +static bool TemplateIsST(const sigslot::single_threaded* p) { + return true; +} +// This function, when passed a has_slots or signalx, will break the build if +// its threading requirement is not multi threaded +static bool TemplateIsMT(const sigslot::multi_threaded_local* p) { + return true; +} + +class SigslotDefault : public ::testing::Test, public sigslot::has_slots<> { + protected: + sigslot::signal0<> signal_; +}; + +template <class slot_policy = sigslot::single_threaded, + class signal_policy = sigslot::single_threaded> +class SigslotReceiver : public sigslot::has_slots<slot_policy> { + public: + SigslotReceiver() : signal_(nullptr), signal_count_(0) {} + ~SigslotReceiver() {} + + // Provide copy constructor so that tests can exercise the has_slots copy + // constructor. + SigslotReceiver(const SigslotReceiver&) = default; + + void Connect(sigslot::signal0<signal_policy>* signal) { + if (!signal) + return; + Disconnect(); + signal_ = signal; + signal->connect(this, + &SigslotReceiver<slot_policy, signal_policy>::OnSignal); + } + void Disconnect() { + if (!signal_) + return; + signal_->disconnect(this); + signal_ = nullptr; + } + void OnSignal() { ++signal_count_; } + int signal_count() { return signal_count_; } + + private: + sigslot::signal0<signal_policy>* signal_; + int signal_count_; +}; + +template <class slot_policy = sigslot::single_threaded, + class mt_signal_policy = sigslot::multi_threaded_local> +class SigslotSlotTest : public ::testing::Test { + protected: + SigslotSlotTest() { + mt_signal_policy mt_policy; + TemplateIsMT(&mt_policy); + } + + virtual void SetUp() { Connect(); } + virtual void TearDown() { Disconnect(); } + + void Disconnect() { + st_receiver_.Disconnect(); + mt_receiver_.Disconnect(); + } + + void Connect() { + st_receiver_.Connect(&SignalSTLoopback); + mt_receiver_.Connect(&SignalMTLoopback); + } + + int st_loop_back_count() { return st_receiver_.signal_count(); } + int mt_loop_back_count() { return mt_receiver_.signal_count(); } + + sigslot::signal0<> SignalSTLoopback; + SigslotReceiver<slot_policy, sigslot::single_threaded> st_receiver_; + sigslot::signal0<mt_signal_policy> SignalMTLoopback; + SigslotReceiver<slot_policy, mt_signal_policy> mt_receiver_; +}; + +typedef SigslotSlotTest<> SigslotSTSlotTest; +typedef SigslotSlotTest<sigslot::multi_threaded_local, + sigslot::multi_threaded_local> + SigslotMTSlotTest; + +class multi_threaded_local_fake : public sigslot::multi_threaded_local { + public: + multi_threaded_local_fake() : lock_count_(0), unlock_count_(0) {} + + void lock() { ++lock_count_; } + void unlock() { ++unlock_count_; } + + int lock_count() { return lock_count_; } + + bool InCriticalSection() { return lock_count_ != unlock_count_; } + + protected: + int lock_count_; + int unlock_count_; +}; + +typedef SigslotSlotTest<multi_threaded_local_fake, multi_threaded_local_fake> + SigslotMTLockBase; + +class SigslotMTLockTest : public SigslotMTLockBase { + protected: + SigslotMTLockTest() {} + + void SetUp() override { + EXPECT_EQ(0, SlotLockCount()); + SigslotMTLockBase::SetUp(); + // Connects to two signals (ST and MT). However, + // SlotLockCount() only gets the count for the + // MT signal (there are two separate SigslotReceiver which + // keep track of their own count). + EXPECT_EQ(1, SlotLockCount()); + } + void TearDown() override { + const int previous_lock_count = SlotLockCount(); + SigslotMTLockBase::TearDown(); + // Disconnects from two signals. Note analogous to SetUp(). + EXPECT_EQ(previous_lock_count + 1, SlotLockCount()); + } + + int SlotLockCount() { return mt_receiver_.lock_count(); } + void Signal() { SignalMTLoopback(); } + int SignalLockCount() { return SignalMTLoopback.lock_count(); } + int signal_count() { return mt_loop_back_count(); } + bool InCriticalSection() { return SignalMTLoopback.InCriticalSection(); } +}; + +// This test will always succeed. However, if the default template instantiation +// changes from single threaded to multi threaded it will break the build here. +TEST_F(SigslotDefault, DefaultIsST) { + EXPECT_TRUE(TemplateIsST(this)); + EXPECT_TRUE(TemplateIsST(&signal_)); +} + +// ST slot, ST signal +TEST_F(SigslotSTSlotTest, STLoopbackTest) { + SignalSTLoopback(); + EXPECT_EQ(1, st_loop_back_count()); + EXPECT_EQ(0, mt_loop_back_count()); +} + +// ST slot, MT signal +TEST_F(SigslotSTSlotTest, MTLoopbackTest) { + SignalMTLoopback(); + EXPECT_EQ(1, mt_loop_back_count()); + EXPECT_EQ(0, st_loop_back_count()); +} + +// ST slot, both ST and MT (separate) signal +TEST_F(SigslotSTSlotTest, AllLoopbackTest) { + SignalSTLoopback(); + SignalMTLoopback(); + EXPECT_EQ(1, mt_loop_back_count()); + EXPECT_EQ(1, st_loop_back_count()); +} + +TEST_F(SigslotSTSlotTest, Reconnect) { + SignalSTLoopback(); + SignalMTLoopback(); + EXPECT_EQ(1, mt_loop_back_count()); + EXPECT_EQ(1, st_loop_back_count()); + Disconnect(); + SignalSTLoopback(); + SignalMTLoopback(); + EXPECT_EQ(1, mt_loop_back_count()); + EXPECT_EQ(1, st_loop_back_count()); + Connect(); + SignalSTLoopback(); + SignalMTLoopback(); + EXPECT_EQ(2, mt_loop_back_count()); + EXPECT_EQ(2, st_loop_back_count()); +} + +// MT slot, ST signal +TEST_F(SigslotMTSlotTest, STLoopbackTest) { + SignalSTLoopback(); + EXPECT_EQ(1, st_loop_back_count()); + EXPECT_EQ(0, mt_loop_back_count()); +} + +// MT slot, MT signal +TEST_F(SigslotMTSlotTest, MTLoopbackTest) { + SignalMTLoopback(); + EXPECT_EQ(1, mt_loop_back_count()); + EXPECT_EQ(0, st_loop_back_count()); +} + +// MT slot, both ST and MT (separate) signal +TEST_F(SigslotMTSlotTest, AllLoopbackTest) { + SignalMTLoopback(); + SignalSTLoopback(); + EXPECT_EQ(1, st_loop_back_count()); + EXPECT_EQ(1, mt_loop_back_count()); +} + +// Test that locks are acquired and released correctly. +TEST_F(SigslotMTLockTest, LockSanity) { + const int lock_count = SignalLockCount(); + Signal(); + EXPECT_FALSE(InCriticalSection()); + EXPECT_EQ(lock_count + 1, SignalLockCount()); + EXPECT_EQ(1, signal_count()); +} + +// Destroy signal and slot in different orders. +TEST(SigslotDestructionOrder, SignalFirst) { + sigslot::signal0<>* signal = new sigslot::signal0<>; + SigslotReceiver<>* receiver = new SigslotReceiver<>(); + receiver->Connect(signal); + (*signal)(); + EXPECT_EQ(1, receiver->signal_count()); + delete signal; + delete receiver; +} + +TEST(SigslotDestructionOrder, SlotFirst) { + sigslot::signal0<>* signal = new sigslot::signal0<>; + SigslotReceiver<>* receiver = new SigslotReceiver<>(); + receiver->Connect(signal); + (*signal)(); + EXPECT_EQ(1, receiver->signal_count()); + + delete receiver; + (*signal)(); + delete signal; +} + +// Test that if a signal is copied, its slot connections are copied as well. +TEST(SigslotTest, CopyConnectedSignal) { + sigslot::signal<> signal; + SigslotReceiver<> receiver; + receiver.Connect(&signal); + + // Fire the copied signal, expecting the receiver to be notified. + sigslot::signal<> copied_signal(signal); + copied_signal(); + EXPECT_EQ(1, receiver.signal_count()); +} + +// Test that if a slot is copied, its signal connections are copied as well. +TEST(SigslotTest, CopyConnectedSlot) { + sigslot::signal<> signal; + SigslotReceiver<> receiver; + receiver.Connect(&signal); + + // Fire the signal after copying the receiver, expecting the copied receiver + // to be notified. + SigslotReceiver<> copied_receiver(receiver); + signal(); + EXPECT_EQ(1, copied_receiver.signal_count()); +} + +// Just used for the test below. +class Disconnector : public sigslot::has_slots<> { + public: + Disconnector(SigslotReceiver<>* receiver1, SigslotReceiver<>* receiver2) + : receiver1_(receiver1), receiver2_(receiver2) {} + + void Connect(sigslot::signal<>* signal) { + signal_ = signal; + signal->connect(this, &Disconnector::Disconnect); + } + + private: + void Disconnect() { + receiver1_->Disconnect(); + receiver2_->Disconnect(); + signal_->disconnect(this); + } + + sigslot::signal<>* signal_; + SigslotReceiver<>* receiver1_; + SigslotReceiver<>* receiver2_; +}; + +// Test that things work as expected if a signal is disconnected from a slot +// while it's firing. +TEST(SigslotTest, DisconnectFromSignalWhileFiring) { + sigslot::signal<> signal; + SigslotReceiver<> receiver1; + SigslotReceiver<> receiver2; + SigslotReceiver<> receiver3; + Disconnector disconnector(&receiver1, &receiver2); + + // From this ordering, receiver1 should receive the signal, then the + // disconnector will be invoked, causing receiver2 to be disconnected before + // it receives the signal. And receiver3 should also receive the signal, + // since it was never disconnected. + receiver1.Connect(&signal); + disconnector.Connect(&signal); + receiver2.Connect(&signal); + receiver3.Connect(&signal); + signal(); + + EXPECT_EQ(1, receiver1.signal_count()); + EXPECT_EQ(0, receiver2.signal_count()); + EXPECT_EQ(1, receiver3.signal_count()); +} + +// Uses disconnect_all instead of disconnect. +class Disconnector2 : public sigslot::has_slots<> { + public: + void Connect(sigslot::signal<>* signal) { + signal_ = signal; + signal->connect(this, &Disconnector2::Disconnect); + } + + private: + void Disconnect() { signal_->disconnect_all(); } + + sigslot::signal<>* signal_; +}; + +// Test that things work as expected if a signal is disconnected from a slot +// while it's firing using disconnect_all. +TEST(SigslotTest, CallDisconnectAllWhileSignalFiring) { + sigslot::signal<> signal; + SigslotReceiver<> receiver1; + SigslotReceiver<> receiver2; + Disconnector2 disconnector; + + // From this ordering, receiver1 should receive the signal, then the + // disconnector will be invoked, causing receiver2 to be disconnected before + // it receives the signal. + receiver1.Connect(&signal); + disconnector.Connect(&signal); + receiver2.Connect(&signal); + signal(); + + EXPECT_EQ(1, receiver1.signal_count()); + EXPECT_EQ(0, receiver2.signal_count()); +} diff --git a/third_party/libwebrtc/rtc_base/sigslottester.h.pump b/third_party/libwebrtc/rtc_base/sigslottester.h.pump new file mode 100755 index 0000000000..c3d2d6e99b --- /dev/null +++ b/third_party/libwebrtc/rtc_base/sigslottester.h.pump @@ -0,0 +1,102 @@ +/* + * Copyright 2014 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 RTC_BASE_SIGSLOTTESTER_H_ +#define RTC_BASE_SIGSLOTTESTER_H_ + +// To generate sigslottester.h from sigslottester.h.pump, execute: +// /home/build/google3/third_party/gtest/scripts/pump.py sigslottester.h.pump + + +// SigslotTester(s) are utility classes to check if signals owned by an +// object are being invoked at the right time and with the right arguments. +// They are meant to be used in tests. Tests must provide "capture" pointers +// (i.e. address of variables) where the arguments from the signal callback +// can be stored. +// +// Example: +// /* Some signal */ +// sigslot::signal1<const std::string&> foo; +// +// /* We want to monitor foo in some test. Note how signal argument is +// const std::string&, but capture-type is std::string. Capture type +// must be type that can be assigned to. */ +// std::string capture; +// SigslotTester1<const std::string&, std::string> slot(&foo, &capture); +// foo.emit("hello"); +// EXPECT_EQ(1, slot.callback_count()); +// EXPECT_EQ("hello", capture); +// /* See unit-tests for more examples */ + +#include "rtc_base/third_party/sigslot/sigslot.h" + +namespace rtc { + +// Base version for testing signals that passes no arguments. +class SigslotTester0 : public sigslot::has_slots<> { + public: + explicit SigslotTester0(sigslot::signal0<>* signal) : callback_count_(0) { + signal->connect(this, &SigslotTester0::OnSignalCallback); + } + + SigslotTester0(const SigslotTester0&) = delete; + SigslotTester0& operator=(const SigslotTester0&) = delete; + + int callback_count() const { return callback_count_; } + + private: + void OnSignalCallback() { callback_count_++; } + int callback_count_; +}; + +// Versions below are for testing signals that pass arguments. For all the +// templates below: +// - A1-A5 is the type of the argument i in the callback. Signals may and often +// do use const-references here for efficiency. +// - C1-C5 is the type of the variable to capture argument i. These should be +// non-const value types suitable for use as lvalues. + +$var n = 5 +$range i 1..n +$for i [[ +$range j 1..i + +template <$for j , [[class A$j]], $for j , [[class C$j]]> +class SigslotTester$i : public sigslot::has_slots<> { + public: + SigslotTester$i(sigslot::signal$i<$for j , [[A$j]]>* signal, + $for j , [[C$j* capture$j]]) + : callback_count_(0), + $for j , [[capture$j[[]]_(capture$j)]] { + signal->connect(this, &SigslotTester$i::OnSignalCallback); + } + + SigslotTester$i(const SigslotTester$i&) = delete; + SigslotTester$i& operator=(const SigslotTester$i&) = delete; + + int callback_count() const { return callback_count_; } + + private: + void OnSignalCallback($for j , [[A$j arg$j]]) { + callback_count_++;$for j [[ + + *capture$j[[]]_ = arg$j;]] + + } + + int callback_count_;$for j [[ + + C$j* capture$j[[]]_;]] +}; + +]] +} // namespace rtc + +#endif // RTC_BASE_SIGSLOTTESTER_H_ diff --git a/third_party/libwebrtc/rtc_base/socket.cc b/third_party/libwebrtc/rtc_base/socket.cc new file mode 100644 index 0000000000..bcd62ad2a4 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/socket.cc @@ -0,0 +1,13 @@ +/* + * 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. + */ + +#include "rtc_base/socket.h" + +namespace rtc {} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/socket.h b/third_party/libwebrtc/rtc_base/socket.h new file mode 100644 index 0000000000..0ed3a7fa6a --- /dev/null +++ b/third_party/libwebrtc/rtc_base/socket.h @@ -0,0 +1,147 @@ +/* + * 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 RTC_BASE_SOCKET_H_ +#define RTC_BASE_SOCKET_H_ + +#include <errno.h> + +#if defined(WEBRTC_POSIX) +#include <arpa/inet.h> +#include <netinet/in.h> +#include <sys/socket.h> +#include <sys/types.h> +#define SOCKET_EACCES EACCES +#endif + +#if defined(WEBRTC_WIN) +#include "rtc_base/win32.h" +#endif + +#include "rtc_base/socket_address.h" +#include "rtc_base/third_party/sigslot/sigslot.h" + +// Rather than converting errors into a private namespace, +// Reuse the POSIX socket api errors. Note this depends on +// Win32 compatibility. + +#if defined(WEBRTC_WIN) +#undef EWOULDBLOCK // Remove errno.h's definition for each macro below. +#define EWOULDBLOCK WSAEWOULDBLOCK +#undef EINPROGRESS +#define EINPROGRESS WSAEINPROGRESS +#undef EALREADY +#define EALREADY WSAEALREADY +#undef EMSGSIZE +#define EMSGSIZE WSAEMSGSIZE +#undef EADDRINUSE +#define EADDRINUSE WSAEADDRINUSE +#undef EADDRNOTAVAIL +#define EADDRNOTAVAIL WSAEADDRNOTAVAIL +#undef ENETDOWN +#define ENETDOWN WSAENETDOWN +#undef ECONNABORTED +#define ECONNABORTED WSAECONNABORTED +#undef ENOBUFS +#define ENOBUFS WSAENOBUFS +#undef EISCONN +#define EISCONN WSAEISCONN +#undef ENOTCONN +#define ENOTCONN WSAENOTCONN +#undef ECONNREFUSED +#define ECONNREFUSED WSAECONNREFUSED +#undef EHOSTUNREACH +#define EHOSTUNREACH WSAEHOSTUNREACH +#undef ENETUNREACH +#define ENETUNREACH WSAENETUNREACH +#define SOCKET_EACCES WSAEACCES +#endif // WEBRTC_WIN + +#if defined(WEBRTC_POSIX) +#define INVALID_SOCKET (-1) +#define SOCKET_ERROR (-1) +#define closesocket(s) close(s) +#endif // WEBRTC_POSIX + +namespace rtc { + +inline bool IsBlockingError(int e) { + return (e == EWOULDBLOCK) || (e == EAGAIN) || (e == EINPROGRESS); +} + +// General interface for the socket implementations of various networks. The +// methods match those of normal UNIX sockets very closely. +class Socket { + public: + virtual ~Socket() {} + + Socket(const Socket&) = delete; + Socket& operator=(const Socket&) = delete; + + // Returns the address to which the socket is bound. If the socket is not + // bound, then the any-address is returned. + virtual SocketAddress GetLocalAddress() const = 0; + + // Returns the address to which the socket is connected. If the socket is + // not connected, then the any-address is returned. + virtual SocketAddress GetRemoteAddress() const = 0; + + virtual int Bind(const SocketAddress& addr) = 0; + virtual int Connect(const SocketAddress& addr) = 0; + virtual int Send(const void* pv, size_t cb) = 0; + virtual int SendTo(const void* pv, size_t cb, const SocketAddress& addr) = 0; + // `timestamp` is in units of microseconds. + virtual int Recv(void* pv, size_t cb, int64_t* timestamp) = 0; + virtual int RecvFrom(void* pv, + size_t cb, + SocketAddress* paddr, + int64_t* timestamp) = 0; + virtual int Listen(int backlog) = 0; + virtual Socket* Accept(SocketAddress* paddr) = 0; + virtual int Close() = 0; + virtual int GetError() const = 0; + virtual void SetError(int error) = 0; + inline bool IsBlocking() const { return IsBlockingError(GetError()); } + + enum ConnState { CS_CLOSED, CS_CONNECTING, CS_CONNECTED }; + virtual ConnState GetState() const = 0; + + enum Option { + OPT_DONTFRAGMENT, + OPT_RCVBUF, // receive buffer size + OPT_SNDBUF, // send buffer size + OPT_NODELAY, // whether Nagle algorithm is enabled + OPT_IPV6_V6ONLY, // Whether the socket is IPv6 only. + OPT_DSCP, // DSCP code + OPT_RTP_SENDTIME_EXTN_ID, // This is a non-traditional socket option param. + // This is specific to libjingle and will be used + // if SendTime option is needed at socket level. + }; + virtual int GetOption(Option opt, int* value) = 0; + virtual int SetOption(Option opt, int value) = 0; + + // SignalReadEvent and SignalWriteEvent use multi_threaded_local to allow + // access concurrently from different thread. + // For example SignalReadEvent::connect will be called in AsyncUDPSocket ctor + // but at the same time the SocketDispatcher may be signaling the read event. + // ready to read + sigslot::signal1<Socket*, sigslot::multi_threaded_local> SignalReadEvent; + // ready to write + sigslot::signal1<Socket*, sigslot::multi_threaded_local> SignalWriteEvent; + sigslot::signal1<Socket*> SignalConnectEvent; // connected + sigslot::signal2<Socket*, int> SignalCloseEvent; // closed + + protected: + Socket() {} +}; + +} // namespace rtc + +#endif // RTC_BASE_SOCKET_H_ diff --git a/third_party/libwebrtc/rtc_base/socket_adapters.cc b/third_party/libwebrtc/rtc_base/socket_adapters.cc new file mode 100644 index 0000000000..4ec93ae3e9 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/socket_adapters.cc @@ -0,0 +1,665 @@ +/* + * 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. + */ + +#if defined(_MSC_VER) && _MSC_VER < 1300 +#pragma warning(disable : 4786) +#endif + +#include "rtc_base/socket_adapters.h" + +#include <algorithm> + +#include "absl/strings/match.h" +#include "absl/strings/string_view.h" +#include "rtc_base/buffer.h" +#include "rtc_base/byte_buffer.h" +#include "rtc_base/checks.h" +#include "rtc_base/http_common.h" +#include "rtc_base/logging.h" +#include "rtc_base/strings/string_builder.h" +#include "rtc_base/zero_memory.h" + +namespace rtc { + +BufferedReadAdapter::BufferedReadAdapter(Socket* socket, size_t size) + : AsyncSocketAdapter(socket), + buffer_size_(size), + data_len_(0), + buffering_(false) { + buffer_ = new char[buffer_size_]; +} + +BufferedReadAdapter::~BufferedReadAdapter() { + delete[] buffer_; +} + +int BufferedReadAdapter::Send(const void* pv, size_t cb) { + if (buffering_) { + // TODO: Spoof error better; Signal Writeable + SetError(EWOULDBLOCK); + return -1; + } + return AsyncSocketAdapter::Send(pv, cb); +} + +int BufferedReadAdapter::Recv(void* pv, size_t cb, int64_t* timestamp) { + if (buffering_) { + SetError(EWOULDBLOCK); + return -1; + } + + size_t read = 0; + + if (data_len_) { + read = std::min(cb, data_len_); + memcpy(pv, buffer_, read); + data_len_ -= read; + if (data_len_ > 0) { + memmove(buffer_, buffer_ + read, data_len_); + } + pv = static_cast<char*>(pv) + read; + cb -= read; + } + + // FIX: If cb == 0, we won't generate another read event + + int res = AsyncSocketAdapter::Recv(pv, cb, timestamp); + if (res >= 0) { + // Read from socket and possibly buffer; return combined length + return res + static_cast<int>(read); + } + + if (read > 0) { + // Failed to read from socket, but still read something from buffer + return static_cast<int>(read); + } + + // Didn't read anything; return error from socket + return res; +} + +void BufferedReadAdapter::BufferInput(bool on) { + buffering_ = on; +} + +void BufferedReadAdapter::OnReadEvent(Socket* socket) { + RTC_DCHECK(socket == GetSocket()); + + if (!buffering_) { + AsyncSocketAdapter::OnReadEvent(socket); + return; + } + + if (data_len_ >= buffer_size_) { + RTC_LOG(LS_ERROR) << "Input buffer overflow"; + RTC_DCHECK_NOTREACHED(); + data_len_ = 0; + } + + int len = AsyncSocketAdapter::Recv(buffer_ + data_len_, + buffer_size_ - data_len_, nullptr); + if (len < 0) { + // TODO: Do something better like forwarding the error to the user. + RTC_LOG_ERR(LS_INFO) << "Recv"; + return; + } + + data_len_ += len; + + ProcessInput(buffer_, &data_len_); +} + +/////////////////////////////////////////////////////////////////////////////// + +// This is a SSL v2 CLIENT_HELLO message. +// TODO: Should this have a session id? The response doesn't have a +// certificate, so the hello should have a session id. +static const uint8_t kSslClientHello[] = { + 0x80, 0x46, // msg len + 0x01, // CLIENT_HELLO + 0x03, 0x01, // SSL 3.1 + 0x00, 0x2d, // ciphersuite len + 0x00, 0x00, // session id len + 0x00, 0x10, // challenge len + 0x01, 0x00, 0x80, 0x03, 0x00, 0x80, 0x07, 0x00, 0xc0, // ciphersuites + 0x06, 0x00, 0x40, 0x02, 0x00, 0x80, 0x04, 0x00, 0x80, // + 0x00, 0x00, 0x04, 0x00, 0xfe, 0xff, 0x00, 0x00, 0x0a, // + 0x00, 0xfe, 0xfe, 0x00, 0x00, 0x09, 0x00, 0x00, 0x64, // + 0x00, 0x00, 0x62, 0x00, 0x00, 0x03, 0x00, 0x00, 0x06, // + 0x1f, 0x17, 0x0c, 0xa6, 0x2f, 0x00, 0x78, 0xfc, // challenge + 0x46, 0x55, 0x2e, 0xb1, 0x83, 0x39, 0xf1, 0xea // +}; + +// static +ArrayView<const uint8_t> AsyncSSLSocket::SslClientHello() { + // Implicit conversion directly from kSslClientHello to ArrayView fails when + // built with gcc. + return {kSslClientHello, sizeof(kSslClientHello)}; +} + +// This is a TLSv1 SERVER_HELLO message. +static const uint8_t kSslServerHello[] = { + 0x16, // handshake message + 0x03, 0x01, // SSL 3.1 + 0x00, 0x4a, // message len + 0x02, // SERVER_HELLO + 0x00, 0x00, 0x46, // handshake len + 0x03, 0x01, // SSL 3.1 + 0x42, 0x85, 0x45, 0xa7, 0x27, 0xa9, 0x5d, 0xa0, // server random + 0xb3, 0xc5, 0xe7, 0x53, 0xda, 0x48, 0x2b, 0x3f, // + 0xc6, 0x5a, 0xca, 0x89, 0xc1, 0x58, 0x52, 0xa1, // + 0x78, 0x3c, 0x5b, 0x17, 0x46, 0x00, 0x85, 0x3f, // + 0x20, // session id len + 0x0e, 0xd3, 0x06, 0x72, 0x5b, 0x5b, 0x1b, 0x5f, // session id + 0x15, 0xac, 0x13, 0xf9, 0x88, 0x53, 0x9d, 0x9b, // + 0xe8, 0x3d, 0x7b, 0x0c, 0x30, 0x32, 0x6e, 0x38, // + 0x4d, 0xa2, 0x75, 0x57, 0x41, 0x6c, 0x34, 0x5c, // + 0x00, 0x04, // RSA/RC4-128/MD5 + 0x00 // null compression +}; + +// static +ArrayView<const uint8_t> AsyncSSLSocket::SslServerHello() { + return {kSslServerHello, sizeof(kSslServerHello)}; +} + +AsyncSSLSocket::AsyncSSLSocket(Socket* socket) + : BufferedReadAdapter(socket, 1024) {} + +int AsyncSSLSocket::Connect(const SocketAddress& addr) { + // Begin buffering before we connect, so that there isn't a race condition + // between potential senders and receiving the OnConnectEvent signal + BufferInput(true); + return BufferedReadAdapter::Connect(addr); +} + +void AsyncSSLSocket::OnConnectEvent(Socket* socket) { + RTC_DCHECK(socket == GetSocket()); + // TODO: we could buffer output too... + const int res = DirectSend(kSslClientHello, sizeof(kSslClientHello)); + if (res != sizeof(kSslClientHello)) { + RTC_LOG(LS_ERROR) << "Sending fake SSL ClientHello message failed."; + Close(); + SignalCloseEvent(this, 0); + } +} + +void AsyncSSLSocket::ProcessInput(char* data, size_t* len) { + if (*len < sizeof(kSslServerHello)) + return; + + if (memcmp(kSslServerHello, data, sizeof(kSslServerHello)) != 0) { + RTC_LOG(LS_ERROR) << "Received non-matching fake SSL ServerHello message."; + Close(); + SignalCloseEvent(this, 0); // TODO: error code? + return; + } + + *len -= sizeof(kSslServerHello); + if (*len > 0) { + memmove(data, data + sizeof(kSslServerHello), *len); + } + + bool remainder = (*len > 0); + BufferInput(false); + SignalConnectEvent(this); + + // FIX: if SignalConnect causes the socket to be destroyed, we are in trouble + if (remainder) + SignalReadEvent(this); +} + +/////////////////////////////////////////////////////////////////////////////// + +AsyncHttpsProxySocket::AsyncHttpsProxySocket(Socket* socket, + absl::string_view user_agent, + const SocketAddress& proxy, + absl::string_view username, + const CryptString& password) + : BufferedReadAdapter(socket, 1024), + proxy_(proxy), + agent_(user_agent), + user_(username), + pass_(password), + force_connect_(false), + state_(PS_ERROR), + context_(0) {} + +AsyncHttpsProxySocket::~AsyncHttpsProxySocket() { + delete context_; +} + +int AsyncHttpsProxySocket::Connect(const SocketAddress& addr) { + int ret; + RTC_LOG(LS_VERBOSE) << "AsyncHttpsProxySocket::Connect(" + << proxy_.ToSensitiveString() << ")"; + dest_ = addr; + state_ = PS_INIT; + if (ShouldIssueConnect()) { + BufferInput(true); + } + ret = BufferedReadAdapter::Connect(proxy_); + // TODO: Set state_ appropriately if Connect fails. + return ret; +} + +SocketAddress AsyncHttpsProxySocket::GetRemoteAddress() const { + return dest_; +} + +int AsyncHttpsProxySocket::Close() { + headers_.clear(); + state_ = PS_ERROR; + dest_.Clear(); + delete context_; + context_ = nullptr; + return BufferedReadAdapter::Close(); +} + +Socket::ConnState AsyncHttpsProxySocket::GetState() const { + if (state_ < PS_TUNNEL) { + return CS_CONNECTING; + } else if (state_ == PS_TUNNEL) { + return CS_CONNECTED; + } else { + return CS_CLOSED; + } +} + +void AsyncHttpsProxySocket::OnConnectEvent(Socket* socket) { + RTC_LOG(LS_VERBOSE) << "AsyncHttpsProxySocket::OnConnectEvent"; + if (!ShouldIssueConnect()) { + state_ = PS_TUNNEL; + BufferedReadAdapter::OnConnectEvent(socket); + return; + } + SendRequest(); +} + +void AsyncHttpsProxySocket::OnCloseEvent(Socket* socket, int err) { + RTC_LOG(LS_VERBOSE) << "AsyncHttpsProxySocket::OnCloseEvent(" << err << ")"; + if ((state_ == PS_WAIT_CLOSE) && (err == 0)) { + state_ = PS_ERROR; + Connect(dest_); + } else { + BufferedReadAdapter::OnCloseEvent(socket, err); + } +} + +void AsyncHttpsProxySocket::ProcessInput(char* data, size_t* len) { + size_t start = 0; + for (size_t pos = start; state_ < PS_TUNNEL && pos < *len;) { + if (state_ == PS_SKIP_BODY) { + size_t consume = std::min(*len - pos, content_length_); + pos += consume; + start = pos; + content_length_ -= consume; + if (content_length_ == 0) { + EndResponse(); + } + continue; + } + + if (data[pos++] != '\n') + continue; + + size_t length = pos - start - 1; + if ((length > 0) && (data[start + length - 1] == '\r')) + --length; + + data[start + length] = 0; + ProcessLine(data + start, length); + start = pos; + } + + *len -= start; + if (*len > 0) { + memmove(data, data + start, *len); + } + + if (state_ != PS_TUNNEL) + return; + + bool remainder = (*len > 0); + BufferInput(false); + SignalConnectEvent(this); + + // FIX: if SignalConnect causes the socket to be destroyed, we are in trouble + if (remainder) + SignalReadEvent(this); // TODO: signal this?? +} + +bool AsyncHttpsProxySocket::ShouldIssueConnect() const { + // TODO: Think about whether a more sophisticated test + // than dest port == 80 is needed. + return force_connect_ || (dest_.port() != 80); +} + +void AsyncHttpsProxySocket::SendRequest() { + rtc::StringBuilder ss; + ss << "CONNECT " << dest_.ToString() << " HTTP/1.0\r\n"; + ss << "User-Agent: " << agent_ << "\r\n"; + ss << "Host: " << dest_.HostAsURIString() << "\r\n"; + ss << "Content-Length: 0\r\n"; + ss << "Proxy-Connection: Keep-Alive\r\n"; + ss << headers_; + ss << "\r\n"; + std::string str = ss.str(); + DirectSend(str.c_str(), str.size()); + state_ = PS_LEADER; + expect_close_ = true; + content_length_ = 0; + headers_.clear(); + + RTC_LOG(LS_VERBOSE) << "AsyncHttpsProxySocket >> " << str; +} + +void AsyncHttpsProxySocket::ProcessLine(char* data, size_t len) { + RTC_LOG(LS_VERBOSE) << "AsyncHttpsProxySocket << " << data; + + if (len == 0) { + if (state_ == PS_TUNNEL_HEADERS) { + state_ = PS_TUNNEL; + } else if (state_ == PS_ERROR_HEADERS) { + Error(defer_error_); + return; + } else if (state_ == PS_SKIP_HEADERS) { + if (content_length_) { + state_ = PS_SKIP_BODY; + } else { + EndResponse(); + return; + } + } else { + if (!unknown_mechanisms_.empty()) { + RTC_LOG(LS_ERROR) << "Unsupported authentication methods: " + << unknown_mechanisms_; + } + // Unexpected end of headers + Error(0); + return; + } + } else if (state_ == PS_LEADER) { + unsigned int code; + if (sscanf(data, "HTTP/%*u.%*u %u", &code) != 1) { + Error(0); + return; + } + switch (code) { + case 200: + // connection good! + state_ = PS_TUNNEL_HEADERS; + return; +#if defined(HTTP_STATUS_PROXY_AUTH_REQ) && (HTTP_STATUS_PROXY_AUTH_REQ != 407) +#error Wrong code for HTTP_STATUS_PROXY_AUTH_REQ +#endif + case 407: // HTTP_STATUS_PROXY_AUTH_REQ + state_ = PS_AUTHENTICATE; + return; + default: + defer_error_ = 0; + state_ = PS_ERROR_HEADERS; + return; + } + } else if ((state_ == PS_AUTHENTICATE) && + absl::StartsWithIgnoreCase(data, "Proxy-Authenticate:")) { + std::string response, auth_method; + switch (HttpAuthenticate(absl::string_view(data + 19, len - 19), proxy_, + "CONNECT", "/", user_, pass_, context_, response, + auth_method)) { + case HAR_IGNORE: + RTC_LOG(LS_VERBOSE) << "Ignoring Proxy-Authenticate: " << auth_method; + if (!unknown_mechanisms_.empty()) + unknown_mechanisms_.append(", "); + unknown_mechanisms_.append(auth_method); + break; + case HAR_RESPONSE: + headers_ = "Proxy-Authorization: "; + headers_.append(response); + headers_.append("\r\n"); + state_ = PS_SKIP_HEADERS; + unknown_mechanisms_.clear(); + break; + case HAR_CREDENTIALS: + defer_error_ = SOCKET_EACCES; + state_ = PS_ERROR_HEADERS; + unknown_mechanisms_.clear(); + break; + case HAR_ERROR: + defer_error_ = 0; + state_ = PS_ERROR_HEADERS; + unknown_mechanisms_.clear(); + break; + } + } else if (absl::StartsWithIgnoreCase(data, "Content-Length:")) { + content_length_ = strtoul(data + 15, 0, 0); + } else if (absl::StartsWithIgnoreCase(data, "Proxy-Connection: Keep-Alive")) { + expect_close_ = false; + /* + } else if (absl::StartsWithIgnoreCase(data, "Connection: close") { + expect_close_ = true; + */ + } +} + +void AsyncHttpsProxySocket::EndResponse() { + if (!expect_close_) { + SendRequest(); + return; + } + + // No point in waiting for the server to close... let's close now + // TODO: Refactor out PS_WAIT_CLOSE + state_ = PS_WAIT_CLOSE; + BufferedReadAdapter::Close(); + OnCloseEvent(this, 0); +} + +void AsyncHttpsProxySocket::Error(int error) { + BufferInput(false); + Close(); + SetError(error); + SignalCloseEvent(this, error); +} + +/////////////////////////////////////////////////////////////////////////////// + +AsyncSocksProxySocket::AsyncSocksProxySocket(Socket* socket, + const SocketAddress& proxy, + absl::string_view username, + const CryptString& password) + : BufferedReadAdapter(socket, 1024), + state_(SS_ERROR), + proxy_(proxy), + user_(username), + pass_(password) {} + +AsyncSocksProxySocket::~AsyncSocksProxySocket() = default; + +int AsyncSocksProxySocket::Connect(const SocketAddress& addr) { + int ret; + dest_ = addr; + state_ = SS_INIT; + BufferInput(true); + ret = BufferedReadAdapter::Connect(proxy_); + // TODO: Set state_ appropriately if Connect fails. + return ret; +} + +SocketAddress AsyncSocksProxySocket::GetRemoteAddress() const { + return dest_; +} + +int AsyncSocksProxySocket::Close() { + state_ = SS_ERROR; + dest_.Clear(); + return BufferedReadAdapter::Close(); +} + +Socket::ConnState AsyncSocksProxySocket::GetState() const { + if (state_ < SS_TUNNEL) { + return CS_CONNECTING; + } else if (state_ == SS_TUNNEL) { + return CS_CONNECTED; + } else { + return CS_CLOSED; + } +} + +void AsyncSocksProxySocket::OnConnectEvent(Socket* socket) { + SendHello(); +} + +void AsyncSocksProxySocket::ProcessInput(char* data, size_t* len) { + RTC_DCHECK(state_ < SS_TUNNEL); + + ByteBufferReader response(data, *len); + + if (state_ == SS_HELLO) { + uint8_t ver, method; + if (!response.ReadUInt8(&ver) || !response.ReadUInt8(&method)) + return; + + if (ver != 5) { + Error(0); + return; + } + + if (method == 0) { + SendConnect(); + } else if (method == 2) { + SendAuth(); + } else { + Error(0); + return; + } + } else if (state_ == SS_AUTH) { + uint8_t ver, status; + if (!response.ReadUInt8(&ver) || !response.ReadUInt8(&status)) + return; + + if ((ver != 1) || (status != 0)) { + Error(SOCKET_EACCES); + return; + } + + SendConnect(); + } else if (state_ == SS_CONNECT) { + uint8_t ver, rep, rsv, atyp; + if (!response.ReadUInt8(&ver) || !response.ReadUInt8(&rep) || + !response.ReadUInt8(&rsv) || !response.ReadUInt8(&atyp)) + return; + + if ((ver != 5) || (rep != 0)) { + Error(0); + return; + } + + uint16_t port; + if (atyp == 1) { + uint32_t addr; + if (!response.ReadUInt32(&addr) || !response.ReadUInt16(&port)) + return; + RTC_LOG(LS_VERBOSE) << "Bound on " << addr << ":" << port; + } else if (atyp == 3) { + uint8_t length; + std::string addr; + if (!response.ReadUInt8(&length) || !response.ReadString(&addr, length) || + !response.ReadUInt16(&port)) + return; + RTC_LOG(LS_VERBOSE) << "Bound on " << addr << ":" << port; + } else if (atyp == 4) { + std::string addr; + if (!response.ReadString(&addr, 16) || !response.ReadUInt16(&port)) + return; + RTC_LOG(LS_VERBOSE) << "Bound on <IPV6>:" << port; + } else { + Error(0); + return; + } + + state_ = SS_TUNNEL; + } + + // Consume parsed data + *len = response.Length(); + memmove(data, response.Data(), *len); + + if (state_ != SS_TUNNEL) + return; + + bool remainder = (*len > 0); + BufferInput(false); + SignalConnectEvent(this); + + // FIX: if SignalConnect causes the socket to be destroyed, we are in trouble + if (remainder) + SignalReadEvent(this); // TODO: signal this?? +} + +void AsyncSocksProxySocket::SendHello() { + ByteBufferWriter request; + request.WriteUInt8(5); // Socks Version + if (user_.empty()) { + request.WriteUInt8(1); // Authentication Mechanisms + request.WriteUInt8(0); // No authentication + } else { + request.WriteUInt8(2); // Authentication Mechanisms + request.WriteUInt8(0); // No authentication + request.WriteUInt8(2); // Username/Password + } + DirectSend(request.Data(), request.Length()); + state_ = SS_HELLO; +} + +void AsyncSocksProxySocket::SendAuth() { + ByteBufferWriterT<ZeroOnFreeBuffer<char>> request; + request.WriteUInt8(1); // Negotiation Version + request.WriteUInt8(static_cast<uint8_t>(user_.size())); + request.WriteString(user_); // Username + request.WriteUInt8(static_cast<uint8_t>(pass_.GetLength())); + size_t len = pass_.GetLength() + 1; + char* sensitive = new char[len]; + pass_.CopyTo(sensitive, true); + request.WriteBytes(sensitive, pass_.GetLength()); // Password + ExplicitZeroMemory(sensitive, len); + delete[] sensitive; + DirectSend(request.Data(), request.Length()); + state_ = SS_AUTH; +} + +void AsyncSocksProxySocket::SendConnect() { + ByteBufferWriter request; + request.WriteUInt8(5); // Socks Version + request.WriteUInt8(1); // CONNECT + request.WriteUInt8(0); // Reserved + if (dest_.IsUnresolvedIP()) { + std::string hostname = dest_.hostname(); + request.WriteUInt8(3); // DOMAINNAME + request.WriteUInt8(static_cast<uint8_t>(hostname.size())); + request.WriteString(hostname); // Destination Hostname + } else { + request.WriteUInt8(1); // IPV4 + request.WriteUInt32(dest_.ip()); // Destination IP + } + request.WriteUInt16(dest_.port()); // Destination Port + DirectSend(request.Data(), request.Length()); + state_ = SS_CONNECT; +} + +void AsyncSocksProxySocket::Error(int error) { + state_ = SS_ERROR; + BufferInput(false); + Close(); + SetError(SOCKET_EACCES); + SignalCloseEvent(this, error); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/socket_adapters.h b/third_party/libwebrtc/rtc_base/socket_adapters.h new file mode 100644 index 0000000000..e78ee18a27 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/socket_adapters.h @@ -0,0 +1,178 @@ +/* + * 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 RTC_BASE_SOCKET_ADAPTERS_H_ +#define RTC_BASE_SOCKET_ADAPTERS_H_ + +#include <string> + +#include "absl/strings/string_view.h" +#include "api/array_view.h" +#include "rtc_base/async_socket.h" +#include "rtc_base/crypt_string.h" + +namespace rtc { + +struct HttpAuthContext; +class ByteBufferReader; +class ByteBufferWriter; + +/////////////////////////////////////////////////////////////////////////////// + +// Implements a socket adapter that can buffer and process data internally, +// as in the case of connecting to a proxy, where you must speak the proxy +// protocol before commencing normal socket behavior. +class BufferedReadAdapter : public AsyncSocketAdapter { + public: + BufferedReadAdapter(Socket* socket, size_t buffer_size); + ~BufferedReadAdapter() override; + + BufferedReadAdapter(const BufferedReadAdapter&) = delete; + BufferedReadAdapter& operator=(const BufferedReadAdapter&) = delete; + + int Send(const void* pv, size_t cb) override; + int Recv(void* pv, size_t cb, int64_t* timestamp) override; + + protected: + int DirectSend(const void* pv, size_t cb) { + return AsyncSocketAdapter::Send(pv, cb); + } + + void BufferInput(bool on = true); + virtual void ProcessInput(char* data, size_t* len) = 0; + + void OnReadEvent(Socket* socket) override; + + private: + char* buffer_; + size_t buffer_size_, data_len_; + bool buffering_; +}; + +/////////////////////////////////////////////////////////////////////////////// + +// Implements a socket adapter that performs the client side of a +// fake SSL handshake. Used for "ssltcp" P2P functionality. +class AsyncSSLSocket : public BufferedReadAdapter { + public: + static ArrayView<const uint8_t> SslClientHello(); + static ArrayView<const uint8_t> SslServerHello(); + + explicit AsyncSSLSocket(Socket* socket); + + AsyncSSLSocket(const AsyncSSLSocket&) = delete; + AsyncSSLSocket& operator=(const AsyncSSLSocket&) = delete; + + int Connect(const SocketAddress& addr) override; + + protected: + void OnConnectEvent(Socket* socket) override; + void ProcessInput(char* data, size_t* len) override; +}; + +/////////////////////////////////////////////////////////////////////////////// + +// Implements a socket adapter that speaks the HTTP/S proxy protocol. +class AsyncHttpsProxySocket : public BufferedReadAdapter { + public: + AsyncHttpsProxySocket(Socket* socket, + absl::string_view user_agent, + const SocketAddress& proxy, + absl::string_view username, + const CryptString& password); + ~AsyncHttpsProxySocket() override; + + AsyncHttpsProxySocket(const AsyncHttpsProxySocket&) = delete; + AsyncHttpsProxySocket& operator=(const AsyncHttpsProxySocket&) = delete; + + // If connect is forced, the adapter will always issue an HTTP CONNECT to the + // target address. Otherwise, it will connect only if the destination port + // is not port 80. + void SetForceConnect(bool force) { force_connect_ = force; } + + int Connect(const SocketAddress& addr) override; + SocketAddress GetRemoteAddress() const override; + int Close() override; + ConnState GetState() const override; + + protected: + void OnConnectEvent(Socket* socket) override; + void OnCloseEvent(Socket* socket, int err) override; + void ProcessInput(char* data, size_t* len) override; + + bool ShouldIssueConnect() const; + void SendRequest(); + void ProcessLine(char* data, size_t len); + void EndResponse(); + void Error(int error); + + private: + SocketAddress proxy_, dest_; + std::string agent_, user_, headers_; + CryptString pass_; + bool force_connect_; + size_t content_length_; + int defer_error_; + bool expect_close_; + enum ProxyState { + PS_INIT, + PS_LEADER, + PS_AUTHENTICATE, + PS_SKIP_HEADERS, + PS_ERROR_HEADERS, + PS_TUNNEL_HEADERS, + PS_SKIP_BODY, + PS_TUNNEL, + PS_WAIT_CLOSE, + PS_ERROR + } state_; + HttpAuthContext* context_; + std::string unknown_mechanisms_; +}; + +/////////////////////////////////////////////////////////////////////////////// + +// Implements a socket adapter that speaks the SOCKS proxy protocol. +class AsyncSocksProxySocket : public BufferedReadAdapter { + public: + AsyncSocksProxySocket(Socket* socket, + const SocketAddress& proxy, + absl::string_view username, + const CryptString& password); + ~AsyncSocksProxySocket() override; + + AsyncSocksProxySocket(const AsyncSocksProxySocket&) = delete; + AsyncSocksProxySocket& operator=(const AsyncSocksProxySocket&) = delete; + + int Connect(const SocketAddress& addr) override; + SocketAddress GetRemoteAddress() const override; + int Close() override; + ConnState GetState() const override; + + protected: + void OnConnectEvent(Socket* socket) override; + void ProcessInput(char* data, size_t* len) override; + + void SendHello(); + void SendConnect(); + void SendAuth(); + void Error(int error); + + private: + enum State { SS_INIT, SS_HELLO, SS_AUTH, SS_CONNECT, SS_TUNNEL, SS_ERROR }; + State state_; + SocketAddress proxy_, dest_; + std::string user_; + CryptString pass_; +}; + +} // namespace rtc + +#endif // RTC_BASE_SOCKET_ADAPTERS_H_ diff --git a/third_party/libwebrtc/rtc_base/socket_address.cc b/third_party/libwebrtc/rtc_base/socket_address.cc new file mode 100644 index 0000000000..8601fc9040 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/socket_address.cc @@ -0,0 +1,354 @@ +/* + * 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 "rtc_base/socket_address.h" + +#include "absl/strings/string_view.h" +#include "rtc_base/numerics/safe_conversions.h" + +#if defined(WEBRTC_POSIX) +#include <netinet/in.h> +#include <sys/socket.h> +#include <sys/types.h> +#if defined(OPENBSD) +#include <netinet/in_systm.h> +#endif +#if !defined(__native_client__) +#include <netinet/ip.h> +#endif +#include <arpa/inet.h> +#include <netdb.h> +#include <unistd.h> +#endif + +#include "rtc_base/byte_order.h" +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" +#include "rtc_base/net_helpers.h" +#include "rtc_base/strings/string_builder.h" + +#if defined(WEBRTC_WIN) +#include "rtc_base/win32.h" +#endif + +namespace rtc { + +SocketAddress::SocketAddress() { + Clear(); +} + +SocketAddress::SocketAddress(absl::string_view hostname, int port) { + SetIP(hostname); + SetPort(port); +} + +SocketAddress::SocketAddress(uint32_t ip_as_host_order_integer, int port) { + SetIP(IPAddress(ip_as_host_order_integer)); + SetPort(port); +} + +SocketAddress::SocketAddress(const IPAddress& ip, int port) { + SetIP(ip); + SetPort(port); +} + +SocketAddress::SocketAddress(const SocketAddress& addr) { + this->operator=(addr); +} + +void SocketAddress::Clear() { + hostname_.clear(); + literal_ = false; + ip_ = IPAddress(); + port_ = 0; + scope_id_ = 0; +} + +bool SocketAddress::IsNil() const { + return hostname_.empty() && IPIsUnspec(ip_) && 0 == port_; +} + +bool SocketAddress::IsComplete() const { + return (!IPIsAny(ip_)) && (0 != port_); +} + +SocketAddress& SocketAddress::operator=(const SocketAddress& addr) { + hostname_ = addr.hostname_; + ip_ = addr.ip_; + port_ = addr.port_; + literal_ = addr.literal_; + scope_id_ = addr.scope_id_; + return *this; +} + +void SocketAddress::SetIP(uint32_t ip_as_host_order_integer) { + hostname_.clear(); + literal_ = false; + ip_ = IPAddress(ip_as_host_order_integer); + scope_id_ = 0; +} + +void SocketAddress::SetIP(const IPAddress& ip) { + hostname_.clear(); + literal_ = false; + ip_ = ip; + scope_id_ = 0; +} + +void SocketAddress::SetIP(absl::string_view hostname) { + hostname_ = std::string(hostname); + literal_ = IPFromString(hostname, &ip_); + if (!literal_) { + ip_ = IPAddress(); + } + scope_id_ = 0; +} + +void SocketAddress::SetResolvedIP(uint32_t ip_as_host_order_integer) { + ip_ = IPAddress(ip_as_host_order_integer); + scope_id_ = 0; +} + +void SocketAddress::SetResolvedIP(const IPAddress& ip) { + ip_ = ip; + scope_id_ = 0; +} + +void SocketAddress::SetPort(int port) { + port_ = rtc::dchecked_cast<uint16_t>(port); +} + +uint32_t SocketAddress::ip() const { + return ip_.v4AddressAsHostOrderInteger(); +} + +const IPAddress& SocketAddress::ipaddr() const { + return ip_; +} + +uint16_t SocketAddress::port() const { + return port_; +} + +std::string SocketAddress::HostAsURIString() const { + // If the hostname was a literal IP string, it may need to have square + // brackets added (for SocketAddress::ToString()). + if (!literal_ && !hostname_.empty()) + return hostname_; + if (ip_.family() == AF_INET6) { + return "[" + ip_.ToString() + "]"; + } else { + return ip_.ToString(); + } +} + +std::string SocketAddress::HostAsSensitiveURIString() const { + // If the hostname was a literal IP string, it may need to have square + // brackets added (for SocketAddress::ToString()). + if (!literal_ && !hostname_.empty()) + return hostname_; + if (ip_.family() == AF_INET6) { + return "[" + ip_.ToSensitiveString() + "]"; + } else { + return ip_.ToSensitiveString(); + } +} + +std::string SocketAddress::PortAsString() const { + return std::to_string(port_); +} + +std::string SocketAddress::ToString() const { + char buf[1024]; + rtc::SimpleStringBuilder sb(buf); + sb << HostAsURIString() << ":" << port(); + return sb.str(); +} + +std::string SocketAddress::ToSensitiveString() const { + char buf[1024]; + rtc::SimpleStringBuilder sb(buf); + sb << HostAsSensitiveURIString() << ":" << port(); + return sb.str(); +} + +std::string SocketAddress::ToSensitiveNameAndAddressString() const { + if (IsUnresolvedIP() || literal_ || hostname_.empty()) { + return ToSensitiveString(); + } + char buf[1024]; + rtc::SimpleStringBuilder sb(buf); + sb << HostAsSensitiveURIString() << ":" << port(); + sb << " ("; + if (ip_.family() == AF_INET6) { + sb << "[" << ipaddr().ToSensitiveString() << "]"; + } else { + sb << ipaddr().ToSensitiveString(); + } + sb << ":" << port() << ")"; + + return sb.str(); +} + +bool SocketAddress::FromString(absl::string_view str) { + if (str.at(0) == '[') { + absl::string_view::size_type closebracket = str.rfind(']'); + if (closebracket != absl::string_view::npos) { + absl::string_view::size_type colon = str.find(':', closebracket); + if (colon != absl::string_view::npos && colon > closebracket) { + SetPort( + strtoul(std::string(str.substr(colon + 1)).c_str(), nullptr, 10)); + SetIP(str.substr(1, closebracket - 1)); + } else { + return false; + } + } + } else { + absl::string_view::size_type pos = str.find(':'); + if (absl::string_view::npos == pos) + return false; + SetPort(strtoul(std::string(str.substr(pos + 1)).c_str(), nullptr, 10)); + SetIP(str.substr(0, pos)); + } + return true; +} + +bool SocketAddress::IsAnyIP() const { + return IPIsAny(ip_); +} + +bool SocketAddress::IsLoopbackIP() const { + return IPIsLoopback(ip_) || + (IPIsAny(ip_) && 0 == strcmp(hostname_.c_str(), "localhost")); +} + +bool SocketAddress::IsPrivateIP() const { + return IPIsPrivate(ip_); +} + +bool SocketAddress::IsUnresolvedIP() const { + return IPIsUnspec(ip_) && !literal_ && !hostname_.empty(); +} + +bool SocketAddress::operator==(const SocketAddress& addr) const { + return EqualIPs(addr) && EqualPorts(addr); +} + +bool SocketAddress::operator<(const SocketAddress& addr) const { + if (ip_ != addr.ip_) + return ip_ < addr.ip_; + + // We only check hostnames if both IPs are ANY or unspecified. This matches + // EqualIPs(). + if ((IPIsAny(ip_) || IPIsUnspec(ip_)) && hostname_ != addr.hostname_) + return hostname_ < addr.hostname_; + + return port_ < addr.port_; +} + +bool SocketAddress::EqualIPs(const SocketAddress& addr) const { + return (ip_ == addr.ip_) && + ((!IPIsAny(ip_) && !IPIsUnspec(ip_)) || (hostname_ == addr.hostname_)); +} + +bool SocketAddress::EqualPorts(const SocketAddress& addr) const { + return (port_ == addr.port_); +} + +size_t SocketAddress::Hash() const { + size_t h = 0; + h ^= HashIP(ip_); + h ^= port_ | (port_ << 16); + return h; +} + +void SocketAddress::ToSockAddr(sockaddr_in* saddr) const { + memset(saddr, 0, sizeof(*saddr)); + if (ip_.family() != AF_INET) { + saddr->sin_family = AF_UNSPEC; + return; + } + saddr->sin_family = AF_INET; + saddr->sin_port = HostToNetwork16(port_); + if (IPIsAny(ip_)) { + saddr->sin_addr.s_addr = INADDR_ANY; + } else { + saddr->sin_addr = ip_.ipv4_address(); + } +} + +bool SocketAddress::FromSockAddr(const sockaddr_in& saddr) { + if (saddr.sin_family != AF_INET) + return false; + SetIP(NetworkToHost32(saddr.sin_addr.s_addr)); + SetPort(NetworkToHost16(saddr.sin_port)); + literal_ = false; + return true; +} + +static size_t ToSockAddrStorageHelper(sockaddr_storage* addr, + const IPAddress& ip, + uint16_t port, + int scope_id) { + memset(addr, 0, sizeof(sockaddr_storage)); + addr->ss_family = static_cast<unsigned short>(ip.family()); + if (addr->ss_family == AF_INET6) { + sockaddr_in6* saddr = reinterpret_cast<sockaddr_in6*>(addr); + saddr->sin6_addr = ip.ipv6_address(); + saddr->sin6_port = HostToNetwork16(port); + saddr->sin6_scope_id = scope_id; + return sizeof(sockaddr_in6); + } else if (addr->ss_family == AF_INET) { + sockaddr_in* saddr = reinterpret_cast<sockaddr_in*>(addr); + saddr->sin_addr = ip.ipv4_address(); + saddr->sin_port = HostToNetwork16(port); + return sizeof(sockaddr_in); + } + return 0; +} + +size_t SocketAddress::ToDualStackSockAddrStorage(sockaddr_storage* addr) const { + return ToSockAddrStorageHelper(addr, ip_.AsIPv6Address(), port_, scope_id_); +} + +size_t SocketAddress::ToSockAddrStorage(sockaddr_storage* addr) const { + return ToSockAddrStorageHelper(addr, ip_, port_, scope_id_); +} + +bool SocketAddressFromSockAddrStorage(const sockaddr_storage& addr, + SocketAddress* out) { + if (!out) { + return false; + } + if (addr.ss_family == AF_INET) { + const sockaddr_in* saddr = reinterpret_cast<const sockaddr_in*>(&addr); + *out = SocketAddress(IPAddress(saddr->sin_addr), + NetworkToHost16(saddr->sin_port)); + return true; + } else if (addr.ss_family == AF_INET6) { + const sockaddr_in6* saddr = reinterpret_cast<const sockaddr_in6*>(&addr); + *out = SocketAddress(IPAddress(saddr->sin6_addr), + NetworkToHost16(saddr->sin6_port)); + out->SetScopeID(saddr->sin6_scope_id); + return true; + } + return false; +} + +SocketAddress EmptySocketAddressWithFamily(int family) { + if (family == AF_INET) { + return SocketAddress(IPAddress(INADDR_ANY), 0); + } else if (family == AF_INET6) { + return SocketAddress(IPAddress(in6addr_any), 0); + } + return SocketAddress(); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/socket_address.h b/third_party/libwebrtc/rtc_base/socket_address.h new file mode 100644 index 0000000000..b58a6db3b7 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/socket_address.h @@ -0,0 +1,209 @@ +/* + * 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 RTC_BASE_SOCKET_ADDRESS_H_ +#define RTC_BASE_SOCKET_ADDRESS_H_ + +#include <string> + +#include "absl/strings/string_view.h" +#ifdef WEBRTC_UNIT_TEST +#include <ostream> // no-presubmit-check TODO(webrtc:8982) +#endif // WEBRTC_UNIT_TEST +#include "rtc_base/ip_address.h" +#include "rtc_base/system/rtc_export.h" + +#undef SetPort + +struct sockaddr_in; +struct sockaddr_storage; + +namespace rtc { + +// Records an IP address and port. +class RTC_EXPORT SocketAddress { + public: + // Creates a nil address. + SocketAddress(); + + // Creates the address with the given host and port. Host may be a + // literal IP string or a hostname to be resolved later. + // DCHECKs that port is in valid range (0 to 2^16-1). + SocketAddress(absl::string_view hostname, int port); + + // Creates the address with the given IP and port. + // IP is given as an integer in host byte order. V4 only, to be deprecated. + // DCHECKs that port is in valid range (0 to 2^16-1). + SocketAddress(uint32_t ip_as_host_order_integer, int port); + + // Creates the address with the given IP and port. + // DCHECKs that port is in valid range (0 to 2^16-1). + SocketAddress(const IPAddress& ip, int port); + + // Creates a copy of the given address. + SocketAddress(const SocketAddress& addr); + + // Resets to the nil address. + void Clear(); + + // Determines if this is a nil address (empty hostname, any IP, null port) + bool IsNil() const; + + // Returns true if ip and port are set. + bool IsComplete() const; + + // Replaces our address with the given one. + SocketAddress& operator=(const SocketAddress& addr); + + // Changes the IP of this address to the given one, and clears the hostname + // IP is given as an integer in host byte order. V4 only, to be deprecated.. + void SetIP(uint32_t ip_as_host_order_integer); + + // Changes the IP of this address to the given one, and clears the hostname. + void SetIP(const IPAddress& ip); + + // Changes the hostname of this address to the given one. + // Does not resolve the address; use Resolve to do so. + void SetIP(absl::string_view hostname); + + // Sets the IP address while retaining the hostname. Useful for bypassing + // DNS for a pre-resolved IP. + // IP is given as an integer in host byte order. V4 only, to be deprecated. + void SetResolvedIP(uint32_t ip_as_host_order_integer); + + // Sets the IP address while retaining the hostname. Useful for bypassing + // DNS for a pre-resolved IP. + void SetResolvedIP(const IPAddress& ip); + + // Changes the port of this address to the given one. + // DCHECKs that port is in valid range (0 to 2^16-1). + void SetPort(int port); + + // Returns the hostname. + const std::string& hostname() const { return hostname_; } + + // Returns the IP address as a host byte order integer. + // Returns 0 for non-v4 addresses. + uint32_t ip() const; + + const IPAddress& ipaddr() const; + + int family() const { return ip_.family(); } + + // Returns the port part of this address. + uint16_t port() const; + + // Returns the scope ID associated with this address. Scope IDs are a + // necessary addition to IPv6 link-local addresses, with different network + // interfaces having different scope-ids for their link-local addresses. + // IPv4 address do not have scope_ids and sockaddr_in structures do not have + // a field for them. + int scope_id() const { return scope_id_; } + void SetScopeID(int id) { scope_id_ = id; } + + // Returns the 'host' portion of the address (hostname or IP) in a form + // suitable for use in a URI. If both IP and hostname are present, hostname + // is preferred. IPv6 addresses are enclosed in square brackets ('[' and ']'). + std::string HostAsURIString() const; + + // Same as HostAsURIString but anonymizes IP addresses by hiding the last + // part. + std::string HostAsSensitiveURIString() const; + + // Returns the port as a string. + std::string PortAsString() const; + + // Returns hostname:port or [hostname]:port. + std::string ToString() const; + + // Same as ToString but anonymizes it by hiding the last part. + std::string ToSensitiveString() const; + + // Returns sensitive description of address in a form which both includes + // resolved and unresolved addresses based on their availability. + std::string ToSensitiveNameAndAddressString() const; + + // Parses hostname:port and [hostname]:port. + bool FromString(absl::string_view str); + +#ifdef WEBRTC_UNIT_TEST + inline std::ostream& operator<<( // no-presubmit-check TODO(webrtc:8982) + std::ostream& os) { // no-presubmit-check TODO(webrtc:8982) + return os << HostAsURIString() << ":" << port(); + } +#endif // WEBRTC_UNIT_TEST + + // Determines whether this represents a missing / any IP address. + // That is, 0.0.0.0 or ::. + // Hostname and/or port may be set. + bool IsAnyIP() const; + + // Determines whether the IP address refers to a loopback address. + // For v4 addresses this means the address is in the range 127.0.0.0/8. + // For v6 addresses this means the address is ::1. + bool IsLoopbackIP() const; + + // Determines whether the IP address is in one of the private ranges: + // For v4: 127.0.0.0/8 10.0.0.0/8 192.168.0.0/16 172.16.0.0/12. + // For v6: FE80::/16 and ::1. + bool IsPrivateIP() const; + + // Determines whether the hostname has been resolved to an IP. + bool IsUnresolvedIP() const; + + // Determines whether this address is identical to the given one. + bool operator==(const SocketAddress& addr) const; + inline bool operator!=(const SocketAddress& addr) const { + return !this->operator==(addr); + } + + // Compares based on IP and then port. + bool operator<(const SocketAddress& addr) const; + + // Determines whether this address has the same IP as the one given. + bool EqualIPs(const SocketAddress& addr) const; + + // Determines whether this address has the same port as the one given. + bool EqualPorts(const SocketAddress& addr) const; + + // Hashes this address into a small number. + size_t Hash() const; + + // Write this address to a sockaddr_in. + // If IPv6, will zero out the sockaddr_in and sets family to AF_UNSPEC. + void ToSockAddr(sockaddr_in* saddr) const; + + // Read this address from a sockaddr_in. + bool FromSockAddr(const sockaddr_in& saddr); + + // Read and write the address to/from a sockaddr_storage. + // Dual stack version always sets family to AF_INET6, and maps v4 addresses. + // The other version doesn't map, and outputs an AF_INET address for + // v4 or mapped addresses, and AF_INET6 addresses for others. + // Returns the size of the sockaddr_in or sockaddr_in6 structure that is + // written to the sockaddr_storage, or zero on failure. + size_t ToDualStackSockAddrStorage(sockaddr_storage* saddr) const; + size_t ToSockAddrStorage(sockaddr_storage* saddr) const; + + private: + std::string hostname_; + IPAddress ip_; + uint16_t port_; + int scope_id_; + bool literal_; // Indicates that 'hostname_' contains a literal IP string. +}; + +RTC_EXPORT bool SocketAddressFromSockAddrStorage(const sockaddr_storage& saddr, + SocketAddress* out); +SocketAddress EmptySocketAddressWithFamily(int family); + +} // namespace rtc + +#endif // RTC_BASE_SOCKET_ADDRESS_H_ diff --git a/third_party/libwebrtc/rtc_base/socket_address_gn/moz.build b/third_party/libwebrtc/rtc_base/socket_address_gn/moz.build new file mode 100644 index 0000000000..86ef2dc1a7 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/socket_address_gn/moz.build @@ -0,0 +1,233 @@ +# 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/rtc_base/socket_address.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_ENABLE_LIBEVENT"] = 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 += [ + "GLESv2", + "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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("socket_address_gn") diff --git a/third_party/libwebrtc/rtc_base/socket_address_pair.cc b/third_party/libwebrtc/rtc_base/socket_address_pair.cc new file mode 100644 index 0000000000..54f70ff17a --- /dev/null +++ b/third_party/libwebrtc/rtc_base/socket_address_pair.cc @@ -0,0 +1,39 @@ +/* + * 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 "rtc_base/socket_address_pair.h" + +namespace rtc { + +SocketAddressPair::SocketAddressPair(const SocketAddress& src, + const SocketAddress& dest) + : src_(src), dest_(dest) {} + +bool SocketAddressPair::operator==(const SocketAddressPair& p) const { + return (src_ == p.src_) && (dest_ == p.dest_); +} + +bool SocketAddressPair::operator<(const SocketAddressPair& p) const { + if (src_ < p.src_) + return true; + if (p.src_ < src_) + return false; + if (dest_ < p.dest_) + return true; + if (p.dest_ < dest_) + return false; + return false; +} + +size_t SocketAddressPair::Hash() const { + return src_.Hash() ^ dest_.Hash(); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/socket_address_pair.h b/third_party/libwebrtc/rtc_base/socket_address_pair.h new file mode 100644 index 0000000000..f315e6460a --- /dev/null +++ b/third_party/libwebrtc/rtc_base/socket_address_pair.h @@ -0,0 +1,43 @@ +/* + * 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 RTC_BASE_SOCKET_ADDRESS_PAIR_H_ +#define RTC_BASE_SOCKET_ADDRESS_PAIR_H_ + +#include <stddef.h> + +#include "rtc_base/socket_address.h" + +namespace rtc { + +// Records a pair (source,destination) of socket addresses. The two addresses +// identify a connection between two machines. (For UDP, this "connection" is +// not maintained explicitly in a socket.) +class SocketAddressPair { + public: + SocketAddressPair() {} + SocketAddressPair(const SocketAddress& srs, const SocketAddress& dest); + + const SocketAddress& source() const { return src_; } + const SocketAddress& destination() const { return dest_; } + + bool operator==(const SocketAddressPair& r) const; + bool operator<(const SocketAddressPair& r) const; + + size_t Hash() const; + + private: + SocketAddress src_; + SocketAddress dest_; +}; + +} // namespace rtc + +#endif // RTC_BASE_SOCKET_ADDRESS_PAIR_H_ diff --git a/third_party/libwebrtc/rtc_base/socket_address_unittest.cc b/third_party/libwebrtc/rtc_base/socket_address_unittest.cc new file mode 100644 index 0000000000..f10e43f148 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/socket_address_unittest.cc @@ -0,0 +1,366 @@ +/* + * 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. + */ + +#if defined(WEBRTC_POSIX) +#include <netinet/in.h> // for sockaddr_in +#endif + +#include <string.h> + +#include "rtc_base/ip_address.h" +#include "rtc_base/socket_address.h" +#include "test/gtest.h" + +namespace rtc { + +const in6_addr kTestV6Addr = { + {{0x20, 0x01, 0x0d, 0xb8, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, + 0x90, 0xA0, 0xB0, 0xC0}}}; +const in6_addr kMappedV4Addr = { + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, + 0x01, 0x02, 0x03, 0x04}}}; +const std::string kTestV6AddrString = "2001:db8:1020:3040:5060:7080:90a0:b0c0"; +const std::string kTestV6AddrAnonymizedString = "2001:db8:1020:x:x:x:x:x"; +const std::string kTestV6AddrFullString = + "[2001:db8:1020:3040:5060:7080:90a0:b0c0]:5678"; +const std::string kTestV6AddrFullAnonymizedString = + "[2001:db8:1020:x:x:x:x:x]:5678"; + +TEST(SocketAddressTest, TestDefaultCtor) { + SocketAddress addr; + EXPECT_FALSE(addr.IsUnresolvedIP()); + EXPECT_EQ(IPAddress(), addr.ipaddr()); + EXPECT_EQ(0, addr.port()); + EXPECT_EQ("", addr.hostname()); +} + +TEST(SocketAddressTest, TestIPPortCtor) { + SocketAddress addr(IPAddress(0x01020304), 5678); + EXPECT_FALSE(addr.IsUnresolvedIP()); + EXPECT_EQ(IPAddress(0x01020304U), addr.ipaddr()); + EXPECT_EQ(5678, addr.port()); + EXPECT_EQ("", addr.hostname()); + EXPECT_EQ("1.2.3.4:5678", addr.ToString()); +} + +TEST(SocketAddressTest, TestIPv4StringPortCtor) { + SocketAddress addr("1.2.3.4", 5678); + EXPECT_FALSE(addr.IsUnresolvedIP()); + EXPECT_EQ(IPAddress(0x01020304U), addr.ipaddr()); + EXPECT_EQ(5678, addr.port()); + EXPECT_EQ("1.2.3.4", addr.hostname()); + EXPECT_EQ("1.2.3.4:5678", addr.ToString()); +} + +TEST(SocketAddressTest, TestIPv6StringPortCtor) { + SocketAddress addr2(kTestV6AddrString, 1234); + IPAddress tocheck(kTestV6Addr); + + EXPECT_FALSE(addr2.IsUnresolvedIP()); + EXPECT_EQ(tocheck, addr2.ipaddr()); + EXPECT_EQ(1234, addr2.port()); + EXPECT_EQ(kTestV6AddrString, addr2.hostname()); + EXPECT_EQ("[" + kTestV6AddrString + "]:1234", addr2.ToString()); +} + +TEST(SocketAddressTest, TestSpecialStringPortCtor) { + // inet_addr doesn't handle this address properly. + SocketAddress addr("255.255.255.255", 5678); + EXPECT_FALSE(addr.IsUnresolvedIP()); + EXPECT_EQ(IPAddress(0xFFFFFFFFU), addr.ipaddr()); + EXPECT_EQ(5678, addr.port()); + EXPECT_EQ("255.255.255.255", addr.hostname()); + EXPECT_EQ("255.255.255.255:5678", addr.ToString()); +} + +TEST(SocketAddressTest, TestHostnamePortCtor) { + SocketAddress addr("a.b.com", 5678); + EXPECT_TRUE(addr.IsUnresolvedIP()); + EXPECT_EQ(IPAddress(), addr.ipaddr()); + EXPECT_EQ(5678, addr.port()); + EXPECT_EQ("a.b.com", addr.hostname()); + EXPECT_EQ("a.b.com:5678", addr.ToString()); +} + +TEST(SocketAddressTest, TestCopyCtor) { + SocketAddress from("1.2.3.4", 5678); + SocketAddress addr(from); + EXPECT_FALSE(addr.IsUnresolvedIP()); + EXPECT_EQ(IPAddress(0x01020304U), addr.ipaddr()); + EXPECT_EQ(5678, addr.port()); + EXPECT_EQ("1.2.3.4", addr.hostname()); + EXPECT_EQ("1.2.3.4:5678", addr.ToString()); +} + +TEST(SocketAddressTest, TestAssign) { + SocketAddress from("1.2.3.4", 5678); + SocketAddress addr(IPAddress(0x88888888), 9999); + addr = from; + EXPECT_FALSE(addr.IsUnresolvedIP()); + EXPECT_EQ(IPAddress(0x01020304U), addr.ipaddr()); + EXPECT_EQ(5678, addr.port()); + EXPECT_EQ("1.2.3.4", addr.hostname()); + EXPECT_EQ("1.2.3.4:5678", addr.ToString()); +} + +TEST(SocketAddressTest, TestSetIPPort) { + SocketAddress addr(IPAddress(0x88888888), 9999); + addr.SetIP(IPAddress(0x01020304)); + addr.SetPort(5678); + EXPECT_FALSE(addr.IsUnresolvedIP()); + EXPECT_EQ(IPAddress(0x01020304U), addr.ipaddr()); + EXPECT_EQ(5678, addr.port()); + EXPECT_EQ("", addr.hostname()); + EXPECT_EQ("1.2.3.4:5678", addr.ToString()); +} + +TEST(SocketAddressTest, TestSetIPFromString) { + SocketAddress addr(IPAddress(0x88888888), 9999); + addr.SetIP("1.2.3.4"); + addr.SetPort(5678); + EXPECT_FALSE(addr.IsUnresolvedIP()); + EXPECT_EQ(IPAddress(0x01020304U), addr.ipaddr()); + EXPECT_EQ(5678, addr.port()); + EXPECT_EQ("1.2.3.4", addr.hostname()); + EXPECT_EQ("1.2.3.4:5678", addr.ToString()); +} + +TEST(SocketAddressTest, TestSetIPFromHostname) { + SocketAddress addr(IPAddress(0x88888888), 9999); + addr.SetIP("a.b.com"); + addr.SetPort(5678); + EXPECT_TRUE(addr.IsUnresolvedIP()); + EXPECT_EQ(IPAddress(), addr.ipaddr()); + EXPECT_EQ(5678, addr.port()); + EXPECT_EQ("a.b.com", addr.hostname()); + EXPECT_EQ("a.b.com:5678", addr.ToString()); + addr.SetResolvedIP(IPAddress(0x01020304)); + EXPECT_FALSE(addr.IsUnresolvedIP()); + EXPECT_EQ(IPAddress(0x01020304U), addr.ipaddr()); + EXPECT_EQ("a.b.com", addr.hostname()); + EXPECT_EQ("a.b.com:5678", addr.ToString()); +} + +TEST(SocketAddressTest, TestFromIPv4String) { + SocketAddress addr; + EXPECT_TRUE(addr.FromString("1.2.3.4:5678")); + EXPECT_FALSE(addr.IsUnresolvedIP()); + EXPECT_EQ(IPAddress(0x01020304U), addr.ipaddr()); + EXPECT_EQ(5678, addr.port()); + EXPECT_EQ("1.2.3.4", addr.hostname()); + EXPECT_EQ("1.2.3.4:5678", addr.ToString()); +} + +TEST(SocketAddressTest, TestFromIPv6String) { + SocketAddress addr; + EXPECT_TRUE(addr.FromString(kTestV6AddrFullString)); + EXPECT_FALSE(addr.IsUnresolvedIP()); + EXPECT_EQ(5678, addr.port()); + EXPECT_EQ(kTestV6AddrString, addr.hostname()); + EXPECT_EQ(kTestV6AddrFullString, addr.ToString()); +} + +TEST(SocketAddressTest, TestFromHostname) { + SocketAddress addr; + EXPECT_TRUE(addr.FromString("a.b.com:5678")); + EXPECT_TRUE(addr.IsUnresolvedIP()); + EXPECT_EQ(IPAddress(), addr.ipaddr()); + EXPECT_EQ(5678, addr.port()); + EXPECT_EQ("a.b.com", addr.hostname()); + EXPECT_EQ("a.b.com:5678", addr.ToString()); +} + +TEST(SocketAddressTest, TestToFromSockAddr) { + SocketAddress from("1.2.3.4", 5678), addr; + sockaddr_in addr_in; + from.ToSockAddr(&addr_in); + EXPECT_TRUE(addr.FromSockAddr(addr_in)); + EXPECT_FALSE(addr.IsUnresolvedIP()); + EXPECT_EQ(IPAddress(0x01020304U), addr.ipaddr()); + EXPECT_EQ(5678, addr.port()); + EXPECT_EQ("", addr.hostname()); + EXPECT_EQ("1.2.3.4:5678", addr.ToString()); +} + +TEST(SocketAddressTest, TestToFromSockAddrStorage) { + SocketAddress from("1.2.3.4", 5678), addr; + sockaddr_storage addr_storage; + from.ToSockAddrStorage(&addr_storage); + EXPECT_TRUE(SocketAddressFromSockAddrStorage(addr_storage, &addr)); + EXPECT_FALSE(addr.IsUnresolvedIP()); + EXPECT_EQ(IPAddress(0x01020304U), addr.ipaddr()); + EXPECT_EQ(5678, addr.port()); + EXPECT_EQ("", addr.hostname()); + EXPECT_EQ("1.2.3.4:5678", addr.ToString()); + + addr.Clear(); + from.ToDualStackSockAddrStorage(&addr_storage); + EXPECT_TRUE(SocketAddressFromSockAddrStorage(addr_storage, &addr)); + EXPECT_FALSE(addr.IsUnresolvedIP()); + EXPECT_EQ(IPAddress(kMappedV4Addr), addr.ipaddr()); + EXPECT_EQ(5678, addr.port()); + EXPECT_EQ("", addr.hostname()); + EXPECT_EQ("[::ffff:1.2.3.4]:5678", addr.ToString()); + + addr.Clear(); + memset(&addr_storage, 0, sizeof(sockaddr_storage)); + from = SocketAddress(kTestV6AddrString, 5678); + from.SetScopeID(6); + from.ToSockAddrStorage(&addr_storage); + EXPECT_TRUE(SocketAddressFromSockAddrStorage(addr_storage, &addr)); + EXPECT_FALSE(addr.IsUnresolvedIP()); + EXPECT_EQ(IPAddress(kTestV6Addr), addr.ipaddr()); + EXPECT_EQ(5678, addr.port()); + EXPECT_EQ("", addr.hostname()); + EXPECT_EQ(kTestV6AddrFullString, addr.ToString()); + EXPECT_EQ(6, addr.scope_id()); + + addr.Clear(); + from.ToDualStackSockAddrStorage(&addr_storage); + EXPECT_TRUE(SocketAddressFromSockAddrStorage(addr_storage, &addr)); + EXPECT_FALSE(addr.IsUnresolvedIP()); + EXPECT_EQ(IPAddress(kTestV6Addr), addr.ipaddr()); + EXPECT_EQ(5678, addr.port()); + EXPECT_EQ("", addr.hostname()); + EXPECT_EQ(kTestV6AddrFullString, addr.ToString()); + EXPECT_EQ(6, addr.scope_id()); + + addr = from; + addr_storage.ss_family = AF_UNSPEC; + EXPECT_FALSE(SocketAddressFromSockAddrStorage(addr_storage, &addr)); + EXPECT_EQ(from, addr); + + EXPECT_FALSE(SocketAddressFromSockAddrStorage(addr_storage, nullptr)); +} + +bool AreEqual(const SocketAddress& addr1, const SocketAddress& addr2) { + return addr1 == addr2 && addr2 == addr1 && !(addr1 != addr2) && + !(addr2 != addr1); +} + +bool AreUnequal(const SocketAddress& addr1, const SocketAddress& addr2) { + return !(addr1 == addr2) && !(addr2 == addr1) && addr1 != addr2 && + addr2 != addr1; +} + +TEST(SocketAddressTest, TestEqualityOperators) { + SocketAddress addr1("1.2.3.4", 5678); + SocketAddress addr2("1.2.3.4", 5678); + EXPECT_TRUE(AreEqual(addr1, addr2)); + + addr2 = SocketAddress("0.0.0.1", 5678); + EXPECT_TRUE(AreUnequal(addr1, addr2)); + + addr2 = SocketAddress("1.2.3.4", 1234); + EXPECT_TRUE(AreUnequal(addr1, addr2)); + + addr2 = SocketAddress(kTestV6AddrString, 5678); + EXPECT_TRUE(AreUnequal(addr1, addr2)); + + addr1 = SocketAddress(kTestV6AddrString, 5678); + EXPECT_TRUE(AreEqual(addr1, addr2)); + + addr2 = SocketAddress(kTestV6AddrString, 1234); + EXPECT_TRUE(AreUnequal(addr1, addr2)); + + addr2 = SocketAddress("fe80::1", 5678); + EXPECT_TRUE(AreUnequal(addr1, addr2)); + + SocketAddress addr3("a.b.c.d", 1); + SocketAddress addr4("b.b.c.d", 1); + EXPECT_TRUE(AreUnequal(addr3, addr4)); + EXPECT_TRUE(AreEqual(addr3, addr3)); + + addr3.SetIP(addr1.ip()); + addr4.SetIP(addr1.ip()); + EXPECT_TRUE(AreEqual(addr3, addr4)); +} + +bool IsLessThan(const SocketAddress& addr1, const SocketAddress& addr2) { + return addr1 < addr2 && !(addr2 < addr1) && !(addr1 == addr2); +} + +TEST(SocketAddressTest, TestComparisonOperator) { + SocketAddress addr1("1.2.3.4", 5678); + SocketAddress addr2("1.2.3.4", 5678); + + EXPECT_FALSE(addr1 < addr2); + EXPECT_FALSE(addr2 < addr1); + + addr2 = SocketAddress("1.2.3.4", 5679); + EXPECT_TRUE(IsLessThan(addr1, addr2)); + + addr2 = SocketAddress("2.2.3.4", 49152); + EXPECT_TRUE(IsLessThan(addr1, addr2)); + + addr2 = SocketAddress(kTestV6AddrString, 5678); + EXPECT_TRUE(IsLessThan(addr1, addr2)); + + addr1 = SocketAddress("fe80::1", 5678); + EXPECT_TRUE(IsLessThan(addr2, addr1)); + + addr2 = SocketAddress("fe80::1", 5679); + EXPECT_TRUE(IsLessThan(addr1, addr2)); + + addr2 = SocketAddress("fe80::1", 5678); + EXPECT_FALSE(addr1 < addr2); + EXPECT_FALSE(addr2 < addr1); + + SocketAddress addr3("a.b.c.d", 1); + SocketAddress addr4("b.b.c.d", 1); + EXPECT_TRUE(IsLessThan(addr3, addr4)); +} + +TEST(SocketAddressTest, TestToSensitiveString) { + SocketAddress addr_v4("1.2.3.4", 5678); + EXPECT_EQ("1.2.3.4", addr_v4.HostAsURIString()); + EXPECT_EQ("1.2.3.4:5678", addr_v4.ToString()); + + EXPECT_EQ("1.2.3.x", addr_v4.HostAsSensitiveURIString()); + EXPECT_EQ("1.2.3.x:5678", addr_v4.ToSensitiveString()); + + SocketAddress addr_v6(kTestV6AddrString, 5678); + EXPECT_EQ("[" + kTestV6AddrString + "]", addr_v6.HostAsURIString()); + EXPECT_EQ(kTestV6AddrFullString, addr_v6.ToString()); + EXPECT_EQ("[" + kTestV6AddrAnonymizedString + "]", + addr_v6.HostAsSensitiveURIString()); + EXPECT_EQ(kTestV6AddrFullAnonymizedString, addr_v6.ToSensitiveString()); +} + +TEST(SocketAddressTest, TestToSensitiveNameAndAddressString) { + SocketAddress ipv4OnlyLiteral("1.2.3.4", 5678); + EXPECT_EQ("1.2.3.x:5678", ipv4OnlyLiteral.ToSensitiveNameAndAddressString()); + + SocketAddress ipv4OnlyAddress(IPAddress(0x01020304), 5678); + EXPECT_EQ("1.2.3.x:5678", ipv4OnlyAddress.ToSensitiveNameAndAddressString()); + + SocketAddress hostOnly("webrtc.org", 443); + EXPECT_EQ("webrtc.org:443", hostOnly.ToSensitiveNameAndAddressString()); + + SocketAddress hostAndIpv4("webrtc.org", 80); + hostAndIpv4.SetResolvedIP(IPAddress(0x01020304)); + EXPECT_EQ("webrtc.org:80 (1.2.3.x:80)", + hostAndIpv4.ToSensitiveNameAndAddressString()); + + SocketAddress ipv6OnlyLiteral(kTestV6AddrString, 5678); + EXPECT_EQ(kTestV6AddrFullAnonymizedString, + ipv6OnlyLiteral.ToSensitiveNameAndAddressString()); + + SocketAddress ipv6OnlyAddress(IPAddress(kTestV6Addr), 5678); + EXPECT_EQ(kTestV6AddrFullAnonymizedString, + ipv6OnlyAddress.ToSensitiveNameAndAddressString()); + + SocketAddress hostAndIpv6("webrtc.org", 5678); + hostAndIpv6.SetResolvedIP(IPAddress(kTestV6Addr)); + EXPECT_EQ("webrtc.org:5678 (" + kTestV6AddrFullAnonymizedString + ")", + hostAndIpv6.ToSensitiveNameAndAddressString()); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/socket_factory.h b/third_party/libwebrtc/rtc_base/socket_factory.h new file mode 100644 index 0000000000..882b44faf2 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/socket_factory.h @@ -0,0 +1,28 @@ +/* + * 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 RTC_BASE_SOCKET_FACTORY_H_ +#define RTC_BASE_SOCKET_FACTORY_H_ + +#include "rtc_base/socket.h" + +namespace rtc { + +class SocketFactory { + public: + virtual ~SocketFactory() {} + + // Returns a new socket. The type can be SOCK_DGRAM and SOCK_STREAM. + virtual Socket* CreateSocket(int family, int type) = 0; +}; + +} // namespace rtc + +#endif // RTC_BASE_SOCKET_FACTORY_H_ diff --git a/third_party/libwebrtc/rtc_base/socket_factory_gn/moz.build b/third_party/libwebrtc/rtc_base/socket_factory_gn/moz.build new file mode 100644 index 0000000000..3a2f72d1e6 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/socket_factory_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" +] + +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_ENABLE_LIBEVENT"] = 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 += [ + "GLESv2", + "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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("socket_factory_gn") diff --git a/third_party/libwebrtc/rtc_base/socket_gn/moz.build b/third_party/libwebrtc/rtc_base/socket_gn/moz.build new file mode 100644 index 0000000000..0d1760a15c --- /dev/null +++ b/third_party/libwebrtc/rtc_base/socket_gn/moz.build @@ -0,0 +1,233 @@ +# 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/rtc_base/socket.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_ENABLE_LIBEVENT"] = 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 += [ + "GLESv2", + "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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("socket_gn") diff --git a/third_party/libwebrtc/rtc_base/socket_server.h b/third_party/libwebrtc/rtc_base/socket_server.h new file mode 100644 index 0000000000..bf1326dad9 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/socket_server.h @@ -0,0 +1,67 @@ +/* + * 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 RTC_BASE_SOCKET_SERVER_H_ +#define RTC_BASE_SOCKET_SERVER_H_ + +#include <memory> + +#include "api/units/time_delta.h" +#include "rtc_base/event.h" +#include "rtc_base/socket_factory.h" + +namespace rtc { + +class Thread; +// Needs to be forward declared because there's a circular dependency between +// NetworkMonitor and Thread. +// TODO(deadbeef): Fix this. +class NetworkBinderInterface; + +// Provides the ability to wait for activity on a set of sockets. The Thread +// class provides a nice wrapper on a socket server. +// +// The server is also a socket factory. The sockets it creates will be +// notified of asynchronous I/O from this server's Wait method. +class SocketServer : public SocketFactory { + public: + static constexpr webrtc::TimeDelta kForever = rtc::Event::kForever; + + static std::unique_ptr<SocketServer> CreateDefault(); + // When the socket server is installed into a Thread, this function is called + // to allow the socket server to use the thread's message queue for any + // messaging that it might need to perform. It is also called with a null + // argument before the thread is destroyed. + virtual void SetMessageQueue(Thread* queue) {} + + // Sleeps until: + // 1) `max_wait_duration` has elapsed (unless `max_wait_duration` == + // `kForever`) + // 2) WakeUp() is called + // While sleeping, I/O is performed if process_io is true. + virtual bool Wait(webrtc::TimeDelta max_wait_duration, bool process_io) = 0; + + // Causes the current wait (if one is in progress) to wake up. + virtual void WakeUp() = 0; + + // A network binder will bind the created sockets to a network. + // It is only used in PhysicalSocketServer. + void set_network_binder(NetworkBinderInterface* binder) { + network_binder_ = binder; + } + NetworkBinderInterface* network_binder() const { return network_binder_; } + + private: + NetworkBinderInterface* network_binder_ = nullptr; +}; + +} // namespace rtc + +#endif // RTC_BASE_SOCKET_SERVER_H_ diff --git a/third_party/libwebrtc/rtc_base/socket_server_gn/moz.build b/third_party/libwebrtc/rtc_base/socket_server_gn/moz.build new file mode 100644 index 0000000000..48972cbb4c --- /dev/null +++ b/third_party/libwebrtc/rtc_base/socket_server_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" +] + +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_ENABLE_LIBEVENT"] = 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 += [ + "GLESv2", + "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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("socket_server_gn") diff --git a/third_party/libwebrtc/rtc_base/socket_stream.cc b/third_party/libwebrtc/rtc_base/socket_stream.cc new file mode 100644 index 0000000000..5c993ea233 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/socket_stream.cc @@ -0,0 +1,121 @@ +/* + * Copyright 2010 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 "rtc_base/socket_stream.h" + +#include "rtc_base/checks.h" +#include "rtc_base/socket.h" + +namespace rtc { + +SocketStream::SocketStream(Socket* socket) : socket_(nullptr) { + Attach(socket); +} + +SocketStream::~SocketStream() { + delete socket_; +} + +void SocketStream::Attach(Socket* socket) { + if (socket_) + delete socket_; + socket_ = socket; + if (socket_) { + socket_->SignalConnectEvent.connect(this, &SocketStream::OnConnectEvent); + socket_->SignalReadEvent.connect(this, &SocketStream::OnReadEvent); + socket_->SignalWriteEvent.connect(this, &SocketStream::OnWriteEvent); + socket_->SignalCloseEvent.connect(this, &SocketStream::OnCloseEvent); + } +} + +Socket* SocketStream::Detach() { + Socket* socket = socket_; + if (socket_) { + socket_->SignalConnectEvent.disconnect(this); + socket_->SignalReadEvent.disconnect(this); + socket_->SignalWriteEvent.disconnect(this); + socket_->SignalCloseEvent.disconnect(this); + socket_ = nullptr; + } + return socket; +} + +StreamState SocketStream::GetState() const { + RTC_DCHECK(socket_ != nullptr); + switch (socket_->GetState()) { + case Socket::CS_CONNECTED: + return SS_OPEN; + case Socket::CS_CONNECTING: + return SS_OPENING; + case Socket::CS_CLOSED: + default: + return SS_CLOSED; + } +} + +StreamResult SocketStream::Read(rtc::ArrayView<uint8_t> buffer, + size_t& read, + int& error) { + RTC_DCHECK(socket_ != nullptr); + int result = socket_->Recv(buffer.data(), buffer.size(), nullptr); + if (result < 0) { + if (socket_->IsBlocking()) + return SR_BLOCK; + error = socket_->GetError(); + return SR_ERROR; + } + if ((result > 0) || (buffer.size() == 0)) { + read = result; + return SR_SUCCESS; + } + return SR_EOS; +} + +StreamResult SocketStream::Write(rtc::ArrayView<const uint8_t> data, + size_t& written, + int& error) { + RTC_DCHECK(socket_ != nullptr); + int result = socket_->Send(data.data(), data.size()); + if (result < 0) { + if (socket_->IsBlocking()) + return SR_BLOCK; + error = socket_->GetError(); + return SR_ERROR; + } + written = result; + return SR_SUCCESS; +} + +void SocketStream::Close() { + RTC_DCHECK(socket_ != nullptr); + socket_->Close(); +} + +void SocketStream::OnConnectEvent(Socket* socket) { + RTC_DCHECK(socket == socket_); + SignalEvent(this, SE_OPEN | SE_READ | SE_WRITE, 0); +} + +void SocketStream::OnReadEvent(Socket* socket) { + RTC_DCHECK(socket == socket_); + SignalEvent(this, SE_READ, 0); +} + +void SocketStream::OnWriteEvent(Socket* socket) { + RTC_DCHECK(socket == socket_); + SignalEvent(this, SE_WRITE, 0); +} + +void SocketStream::OnCloseEvent(Socket* socket, int err) { + RTC_DCHECK(socket == socket_); + SignalEvent(this, SE_CLOSE, err); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/socket_stream.h b/third_party/libwebrtc/rtc_base/socket_stream.h new file mode 100644 index 0000000000..492cc42e96 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/socket_stream.h @@ -0,0 +1,62 @@ +/* + * Copyright 2005 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 RTC_BASE_SOCKET_STREAM_H_ +#define RTC_BASE_SOCKET_STREAM_H_ + +#include <stddef.h> + +#include "rtc_base/socket.h" +#include "rtc_base/stream.h" +#include "rtc_base/third_party/sigslot/sigslot.h" + +namespace rtc { + +/////////////////////////////////////////////////////////////////////////////// + +class SocketStream : public StreamInterface, public sigslot::has_slots<> { + public: + explicit SocketStream(Socket* socket); + ~SocketStream() override; + + SocketStream(const SocketStream&) = delete; + SocketStream& operator=(const SocketStream&) = delete; + + void Attach(Socket* socket); + Socket* Detach(); + + Socket* GetSocket() { return socket_; } + + StreamState GetState() const override; + + StreamResult Read(rtc::ArrayView<uint8_t> buffer, + size_t& read, + int& error) override; + + StreamResult Write(rtc::ArrayView<const uint8_t> data, + size_t& written, + int& error) override; + + void Close() override; + + private: + void OnConnectEvent(Socket* socket); + void OnReadEvent(Socket* socket); + void OnWriteEvent(Socket* socket); + void OnCloseEvent(Socket* socket, int err); + + Socket* socket_; +}; + +/////////////////////////////////////////////////////////////////////////////// + +} // namespace rtc + +#endif // RTC_BASE_SOCKET_STREAM_H_ diff --git a/third_party/libwebrtc/rtc_base/socket_unittest.cc b/third_party/libwebrtc/rtc_base/socket_unittest.cc new file mode 100644 index 0000000000..0a41a776ac --- /dev/null +++ b/third_party/libwebrtc/rtc_base/socket_unittest.cc @@ -0,0 +1,1144 @@ +/* + * Copyright 2007 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 "rtc_base/socket.h" + +#include <errno.h> +#include <stdint.h> +#include <string.h> + +#include <cstddef> +#include <cstdint> +#include <memory> + +#include "absl/memory/memory.h" +#include "absl/strings/string_view.h" +#include "rtc_base/arraysize.h" +#include "rtc_base/async_packet_socket.h" +#include "rtc_base/async_udp_socket.h" +#include "rtc_base/buffer.h" +#include "rtc_base/gunit.h" +#include "rtc_base/logging.h" +#include "rtc_base/net_helpers.h" +#include "rtc_base/net_test_helpers.h" +#include "rtc_base/socket_address.h" +#include "rtc_base/socket_server.h" +#include "rtc_base/socket_unittest.h" +#include "rtc_base/test_client.h" +#include "rtc_base/test_utils.h" +#include "rtc_base/third_party/sigslot/sigslot.h" +#include "rtc_base/thread.h" +#include "rtc_base/time_utils.h" + +namespace rtc { + +using webrtc::testing::SSE_CLOSE; +using webrtc::testing::SSE_ERROR; +using webrtc::testing::SSE_OPEN; +using webrtc::testing::SSE_READ; +using webrtc::testing::SSE_WRITE; +using webrtc::testing::StreamSink; + +#define MAYBE_SKIP_IPV6 \ + if (!HasIPv6Enabled()) { \ + RTC_LOG(LS_INFO) << "No IPv6... skipping"; \ + return; \ + } + +// Data size to be used in TcpInternal tests. +static const size_t kTcpInternalDataSize = 1024 * 1024; // bytes + +void SocketTest::TestConnectIPv4() { + ConnectInternal(kIPv4Loopback); +} + +void SocketTest::TestConnectIPv6() { + MAYBE_SKIP_IPV6; + ConnectInternal(kIPv6Loopback); +} + +void SocketTest::TestConnectWithDnsLookupIPv4() { + ConnectWithDnsLookupInternal(kIPv4Loopback, "localhost"); +} + +void SocketTest::TestConnectWithDnsLookupIPv6() { + // TODO: Enable this when DNS resolution supports IPv6. + RTC_LOG(LS_INFO) << "Skipping IPv6 DNS test"; + // ConnectWithDnsLookupInternal(kIPv6Loopback, "localhost6"); +} + +void SocketTest::TestConnectFailIPv4() { + ConnectFailInternal(kIPv4Loopback); +} + +void SocketTest::TestConnectFailIPv6() { + MAYBE_SKIP_IPV6; + ConnectFailInternal(kIPv6Loopback); +} + +void SocketTest::TestConnectWithDnsLookupFailIPv4() { + ConnectWithDnsLookupFailInternal(kIPv4Loopback); +} + +void SocketTest::TestConnectWithDnsLookupFailIPv6() { + MAYBE_SKIP_IPV6; + ConnectWithDnsLookupFailInternal(kIPv6Loopback); +} + +void SocketTest::TestConnectWithClosedSocketIPv4() { + ConnectWithClosedSocketInternal(kIPv4Loopback); +} + +void SocketTest::TestConnectWithClosedSocketIPv6() { + MAYBE_SKIP_IPV6; + ConnectWithClosedSocketInternal(kIPv6Loopback); +} + +void SocketTest::TestConnectWhileNotClosedIPv4() { + ConnectWhileNotClosedInternal(kIPv4Loopback); +} + +void SocketTest::TestConnectWhileNotClosedIPv6() { + MAYBE_SKIP_IPV6; + ConnectWhileNotClosedInternal(kIPv6Loopback); +} + +void SocketTest::TestServerCloseDuringConnectIPv4() { + ServerCloseDuringConnectInternal(kIPv4Loopback); +} + +void SocketTest::TestServerCloseDuringConnectIPv6() { + MAYBE_SKIP_IPV6; + ServerCloseDuringConnectInternal(kIPv6Loopback); +} + +void SocketTest::TestClientCloseDuringConnectIPv4() { + ClientCloseDuringConnectInternal(kIPv4Loopback); +} + +void SocketTest::TestClientCloseDuringConnectIPv6() { + MAYBE_SKIP_IPV6; + ClientCloseDuringConnectInternal(kIPv6Loopback); +} + +void SocketTest::TestServerCloseIPv4() { + ServerCloseInternal(kIPv4Loopback); +} + +void SocketTest::TestServerCloseIPv6() { + MAYBE_SKIP_IPV6; + ServerCloseInternal(kIPv6Loopback); +} + +void SocketTest::TestCloseInClosedCallbackIPv4() { + CloseInClosedCallbackInternal(kIPv4Loopback); +} + +void SocketTest::TestCloseInClosedCallbackIPv6() { + MAYBE_SKIP_IPV6; + CloseInClosedCallbackInternal(kIPv6Loopback); +} + +void SocketTest::TestDeleteInReadCallbackIPv4() { + DeleteInReadCallbackInternal(kIPv4Loopback); +} + +void SocketTest::TestDeleteInReadCallbackIPv6() { + MAYBE_SKIP_IPV6; + DeleteInReadCallbackInternal(kIPv6Loopback); +} + +void SocketTest::TestSocketServerWaitIPv4() { + SocketServerWaitInternal(kIPv4Loopback); +} + +void SocketTest::TestSocketServerWaitIPv6() { + MAYBE_SKIP_IPV6; + SocketServerWaitInternal(kIPv6Loopback); +} + +void SocketTest::TestTcpIPv4() { + TcpInternal(kIPv4Loopback, kTcpInternalDataSize, -1); +} + +void SocketTest::TestTcpIPv6() { + MAYBE_SKIP_IPV6; + TcpInternal(kIPv6Loopback, kTcpInternalDataSize, -1); +} + +void SocketTest::TestSingleFlowControlCallbackIPv4() { + SingleFlowControlCallbackInternal(kIPv4Loopback); +} + +void SocketTest::TestSingleFlowControlCallbackIPv6() { + MAYBE_SKIP_IPV6; + SingleFlowControlCallbackInternal(kIPv6Loopback); +} + +void SocketTest::TestUdpIPv4() { + UdpInternal(kIPv4Loopback); +} + +void SocketTest::TestUdpIPv6() { + MAYBE_SKIP_IPV6; + UdpInternal(kIPv6Loopback); +} + +void SocketTest::TestUdpReadyToSendIPv4() { +#if !defined(WEBRTC_MAC) + // TODO(ronghuawu): Enable this test on mac/ios. + UdpReadyToSend(kIPv4Loopback); +#endif +} + +void SocketTest::TestUdpReadyToSendIPv6() { +#if defined(WEBRTC_WIN) + // TODO(ronghuawu): Enable this test (currently flakey) on mac and linux. + MAYBE_SKIP_IPV6; + UdpReadyToSend(kIPv6Loopback); +#endif +} + +void SocketTest::TestGetSetOptionsIPv4() { + GetSetOptionsInternal(kIPv4Loopback); +} + +void SocketTest::TestGetSetOptionsIPv6() { + MAYBE_SKIP_IPV6; + GetSetOptionsInternal(kIPv6Loopback); +} + +void SocketTest::TestSocketRecvTimestampIPv4() { + SocketRecvTimestamp(kIPv4Loopback); +} + +void SocketTest::TestSocketRecvTimestampIPv6() { + MAYBE_SKIP_IPV6; + SocketRecvTimestamp(kIPv6Loopback); +} + +void SocketTest::TestUdpSocketRecvTimestampUseRtcEpochIPv4() { + UdpSocketRecvTimestampUseRtcEpoch(kIPv4Loopback); +} + +void SocketTest::TestUdpSocketRecvTimestampUseRtcEpochIPv6() { + MAYBE_SKIP_IPV6; + UdpSocketRecvTimestampUseRtcEpoch(kIPv6Loopback); +} + +// For unbound sockets, GetLocalAddress / GetRemoteAddress return AF_UNSPEC +// values on Windows, but an empty address of the same family on Linux/MacOS X. +bool IsUnspecOrEmptyIP(const IPAddress& address) { +#if !defined(WEBRTC_WIN) + return IPIsAny(address); +#else + return address.family() == AF_UNSPEC; +#endif +} + +void SocketTest::ConnectInternal(const IPAddress& loopback) { + StreamSink sink; + SocketAddress accept_addr; + + // Create client. + std::unique_ptr<Socket> client( + socket_factory_->CreateSocket(loopback.family(), SOCK_STREAM)); + sink.Monitor(client.get()); + EXPECT_EQ(Socket::CS_CLOSED, client->GetState()); + EXPECT_TRUE(IsUnspecOrEmptyIP(client->GetLocalAddress().ipaddr())); + + // Create server and listen. + std::unique_ptr<Socket> server( + socket_factory_->CreateSocket(loopback.family(), SOCK_STREAM)); + sink.Monitor(server.get()); + EXPECT_EQ(0, server->Bind(SocketAddress(loopback, 0))); + EXPECT_EQ(0, server->Listen(5)); + EXPECT_EQ(Socket::CS_CONNECTING, server->GetState()); + + // Ensure no pending server connections, since we haven't done anything yet. + EXPECT_FALSE(sink.Check(server.get(), SSE_READ)); + EXPECT_TRUE(nullptr == server->Accept(&accept_addr)); + EXPECT_TRUE(accept_addr.IsNil()); + + // Attempt connect to listening socket. + EXPECT_EQ(0, client->Connect(server->GetLocalAddress())); + EXPECT_FALSE(client->GetLocalAddress().IsNil()); + EXPECT_NE(server->GetLocalAddress(), client->GetLocalAddress()); + + // Client is connecting, outcome not yet determined. + EXPECT_EQ(Socket::CS_CONNECTING, client->GetState()); + EXPECT_FALSE(sink.Check(client.get(), SSE_OPEN)); + EXPECT_FALSE(sink.Check(client.get(), SSE_CLOSE)); + + // Server has pending connection, accept it. + EXPECT_TRUE_WAIT((sink.Check(server.get(), SSE_READ)), kTimeout); + std::unique_ptr<Socket> accepted(server->Accept(&accept_addr)); + ASSERT_TRUE(accepted); + EXPECT_FALSE(accept_addr.IsNil()); + EXPECT_EQ(accepted->GetRemoteAddress(), accept_addr); + + // Connected from server perspective, check the addresses are correct. + EXPECT_EQ(Socket::CS_CONNECTED, accepted->GetState()); + EXPECT_EQ(server->GetLocalAddress(), accepted->GetLocalAddress()); + EXPECT_EQ(client->GetLocalAddress(), accepted->GetRemoteAddress()); + + // Connected from client perspective, check the addresses are correct. + EXPECT_EQ_WAIT(Socket::CS_CONNECTED, client->GetState(), kTimeout); + EXPECT_TRUE(sink.Check(client.get(), SSE_OPEN)); + EXPECT_FALSE(sink.Check(client.get(), SSE_CLOSE)); + EXPECT_EQ(client->GetRemoteAddress(), server->GetLocalAddress()); + EXPECT_EQ(client->GetRemoteAddress(), accepted->GetLocalAddress()); +} + +void SocketTest::ConnectWithDnsLookupInternal(const IPAddress& loopback, + absl::string_view host) { + StreamSink sink; + SocketAddress accept_addr; + + // Create client. + std::unique_ptr<Socket> client( + socket_factory_->CreateSocket(loopback.family(), SOCK_STREAM)); + sink.Monitor(client.get()); + + // Create server and listen. + std::unique_ptr<Socket> server( + socket_factory_->CreateSocket(loopback.family(), SOCK_STREAM)); + sink.Monitor(server.get()); + EXPECT_EQ(0, server->Bind(SocketAddress(loopback, 0))); + EXPECT_EQ(0, server->Listen(5)); + + // Attempt connect to listening socket. + SocketAddress dns_addr(server->GetLocalAddress()); + dns_addr.SetIP(host); + EXPECT_EQ(0, client->Connect(dns_addr)); + // TODO: Bind when doing DNS lookup. + // EXPECT_NE(kEmptyAddr, client->GetLocalAddress()); // Implicit Bind + + // Client is connecting, outcome not yet determined. + EXPECT_EQ(Socket::CS_CONNECTING, client->GetState()); + EXPECT_FALSE(sink.Check(client.get(), SSE_OPEN)); + EXPECT_FALSE(sink.Check(client.get(), SSE_CLOSE)); + + // Server has pending connection, accept it. + EXPECT_TRUE_WAIT((sink.Check(server.get(), SSE_READ)), kTimeout); + std::unique_ptr<Socket> accepted(server->Accept(&accept_addr)); + ASSERT_TRUE(accepted); + EXPECT_FALSE(accept_addr.IsNil()); + EXPECT_EQ(accepted->GetRemoteAddress(), accept_addr); + + // Connected from server perspective, check the addresses are correct. + EXPECT_EQ(Socket::CS_CONNECTED, accepted->GetState()); + EXPECT_EQ(server->GetLocalAddress(), accepted->GetLocalAddress()); + EXPECT_EQ(client->GetLocalAddress(), accepted->GetRemoteAddress()); + + // Connected from client perspective, check the addresses are correct. + EXPECT_EQ_WAIT(Socket::CS_CONNECTED, client->GetState(), kTimeout); + EXPECT_TRUE(sink.Check(client.get(), SSE_OPEN)); + EXPECT_FALSE(sink.Check(client.get(), SSE_CLOSE)); + EXPECT_EQ(client->GetRemoteAddress(), server->GetLocalAddress()); + EXPECT_EQ(client->GetRemoteAddress(), accepted->GetLocalAddress()); +} + +void SocketTest::ConnectFailInternal(const IPAddress& loopback) { + StreamSink sink; + SocketAddress accept_addr; + + // Create client. + std::unique_ptr<Socket> client( + socket_factory_->CreateSocket(loopback.family(), SOCK_STREAM)); + sink.Monitor(client.get()); + + // Create server, but don't listen yet. + std::unique_ptr<Socket> server( + socket_factory_->CreateSocket(loopback.family(), SOCK_STREAM)); + sink.Monitor(server.get()); + EXPECT_EQ(0, server->Bind(SocketAddress(loopback, 0))); + + // Attempt connect to a non-existent socket. + // We don't connect to the server socket created above, since on + // MacOS it takes about 75 seconds to get back an error! + SocketAddress bogus_addr(loopback, 65535); + EXPECT_EQ(0, client->Connect(bogus_addr)); + + // Wait for connection to fail (ECONNREFUSED). + EXPECT_EQ_WAIT(Socket::CS_CLOSED, client->GetState(), kTimeout); + EXPECT_FALSE(sink.Check(client.get(), SSE_OPEN)); + EXPECT_TRUE(sink.Check(client.get(), SSE_ERROR)); + EXPECT_TRUE(client->GetRemoteAddress().IsNil()); + + // Should be no pending server connections. + EXPECT_FALSE(sink.Check(server.get(), SSE_READ)); + EXPECT_TRUE(nullptr == server->Accept(&accept_addr)); + EXPECT_EQ(IPAddress(), accept_addr.ipaddr()); +} + +void SocketTest::ConnectWithDnsLookupFailInternal(const IPAddress& loopback) { + StreamSink sink; + SocketAddress accept_addr; + + // Create client. + std::unique_ptr<Socket> client( + socket_factory_->CreateSocket(loopback.family(), SOCK_STREAM)); + sink.Monitor(client.get()); + + // Create server, but don't listen yet. + std::unique_ptr<Socket> server( + socket_factory_->CreateSocket(loopback.family(), SOCK_STREAM)); + sink.Monitor(server.get()); + EXPECT_EQ(0, server->Bind(SocketAddress(loopback, 0))); + + // Attempt connect to a non-existent host. + // We don't connect to the server socket created above, since on + // MacOS it takes about 75 seconds to get back an error! + SocketAddress bogus_dns_addr("not-a-real-hostname", 65535); + EXPECT_EQ(0, client->Connect(bogus_dns_addr)); + + // Wait for connection to fail (EHOSTNOTFOUND). + bool dns_lookup_finished = false; + WAIT_(client->GetState() == Socket::CS_CLOSED, kTimeout, dns_lookup_finished); + if (!dns_lookup_finished) { + RTC_LOG(LS_WARNING) << "Skipping test; DNS resolution took longer than 5 " + "seconds."; + return; + } + + EXPECT_EQ_WAIT(Socket::CS_CLOSED, client->GetState(), kTimeout); + EXPECT_FALSE(sink.Check(client.get(), SSE_OPEN)); + EXPECT_TRUE(sink.Check(client.get(), SSE_ERROR)); + EXPECT_TRUE(client->GetRemoteAddress().IsNil()); + // Should be no pending server connections. + EXPECT_FALSE(sink.Check(server.get(), SSE_READ)); + EXPECT_TRUE(nullptr == server->Accept(&accept_addr)); + EXPECT_TRUE(accept_addr.IsNil()); +} + +void SocketTest::ConnectWithClosedSocketInternal(const IPAddress& loopback) { + // Create server and listen. + std::unique_ptr<Socket> server( + socket_factory_->CreateSocket(loopback.family(), SOCK_STREAM)); + EXPECT_EQ(0, server->Bind(SocketAddress(loopback, 0))); + EXPECT_EQ(0, server->Listen(5)); + + // Create a client and put in to CS_CLOSED state. + std::unique_ptr<Socket> client( + socket_factory_->CreateSocket(loopback.family(), SOCK_STREAM)); + EXPECT_EQ(0, client->Close()); + EXPECT_EQ(Socket::CS_CLOSED, client->GetState()); + + // Connect() should reinitialize the socket, and put it in to CS_CONNECTING. + EXPECT_EQ(0, client->Connect(SocketAddress(server->GetLocalAddress()))); + EXPECT_EQ(Socket::CS_CONNECTING, client->GetState()); +} + +void SocketTest::ConnectWhileNotClosedInternal(const IPAddress& loopback) { + // Create server and listen. + StreamSink sink; + std::unique_ptr<Socket> server( + socket_factory_->CreateSocket(loopback.family(), SOCK_STREAM)); + sink.Monitor(server.get()); + EXPECT_EQ(0, server->Bind(SocketAddress(loopback, 0))); + EXPECT_EQ(0, server->Listen(5)); + // Create client, connect. + std::unique_ptr<Socket> client( + socket_factory_->CreateSocket(loopback.family(), SOCK_STREAM)); + EXPECT_EQ(0, client->Connect(SocketAddress(server->GetLocalAddress()))); + EXPECT_EQ(Socket::CS_CONNECTING, client->GetState()); + // Try to connect again. Should fail, but not interfere with original attempt. + EXPECT_EQ(SOCKET_ERROR, + client->Connect(SocketAddress(server->GetLocalAddress()))); + + // Accept the original connection. + SocketAddress accept_addr; + EXPECT_TRUE_WAIT((sink.Check(server.get(), SSE_READ)), kTimeout); + std::unique_ptr<Socket> accepted(server->Accept(&accept_addr)); + ASSERT_TRUE(accepted); + EXPECT_FALSE(accept_addr.IsNil()); + + // Check the states and addresses. + EXPECT_EQ(Socket::CS_CONNECTED, accepted->GetState()); + EXPECT_EQ(server->GetLocalAddress(), accepted->GetLocalAddress()); + EXPECT_EQ(client->GetLocalAddress(), accepted->GetRemoteAddress()); + EXPECT_EQ_WAIT(Socket::CS_CONNECTED, client->GetState(), kTimeout); + EXPECT_EQ(client->GetRemoteAddress(), server->GetLocalAddress()); + EXPECT_EQ(client->GetRemoteAddress(), accepted->GetLocalAddress()); + + // Try to connect again, to an unresolved hostname. + // Shouldn't break anything. + EXPECT_EQ(SOCKET_ERROR, client->Connect(SocketAddress( + "localhost", server->GetLocalAddress().port()))); + EXPECT_EQ(Socket::CS_CONNECTED, accepted->GetState()); + EXPECT_EQ(Socket::CS_CONNECTED, client->GetState()); + EXPECT_EQ(client->GetRemoteAddress(), server->GetLocalAddress()); + EXPECT_EQ(client->GetRemoteAddress(), accepted->GetLocalAddress()); +} + +void SocketTest::ServerCloseDuringConnectInternal(const IPAddress& loopback) { + StreamSink sink; + + // Create client. + std::unique_ptr<Socket> client( + socket_factory_->CreateSocket(loopback.family(), SOCK_STREAM)); + sink.Monitor(client.get()); + + // Create server and listen. + std::unique_ptr<Socket> server( + socket_factory_->CreateSocket(loopback.family(), SOCK_STREAM)); + sink.Monitor(server.get()); + EXPECT_EQ(0, server->Bind(SocketAddress(loopback, 0))); + EXPECT_EQ(0, server->Listen(5)); + + // Attempt connect to listening socket. + EXPECT_EQ(0, client->Connect(server->GetLocalAddress())); + + // Close down the server while the socket is in the accept queue. + EXPECT_TRUE_WAIT(sink.Check(server.get(), SSE_READ), kTimeout); + server->Close(); + + // This should fail the connection for the client. Clean up. + EXPECT_EQ_WAIT(Socket::CS_CLOSED, client->GetState(), kTimeout); + EXPECT_TRUE(sink.Check(client.get(), SSE_ERROR)); + client->Close(); +} + +void SocketTest::ClientCloseDuringConnectInternal(const IPAddress& loopback) { + StreamSink sink; + SocketAddress accept_addr; + + // Create client. + std::unique_ptr<Socket> client( + socket_factory_->CreateSocket(loopback.family(), SOCK_STREAM)); + sink.Monitor(client.get()); + + // Create server and listen. + std::unique_ptr<Socket> server( + socket_factory_->CreateSocket(loopback.family(), SOCK_STREAM)); + sink.Monitor(server.get()); + EXPECT_EQ(0, server->Bind(SocketAddress(loopback, 0))); + EXPECT_EQ(0, server->Listen(5)); + + // Attempt connect to listening socket. + EXPECT_EQ(0, client->Connect(server->GetLocalAddress())); + + // Close down the client while the socket is in the accept queue. + EXPECT_TRUE_WAIT(sink.Check(server.get(), SSE_READ), kTimeout); + client->Close(); + + // The connection should still be able to be accepted. + std::unique_ptr<Socket> accepted(server->Accept(&accept_addr)); + ASSERT_TRUE(accepted); + sink.Monitor(accepted.get()); + EXPECT_EQ(Socket::CS_CONNECTED, accepted->GetState()); + + // The accepted socket should then close (possibly with err, timing-related) + EXPECT_EQ_WAIT(Socket::CS_CLOSED, accepted->GetState(), kTimeout); + EXPECT_TRUE(sink.Check(accepted.get(), SSE_CLOSE) || + sink.Check(accepted.get(), SSE_ERROR)); + + // The client should not get a close event. + EXPECT_FALSE(sink.Check(client.get(), SSE_CLOSE)); +} + +void SocketTest::ServerCloseInternal(const IPAddress& loopback) { + StreamSink sink; + SocketAddress accept_addr; + + // Create client. + std::unique_ptr<Socket> client( + socket_factory_->CreateSocket(loopback.family(), SOCK_STREAM)); + sink.Monitor(client.get()); + + // Create server and listen. + std::unique_ptr<Socket> server( + socket_factory_->CreateSocket(loopback.family(), SOCK_STREAM)); + sink.Monitor(server.get()); + EXPECT_EQ(0, server->Bind(SocketAddress(loopback, 0))); + EXPECT_EQ(0, server->Listen(5)); + + // Attempt connection. + EXPECT_EQ(0, client->Connect(server->GetLocalAddress())); + + // Accept connection. + EXPECT_TRUE_WAIT((sink.Check(server.get(), SSE_READ)), kTimeout); + std::unique_ptr<Socket> accepted(server->Accept(&accept_addr)); + ASSERT_TRUE(accepted); + sink.Monitor(accepted.get()); + + // Both sides are now connected. + EXPECT_EQ_WAIT(Socket::CS_CONNECTED, client->GetState(), kTimeout); + EXPECT_TRUE(sink.Check(client.get(), SSE_OPEN)); + EXPECT_EQ(client->GetRemoteAddress(), accepted->GetLocalAddress()); + EXPECT_EQ(accepted->GetRemoteAddress(), client->GetLocalAddress()); + + // Send data to the client, and then close the connection. + EXPECT_EQ(1, accepted->Send("a", 1)); + accepted->Close(); + EXPECT_EQ(Socket::CS_CLOSED, accepted->GetState()); + + // Expect that the client is notified, and has not yet closed. + EXPECT_TRUE_WAIT(sink.Check(client.get(), SSE_READ), kTimeout); + EXPECT_FALSE(sink.Check(client.get(), SSE_CLOSE)); + EXPECT_EQ(Socket::CS_CONNECTED, client->GetState()); + + // Ensure the data can be read. + char buffer[10]; + EXPECT_EQ(1, client->Recv(buffer, sizeof(buffer), nullptr)); + EXPECT_EQ('a', buffer[0]); + + // Now we should close, but the remote address will remain. + EXPECT_EQ_WAIT(Socket::CS_CLOSED, client->GetState(), kTimeout); + EXPECT_TRUE(sink.Check(client.get(), SSE_CLOSE)); + EXPECT_FALSE(client->GetRemoteAddress().IsAnyIP()); + + // The closer should not get a close signal. + EXPECT_FALSE(sink.Check(accepted.get(), SSE_CLOSE)); + EXPECT_TRUE(accepted->GetRemoteAddress().IsNil()); + + // And the closee should only get a single signal. + Thread::Current()->ProcessMessages(0); + EXPECT_FALSE(sink.Check(client.get(), SSE_CLOSE)); + + // Close down the client and ensure all is good. + client->Close(); + EXPECT_FALSE(sink.Check(client.get(), SSE_CLOSE)); + EXPECT_TRUE(client->GetRemoteAddress().IsNil()); +} + +class SocketCloser : public sigslot::has_slots<> { + public: + void OnClose(Socket* socket, int error) { + socket->Close(); // Deleting here would blow up the vector of handlers + // for the socket's signal. + } +}; + +void SocketTest::CloseInClosedCallbackInternal(const IPAddress& loopback) { + StreamSink sink; + SocketCloser closer; + SocketAddress accept_addr; + + // Create client. + std::unique_ptr<Socket> client( + socket_factory_->CreateSocket(loopback.family(), SOCK_STREAM)); + sink.Monitor(client.get()); + client->SignalCloseEvent.connect(&closer, &SocketCloser::OnClose); + + // Create server and listen. + std::unique_ptr<Socket> server( + socket_factory_->CreateSocket(loopback.family(), SOCK_STREAM)); + sink.Monitor(server.get()); + EXPECT_EQ(0, server->Bind(SocketAddress(loopback, 0))); + EXPECT_EQ(0, server->Listen(5)); + + // Attempt connection. + EXPECT_EQ(0, client->Connect(server->GetLocalAddress())); + + // Accept connection. + EXPECT_TRUE_WAIT((sink.Check(server.get(), SSE_READ)), kTimeout); + std::unique_ptr<Socket> accepted(server->Accept(&accept_addr)); + ASSERT_TRUE(accepted); + sink.Monitor(accepted.get()); + + // Both sides are now connected. + EXPECT_EQ_WAIT(Socket::CS_CONNECTED, client->GetState(), kTimeout); + EXPECT_TRUE(sink.Check(client.get(), SSE_OPEN)); + EXPECT_EQ(client->GetRemoteAddress(), accepted->GetLocalAddress()); + EXPECT_EQ(accepted->GetRemoteAddress(), client->GetLocalAddress()); + + // Send data to the client, and then close the connection. + accepted->Close(); + EXPECT_EQ(Socket::CS_CLOSED, accepted->GetState()); + + // Expect that the client is notified, and has not yet closed. + EXPECT_FALSE(sink.Check(client.get(), SSE_CLOSE)); + EXPECT_EQ(Socket::CS_CONNECTED, client->GetState()); + + // Now we should be closed and invalidated + EXPECT_EQ_WAIT(Socket::CS_CLOSED, client->GetState(), kTimeout); + EXPECT_TRUE(sink.Check(client.get(), SSE_CLOSE)); + EXPECT_TRUE(Socket::CS_CLOSED == client->GetState()); +} + +// Helper class specifically for the test below. +class SocketDeleter : public sigslot::has_slots<> { + public: + explicit SocketDeleter(std::unique_ptr<Socket> socket) + : socket_(std::move(socket)) {} + + void Delete(Socket* other) { socket_.reset(); } + + bool deleted() const { return socket_ == nullptr; } + + private: + std::unique_ptr<Socket> socket_; +}; + +// Tested deleting a socket within another socket's read callback. A previous +// iteration of the select loop failed in this situation, if both sockets +// became readable at the same time. +void SocketTest::DeleteInReadCallbackInternal(const IPAddress& loopback) { + std::unique_ptr<Socket> socket1( + socket_factory_->CreateSocket(loopback.family(), SOCK_DGRAM)); + std::unique_ptr<Socket> socket2( + socket_factory_->CreateSocket(loopback.family(), SOCK_DGRAM)); + EXPECT_EQ(0, socket1->Bind(SocketAddress(loopback, 0))); + EXPECT_EQ(0, socket2->Bind(SocketAddress(loopback, 0))); + EXPECT_EQ(3, socket1->SendTo("foo", 3, socket1->GetLocalAddress())); + EXPECT_EQ(3, socket2->SendTo("bar", 3, socket1->GetLocalAddress())); + // Sleep a while to ensure sends are both completed at the same time. + Thread::SleepMs(1000); + + // Configure the helper class to delete socket 2 when socket 1 has a read + // event. + SocketDeleter deleter(std::move(socket2)); + socket1->SignalReadEvent.connect(&deleter, &SocketDeleter::Delete); + EXPECT_TRUE_WAIT(deleter.deleted(), kTimeout); +} + +void SocketTest::SocketServerWaitInternal(const IPAddress& loopback) { + StreamSink sink; + SocketAddress accept_addr; + + // Create & connect server and client sockets. + std::unique_ptr<Socket> client( + socket_factory_->CreateSocket(loopback.family(), SOCK_STREAM)); + std::unique_ptr<Socket> server( + socket_factory_->CreateSocket(loopback.family(), SOCK_STREAM)); + sink.Monitor(client.get()); + sink.Monitor(server.get()); + EXPECT_EQ(0, server->Bind(SocketAddress(loopback, 0))); + EXPECT_EQ(0, server->Listen(5)); + + EXPECT_EQ(0, client->Connect(server->GetLocalAddress())); + EXPECT_TRUE_WAIT((sink.Check(server.get(), SSE_READ)), kTimeout); + + std::unique_ptr<Socket> accepted(server->Accept(&accept_addr)); + ASSERT_TRUE(accepted); + sink.Monitor(accepted.get()); + EXPECT_EQ(Socket::CS_CONNECTED, accepted->GetState()); + EXPECT_EQ(server->GetLocalAddress(), accepted->GetLocalAddress()); + EXPECT_EQ(client->GetLocalAddress(), accepted->GetRemoteAddress()); + + EXPECT_EQ_WAIT(Socket::CS_CONNECTED, client->GetState(), kTimeout); + EXPECT_TRUE(sink.Check(client.get(), SSE_OPEN)); + EXPECT_FALSE(sink.Check(client.get(), SSE_CLOSE)); + EXPECT_EQ(client->GetRemoteAddress(), server->GetLocalAddress()); + EXPECT_EQ(client->GetRemoteAddress(), accepted->GetLocalAddress()); + + // Do an i/o operation, triggering an eventual callback. + EXPECT_FALSE(sink.Check(accepted.get(), SSE_READ)); + char buf[1024] = {0}; + + EXPECT_EQ(1024, client->Send(buf, 1024)); + EXPECT_FALSE(sink.Check(accepted.get(), SSE_READ)); + + // Shouldn't signal when blocked in a thread Send, where process_io is false. + std::unique_ptr<Thread> thread(Thread::CreateWithSocketServer()); + thread->Start(); + thread->BlockingCall([] { Thread::SleepMs(500); }); + EXPECT_FALSE(sink.Check(accepted.get(), SSE_READ)); + + // But should signal when process_io is true. + EXPECT_TRUE_WAIT((sink.Check(accepted.get(), SSE_READ)), kTimeout); + EXPECT_LT(0, accepted->Recv(buf, 1024, nullptr)); +} + +void SocketTest::TcpInternal(const IPAddress& loopback, + size_t data_size, + ptrdiff_t max_send_size) { + StreamSink sink; + SocketAddress accept_addr; + + // Create receiving client. + std::unique_ptr<Socket> receiver( + socket_factory_->CreateSocket(loopback.family(), SOCK_STREAM)); + sink.Monitor(receiver.get()); + + // Create server and listen. + std::unique_ptr<Socket> server( + socket_factory_->CreateSocket(loopback.family(), SOCK_STREAM)); + sink.Monitor(server.get()); + EXPECT_EQ(0, server->Bind(SocketAddress(loopback, 0))); + EXPECT_EQ(0, server->Listen(5)); + + // Attempt connection. + EXPECT_EQ(0, receiver->Connect(server->GetLocalAddress())); + + // Accept connection which will be used for sending. + EXPECT_TRUE_WAIT((sink.Check(server.get(), SSE_READ)), kTimeout); + std::unique_ptr<Socket> sender(server->Accept(&accept_addr)); + ASSERT_TRUE(sender); + sink.Monitor(sender.get()); + + // Both sides are now connected. + EXPECT_EQ_WAIT(Socket::CS_CONNECTED, receiver->GetState(), kTimeout); + EXPECT_TRUE(sink.Check(receiver.get(), SSE_OPEN)); + EXPECT_EQ(receiver->GetRemoteAddress(), sender->GetLocalAddress()); + EXPECT_EQ(sender->GetRemoteAddress(), receiver->GetLocalAddress()); + + // Create test data. + rtc::Buffer send_buffer(0, data_size); + rtc::Buffer recv_buffer(0, data_size); + for (size_t i = 0; i < data_size; ++i) { + char ch = static_cast<char>(i % 256); + send_buffer.AppendData(&ch, sizeof(ch)); + } + rtc::Buffer recved_data(0, data_size); + + // Send and receive a bunch of data. + size_t sent_size = 0; + bool writable = true; + bool send_called = false; + bool readable = false; + bool recv_called = false; + while (recv_buffer.size() < send_buffer.size()) { + // Send as much as we can while we're cleared to send. + while (writable && sent_size < send_buffer.size()) { + int unsent_size = static_cast<int>(send_buffer.size() - sent_size); + int sent = sender->Send(send_buffer.data() + sent_size, unsent_size); + if (!send_called) { + // The first Send() after connecting or getting writability should + // succeed and send some data. + EXPECT_GT(sent, 0); + send_called = true; + } + if (sent >= 0) { + EXPECT_LE(sent, unsent_size); + sent_size += sent; + if (max_send_size >= 0) { + EXPECT_LE(static_cast<ptrdiff_t>(sent), max_send_size); + if (sent < unsent_size) { + // If max_send_size is limiting the amount to send per call such + // that the sent amount is less than the unsent amount, we simulate + // that the socket is no longer writable. + writable = false; + } + } + } else { + ASSERT_TRUE(sender->IsBlocking()); + writable = false; + } + } + + // Read all the sent data. + while (recv_buffer.size() < sent_size) { + if (!readable) { + // Wait until data is available. + EXPECT_TRUE_WAIT(sink.Check(receiver.get(), SSE_READ), kTimeout); + readable = true; + recv_called = false; + } + + // Receive as much as we can get in a single recv call. + int recved_size = receiver->Recv(recved_data.data(), data_size, nullptr); + + if (!recv_called) { + // The first Recv() after getting readability should succeed and receive + // some data. + // TODO: The following line is disabled due to flakey pulse + // builds. Re-enable if/when possible. + // EXPECT_GT(recved_size, 0); + recv_called = true; + } + if (recved_size >= 0) { + EXPECT_LE(static_cast<size_t>(recved_size), + sent_size - recv_buffer.size()); + recv_buffer.AppendData(recved_data.data(), recved_size); + } else { + ASSERT_TRUE(receiver->IsBlocking()); + readable = false; + } + } + + // Once all that we've sent has been received, expect to be able to send + // again. + if (!writable) { + ASSERT_TRUE_WAIT(sink.Check(sender.get(), SSE_WRITE), kTimeout); + writable = true; + send_called = false; + } + } + + // The received data matches the sent data. + EXPECT_EQ(data_size, sent_size); + EXPECT_EQ(data_size, recv_buffer.size()); + EXPECT_EQ(recv_buffer, send_buffer); + + // Close down. + sender->Close(); + EXPECT_EQ_WAIT(Socket::CS_CLOSED, receiver->GetState(), kTimeout); + EXPECT_TRUE(sink.Check(receiver.get(), SSE_CLOSE)); + receiver->Close(); +} + +void SocketTest::SingleFlowControlCallbackInternal(const IPAddress& loopback) { + StreamSink sink; + SocketAddress accept_addr; + + // Create client. + std::unique_ptr<Socket> client( + socket_factory_->CreateSocket(loopback.family(), SOCK_STREAM)); + sink.Monitor(client.get()); + + // Create server and listen. + std::unique_ptr<Socket> server( + socket_factory_->CreateSocket(loopback.family(), SOCK_STREAM)); + sink.Monitor(server.get()); + EXPECT_EQ(0, server->Bind(SocketAddress(loopback, 0))); + EXPECT_EQ(0, server->Listen(5)); + + // Attempt connection. + EXPECT_EQ(0, client->Connect(server->GetLocalAddress())); + + // Accept connection. + EXPECT_TRUE_WAIT((sink.Check(server.get(), SSE_READ)), kTimeout); + std::unique_ptr<Socket> accepted(server->Accept(&accept_addr)); + ASSERT_TRUE(accepted); + sink.Monitor(accepted.get()); + + // Both sides are now connected. + EXPECT_EQ_WAIT(Socket::CS_CONNECTED, client->GetState(), kTimeout); + EXPECT_TRUE(sink.Check(client.get(), SSE_OPEN)); + EXPECT_EQ(client->GetRemoteAddress(), accepted->GetLocalAddress()); + EXPECT_EQ(accepted->GetRemoteAddress(), client->GetLocalAddress()); + + // Expect a writable callback from the connect. + EXPECT_TRUE_WAIT(sink.Check(accepted.get(), SSE_WRITE), kTimeout); + + // Fill the socket buffer. + char buf[1024 * 16] = {0}; + int sends = 0; + while (++sends && accepted->Send(&buf, arraysize(buf)) != -1) { + } + EXPECT_TRUE(accepted->IsBlocking()); + + // Wait until data is available. + EXPECT_TRUE_WAIT(sink.Check(client.get(), SSE_READ), kTimeout); + + // Pull data. + for (int i = 0; i < sends; ++i) { + client->Recv(buf, arraysize(buf), nullptr); + } + + // Expect at least one additional writable callback. + EXPECT_TRUE_WAIT(sink.Check(accepted.get(), SSE_WRITE), kTimeout); + + // Adding data in response to the writeable callback shouldn't cause infinite + // callbacks. + int extras = 0; + for (int i = 0; i < 100; ++i) { + accepted->Send(&buf, arraysize(buf)); + rtc::Thread::Current()->ProcessMessages(1); + if (sink.Check(accepted.get(), SSE_WRITE)) { + extras++; + } + } + EXPECT_LT(extras, 2); + + // Close down. + accepted->Close(); + client->Close(); +} + +void SocketTest::UdpInternal(const IPAddress& loopback) { + SocketAddress empty = EmptySocketAddressWithFamily(loopback.family()); + // Test basic bind and connect behavior. + Socket* socket = socket_factory_->CreateSocket(loopback.family(), SOCK_DGRAM); + EXPECT_EQ(Socket::CS_CLOSED, socket->GetState()); + EXPECT_EQ(0, socket->Bind(SocketAddress(loopback, 0))); + SocketAddress addr1 = socket->GetLocalAddress(); + EXPECT_EQ(0, socket->Connect(addr1)); + EXPECT_EQ(Socket::CS_CONNECTED, socket->GetState()); + socket->Close(); + EXPECT_EQ(Socket::CS_CLOSED, socket->GetState()); + delete socket; + + // Test send/receive behavior. + auto client1 = std::make_unique<TestClient>( + absl::WrapUnique(AsyncUDPSocket::Create(socket_factory_, addr1))); + auto client2 = std::make_unique<TestClient>( + absl::WrapUnique(AsyncUDPSocket::Create(socket_factory_, empty))); + + SocketAddress addr2; + EXPECT_EQ(3, client2->SendTo("foo", 3, addr1)); + EXPECT_TRUE(client1->CheckNextPacket("foo", 3, &addr2)); + + SocketAddress addr3; + EXPECT_EQ(6, client1->SendTo("bizbaz", 6, addr2)); + EXPECT_TRUE(client2->CheckNextPacket("bizbaz", 6, &addr3)); + EXPECT_EQ(addr3, addr1); + // TODO: figure out what the intent is here + for (int i = 0; i < 10; ++i) { + client2 = std::make_unique<TestClient>( + absl::WrapUnique(AsyncUDPSocket::Create(socket_factory_, empty))); + + SocketAddress addr4; + EXPECT_EQ(3, client2->SendTo("foo", 3, addr1)); + EXPECT_TRUE(client1->CheckNextPacket("foo", 3, &addr4)); + EXPECT_EQ(addr4.ipaddr(), addr2.ipaddr()); + + SocketAddress addr5; + EXPECT_EQ(6, client1->SendTo("bizbaz", 6, addr4)); + EXPECT_TRUE(client2->CheckNextPacket("bizbaz", 6, &addr5)); + EXPECT_EQ(addr5, addr1); + + addr2 = addr4; + } +} + +void SocketTest::UdpReadyToSend(const IPAddress& loopback) { + SocketAddress empty = EmptySocketAddressWithFamily(loopback.family()); + // RFC 5737 - The blocks 192.0.2.0/24 (TEST-NET-1) ... are provided for use in + // documentation. + // RFC 3849 - 2001:DB8::/32 as a documentation-only prefix. + std::string dest = + (loopback.family() == AF_INET6) ? "2001:db8::1" : "192.0.2.0"; + SocketAddress test_addr(dest, 2345); + + // Test send + auto client = std::make_unique<TestClient>( + absl::WrapUnique(AsyncUDPSocket::Create(socket_factory_, empty))); + int test_packet_size = 1200; + std::unique_ptr<char[]> test_packet(new char[test_packet_size]); + // Init the test packet just to avoid memcheck warning. + memset(test_packet.get(), 0, test_packet_size); + // Set the send buffer size to the same size as the test packet to have a + // better chance to get EWOULDBLOCK. + int send_buffer_size = test_packet_size; +#if defined(WEBRTC_LINUX) && !defined(WEBRTC_ANDROID) + send_buffer_size /= 2; +#endif + client->SetOption(rtc::Socket::OPT_SNDBUF, send_buffer_size); + + int error = 0; + uint32_t start_ms = Time(); + int sent_packet_num = 0; + int expected_error = EWOULDBLOCK; + while (start_ms + kTimeout > Time()) { + int ret = client->SendTo(test_packet.get(), test_packet_size, test_addr); + ++sent_packet_num; + if (ret != test_packet_size) { + error = client->GetError(); + if (error == expected_error) { + RTC_LOG(LS_INFO) << "Got expected error code after sending " + << sent_packet_num << " packets."; + break; + } + } + } + EXPECT_EQ(expected_error, error); + EXPECT_FALSE(client->ready_to_send()); + EXPECT_TRUE_WAIT(client->ready_to_send(), kTimeout); + RTC_LOG(LS_INFO) << "Got SignalReadyToSend"; +} + +void SocketTest::GetSetOptionsInternal(const IPAddress& loopback) { + std::unique_ptr<Socket> socket( + socket_factory_->CreateSocket(loopback.family(), SOCK_DGRAM)); + socket->Bind(SocketAddress(loopback, 0)); + + // Check SNDBUF/RCVBUF. + const int desired_size = 12345; +#if defined(WEBRTC_LINUX) + // Yes, really. It's in the kernel source. + const int expected_size = desired_size * 2; +#else // !WEBRTC_LINUX + const int expected_size = desired_size; +#endif // !WEBRTC_LINUX + int recv_size = 0; + int send_size = 0; + // get the initial sizes + ASSERT_NE(-1, socket->GetOption(Socket::OPT_RCVBUF, &recv_size)); + ASSERT_NE(-1, socket->GetOption(Socket::OPT_SNDBUF, &send_size)); + // set our desired sizes + ASSERT_NE(-1, socket->SetOption(Socket::OPT_RCVBUF, desired_size)); + ASSERT_NE(-1, socket->SetOption(Socket::OPT_SNDBUF, desired_size)); + // get the sizes again + ASSERT_NE(-1, socket->GetOption(Socket::OPT_RCVBUF, &recv_size)); + ASSERT_NE(-1, socket->GetOption(Socket::OPT_SNDBUF, &send_size)); + // make sure they are right + ASSERT_EQ(expected_size, recv_size); + ASSERT_EQ(expected_size, send_size); + + // Check that we can't set NODELAY on a UDP socket. + int current_nd, desired_nd = 1; + ASSERT_EQ(-1, socket->GetOption(Socket::OPT_NODELAY, ¤t_nd)); + ASSERT_EQ(-1, socket->SetOption(Socket::OPT_NODELAY, desired_nd)); + +#if defined(WEBRTC_POSIX) + // Check DSCP. + int current_dscp, desired_dscp = 1; + ASSERT_NE(-1, socket->GetOption(Socket::OPT_DSCP, ¤t_dscp)); + ASSERT_NE(-1, socket->SetOption(Socket::OPT_DSCP, desired_dscp)); + ASSERT_NE(-1, socket->GetOption(Socket::OPT_DSCP, ¤t_dscp)); + ASSERT_EQ(desired_dscp, current_dscp); +#endif +} + +void SocketTest::SocketRecvTimestamp(const IPAddress& loopback) { + StreamSink sink; + std::unique_ptr<Socket> socket( + socket_factory_->CreateSocket(loopback.family(), SOCK_DGRAM)); + EXPECT_EQ(0, socket->Bind(SocketAddress(loopback, 0))); + SocketAddress address = socket->GetLocalAddress(); + sink.Monitor(socket.get()); + + int64_t send_time_1 = TimeMicros(); + socket->SendTo("foo", 3, address); + + int64_t recv_timestamp_1; + // Wait until data is available. + EXPECT_TRUE_WAIT(sink.Check(socket.get(), SSE_READ), kTimeout); + char buffer[3]; + ASSERT_GT(socket->RecvFrom(buffer, 3, nullptr, &recv_timestamp_1), 0); + + const int64_t kTimeBetweenPacketsMs = 100; + Thread::SleepMs(kTimeBetweenPacketsMs); + + int64_t send_time_2 = TimeMicros(); + socket->SendTo("bar", 3, address); + // Wait until data is available. + EXPECT_TRUE_WAIT(sink.Check(socket.get(), SSE_READ), kTimeout); + int64_t recv_timestamp_2; + ASSERT_GT(socket->RecvFrom(buffer, 3, nullptr, &recv_timestamp_2), 0); + + int64_t system_time_diff = send_time_2 - send_time_1; + int64_t recv_timestamp_diff = recv_timestamp_2 - recv_timestamp_1; + // Compare against the system time at the point of sending, because + // SleepMs may not sleep for exactly the requested time. + EXPECT_NEAR(system_time_diff, recv_timestamp_diff, 10000); +} + +void SocketTest::UdpSocketRecvTimestampUseRtcEpoch(const IPAddress& loopback) { + SocketAddress empty = EmptySocketAddressWithFamily(loopback.family()); + std::unique_ptr<Socket> socket( + socket_factory_->CreateSocket(loopback.family(), SOCK_DGRAM)); + ASSERT_EQ(socket->Bind(SocketAddress(loopback, 0)), 0); + SocketAddress address = socket->GetLocalAddress(); + socket = nullptr; + + auto client1 = std::make_unique<TestClient>( + absl::WrapUnique(AsyncUDPSocket::Create(socket_factory_, address))); + auto client2 = std::make_unique<TestClient>( + absl::WrapUnique(AsyncUDPSocket::Create(socket_factory_, empty))); + + SocketAddress addr2; + client2->SendTo("foo", 3, address); + std::unique_ptr<TestClient::Packet> packet_1 = client1->NextPacket(10000); + ASSERT_TRUE(packet_1 != nullptr); + EXPECT_NEAR(packet_1->packet_time_us, rtc::TimeMicros(), 1000'000); + + Thread::SleepMs(100); + client2->SendTo("bar", 3, address); + std::unique_ptr<TestClient::Packet> packet_2 = client1->NextPacket(10000); + ASSERT_TRUE(packet_2 != nullptr); + EXPECT_GT(packet_2->packet_time_us, packet_1->packet_time_us); + EXPECT_NEAR(packet_2->packet_time_us, rtc::TimeMicros(), 1000'000); +} +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/socket_unittest.h b/third_party/libwebrtc/rtc_base/socket_unittest.h new file mode 100644 index 0000000000..db79be2eb8 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/socket_unittest.h @@ -0,0 +1,108 @@ +/* + * Copyright 2009 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 RTC_BASE_SOCKET_UNITTEST_H_ +#define RTC_BASE_SOCKET_UNITTEST_H_ + +#include "absl/strings/string_view.h" +#include "rtc_base/gunit.h" +#include "rtc_base/thread.h" + +namespace rtc { + +// Generic socket tests, to be used when testing individual socketservers. +// Derive your specific test class from SocketTest, install your +// socketserver, and call the SocketTest test methods. +class SocketTest : public ::testing::Test { + protected: + explicit SocketTest(rtc::SocketFactory* socket_factory) + : kIPv4Loopback(INADDR_LOOPBACK), + kIPv6Loopback(in6addr_loopback), + socket_factory_(socket_factory) {} + void TestConnectIPv4(); + void TestConnectIPv6(); + void TestConnectWithDnsLookupIPv4(); + void TestConnectWithDnsLookupIPv6(); + void TestConnectFailIPv4(); + void TestConnectFailIPv6(); + void TestConnectWithDnsLookupFailIPv4(); + void TestConnectWithDnsLookupFailIPv6(); + void TestConnectWithClosedSocketIPv4(); + void TestConnectWithClosedSocketIPv6(); + void TestConnectWhileNotClosedIPv4(); + void TestConnectWhileNotClosedIPv6(); + void TestServerCloseDuringConnectIPv4(); + void TestServerCloseDuringConnectIPv6(); + void TestClientCloseDuringConnectIPv4(); + void TestClientCloseDuringConnectIPv6(); + void TestServerCloseIPv4(); + void TestServerCloseIPv6(); + void TestCloseInClosedCallbackIPv4(); + void TestCloseInClosedCallbackIPv6(); + void TestDeleteInReadCallbackIPv4(); + void TestDeleteInReadCallbackIPv6(); + void TestSocketServerWaitIPv4(); + void TestSocketServerWaitIPv6(); + void TestTcpIPv4(); + void TestTcpIPv6(); + void TestSingleFlowControlCallbackIPv4(); + void TestSingleFlowControlCallbackIPv6(); + void TestUdpIPv4(); + void TestUdpIPv6(); + void TestUdpReadyToSendIPv4(); + void TestUdpReadyToSendIPv6(); + void TestGetSetOptionsIPv4(); + void TestGetSetOptionsIPv6(); + void TestSocketRecvTimestampIPv4(); + void TestSocketRecvTimestampIPv6(); + void TestUdpSocketRecvTimestampUseRtcEpochIPv4(); + void TestUdpSocketRecvTimestampUseRtcEpochIPv6(); + + static const int kTimeout = 5000; // ms + const IPAddress kIPv4Loopback; + const IPAddress kIPv6Loopback; + + protected: + void TcpInternal(const IPAddress& loopback, + size_t data_size, + ptrdiff_t max_send_size); + + private: + void ConnectInternal(const IPAddress& loopback); + void ConnectWithDnsLookupInternal(const IPAddress& loopback, + absl::string_view host); + void ConnectFailInternal(const IPAddress& loopback); + + void ConnectWithDnsLookupFailInternal(const IPAddress& loopback); + void ConnectWithClosedSocketInternal(const IPAddress& loopback); + void ConnectWhileNotClosedInternal(const IPAddress& loopback); + void ServerCloseDuringConnectInternal(const IPAddress& loopback); + void ClientCloseDuringConnectInternal(const IPAddress& loopback); + void ServerCloseInternal(const IPAddress& loopback); + void CloseInClosedCallbackInternal(const IPAddress& loopback); + void DeleteInReadCallbackInternal(const IPAddress& loopback); + void SocketServerWaitInternal(const IPAddress& loopback); + void SingleFlowControlCallbackInternal(const IPAddress& loopback); + void UdpInternal(const IPAddress& loopback); + void UdpReadyToSend(const IPAddress& loopback); + void GetSetOptionsInternal(const IPAddress& loopback); + void SocketRecvTimestamp(const IPAddress& loopback); + void UdpSocketRecvTimestampUseRtcEpoch(const IPAddress& loopback); + + SocketFactory* socket_factory_; +}; + +// For unbound sockets, GetLocalAddress / GetRemoteAddress return AF_UNSPEC +// values on Windows, but an empty address of the same family on Linux/MacOS X. +bool IsUnspecOrEmptyIP(const IPAddress& address); + +} // namespace rtc + +#endif // RTC_BASE_SOCKET_UNITTEST_H_ diff --git a/third_party/libwebrtc/rtc_base/ssl_adapter.cc b/third_party/libwebrtc/rtc_base/ssl_adapter.cc new file mode 100644 index 0000000000..ff936a79fb --- /dev/null +++ b/third_party/libwebrtc/rtc_base/ssl_adapter.cc @@ -0,0 +1,39 @@ +/* + * 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 "rtc_base/ssl_adapter.h" + +#include "rtc_base/openssl_adapter.h" + +/////////////////////////////////////////////////////////////////////////////// + +namespace rtc { + +std::unique_ptr<SSLAdapterFactory> SSLAdapterFactory::Create() { + return std::make_unique<OpenSSLAdapterFactory>(); +} + +SSLAdapter* SSLAdapter::Create(Socket* socket) { + return new OpenSSLAdapter(socket); +} + +/////////////////////////////////////////////////////////////////////////////// + +bool InitializeSSL() { + return OpenSSLAdapter::InitializeSSL(); +} + +bool CleanupSSL() { + return OpenSSLAdapter::CleanupSSL(); +} + +/////////////////////////////////////////////////////////////////////////////// + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/ssl_adapter.h b/third_party/libwebrtc/rtc_base/ssl_adapter.h new file mode 100644 index 0000000000..4b8b9c74e0 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/ssl_adapter.h @@ -0,0 +1,124 @@ +/* + * 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 RTC_BASE_SSL_ADAPTER_H_ +#define RTC_BASE_SSL_ADAPTER_H_ + +#include <string> +#include <vector> + +#include "absl/strings/string_view.h" +#include "rtc_base/async_socket.h" +#include "rtc_base/ssl_certificate.h" +#include "rtc_base/ssl_identity.h" +#include "rtc_base/ssl_stream_adapter.h" +#include "rtc_base/system/rtc_export.h" + +namespace rtc { + +class SSLAdapter; + +// Class for creating SSL adapters with shared state, e.g., a session cache, +// which allows clients to resume SSL sessions to previously-contacted hosts. +// Clients should create the factory using Create(), set up the factory as +// needed using SetMode, and then call CreateAdapter to create adapters when +// needed. +class SSLAdapterFactory { + public: + virtual ~SSLAdapterFactory() {} + + // Specifies whether TLS or DTLS is to be used for the SSL adapters. + virtual void SetMode(SSLMode mode) = 0; + + // Specify a custom certificate verifier for SSL. + virtual void SetCertVerifier(SSLCertificateVerifier* ssl_cert_verifier) = 0; + + // Set the certificate this socket will present to incoming clients. + // Takes ownership of `identity`. + virtual void SetIdentity(std::unique_ptr<SSLIdentity> identity) = 0; + + // Choose whether the socket acts as a server socket or client socket. + virtual void SetRole(SSLRole role) = 0; + + // Methods that control server certificate verification, used in unit tests. + // Do not call these methods in production code. + virtual void SetIgnoreBadCert(bool ignore) = 0; + + // Creates a new SSL adapter, but from a shared context. + virtual SSLAdapter* CreateAdapter(Socket* socket) = 0; + + static std::unique_ptr<SSLAdapterFactory> Create(); +}; + +// Class that abstracts a client-to-server SSL session. It can be created +// standalone, via SSLAdapter::Create, or through a factory as described above, +// in which case it will share state with other SSLAdapters created from the +// same factory. +// After creation, call StartSSL to initiate the SSL handshake to the server. +class SSLAdapter : public AsyncSocketAdapter { + public: + explicit SSLAdapter(Socket* socket) : AsyncSocketAdapter(socket) {} + + // Methods that control server certificate verification, used in unit tests. + // Do not call these methods in production code. + // TODO(juberti): Remove the opportunistic encryption mechanism in + // BasicPacketSocketFactory that uses this function. + virtual void SetIgnoreBadCert(bool ignore) = 0; + + virtual void SetAlpnProtocols(const std::vector<std::string>& protos) = 0; + virtual void SetEllipticCurves(const std::vector<std::string>& curves) = 0; + + // Do DTLS or TLS (default is TLS, if unspecified) + virtual void SetMode(SSLMode mode) = 0; + // Specify a custom certificate verifier for SSL. + virtual void SetCertVerifier(SSLCertificateVerifier* ssl_cert_verifier) = 0; + + // Set the certificate this socket will present to incoming clients. + // Takes ownership of `identity`. + virtual void SetIdentity(std::unique_ptr<SSLIdentity> identity) = 0; + + // Choose whether the socket acts as a server socket or client socket. + virtual void SetRole(SSLRole role) = 0; + + // StartSSL returns 0 if successful. + // If StartSSL is called while the socket is closed or connecting, the SSL + // negotiation will begin as soon as the socket connects. + virtual int StartSSL(absl::string_view hostname) = 0; + + // When an SSLAdapterFactory is used, an SSLAdapter may be used to resume + // a previous SSL session, which results in an abbreviated handshake. + // This method, if called after SSL has been established for this adapter, + // indicates whether the current session is a resumption of a previous + // session. + virtual bool IsResumedSession() = 0; + + // Create the default SSL adapter for this platform. On failure, returns null + // and deletes `socket`. Otherwise, the returned SSLAdapter takes ownership + // of `socket`. + static SSLAdapter* Create(Socket* socket); + + private: + // Not supported. + int Listen(int backlog) override { RTC_CHECK(false); } + Socket* Accept(SocketAddress* paddr) override { RTC_CHECK(false); } +}; + +/////////////////////////////////////////////////////////////////////////////// + +// Call this on the main thread, before using SSL. +// Call CleanupSSL when finished with SSL. +RTC_EXPORT bool InitializeSSL(); + +// Call to cleanup additional threads, and also the main thread. +RTC_EXPORT bool CleanupSSL(); + +} // namespace rtc + +#endif // RTC_BASE_SSL_ADAPTER_H_ diff --git a/third_party/libwebrtc/rtc_base/ssl_adapter_unittest.cc b/third_party/libwebrtc/rtc_base/ssl_adapter_unittest.cc new file mode 100644 index 0000000000..2da59ddbb2 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/ssl_adapter_unittest.cc @@ -0,0 +1,610 @@ +/* + * Copyright 2014 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 "rtc_base/ssl_adapter.h" + +#include <memory> +#include <string> +#include <utility> + +#include "absl/memory/memory.h" +#include "absl/strings/string_view.h" +#include "rtc_base/gunit.h" +#include "rtc_base/ip_address.h" +#include "rtc_base/message_digest.h" +#include "rtc_base/socket_stream.h" +#include "rtc_base/ssl_identity.h" +#include "rtc_base/ssl_stream_adapter.h" +#include "rtc_base/stream.h" +#include "rtc_base/string_encode.h" +#include "rtc_base/virtual_socket_server.h" +#include "test/gmock.h" + +using ::testing::_; +using ::testing::Return; + +static const int kTimeout = 5000; + +static rtc::Socket* CreateSocket(const rtc::SSLMode& ssl_mode) { + rtc::SocketAddress address(rtc::IPAddress(INADDR_ANY), 0); + + rtc::Socket* socket = rtc::Thread::Current()->socketserver()->CreateSocket( + address.family(), + (ssl_mode == rtc::SSL_MODE_DTLS) ? SOCK_DGRAM : SOCK_STREAM); + socket->Bind(address); + + return socket; +} + +static std::string GetSSLProtocolName(const rtc::SSLMode& ssl_mode) { + return (ssl_mode == rtc::SSL_MODE_DTLS) ? "DTLS" : "TLS"; +} + +// Simple mock for the certificate verifier. +class MockCertVerifier : public rtc::SSLCertificateVerifier { + public: + virtual ~MockCertVerifier() = default; + MOCK_METHOD(bool, Verify, (const rtc::SSLCertificate&), (override)); +}; + +// TODO(benwright) - Move to using INSTANTIATE_TEST_SUITE_P instead of using +// duplicate test cases for simple parameter changes. +class SSLAdapterTestDummyClient : public sigslot::has_slots<> { + public: + explicit SSLAdapterTestDummyClient(const rtc::SSLMode& ssl_mode) + : ssl_mode_(ssl_mode) { + rtc::Socket* socket = CreateSocket(ssl_mode_); + + ssl_adapter_.reset(rtc::SSLAdapter::Create(socket)); + + ssl_adapter_->SetMode(ssl_mode_); + + // Ignore any certificate errors for the purpose of testing. + // Note: We do this only because we don't have a real certificate. + // NEVER USE THIS IN PRODUCTION CODE! + ssl_adapter_->SetIgnoreBadCert(true); + + ssl_adapter_->SignalReadEvent.connect( + this, &SSLAdapterTestDummyClient::OnSSLAdapterReadEvent); + ssl_adapter_->SignalCloseEvent.connect( + this, &SSLAdapterTestDummyClient::OnSSLAdapterCloseEvent); + } + + void SetIgnoreBadCert(bool ignore_bad_cert) { + ssl_adapter_->SetIgnoreBadCert(ignore_bad_cert); + } + + void SetCertVerifier(rtc::SSLCertificateVerifier* ssl_cert_verifier) { + ssl_adapter_->SetCertVerifier(ssl_cert_verifier); + } + + void SetAlpnProtocols(const std::vector<std::string>& protos) { + ssl_adapter_->SetAlpnProtocols(protos); + } + + void SetEllipticCurves(const std::vector<std::string>& curves) { + ssl_adapter_->SetEllipticCurves(curves); + } + + rtc::SocketAddress GetAddress() const { + return ssl_adapter_->GetLocalAddress(); + } + + rtc::Socket::ConnState GetState() const { return ssl_adapter_->GetState(); } + + const std::string& GetReceivedData() const { return data_; } + + int Connect(absl::string_view hostname, const rtc::SocketAddress& address) { + RTC_LOG(LS_INFO) << "Initiating connection with " << address.ToString(); + + int rv = ssl_adapter_->Connect(address); + + if (rv == 0) { + RTC_LOG(LS_INFO) << "Starting " << GetSSLProtocolName(ssl_mode_) + << " handshake with " << hostname; + + if (ssl_adapter_->StartSSL(hostname) != 0) { + return -1; + } + } + + return rv; + } + + int Close() { return ssl_adapter_->Close(); } + + int Send(absl::string_view message) { + RTC_LOG(LS_INFO) << "Client sending '" << message << "'"; + + return ssl_adapter_->Send(message.data(), message.length()); + } + + void OnSSLAdapterReadEvent(rtc::Socket* socket) { + char buffer[4096] = ""; + + // Read data received from the server and store it in our internal buffer. + int read = socket->Recv(buffer, sizeof(buffer) - 1, nullptr); + if (read != -1) { + buffer[read] = '\0'; + + RTC_LOG(LS_INFO) << "Client received '" << buffer << "'"; + + data_ += buffer; + } + } + + void OnSSLAdapterCloseEvent(rtc::Socket* socket, int error) { + // OpenSSLAdapter signals handshake failure with a close event, but without + // closing the socket! Let's close the socket here. This way GetState() can + // return CS_CLOSED after failure. + if (socket->GetState() != rtc::Socket::CS_CLOSED) { + socket->Close(); + } + } + + private: + const rtc::SSLMode ssl_mode_; + + std::unique_ptr<rtc::SSLAdapter> ssl_adapter_; + + std::string data_; +}; + +class SSLAdapterTestDummyServer : public sigslot::has_slots<> { + public: + explicit SSLAdapterTestDummyServer(const rtc::SSLMode& ssl_mode, + const rtc::KeyParams& key_params) + : ssl_mode_(ssl_mode) { + // Generate a key pair and a certificate for this host. + ssl_identity_ = rtc::SSLIdentity::Create(GetHostname(), key_params); + + server_socket_.reset(CreateSocket(ssl_mode_)); + + if (ssl_mode_ == rtc::SSL_MODE_TLS) { + server_socket_->SignalReadEvent.connect( + this, &SSLAdapterTestDummyServer::OnServerSocketReadEvent); + + server_socket_->Listen(1); + } + + RTC_LOG(LS_INFO) << ((ssl_mode_ == rtc::SSL_MODE_DTLS) ? "UDP" : "TCP") + << " server listening on " + << server_socket_->GetLocalAddress().ToString(); + } + + rtc::SocketAddress GetAddress() const { + return server_socket_->GetLocalAddress(); + } + + std::string GetHostname() const { + // Since we don't have a real certificate anyway, the value here doesn't + // really matter. + return "example.com"; + } + + const std::string& GetReceivedData() const { return data_; } + + int Send(absl::string_view message) { + if (ssl_stream_adapter_ == nullptr || + ssl_stream_adapter_->GetState() != rtc::SS_OPEN) { + // No connection yet. + return -1; + } + + RTC_LOG(LS_INFO) << "Server sending '" << message << "'"; + + size_t written; + int error; + + rtc::StreamResult r = ssl_stream_adapter_->Write( + rtc::MakeArrayView(reinterpret_cast<const uint8_t*>(message.data()), + message.size()), + written, error); + if (r == rtc::SR_SUCCESS) { + return written; + } else { + return -1; + } + } + + void AcceptConnection(const rtc::SocketAddress& address) { + // Only a single connection is supported. + ASSERT_TRUE(ssl_stream_adapter_ == nullptr); + + // This is only for DTLS. + ASSERT_EQ(rtc::SSL_MODE_DTLS, ssl_mode_); + + // Transfer ownership of the socket to the SSLStreamAdapter object. + rtc::Socket* socket = server_socket_.release(); + + socket->Connect(address); + + DoHandshake(socket); + } + + void OnServerSocketReadEvent(rtc::Socket* socket) { + // Only a single connection is supported. + ASSERT_TRUE(ssl_stream_adapter_ == nullptr); + + DoHandshake(server_socket_->Accept(nullptr)); + } + + void OnSSLStreamAdapterEvent(rtc::StreamInterface* stream, int sig, int err) { + if (sig & rtc::SE_READ) { + uint8_t buffer[4096] = ""; + size_t read; + int error; + + // Read data received from the client and store it in our internal + // buffer. + rtc::StreamResult r = stream->Read(buffer, read, error); + if (r == rtc::SR_SUCCESS) { + buffer[read] = '\0'; + // Here we assume that the buffer is interpretable as string. + char* buffer_as_char = reinterpret_cast<char*>(buffer); + RTC_LOG(LS_INFO) << "Server received '" << buffer_as_char << "'"; + data_ += buffer_as_char; + } + } + } + + private: + void DoHandshake(rtc::Socket* socket) { + ssl_stream_adapter_ = rtc::SSLStreamAdapter::Create( + std::make_unique<rtc::SocketStream>(socket)); + + ssl_stream_adapter_->SetMode(ssl_mode_); + ssl_stream_adapter_->SetServerRole(); + + // SSLStreamAdapter is normally used for peer-to-peer communication, but + // here we're testing communication between a client and a server + // (e.g. a WebRTC-based application and an RFC 5766 TURN server), where + // clients are not required to provide a certificate during handshake. + // Accordingly, we must disable client authentication here. + ssl_stream_adapter_->SetClientAuthEnabledForTesting(false); + + ssl_stream_adapter_->SetIdentity(ssl_identity_->Clone()); + + // Set a bogus peer certificate digest. + unsigned char digest[20]; + size_t digest_len = sizeof(digest); + ssl_stream_adapter_->SetPeerCertificateDigest(rtc::DIGEST_SHA_1, digest, + digest_len); + + ssl_stream_adapter_->StartSSL(); + + ssl_stream_adapter_->SignalEvent.connect( + this, &SSLAdapterTestDummyServer::OnSSLStreamAdapterEvent); + } + + const rtc::SSLMode ssl_mode_; + + std::unique_ptr<rtc::Socket> server_socket_; + std::unique_ptr<rtc::SSLStreamAdapter> ssl_stream_adapter_; + + std::unique_ptr<rtc::SSLIdentity> ssl_identity_; + + std::string data_; +}; + +class SSLAdapterTestBase : public ::testing::Test, public sigslot::has_slots<> { + public: + explicit SSLAdapterTestBase(const rtc::SSLMode& ssl_mode, + const rtc::KeyParams& key_params) + : ssl_mode_(ssl_mode), + vss_(new rtc::VirtualSocketServer()), + thread_(vss_.get()), + server_(new SSLAdapterTestDummyServer(ssl_mode_, key_params)), + client_(new SSLAdapterTestDummyClient(ssl_mode_)), + handshake_wait_(kTimeout) {} + + void SetHandshakeWait(int wait) { handshake_wait_ = wait; } + + void SetIgnoreBadCert(bool ignore_bad_cert) { + client_->SetIgnoreBadCert(ignore_bad_cert); + } + + void SetCertVerifier(rtc::SSLCertificateVerifier* ssl_cert_verifier) { + client_->SetCertVerifier(ssl_cert_verifier); + } + + void SetAlpnProtocols(const std::vector<std::string>& protos) { + client_->SetAlpnProtocols(protos); + } + + void SetEllipticCurves(const std::vector<std::string>& curves) { + client_->SetEllipticCurves(curves); + } + + void SetMockCertVerifier(bool return_value) { + auto mock_verifier = std::make_unique<MockCertVerifier>(); + EXPECT_CALL(*mock_verifier, Verify(_)).WillRepeatedly(Return(return_value)); + cert_verifier_ = + std::unique_ptr<rtc::SSLCertificateVerifier>(std::move(mock_verifier)); + + SetIgnoreBadCert(false); + SetCertVerifier(cert_verifier_.get()); + } + + void TestHandshake(bool expect_success) { + int rv; + + // The initial state is CS_CLOSED + ASSERT_EQ(rtc::Socket::CS_CLOSED, client_->GetState()); + + rv = client_->Connect(server_->GetHostname(), server_->GetAddress()); + ASSERT_EQ(0, rv); + + // Now the state should be CS_CONNECTING + ASSERT_EQ(rtc::Socket::CS_CONNECTING, client_->GetState()); + + if (ssl_mode_ == rtc::SSL_MODE_DTLS) { + // For DTLS, call AcceptConnection() with the client's address. + server_->AcceptConnection(client_->GetAddress()); + } + + if (expect_success) { + // If expecting success, the client should end up in the CS_CONNECTED + // state after handshake. + EXPECT_EQ_WAIT(rtc::Socket::CS_CONNECTED, client_->GetState(), + handshake_wait_); + + RTC_LOG(LS_INFO) << GetSSLProtocolName(ssl_mode_) + << " handshake complete."; + + } else { + // On handshake failure the client should end up in the CS_CLOSED state. + EXPECT_EQ_WAIT(rtc::Socket::CS_CLOSED, client_->GetState(), + handshake_wait_); + + RTC_LOG(LS_INFO) << GetSSLProtocolName(ssl_mode_) << " handshake failed."; + } + } + + void TestTransfer(absl::string_view message) { + int rv; + + rv = client_->Send(message); + ASSERT_EQ(static_cast<int>(message.length()), rv); + + // The server should have received the client's message. + EXPECT_EQ_WAIT(message, server_->GetReceivedData(), kTimeout); + + rv = server_->Send(message); + ASSERT_EQ(static_cast<int>(message.length()), rv); + + // The client should have received the server's message. + EXPECT_EQ_WAIT(message, client_->GetReceivedData(), kTimeout); + + RTC_LOG(LS_INFO) << "Transfer complete."; + } + + protected: + const rtc::SSLMode ssl_mode_; + + std::unique_ptr<rtc::VirtualSocketServer> vss_; + rtc::AutoSocketServerThread thread_; + std::unique_ptr<SSLAdapterTestDummyServer> server_; + std::unique_ptr<SSLAdapterTestDummyClient> client_; + std::unique_ptr<rtc::SSLCertificateVerifier> cert_verifier_; + + int handshake_wait_; +}; + +class SSLAdapterTestTLS_RSA : public SSLAdapterTestBase { + public: + SSLAdapterTestTLS_RSA() + : SSLAdapterTestBase(rtc::SSL_MODE_TLS, rtc::KeyParams::RSA()) {} +}; + +class SSLAdapterTestTLS_ECDSA : public SSLAdapterTestBase { + public: + SSLAdapterTestTLS_ECDSA() + : SSLAdapterTestBase(rtc::SSL_MODE_TLS, rtc::KeyParams::ECDSA()) {} +}; + +class SSLAdapterTestDTLS_RSA : public SSLAdapterTestBase { + public: + SSLAdapterTestDTLS_RSA() + : SSLAdapterTestBase(rtc::SSL_MODE_DTLS, rtc::KeyParams::RSA()) {} +}; + +class SSLAdapterTestDTLS_ECDSA : public SSLAdapterTestBase { + public: + SSLAdapterTestDTLS_ECDSA() + : SSLAdapterTestBase(rtc::SSL_MODE_DTLS, rtc::KeyParams::ECDSA()) {} +}; + +// Basic tests: TLS + +// Test that handshake works, using RSA +TEST_F(SSLAdapterTestTLS_RSA, TestTLSConnect) { + TestHandshake(true); +} + +// Test that handshake works with a custom verifier that returns true. RSA. +TEST_F(SSLAdapterTestTLS_RSA, TestTLSConnectCustomCertVerifierSucceeds) { + SetMockCertVerifier(/*return_value=*/true); + TestHandshake(/*expect_success=*/true); +} + +// Test that handshake fails with a custom verifier that returns false. RSA. +TEST_F(SSLAdapterTestTLS_RSA, TestTLSConnectCustomCertVerifierFails) { + SetMockCertVerifier(/*return_value=*/false); + TestHandshake(/*expect_success=*/false); +} + +// Test that handshake works, using ECDSA +TEST_F(SSLAdapterTestTLS_ECDSA, TestTLSConnect) { + SetMockCertVerifier(/*return_value=*/true); + TestHandshake(/*expect_success=*/true); +} + +// Test that handshake works with a custom verifier that returns true. ECDSA. +TEST_F(SSLAdapterTestTLS_ECDSA, TestTLSConnectCustomCertVerifierSucceeds) { + SetMockCertVerifier(/*return_value=*/true); + TestHandshake(/*expect_success=*/true); +} + +// Test that handshake fails with a custom verifier that returns false. ECDSA. +TEST_F(SSLAdapterTestTLS_ECDSA, TestTLSConnectCustomCertVerifierFails) { + SetMockCertVerifier(/*return_value=*/false); + TestHandshake(/*expect_success=*/false); +} + +// Test transfer between client and server, using RSA +TEST_F(SSLAdapterTestTLS_RSA, TestTLSTransfer) { + TestHandshake(true); + TestTransfer("Hello, world!"); +} + +// Test transfer between client and server, using RSA with custom cert verifier. +TEST_F(SSLAdapterTestTLS_RSA, TestTLSTransferCustomCertVerifier) { + SetMockCertVerifier(/*return_value=*/true); + TestHandshake(/*expect_success=*/true); + TestTransfer("Hello, world!"); +} + +TEST_F(SSLAdapterTestTLS_RSA, TestTLSTransferWithBlockedSocket) { + TestHandshake(true); + + // Tell the underlying socket to simulate being blocked. + vss_->SetSendingBlocked(true); + + std::string expected; + int rv; + // Send messages until the SSL socket adapter starts applying backpressure. + // Note that this may not occur immediately since there may be some amount of + // intermediate buffering (either in our code or in BoringSSL). + for (int i = 0; i < 1024; ++i) { + std::string message = "Hello, world: " + rtc::ToString(i); + rv = client_->Send(message); + if (rv != static_cast<int>(message.size())) { + // This test assumes either the whole message or none of it is sent. + ASSERT_EQ(-1, rv); + break; + } + expected += message; + } + // Assert that the loop above exited due to Send returning -1. + ASSERT_EQ(-1, rv); + + // Try sending another message while blocked. -1 should be returned again and + // it shouldn't end up received by the server later. + EXPECT_EQ(-1, client_->Send("Never sent")); + + // Unblock the underlying socket. All of the buffered messages should be sent + // without any further action. + vss_->SetSendingBlocked(false); + EXPECT_EQ_WAIT(expected, server_->GetReceivedData(), kTimeout); + + // Send another message. This previously wasn't working + std::string final_message = "Fin."; + expected += final_message; + EXPECT_EQ(static_cast<int>(final_message.size()), + client_->Send(final_message)); + EXPECT_EQ_WAIT(expected, server_->GetReceivedData(), kTimeout); +} + +// Test transfer between client and server, using ECDSA +TEST_F(SSLAdapterTestTLS_ECDSA, TestTLSTransfer) { + TestHandshake(true); + TestTransfer("Hello, world!"); +} + +// Test transfer between client and server, using ECDSA with custom cert +// verifier. +TEST_F(SSLAdapterTestTLS_ECDSA, TestTLSTransferCustomCertVerifier) { + SetMockCertVerifier(/*return_value=*/true); + TestHandshake(/*expect_success=*/true); + TestTransfer("Hello, world!"); +} + +// Test transfer using ALPN with protos as h2 and http/1.1 +TEST_F(SSLAdapterTestTLS_ECDSA, TestTLSALPN) { + std::vector<std::string> alpn_protos{"h2", "http/1.1"}; + SetAlpnProtocols(alpn_protos); + TestHandshake(true); + TestTransfer("Hello, world!"); +} + +// Test transfer with TLS Elliptic curves set to "X25519:P-256:P-384:P-521" +TEST_F(SSLAdapterTestTLS_ECDSA, TestTLSEllipticCurves) { + std::vector<std::string> elliptic_curves{"X25519", "P-256", "P-384", "P-521"}; + SetEllipticCurves(elliptic_curves); + TestHandshake(true); + TestTransfer("Hello, world!"); +} + +// Basic tests: DTLS + +// Test that handshake works, using RSA +TEST_F(SSLAdapterTestDTLS_RSA, TestDTLSConnect) { + TestHandshake(true); +} + +// Test that handshake works with a custom verifier that returns true. DTLS_RSA. +TEST_F(SSLAdapterTestDTLS_RSA, TestDTLSConnectCustomCertVerifierSucceeds) { + SetMockCertVerifier(/*return_value=*/true); + TestHandshake(/*expect_success=*/true); +} + +// Test that handshake fails with a custom verifier that returns false. +// DTLS_RSA. +TEST_F(SSLAdapterTestDTLS_RSA, TestTLSConnectCustomCertVerifierFails) { + SetMockCertVerifier(/*return_value=*/false); + TestHandshake(/*expect_success=*/false); +} + +// Test that handshake works, using ECDSA +TEST_F(SSLAdapterTestDTLS_ECDSA, TestDTLSConnect) { + TestHandshake(true); +} + +// Test that handshake works with a custom verifier that returns true. +// DTLS_ECDSA. +TEST_F(SSLAdapterTestDTLS_ECDSA, TestDTLSConnectCustomCertVerifierSucceeds) { + SetMockCertVerifier(/*return_value=*/true); + TestHandshake(/*expect_success=*/true); +} + +// Test that handshake fails with a custom verifier that returns false. +// DTLS_ECDSA. +TEST_F(SSLAdapterTestDTLS_ECDSA, TestTLSConnectCustomCertVerifierFails) { + SetMockCertVerifier(/*return_value=*/false); + TestHandshake(/*expect_success=*/false); +} + +// Test transfer between client and server, using RSA +TEST_F(SSLAdapterTestDTLS_RSA, TestDTLSTransfer) { + TestHandshake(true); + TestTransfer("Hello, world!"); +} + +// Test transfer between client and server, using RSA with custom cert verifier. +TEST_F(SSLAdapterTestDTLS_RSA, TestDTLSTransferCustomCertVerifier) { + SetMockCertVerifier(/*return_value=*/true); + TestHandshake(/*expect_success=*/true); + TestTransfer("Hello, world!"); +} + +// Test transfer between client and server, using ECDSA +TEST_F(SSLAdapterTestDTLS_ECDSA, TestDTLSTransfer) { + TestHandshake(true); + TestTransfer("Hello, world!"); +} + +// Test transfer between client and server, using ECDSA with custom cert +// verifier. +TEST_F(SSLAdapterTestDTLS_ECDSA, TestDTLSTransferCustomCertVerifier) { + SetMockCertVerifier(/*return_value=*/true); + TestHandshake(/*expect_success=*/true); + TestTransfer("Hello, world!"); +} diff --git a/third_party/libwebrtc/rtc_base/ssl_certificate.cc b/third_party/libwebrtc/rtc_base/ssl_certificate.cc new file mode 100644 index 0000000000..d1fd57fca5 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/ssl_certificate.cc @@ -0,0 +1,139 @@ +/* + * 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 "rtc_base/ssl_certificate.h" + +#include <memory> +#include <string> +#include <utility> + +#include "absl/algorithm/container.h" +#include "absl/strings/string_view.h" +#include "rtc_base/checks.h" +#include "rtc_base/openssl.h" +#ifdef OPENSSL_IS_BORINGSSL +#include "rtc_base/boringssl_identity.h" +#else +#include "rtc_base/openssl_identity.h" +#endif +#include "rtc_base/ssl_fingerprint.h" +#include "rtc_base/third_party/base64/base64.h" + +namespace rtc { + +////////////////////////////////////////////////////////////////////// +// SSLCertificateStats +////////////////////////////////////////////////////////////////////// + +SSLCertificateStats::SSLCertificateStats( + std::string&& fingerprint, + std::string&& fingerprint_algorithm, + std::string&& base64_certificate, + std::unique_ptr<SSLCertificateStats> issuer) + : fingerprint(std::move(fingerprint)), + fingerprint_algorithm(std::move(fingerprint_algorithm)), + base64_certificate(std::move(base64_certificate)), + issuer(std::move(issuer)) {} + +SSLCertificateStats::~SSLCertificateStats() {} + +std::unique_ptr<SSLCertificateStats> SSLCertificateStats::Copy() const { + return std::make_unique<SSLCertificateStats>( + std::string(fingerprint), std::string(fingerprint_algorithm), + std::string(base64_certificate), issuer ? issuer->Copy() : nullptr); +} + +////////////////////////////////////////////////////////////////////// +// SSLCertificate +////////////////////////////////////////////////////////////////////// + +std::unique_ptr<SSLCertificateStats> SSLCertificate::GetStats() const { + // TODO(bemasc): Move this computation to a helper class that caches these + // values to reduce CPU use in `StatsCollector::GetStats`. This will require + // adding a fast `SSLCertificate::Equals` to detect certificate changes. + std::string digest_algorithm; + if (!GetSignatureDigestAlgorithm(&digest_algorithm)) + return nullptr; + + // `SSLFingerprint::Create` can fail if the algorithm returned by + // `SSLCertificate::GetSignatureDigestAlgorithm` is not supported by the + // implementation of `SSLCertificate::ComputeDigest`. This currently happens + // with MD5- and SHA-224-signed certificates when linked to libNSS. + std::unique_ptr<SSLFingerprint> ssl_fingerprint = + SSLFingerprint::Create(digest_algorithm, *this); + if (!ssl_fingerprint) + return nullptr; + std::string fingerprint = ssl_fingerprint->GetRfc4572Fingerprint(); + + Buffer der_buffer; + ToDER(&der_buffer); + std::string der_base64; + Base64::EncodeFromArray(der_buffer.data(), der_buffer.size(), &der_base64); + + return std::make_unique<SSLCertificateStats>(std::move(fingerprint), + std::move(digest_algorithm), + std::move(der_base64), nullptr); +} + +////////////////////////////////////////////////////////////////////// +// SSLCertChain +////////////////////////////////////////////////////////////////////// + +SSLCertChain::SSLCertChain(std::unique_ptr<SSLCertificate> single_cert) { + certs_.push_back(std::move(single_cert)); +} + +SSLCertChain::SSLCertChain(std::vector<std::unique_ptr<SSLCertificate>> certs) + : certs_(std::move(certs)) {} + +SSLCertChain::SSLCertChain(SSLCertChain&& rhs) = default; + +SSLCertChain& SSLCertChain::operator=(SSLCertChain&&) = default; + +SSLCertChain::~SSLCertChain() = default; + +std::unique_ptr<SSLCertChain> SSLCertChain::Clone() const { + std::vector<std::unique_ptr<SSLCertificate>> new_certs(certs_.size()); + absl::c_transform( + certs_, new_certs.begin(), + [](const std::unique_ptr<SSLCertificate>& cert) + -> std::unique_ptr<SSLCertificate> { return cert->Clone(); }); + return std::make_unique<SSLCertChain>(std::move(new_certs)); +} + +std::unique_ptr<SSLCertificateStats> SSLCertChain::GetStats() const { + // We have a linked list of certificates, starting with the first element of + // `certs_` and ending with the last element of `certs_`. The "issuer" of a + // certificate is the next certificate in the chain. Stats are produced for + // each certificate in the list. Here, the "issuer" is the issuer's stats. + std::unique_ptr<SSLCertificateStats> issuer; + // The loop runs in reverse so that the `issuer` is known before the + // certificate issued by `issuer`. + for (ptrdiff_t i = certs_.size() - 1; i >= 0; --i) { + std::unique_ptr<SSLCertificateStats> new_stats = certs_[i]->GetStats(); + if (new_stats) { + new_stats->issuer = std::move(issuer); + } + issuer = std::move(new_stats); + } + return issuer; +} + +// static +std::unique_ptr<SSLCertificate> SSLCertificate::FromPEMString( + absl::string_view pem_string) { +#ifdef OPENSSL_IS_BORINGSSL + return BoringSSLCertificate::FromPEMString(pem_string); +#else + return OpenSSLCertificate::FromPEMString(pem_string); +#endif +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/ssl_certificate.h b/third_party/libwebrtc/rtc_base/ssl_certificate.h new file mode 100644 index 0000000000..2e198800c4 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/ssl_certificate.h @@ -0,0 +1,142 @@ +/* + * 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. + */ + +// Generic interface for SSL Certificates, used in both the SSLAdapter +// for TLS TURN connections and the SSLStreamAdapter for DTLS Peer to Peer +// Connections for SRTP Key negotiation and SCTP encryption. + +#ifndef RTC_BASE_SSL_CERTIFICATE_H_ +#define RTC_BASE_SSL_CERTIFICATE_H_ + +#include <stddef.h> +#include <stdint.h> + +#include <memory> +#include <string> +#include <vector> + +#include "absl/strings/string_view.h" +#include "rtc_base/buffer.h" +#include "rtc_base/system/rtc_export.h" + +namespace rtc { + +struct RTC_EXPORT SSLCertificateStats { + SSLCertificateStats(std::string&& fingerprint, + std::string&& fingerprint_algorithm, + std::string&& base64_certificate, + std::unique_ptr<SSLCertificateStats> issuer); + ~SSLCertificateStats(); + std::string fingerprint; + std::string fingerprint_algorithm; + std::string base64_certificate; + std::unique_ptr<SSLCertificateStats> issuer; + + std::unique_ptr<SSLCertificateStats> Copy() const; +}; + +// Abstract interface overridden by SSL library specific +// implementations. + +// A somewhat opaque type used to encapsulate a certificate. +// Wraps the SSL library's notion of a certificate, with reference counting. +// The SSLCertificate object is pretty much immutable once created. +// (The OpenSSL implementation only does reference counting and +// possibly caching of intermediate results.) +class RTC_EXPORT SSLCertificate { + public: + // Parses and builds a certificate from a PEM encoded string. + // Returns null on failure. + // The length of the string representation of the certificate is + // stored in *pem_length if it is non-null, and only if + // parsing was successful. + static std::unique_ptr<SSLCertificate> FromPEMString( + absl::string_view pem_string); + virtual ~SSLCertificate() = default; + + // Returns a new SSLCertificate object instance wrapping the same + // underlying certificate, including its chain if present. + virtual std::unique_ptr<SSLCertificate> Clone() const = 0; + + // Returns a PEM encoded string representation of the certificate. + virtual std::string ToPEMString() const = 0; + + // Provides a DER encoded binary representation of the certificate. + virtual void ToDER(Buffer* der_buffer) const = 0; + + // Gets the name of the digest algorithm that was used to compute this + // certificate's signature. + virtual bool GetSignatureDigestAlgorithm(std::string* algorithm) const = 0; + + // Compute the digest of the certificate given algorithm + virtual bool ComputeDigest(absl::string_view algorithm, + unsigned char* digest, + size_t size, + size_t* length) const = 0; + + // Returns the time in seconds relative to epoch, 1970-01-01T00:00:00Z (UTC), + // or -1 if an expiration time could not be retrieved. + virtual int64_t CertificateExpirationTime() const = 0; + + // Gets information (fingerprint, etc.) about this certificate. This is used + // for certificate stats, see + // https://w3c.github.io/webrtc-stats/#certificatestats-dict*. + std::unique_ptr<SSLCertificateStats> GetStats() const; +}; + +// SSLCertChain is a simple wrapper for a vector of SSLCertificates. It serves +// primarily to ensure proper memory management (especially deletion) of the +// SSLCertificate pointers. +class RTC_EXPORT SSLCertChain final { + public: + explicit SSLCertChain(std::unique_ptr<SSLCertificate> single_cert); + explicit SSLCertChain(std::vector<std::unique_ptr<SSLCertificate>> certs); + // Allow move semantics for the object. + SSLCertChain(SSLCertChain&&); + SSLCertChain& operator=(SSLCertChain&&); + + ~SSLCertChain(); + + SSLCertChain(const SSLCertChain&) = delete; + SSLCertChain& operator=(const SSLCertChain&) = delete; + + // Vector access methods. + size_t GetSize() const { return certs_.size(); } + + // Returns a temporary reference, only valid until the chain is destroyed. + const SSLCertificate& Get(size_t pos) const { return *(certs_[pos]); } + + // Returns a new SSLCertChain object instance wrapping the same underlying + // certificate chain. + std::unique_ptr<SSLCertChain> Clone() const; + + // Gets information (fingerprint, etc.) about this certificate chain. This is + // used for certificate stats, see + // https://w3c.github.io/webrtc-stats/#certificatestats-dict*. + std::unique_ptr<SSLCertificateStats> GetStats() const; + + private: + std::vector<std::unique_ptr<SSLCertificate>> certs_; +}; + +// SSLCertificateVerifier provides a simple interface to allow third parties to +// define their own certificate verification code. It is completely independent +// from the underlying SSL implementation. +class SSLCertificateVerifier { + public: + virtual ~SSLCertificateVerifier() = default; + // Returns true if the certificate is valid, else false. It is up to the + // implementer to define what a valid certificate looks like. + virtual bool Verify(const SSLCertificate& certificate) = 0; +}; + +} // namespace rtc + +#endif // RTC_BASE_SSL_CERTIFICATE_H_ diff --git a/third_party/libwebrtc/rtc_base/ssl_fingerprint.cc b/third_party/libwebrtc/rtc_base/ssl_fingerprint.cc new file mode 100644 index 0000000000..a43bb159c3 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/ssl_fingerprint.cc @@ -0,0 +1,127 @@ +/* + * Copyright 2012 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 "rtc_base/ssl_fingerprint.h" + +#include <ctype.h> + +#include <cstdint> +#include <memory> +#include <string> + +#include "absl/algorithm/container.h" +#include "absl/strings/string_view.h" +#include "api/array_view.h" +#include "rtc_base/logging.h" +#include "rtc_base/message_digest.h" +#include "rtc_base/rtc_certificate.h" +#include "rtc_base/ssl_certificate.h" +#include "rtc_base/ssl_identity.h" +#include "rtc_base/string_encode.h" + +namespace rtc { + +SSLFingerprint* SSLFingerprint::Create(absl::string_view algorithm, + const rtc::SSLIdentity* identity) { + return CreateUnique(algorithm, *identity).release(); +} + +std::unique_ptr<SSLFingerprint> SSLFingerprint::CreateUnique( + absl::string_view algorithm, + const rtc::SSLIdentity& identity) { + return Create(algorithm, identity.certificate()); +} + +std::unique_ptr<SSLFingerprint> SSLFingerprint::Create( + absl::string_view algorithm, + const rtc::SSLCertificate& cert) { + uint8_t digest_val[64]; + size_t digest_len; + bool ret = cert.ComputeDigest(algorithm, digest_val, sizeof(digest_val), + &digest_len); + if (!ret) { + return nullptr; + } + return std::make_unique<SSLFingerprint>( + algorithm, ArrayView<const uint8_t>(digest_val, digest_len)); +} + +SSLFingerprint* SSLFingerprint::CreateFromRfc4572( + absl::string_view algorithm, + absl::string_view fingerprint) { + return CreateUniqueFromRfc4572(algorithm, fingerprint).release(); +} + +std::unique_ptr<SSLFingerprint> SSLFingerprint::CreateUniqueFromRfc4572( + absl::string_view algorithm, + absl::string_view fingerprint) { + if (algorithm.empty() || !rtc::IsFips180DigestAlgorithm(algorithm)) + return nullptr; + + if (fingerprint.empty()) + return nullptr; + + char value[rtc::MessageDigest::kMaxSize]; + size_t value_len = + rtc::hex_decode_with_delimiter(ArrayView<char>(value), fingerprint, ':'); + if (!value_len) + return nullptr; + + return std::make_unique<SSLFingerprint>( + algorithm, + ArrayView<const uint8_t>(reinterpret_cast<uint8_t*>(value), value_len)); +} + +std::unique_ptr<SSLFingerprint> SSLFingerprint::CreateFromCertificate( + const RTCCertificate& cert) { + std::string digest_alg; + if (!cert.GetSSLCertificate().GetSignatureDigestAlgorithm(&digest_alg)) { + RTC_LOG(LS_ERROR) + << "Failed to retrieve the certificate's digest algorithm"; + return nullptr; + } + + std::unique_ptr<SSLFingerprint> fingerprint = + CreateUnique(digest_alg, *cert.identity()); + if (!fingerprint) { + RTC_LOG(LS_ERROR) << "Failed to create identity fingerprint, alg=" + << digest_alg; + } + return fingerprint; +} + +SSLFingerprint::SSLFingerprint(absl::string_view algorithm, + ArrayView<const uint8_t> digest_view) + : algorithm(algorithm), digest(digest_view.data(), digest_view.size()) {} + +SSLFingerprint::SSLFingerprint(absl::string_view algorithm, + const uint8_t* digest_in, + size_t digest_len) + : SSLFingerprint(algorithm, MakeArrayView(digest_in, digest_len)) {} + +bool SSLFingerprint::operator==(const SSLFingerprint& other) const { + return algorithm == other.algorithm && digest == other.digest; +} + +std::string SSLFingerprint::GetRfc4572Fingerprint() const { + std::string fingerprint = rtc::hex_encode_with_delimiter( + absl::string_view(digest.data<char>(), digest.size()), ':'); + absl::c_transform(fingerprint, fingerprint.begin(), ::toupper); + return fingerprint; +} + +std::string SSLFingerprint::ToString() const { + std::string fp_str = algorithm; + fp_str.append(" "); + fp_str.append(GetRfc4572Fingerprint()); + return fp_str; +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/ssl_fingerprint.h b/third_party/libwebrtc/rtc_base/ssl_fingerprint.h new file mode 100644 index 0000000000..cfa26dd433 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/ssl_fingerprint.h @@ -0,0 +1,77 @@ +/* + * Copyright 2012 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 RTC_BASE_SSL_FINGERPRINT_H_ +#define RTC_BASE_SSL_FINGERPRINT_H_ + +#include <stddef.h> +#include <stdint.h> + +#include <string> + +#include "absl/strings/string_view.h" +#include "rtc_base/copy_on_write_buffer.h" +#include "rtc_base/system/rtc_export.h" + +namespace rtc { + +class RTCCertificate; +class SSLCertificate; +class SSLIdentity; + +struct RTC_EXPORT SSLFingerprint { + // TODO(steveanton): Remove once downstream projects have moved off of this. + static SSLFingerprint* Create(absl::string_view algorithm, + const rtc::SSLIdentity* identity); + // TODO(steveanton): Rename to Create once projects have migrated. + static std::unique_ptr<SSLFingerprint> CreateUnique( + absl::string_view algorithm, + const rtc::SSLIdentity& identity); + + static std::unique_ptr<SSLFingerprint> Create( + absl::string_view algorithm, + const rtc::SSLCertificate& cert); + + // TODO(steveanton): Remove once downstream projects have moved off of this. + static SSLFingerprint* CreateFromRfc4572(absl::string_view algorithm, + absl::string_view fingerprint); + // TODO(steveanton): Rename to CreateFromRfc4572 once projects have migrated. + static std::unique_ptr<SSLFingerprint> CreateUniqueFromRfc4572( + absl::string_view algorithm, + absl::string_view fingerprint); + + // Creates a fingerprint from a certificate, using the same digest algorithm + // as the certificate's signature. + static std::unique_ptr<SSLFingerprint> CreateFromCertificate( + const RTCCertificate& cert); + + SSLFingerprint(absl::string_view algorithm, + ArrayView<const uint8_t> digest_view); + // TODO(steveanton): Remove once downstream projects have moved off of this. + SSLFingerprint(absl::string_view algorithm, + const uint8_t* digest_in, + size_t digest_len); + + SSLFingerprint(const SSLFingerprint& from) = default; + SSLFingerprint& operator=(const SSLFingerprint& from) = default; + + bool operator==(const SSLFingerprint& other) const; + + std::string GetRfc4572Fingerprint() const; + + std::string ToString() const; + + std::string algorithm; + rtc::CopyOnWriteBuffer digest; +}; + +} // namespace rtc + +#endif // RTC_BASE_SSL_FINGERPRINT_H_ diff --git a/third_party/libwebrtc/rtc_base/ssl_gn/moz.build b/third_party/libwebrtc/rtc_base/ssl_gn/moz.build new file mode 100644 index 0000000000..4be1ae9766 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/ssl_gn/moz.build @@ -0,0 +1,205 @@ +# 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("ssl_gn") diff --git a/third_party/libwebrtc/rtc_base/ssl_identity.cc b/third_party/libwebrtc/rtc_base/ssl_identity.cc new file mode 100644 index 0000000000..3b4232b06b --- /dev/null +++ b/third_party/libwebrtc/rtc_base/ssl_identity.cc @@ -0,0 +1,293 @@ +/* + * 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. + */ + +// Handling of certificates and keypairs for SSLStreamAdapter's peer mode. +#include "rtc_base/ssl_identity.h" + +#include <openssl/ossl_typ.h> +#include <string.h> +#include <time.h> + +#include "absl/strings/string_view.h" +#include "rtc_base/checks.h" +#ifdef OPENSSL_IS_BORINGSSL +#include "rtc_base/boringssl_identity.h" +#else +#include "rtc_base/openssl_identity.h" +#endif +#include "rtc_base/ssl_certificate.h" +#include "rtc_base/strings/string_builder.h" +#include "rtc_base/third_party/base64/base64.h" +#include "rtc_base/time_utils.h" + +namespace rtc { + +////////////////////////////////////////////////////////////////////// +// Helper Functions +////////////////////////////////////////////////////////////////////// + +namespace { +// Read `n` bytes from ASN1 number string at *`pp` and return the numeric value. +// Update *`pp` and *`np` to reflect number of read bytes. +// TODO(bugs.webrtc.org/9860) - Remove this code. +inline int ASN1ReadInt(const unsigned char** pp, size_t* np, size_t n) { + const unsigned char* p = *pp; + int x = 0; + for (size_t i = 0; i < n; i++) { + x = 10 * x + p[i] - '0'; + } + *pp = p + n; + *np = *np - n; + return x; +} + +} // namespace + +// TODO(bugs.webrtc.org/9860) - Remove this code. +int64_t ASN1TimeToSec(const unsigned char* s, size_t length, bool long_format) { + size_t bytes_left = length; + // Make sure the string ends with Z. Doing it here protects the strspn call + // from running off the end of the string in Z's absense. + if (length == 0 || s[length - 1] != 'Z') { + return -1; + } + // Make sure we only have ASCII digits so that we don't need to clutter the + // code below and ASN1ReadInt with error checking. + size_t n = strspn(reinterpret_cast<const char*>(s), "0123456789"); + if (n + 1 != length) { + return -1; + } + // Read out ASN1 year, in either 2-char "UTCTIME" or 4-char "GENERALIZEDTIME" + // format. Both format use UTC in this context. + int year = 0; + if (long_format) { + // ASN1 format: yyyymmddhh[mm[ss[.fff]]]Z where the Z is literal, but + // RFC 5280 requires us to only support exactly yyyymmddhhmmssZ. + if (bytes_left < 11) { + return -1; + } + year = ASN1ReadInt(&s, &bytes_left, 4); + year -= 1900; + } else { + // ASN1 format: yymmddhhmm[ss]Z where the Z is literal, but RFC 5280 + // requires us to only support exactly yymmddhhmmssZ. + if (bytes_left < 9) { + return -1; + } + year = ASN1ReadInt(&s, &bytes_left, 2); + // Per RFC 5280 4.1.2.5.1 + if (year < 50) { + year += 100; + } + } + + // Read out remaining ASN1 time data and store it in `tm` in documented + // std::tm format. + tm tm; + tm.tm_year = year; + tm.tm_mon = ASN1ReadInt(&s, &bytes_left, 2) - 1; + tm.tm_mday = ASN1ReadInt(&s, &bytes_left, 2); + tm.tm_hour = ASN1ReadInt(&s, &bytes_left, 2); + tm.tm_min = ASN1ReadInt(&s, &bytes_left, 2); + tm.tm_sec = ASN1ReadInt(&s, &bytes_left, 2); + + // Now just Z should remain. Its existence was asserted above. + if (bytes_left != 1) { + return -1; + } + return TmToSeconds(tm); +} + +////////////////////////////////////////////////////////////////////// +// KeyParams +////////////////////////////////////////////////////////////////////// + +const char kPemTypeCertificate[] = "CERTIFICATE"; +const char kPemTypeRsaPrivateKey[] = "RSA PRIVATE KEY"; +const char kPemTypeEcPrivateKey[] = "EC PRIVATE KEY"; + +KeyParams::KeyParams(KeyType key_type) { + if (key_type == KT_ECDSA) { + type_ = KT_ECDSA; + params_.curve = EC_NIST_P256; + } else if (key_type == KT_RSA) { + type_ = KT_RSA; + params_.rsa.mod_size = kRsaDefaultModSize; + params_.rsa.pub_exp = kRsaDefaultExponent; + } else { + RTC_DCHECK_NOTREACHED(); + } +} + +// static +KeyParams KeyParams::RSA(int mod_size, int pub_exp) { + KeyParams kt(KT_RSA); + kt.params_.rsa.mod_size = mod_size; + kt.params_.rsa.pub_exp = pub_exp; + return kt; +} + +// static +KeyParams KeyParams::ECDSA(ECCurve curve) { + KeyParams kt(KT_ECDSA); + kt.params_.curve = curve; + return kt; +} + +bool KeyParams::IsValid() const { + if (type_ == KT_RSA) { + return (params_.rsa.mod_size >= kRsaMinModSize && + params_.rsa.mod_size <= kRsaMaxModSize && + params_.rsa.pub_exp > params_.rsa.mod_size); + } else if (type_ == KT_ECDSA) { + return (params_.curve == EC_NIST_P256); + } + return false; +} + +RSAParams KeyParams::rsa_params() const { + RTC_DCHECK(type_ == KT_RSA); + return params_.rsa; +} + +ECCurve KeyParams::ec_curve() const { + RTC_DCHECK(type_ == KT_ECDSA); + return params_.curve; +} + +KeyType IntKeyTypeFamilyToKeyType(int key_type_family) { + return static_cast<KeyType>(key_type_family); +} + +////////////////////////////////////////////////////////////////////// +// SSLIdentity +////////////////////////////////////////////////////////////////////// + +bool SSLIdentity::PemToDer(absl::string_view pem_type, + absl::string_view pem_string, + std::string* der) { + // Find the inner body. We need this to fulfill the contract of returning + // pem_length. + std::string pem_type_str(pem_type); + size_t header = pem_string.find("-----BEGIN " + pem_type_str + "-----"); + if (header == absl::string_view::npos) { + return false; + } + size_t body = pem_string.find('\n', header); + if (body == absl::string_view::npos) { + return false; + } + size_t trailer = pem_string.find("-----END " + pem_type_str + "-----"); + if (trailer == absl::string_view::npos) { + return false; + } + std::string inner(pem_string.substr(body + 1, trailer - (body + 1))); + *der = Base64::Decode(inner, Base64::DO_PARSE_WHITE | Base64::DO_PAD_ANY | + Base64::DO_TERM_BUFFER); + return true; +} + +std::string SSLIdentity::DerToPem(absl::string_view pem_type, + const unsigned char* data, + size_t length) { + rtc::StringBuilder result; + result << "-----BEGIN " << pem_type << "-----\n"; + + std::string b64_encoded; + Base64::EncodeFromArray(data, length, &b64_encoded); + // Divide the Base-64 encoded data into 64-character chunks, as per 4.3.2.4 + // of RFC 1421. + static const size_t kChunkSize = 64; + size_t chunks = (b64_encoded.size() + (kChunkSize - 1)) / kChunkSize; + for (size_t i = 0, chunk_offset = 0; i < chunks; + ++i, chunk_offset += kChunkSize) { + result << b64_encoded.substr(chunk_offset, kChunkSize); + result << "\n"; + } + result << "-----END " << pem_type << "-----\n"; + return result.Release(); +} + +// static +std::unique_ptr<SSLIdentity> SSLIdentity::Create(absl::string_view common_name, + const KeyParams& key_param, + time_t certificate_lifetime) { +#ifdef OPENSSL_IS_BORINGSSL + return BoringSSLIdentity::CreateWithExpiration(common_name, key_param, + certificate_lifetime); +#else + return OpenSSLIdentity::CreateWithExpiration(common_name, key_param, + certificate_lifetime); +#endif +} + +// static +std::unique_ptr<SSLIdentity> SSLIdentity::Create(absl::string_view common_name, + const KeyParams& key_param) { + return Create(common_name, key_param, kDefaultCertificateLifetimeInSeconds); +} + +// static +std::unique_ptr<SSLIdentity> SSLIdentity::Create(absl::string_view common_name, + KeyType key_type) { + return Create(common_name, KeyParams(key_type), + kDefaultCertificateLifetimeInSeconds); +} + +// static +std::unique_ptr<SSLIdentity> SSLIdentity::CreateForTest( + const SSLIdentityParams& params) { +#ifdef OPENSSL_IS_BORINGSSL + return BoringSSLIdentity::CreateForTest(params); +#else + return OpenSSLIdentity::CreateForTest(params); +#endif +} + +// Construct an identity from a private key and a certificate. +// static +std::unique_ptr<SSLIdentity> SSLIdentity::CreateFromPEMStrings( + absl::string_view private_key, + absl::string_view certificate) { +#ifdef OPENSSL_IS_BORINGSSL + return BoringSSLIdentity::CreateFromPEMStrings(private_key, certificate); +#else + return OpenSSLIdentity::CreateFromPEMStrings(private_key, certificate); +#endif +} + +// Construct an identity from a private key and a certificate chain. +// static +std::unique_ptr<SSLIdentity> SSLIdentity::CreateFromPEMChainStrings( + absl::string_view private_key, + absl::string_view certificate_chain) { +#ifdef OPENSSL_IS_BORINGSSL + return BoringSSLIdentity::CreateFromPEMChainStrings(private_key, + certificate_chain); +#else + return OpenSSLIdentity::CreateFromPEMChainStrings(private_key, + certificate_chain); +#endif +} + +bool operator==(const SSLIdentity& a, const SSLIdentity& b) { +#ifdef OPENSSL_IS_BORINGSSL + return static_cast<const BoringSSLIdentity&>(a) == + static_cast<const BoringSSLIdentity&>(b); +#else + return static_cast<const OpenSSLIdentity&>(a) == + static_cast<const OpenSSLIdentity&>(b); +#endif +} +bool operator!=(const SSLIdentity& a, const SSLIdentity& b) { + return !(a == b); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/ssl_identity.h b/third_party/libwebrtc/rtc_base/ssl_identity.h new file mode 100644 index 0000000000..a0119bb1c4 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/ssl_identity.h @@ -0,0 +1,174 @@ +/* + * 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. + */ + +// Handling of certificates and keypairs for SSLStreamAdapter's peer mode. + +#ifndef RTC_BASE_SSL_IDENTITY_H_ +#define RTC_BASE_SSL_IDENTITY_H_ + +#include <stdint.h> + +#include <ctime> +#include <memory> +#include <string> + +#include "absl/strings/string_view.h" +#include "rtc_base/system/rtc_export.h" + +namespace rtc { + +class SSLCertChain; +class SSLCertificate; + +// KT_LAST is intended for vector declarations and loops over all key types; +// it does not represent any key type in itself. +// KT_DEFAULT is used as the default KeyType for KeyParams. +enum KeyType { KT_RSA, KT_ECDSA, KT_LAST, KT_DEFAULT = KT_ECDSA }; + +static const int kRsaDefaultModSize = 1024; +static const int kRsaDefaultExponent = 0x10001; // = 2^16+1 = 65537 +static const int kRsaMinModSize = 1024; +static const int kRsaMaxModSize = 8192; + +// Certificate default validity lifetime. +static const int kDefaultCertificateLifetimeInSeconds = + 60 * 60 * 24 * 30; // 30 days +// Certificate validity window. +// This is to compensate for slightly incorrect system clocks. +static const int kCertificateWindowInSeconds = -60 * 60 * 24; + +struct RSAParams { + unsigned int mod_size; + unsigned int pub_exp; +}; + +enum ECCurve { EC_NIST_P256, /* EC_FANCY, */ EC_LAST }; + +class RTC_EXPORT KeyParams { + public: + // Generate a KeyParams object from a simple KeyType, using default params. + explicit KeyParams(KeyType key_type = KT_DEFAULT); + + // Generate a a KeyParams for RSA with explicit parameters. + static KeyParams RSA(int mod_size = kRsaDefaultModSize, + int pub_exp = kRsaDefaultExponent); + + // Generate a a KeyParams for ECDSA specifying the curve. + static KeyParams ECDSA(ECCurve curve = EC_NIST_P256); + + // Check validity of a KeyParams object. Since the factory functions have + // no way of returning errors, this function can be called after creation + // to make sure the parameters are OK. + bool IsValid() const; + + RSAParams rsa_params() const; + + ECCurve ec_curve() const; + + KeyType type() const { return type_; } + + private: + KeyType type_; + union { + RSAParams rsa; + ECCurve curve; + } params_; +}; + +// TODO(hbos): Remove once rtc::KeyType (to be modified) and +// blink::WebRTCKeyType (to be landed) match. By using this function in Chromium +// appropriately we can change KeyType enum -> class without breaking Chromium. +KeyType IntKeyTypeFamilyToKeyType(int key_type_family); + +// Parameters for generating a certificate. If `common_name` is non-empty, it +// will be used for the certificate's subject and issuer name, otherwise a +// random string will be used. +struct SSLIdentityParams { + std::string common_name; + time_t not_before; // Absolute time since epoch in seconds. + time_t not_after; // Absolute time since epoch in seconds. + KeyParams key_params; +}; + +// Our identity in an SSL negotiation: a keypair and certificate (both +// with the same public key). +// This too is pretty much immutable once created. +class RTC_EXPORT SSLIdentity { + public: + // Generates an identity (keypair and self-signed certificate). If + // `common_name` is non-empty, it will be used for the certificate's subject + // and issuer name, otherwise a random string will be used. The key type and + // parameters are defined in `key_param`. The certificate's lifetime in + // seconds from the current time is defined in `certificate_lifetime`; it + // should be a non-negative number. + // Returns null on failure. + // Caller is responsible for freeing the returned object. + static std::unique_ptr<SSLIdentity> Create(absl::string_view common_name, + const KeyParams& key_param, + time_t certificate_lifetime); + static std::unique_ptr<SSLIdentity> Create(absl::string_view common_name, + const KeyParams& key_param); + static std::unique_ptr<SSLIdentity> Create(absl::string_view common_name, + KeyType key_type); + + // Allows fine-grained control over expiration time. + static std::unique_ptr<SSLIdentity> CreateForTest( + const SSLIdentityParams& params); + + // Construct an identity from a private key and a certificate. + static std::unique_ptr<SSLIdentity> CreateFromPEMStrings( + absl::string_view private_key, + absl::string_view certificate); + + // Construct an identity from a private key and a certificate chain. + static std::unique_ptr<SSLIdentity> CreateFromPEMChainStrings( + absl::string_view private_key, + absl::string_view certificate_chain); + + virtual ~SSLIdentity() {} + + // Returns a new SSLIdentity object instance wrapping the same + // identity information. + std::unique_ptr<SSLIdentity> Clone() const { return CloneInternal(); } + + // Returns a temporary reference to the end-entity (leaf) certificate. + virtual const SSLCertificate& certificate() const = 0; + // Returns a temporary reference to the entire certificate chain. + virtual const SSLCertChain& cert_chain() const = 0; + virtual std::string PrivateKeyToPEMString() const = 0; + virtual std::string PublicKeyToPEMString() const = 0; + + // Helpers for parsing converting between PEM and DER format. + static bool PemToDer(absl::string_view pem_type, + absl::string_view pem_string, + std::string* der); + static std::string DerToPem(absl::string_view pem_type, + const unsigned char* data, + size_t length); + + protected: + virtual std::unique_ptr<SSLIdentity> CloneInternal() const = 0; +}; + +bool operator==(const SSLIdentity& a, const SSLIdentity& b); +bool operator!=(const SSLIdentity& a, const SSLIdentity& b); + +// Convert from ASN1 time as restricted by RFC 5280 to seconds from 1970-01-01 +// 00.00 ("epoch"). If the ASN1 time cannot be read, return -1. The data at +// `s` is not 0-terminated; its char count is defined by `length`. +int64_t ASN1TimeToSec(const unsigned char* s, size_t length, bool long_format); + +extern const char kPemTypeCertificate[]; +extern const char kPemTypeRsaPrivateKey[]; +extern const char kPemTypeEcPrivateKey[]; + +} // namespace rtc + +#endif // RTC_BASE_SSL_IDENTITY_H_ diff --git a/third_party/libwebrtc/rtc_base/ssl_identity_unittest.cc b/third_party/libwebrtc/rtc_base/ssl_identity_unittest.cc new file mode 100644 index 0000000000..1f0278ac71 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/ssl_identity_unittest.cc @@ -0,0 +1,618 @@ +/* + * Copyright 2011 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 "rtc_base/ssl_identity.h" + +#include <string.h> + +#include <memory> +#include <string> +#include <vector> + +#include "absl/strings/str_replace.h" +#include "absl/strings/string_view.h" +#include "rtc_base/checks.h" +#include "rtc_base/fake_ssl_identity.h" +#include "rtc_base/helpers.h" +#include "rtc_base/logging.h" +#include "rtc_base/message_digest.h" +#include "rtc_base/ssl_fingerprint.h" +#include "test/gtest.h" + +using rtc::SSLIdentity; + +const char kTestCertificate[] = + "-----BEGIN CERTIFICATE-----\n" + "MIIB6TCCAVICAQYwDQYJKoZIhvcNAQEEBQAwWzELMAkGA1UEBhMCQVUxEzARBgNV\n" + "BAgTClF1ZWVuc2xhbmQxGjAYBgNVBAoTEUNyeXB0U29mdCBQdHkgTHRkMRswGQYD\n" + "VQQDExJUZXN0IENBICgxMDI0IGJpdCkwHhcNMDAxMDE2MjIzMTAzWhcNMDMwMTE0\n" + "MjIzMTAzWjBjMQswCQYDVQQGEwJBVTETMBEGA1UECBMKUXVlZW5zbGFuZDEaMBgG\n" + "A1UEChMRQ3J5cHRTb2Z0IFB0eSBMdGQxIzAhBgNVBAMTGlNlcnZlciB0ZXN0IGNl\n" + "cnQgKDUxMiBiaXQpMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJ+zw4Qnlf8SMVIP\n" + "Fe9GEcStgOY2Ww/dgNdhjeD8ckUJNP5VZkVDTGiXav6ooKXfX3j/7tdkuD8Ey2//\n" + "Kv7+ue0CAwEAATANBgkqhkiG9w0BAQQFAAOBgQCT0grFQeZaqYb5EYfk20XixZV4\n" + "GmyAbXMftG1Eo7qGiMhYzRwGNWxEYojf5PZkYZXvSqZ/ZXHXa4g59jK/rJNnaVGM\n" + "k+xIX8mxQvlV0n5O9PIha5BX5teZnkHKgL8aKKLKW1BK7YTngsfSzzaeame5iKfz\n" + "itAE+OjGF+PFKbwX8Q==\n" + "-----END CERTIFICATE-----\n"; + +const unsigned char kTestCertSha1[] = {0xA6, 0xC8, 0x59, 0xEA, 0xC3, 0x7E, 0x6D, + 0x33, 0xCF, 0xE2, 0x69, 0x9D, 0x74, 0xE6, + 0xF6, 0x8A, 0x9E, 0x47, 0xA7, 0xCA}; +const unsigned char kTestCertSha224[] = { + 0xd4, 0xce, 0xc6, 0xcf, 0x28, 0xcb, 0xe9, 0x77, 0x38, 0x36, + 0xcf, 0xb1, 0x3b, 0x4a, 0xd7, 0xbd, 0xae, 0x24, 0x21, 0x08, + 0xcf, 0x6a, 0x44, 0x0d, 0x3f, 0x94, 0x2a, 0x5b}; +const unsigned char kTestCertSha256[] = { + 0x41, 0x6b, 0xb4, 0x93, 0x47, 0x79, 0x77, 0x24, 0x77, 0x0b, 0x8b, + 0x2e, 0xa6, 0x2b, 0xe0, 0xf9, 0x0a, 0xed, 0x1f, 0x31, 0xa6, 0xf7, + 0x5c, 0xa1, 0x5a, 0xc4, 0xb0, 0xa2, 0xa4, 0x78, 0xb9, 0x76}; +const unsigned char kTestCertSha384[] = { + 0x42, 0x31, 0x9a, 0x79, 0x1d, 0xd6, 0x08, 0xbf, 0x3b, 0xba, 0x36, 0xd8, + 0x37, 0x4a, 0x9a, 0x75, 0xd3, 0x25, 0x6e, 0x28, 0x92, 0xbe, 0x06, 0xb7, + 0xc5, 0xa0, 0x83, 0xe3, 0x86, 0xb1, 0x03, 0xfc, 0x64, 0x47, 0xd6, 0xd8, + 0xaa, 0xd9, 0x36, 0x60, 0x04, 0xcc, 0xbe, 0x7d, 0x6a, 0xe8, 0x34, 0x49}; +const unsigned char kTestCertSha512[] = { + 0x51, 0x1d, 0xec, 0x02, 0x3d, 0x51, 0x45, 0xd3, 0xd8, 0x1d, 0xa4, + 0x9d, 0x43, 0xc9, 0xee, 0x32, 0x6f, 0x4f, 0x37, 0xee, 0xab, 0x3f, + 0x25, 0xdf, 0x72, 0xfc, 0x61, 0x1a, 0xd5, 0x92, 0xff, 0x6b, 0x28, + 0x71, 0x58, 0xb3, 0xe1, 0x8a, 0x18, 0xcf, 0x61, 0x33, 0x0e, 0x14, + 0xc3, 0x04, 0xaa, 0x07, 0xf6, 0xa5, 0xda, 0xdc, 0x42, 0x42, 0x22, + 0x35, 0xce, 0x26, 0x58, 0x4a, 0x33, 0x6d, 0xbc, 0xb6}; + +// These PEM strings were created by generating an identity with +// `SSLIdentity::Create` and invoking `identity->PrivateKeyToPEMString()`, +// `identity->PublicKeyToPEMString()` and +// `identity->certificate().ToPEMString()`. If the crypto library is updated, +// and the update changes the string form of the keys, these will have to be +// updated too. The fingerprint, fingerprint algorithm and base64 certificate +// were created by calling `identity->certificate().GetStats()`. +static const char kRSA_PRIVATE_KEY_PEM[] = + "-----BEGIN PRIVATE KEY-----\n" + "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAMQPqDStRlYeDpkX\n" + "erRmv+a1naM8vSVSY0gG2plnrnofViWRW3MRqWC+020MsIj3hPZeSAnt/y/FL/nr\n" + "4Ea7NXcwdRo1/1xEK7U/f/cjSg1aunyvHCHwcFcMr31HLFvHr0ZgcFwbgIuFLNEl\n" + "7kK5HMO9APz1ntUjek8BmBj8yMl9AgMBAAECgYA8FWBC5GcNtSBcIinkZyigF0A7\n" + "6j081sa+J/uNz4xUuI257ZXM6biygUhhvuXK06/XoIULJfhyN0fAm1yb0HtNhiUs\n" + "kMOYeon6b8FqFaPjrQf7Gr9FMiIHXNK19uegTMKztXyPZoUWlX84X0iawY95x0Y3\n" + "73f6P2rN2UOjlVVjAQJBAOKy3l2w3Zj2w0oAJox0eMwl+RxBNt1C42SHrob2mFUT\n" + "rytpVVYOasr8CoDI0kjacjI94sLum+buJoXXX6YTGO0CQQDdZwlYIEkoS3ftfxPa\n" + "Ai0YTBzAWvHJg0r8Gk/TkHo6IM+LSsZ9ZYUv/vBe4BKLw1I4hZ+bQvBiq+f8ROtk\n" + "+TDRAkAPL3ghwoU1h+IRBO2QHwUwd6K2N9AbBi4BP+168O3HVSg4ujeTKigRLMzv\n" + "T4R2iNt5bhfQgvdCgtVlxcWMdF8JAkBwDCg3eEdt5BuyjwBt8XH+/O4ED0KUWCTH\n" + "x00k5dZlupsuhE5Fwe4QpzXg3gekwdnHjyCCQ/NCDHvgOMTkmhQxAkA9V03KRX9b\n" + "bhvEzY/fu8gEp+EzsER96/D79az5z1BaMGL5OPM2xHBPJATKlswnAa7Lp3QKGZGk\n" + "TxslfL18J71s\n" + "-----END PRIVATE KEY-----\n"; +static const char kRSA_PUBLIC_KEY_PEM[] = + "-----BEGIN PUBLIC KEY-----\n" + "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDED6g0rUZWHg6ZF3q0Zr/mtZ2j\n" + "PL0lUmNIBtqZZ656H1YlkVtzEalgvtNtDLCI94T2XkgJ7f8vxS/56+BGuzV3MHUa\n" + "Nf9cRCu1P3/3I0oNWrp8rxwh8HBXDK99Ryxbx69GYHBcG4CLhSzRJe5CuRzDvQD8\n" + "9Z7VI3pPAZgY/MjJfQIDAQAB\n" + "-----END PUBLIC KEY-----\n"; +static const char kRSA_CERT_PEM[] = + "-----BEGIN CERTIFICATE-----\n" + "MIIBnDCCAQWgAwIBAgIJAOEHLgeWYwrpMA0GCSqGSIb3DQEBCwUAMBAxDjAMBgNV\n" + "BAMMBXRlc3QxMB4XDTE2MDQyNDE4MTAyMloXDTE2MDUyNTE4MTAyMlowEDEOMAwG\n" + "A1UEAwwFdGVzdDEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMQPqDStRlYe\n" + "DpkXerRmv+a1naM8vSVSY0gG2plnrnofViWRW3MRqWC+020MsIj3hPZeSAnt/y/F\n" + "L/nr4Ea7NXcwdRo1/1xEK7U/f/cjSg1aunyvHCHwcFcMr31HLFvHr0ZgcFwbgIuF\n" + "LNEl7kK5HMO9APz1ntUjek8BmBj8yMl9AgMBAAEwDQYJKoZIhvcNAQELBQADgYEA\n" + "C3ehaZFl+oEYN069C2ht/gMzuC77L854RF/x7xRtNZzkcg9TVgXXdM3auUvJi8dx\n" + "yTpU3ixErjQvoZew5ngXTEvTY8BSQUijJEaLWh8n6NDKRbEGTdAk8nPAmq9hdCFq\n" + "e3UkexqNHm3g/VxG4NUC1Y+w29ai0/Rgh+VvgbDwK+Q=\n" + "-----END CERTIFICATE-----\n"; +static const char kRSA_FINGERPRINT[] = + "3C:E8:B2:70:09:CF:A9:09:5A:F4:EF:8F:8D:8A:32:FF:EA:04:91:BA:6E:D4:17:78:16" + ":2A:EE:F9:9A:DD:E2:2B"; +static const char kRSA_FINGERPRINT_ALGORITHM[] = "sha-256"; +static const char kRSA_BASE64_CERTIFICATE[] = + "MIIBnDCCAQWgAwIBAgIJAOEHLgeWYwrpMA0GCSqGSIb3DQEBCwUAMBAxDjAMBgNVBAMMBXRlc3" + "QxMB4XDTE2MDQyNDE4MTAyMloXDTE2MDUyNTE4MTAyMlowEDEOMAwGA1UEAwwFdGVzdDEwgZ8w" + "DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMQPqDStRlYeDpkXerRmv+a1naM8vSVSY0gG2plnrn" + "ofViWRW3MRqWC+020MsIj3hPZeSAnt/y/FL/nr4Ea7NXcwdRo1/1xEK7U/f/cjSg1aunyvHCHw" + "cFcMr31HLFvHr0ZgcFwbgIuFLNEl7kK5HMO9APz1ntUjek8BmBj8yMl9AgMBAAEwDQYJKoZIhv" + "cNAQELBQADgYEAC3ehaZFl+oEYN069C2ht/gMzuC77L854RF/x7xRtNZzkcg9TVgXXdM3auUvJ" + "i8dxyTpU3ixErjQvoZew5ngXTEvTY8BSQUijJEaLWh8n6NDKRbEGTdAk8nPAmq9hdCFqe3Ukex" + "qNHm3g/VxG4NUC1Y+w29ai0/Rgh+VvgbDwK+Q="; + +static const char kECDSA_PRIVATE_KEY_PEM[] = + "-----BEGIN PRIVATE KEY-----\n" + "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg/AkEA2hklq7dQ2rN\n" + "ZxYL6hOUACL4pn7P4FYlA3ZQhIChRANCAAR7YgdO3utP/8IqVRq8G4VZKreMAxeN\n" + "rUa12twthv4uFjuHAHa9D9oyAjncmn+xvZZRyVmKrA56jRzENcEEHoAg\n" + "-----END PRIVATE KEY-----\n"; +static const char kECDSA_PUBLIC_KEY_PEM[] = + "-----BEGIN PUBLIC KEY-----\n" + "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEe2IHTt7rT//CKlUavBuFWSq3jAMX\n" + "ja1GtdrcLYb+LhY7hwB2vQ/aMgI53Jp/sb2WUclZiqwOeo0cxDXBBB6AIA==\n" + "-----END PUBLIC KEY-----\n"; +static const char kECDSA_CERT_PEM[] = + "-----BEGIN CERTIFICATE-----\n" + "MIIBFDCBu6ADAgECAgkArpkxjw62sW4wCgYIKoZIzj0EAwIwEDEOMAwGA1UEAwwF\n" + "dGVzdDMwHhcNMTYwNDI0MTgxNDM4WhcNMTYwNTI1MTgxNDM4WjAQMQ4wDAYDVQQD\n" + "DAV0ZXN0MzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABHtiB07e60//wipVGrwb\n" + "hVkqt4wDF42tRrXa3C2G/i4WO4cAdr0P2jICOdyaf7G9llHJWYqsDnqNHMQ1wQQe\n" + "gCAwCgYIKoZIzj0EAwIDSAAwRQIhANyreQ/K5yuPPpirsd0e/4WGLHou6bIOSQks\n" + "DYzo56NmAiAKOr3u8ol3LmygbUCwEvtWrS8QcJDygxHPACo99hkekw==\n" + "-----END CERTIFICATE-----\n"; +static const char kECDSA_FINGERPRINT[] = + "9F:47:FA:88:76:3D:18:B8:00:A0:59:9D:C3:5D:34:0B:1F:B8:99:9E:68:DA:F3:A5:DA" + ":50:33:A9:FF:4D:31:89"; +static const char kECDSA_FINGERPRINT_ALGORITHM[] = "sha-256"; +static const char kECDSA_BASE64_CERTIFICATE[] = + "MIIBFDCBu6ADAgECAgkArpkxjw62sW4wCgYIKoZIzj0EAwIwEDEOMAwGA1UEAwwFdGVzdDMwHh" + "cNMTYwNDI0MTgxNDM4WhcNMTYwNTI1MTgxNDM4WjAQMQ4wDAYDVQQDDAV0ZXN0MzBZMBMGByqG" + "SM49AgEGCCqGSM49AwEHA0IABHtiB07e60//wipVGrwbhVkqt4wDF42tRrXa3C2G/i4WO4cAdr" + "0P2jICOdyaf7G9llHJWYqsDnqNHMQ1wQQegCAwCgYIKoZIzj0EAwIDSAAwRQIhANyreQ/K5yuP" + "Ppirsd0e/4WGLHou6bIOSQksDYzo56NmAiAKOr3u8ol3LmygbUCwEvtWrS8QcJDygxHPACo99h" + "kekw=="; + +struct IdentityAndInfo { + std::unique_ptr<rtc::SSLIdentity> identity; + std::vector<std::string> ders; + std::vector<std::string> pems; + std::vector<std::string> fingerprints; +}; + +IdentityAndInfo CreateFakeIdentityAndInfoFromDers( + const std::vector<std::string>& ders) { + RTC_CHECK(!ders.empty()); + IdentityAndInfo info; + info.ders = ders; + for (const std::string& der : ders) { + info.pems.push_back(rtc::SSLIdentity::DerToPem( + "CERTIFICATE", reinterpret_cast<const unsigned char*>(der.c_str()), + der.length())); + } + info.identity.reset(new rtc::FakeSSLIdentity(info.pems)); + // Strip header/footer and newline characters of PEM strings. + for (size_t i = 0; i < info.pems.size(); ++i) { + absl::StrReplaceAll({{"-----BEGIN CERTIFICATE-----", ""}, + {"-----END CERTIFICATE-----", ""}, + {"\n", ""}}, + &info.pems[i]); + } + // Fingerprints for the whole certificate chain, starting with leaf + // certificate. + const rtc::SSLCertChain& chain = info.identity->cert_chain(); + std::unique_ptr<rtc::SSLFingerprint> fp; + for (size_t i = 0; i < chain.GetSize(); i++) { + fp = rtc::SSLFingerprint::Create("sha-1", chain.Get(i)); + EXPECT_TRUE(fp); + info.fingerprints.push_back(fp->GetRfc4572Fingerprint()); + } + EXPECT_EQ(info.ders.size(), info.fingerprints.size()); + return info; +} + +class SSLIdentityTest : public ::testing::Test { + public: + void SetUp() override { + identity_rsa1_ = SSLIdentity::Create("test1", rtc::KT_RSA); + identity_rsa2_ = SSLIdentity::Create("test2", rtc::KT_RSA); + identity_ecdsa1_ = SSLIdentity::Create("test3", rtc::KT_ECDSA); + identity_ecdsa2_ = SSLIdentity::Create("test4", rtc::KT_ECDSA); + + ASSERT_TRUE(identity_rsa1_); + ASSERT_TRUE(identity_rsa2_); + ASSERT_TRUE(identity_ecdsa1_); + ASSERT_TRUE(identity_ecdsa2_); + + test_cert_ = rtc::SSLCertificate::FromPEMString(kTestCertificate); + ASSERT_TRUE(test_cert_); + } + + void TestGetSignatureDigestAlgorithm() { + std::string digest_algorithm; + + ASSERT_TRUE(identity_rsa1_->certificate().GetSignatureDigestAlgorithm( + &digest_algorithm)); + ASSERT_EQ(rtc::DIGEST_SHA_256, digest_algorithm); + + ASSERT_TRUE(identity_rsa2_->certificate().GetSignatureDigestAlgorithm( + &digest_algorithm)); + ASSERT_EQ(rtc::DIGEST_SHA_256, digest_algorithm); + + ASSERT_TRUE(identity_ecdsa1_->certificate().GetSignatureDigestAlgorithm( + &digest_algorithm)); + ASSERT_EQ(rtc::DIGEST_SHA_256, digest_algorithm); + + ASSERT_TRUE(identity_ecdsa2_->certificate().GetSignatureDigestAlgorithm( + &digest_algorithm)); + ASSERT_EQ(rtc::DIGEST_SHA_256, digest_algorithm); + + // The test certificate has an MD5-based signature. + ASSERT_TRUE(test_cert_->GetSignatureDigestAlgorithm(&digest_algorithm)); + ASSERT_EQ(rtc::DIGEST_MD5, digest_algorithm); + } + + typedef unsigned char DigestType[rtc::MessageDigest::kMaxSize]; + + void TestDigestHelper(DigestType digest, + const SSLIdentity* identity, + absl::string_view algorithm, + size_t expected_len) { + DigestType digest1; + size_t digest_len; + bool rv; + + memset(digest, 0, expected_len); + rv = identity->certificate().ComputeDigest(algorithm, digest, + sizeof(DigestType), &digest_len); + EXPECT_TRUE(rv); + EXPECT_EQ(expected_len, digest_len); + + // Repeat digest computation for the identity as a sanity check. + memset(digest1, 0xff, expected_len); + rv = identity->certificate().ComputeDigest(algorithm, digest1, + sizeof(DigestType), &digest_len); + EXPECT_TRUE(rv); + EXPECT_EQ(expected_len, digest_len); + + EXPECT_EQ(0, memcmp(digest, digest1, expected_len)); + } + + void TestDigestForGeneratedCert(absl::string_view algorithm, + size_t expected_len) { + DigestType digest[4]; + + ASSERT_TRUE(expected_len <= sizeof(DigestType)); + + TestDigestHelper(digest[0], identity_rsa1_.get(), algorithm, expected_len); + TestDigestHelper(digest[1], identity_rsa2_.get(), algorithm, expected_len); + TestDigestHelper(digest[2], identity_ecdsa1_.get(), algorithm, + expected_len); + TestDigestHelper(digest[3], identity_ecdsa2_.get(), algorithm, + expected_len); + + // Sanity check that all four digests are unique. This could theoretically + // fail, since cryptographic hash collisions have a non-zero probability. + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + if (i != j) + EXPECT_NE(0, memcmp(digest[i], digest[j], expected_len)); + } + } + } + + void TestDigestForFixedCert(absl::string_view algorithm, + size_t expected_len, + const unsigned char* expected_digest) { + bool rv; + DigestType digest; + size_t digest_len; + + ASSERT_TRUE(expected_len <= sizeof(DigestType)); + + rv = test_cert_->ComputeDigest(algorithm, digest, sizeof(digest), + &digest_len); + EXPECT_TRUE(rv); + EXPECT_EQ(expected_len, digest_len); + EXPECT_EQ(0, memcmp(digest, expected_digest, expected_len)); + } + + void TestCloningIdentity(const SSLIdentity& identity) { + // Convert `identity` to PEM strings and create a new identity by converting + // back from the string format. + std::string priv_pem = identity.PrivateKeyToPEMString(); + std::string publ_pem = identity.PublicKeyToPEMString(); + std::string cert_pem = identity.certificate().ToPEMString(); + std::unique_ptr<SSLIdentity> clone = + SSLIdentity::CreateFromPEMStrings(priv_pem, cert_pem); + EXPECT_TRUE(clone); + + // Make sure the clone is identical to the original. + EXPECT_TRUE(identity == *clone); + ASSERT_EQ(identity.certificate().CertificateExpirationTime(), + clone->certificate().CertificateExpirationTime()); + + // At this point we are confident that the identities are identical. To be + // extra sure, we compare PEM strings of the clone with the original. Note + // that the PEM strings of two identities are not strictly guaranteed to be + // equal (they describe structs whose members could be listed in a different + // order, for example). But because the same function is used to produce + // both PEMs, its a good enough bet that this comparison will work. If the + // assumption stops holding in the future we can always remove this from the + // unittest. + std::string clone_priv_pem = clone->PrivateKeyToPEMString(); + std::string clone_publ_pem = clone->PublicKeyToPEMString(); + std::string clone_cert_pem = clone->certificate().ToPEMString(); + ASSERT_EQ(priv_pem, clone_priv_pem); + ASSERT_EQ(publ_pem, clone_publ_pem); + ASSERT_EQ(cert_pem, clone_cert_pem); + } + + protected: + std::unique_ptr<SSLIdentity> identity_rsa1_; + std::unique_ptr<SSLIdentity> identity_rsa2_; + std::unique_ptr<SSLIdentity> identity_ecdsa1_; + std::unique_ptr<SSLIdentity> identity_ecdsa2_; + std::unique_ptr<rtc::SSLCertificate> test_cert_; +}; + +TEST_F(SSLIdentityTest, FixedDigestSHA1) { + TestDigestForFixedCert(rtc::DIGEST_SHA_1, 20, kTestCertSha1); +} + +// HASH_AlgSHA224 is not supported in the chromium linux build. +TEST_F(SSLIdentityTest, FixedDigestSHA224) { + TestDigestForFixedCert(rtc::DIGEST_SHA_224, 28, kTestCertSha224); +} + +TEST_F(SSLIdentityTest, FixedDigestSHA256) { + TestDigestForFixedCert(rtc::DIGEST_SHA_256, 32, kTestCertSha256); +} + +TEST_F(SSLIdentityTest, FixedDigestSHA384) { + TestDigestForFixedCert(rtc::DIGEST_SHA_384, 48, kTestCertSha384); +} + +TEST_F(SSLIdentityTest, FixedDigestSHA512) { + TestDigestForFixedCert(rtc::DIGEST_SHA_512, 64, kTestCertSha512); +} + +// HASH_AlgSHA224 is not supported in the chromium linux build. +TEST_F(SSLIdentityTest, DigestSHA224) { + TestDigestForGeneratedCert(rtc::DIGEST_SHA_224, 28); +} + +TEST_F(SSLIdentityTest, DigestSHA256) { + TestDigestForGeneratedCert(rtc::DIGEST_SHA_256, 32); +} + +TEST_F(SSLIdentityTest, DigestSHA384) { + TestDigestForGeneratedCert(rtc::DIGEST_SHA_384, 48); +} + +TEST_F(SSLIdentityTest, DigestSHA512) { + TestDigestForGeneratedCert(rtc::DIGEST_SHA_512, 64); +} + +TEST_F(SSLIdentityTest, IdentityComparison) { + EXPECT_TRUE(*identity_rsa1_ == *identity_rsa1_); + EXPECT_FALSE(*identity_rsa1_ == *identity_rsa2_); + EXPECT_FALSE(*identity_rsa1_ == *identity_ecdsa1_); + EXPECT_FALSE(*identity_rsa1_ == *identity_ecdsa2_); + + EXPECT_TRUE(*identity_rsa2_ == *identity_rsa2_); + EXPECT_FALSE(*identity_rsa2_ == *identity_ecdsa1_); + EXPECT_FALSE(*identity_rsa2_ == *identity_ecdsa2_); + + EXPECT_TRUE(*identity_ecdsa1_ == *identity_ecdsa1_); + EXPECT_FALSE(*identity_ecdsa1_ == *identity_ecdsa2_); +} + +TEST_F(SSLIdentityTest, FromPEMStringsRSA) { + std::unique_ptr<SSLIdentity> identity( + SSLIdentity::CreateFromPEMStrings(kRSA_PRIVATE_KEY_PEM, kRSA_CERT_PEM)); + EXPECT_TRUE(identity); + EXPECT_EQ(kRSA_PRIVATE_KEY_PEM, identity->PrivateKeyToPEMString()); + EXPECT_EQ(kRSA_PUBLIC_KEY_PEM, identity->PublicKeyToPEMString()); + EXPECT_EQ(kRSA_CERT_PEM, identity->certificate().ToPEMString()); +} + +TEST_F(SSLIdentityTest, FromPEMStringsEC) { + std::unique_ptr<SSLIdentity> identity(SSLIdentity::CreateFromPEMStrings( + kECDSA_PRIVATE_KEY_PEM, kECDSA_CERT_PEM)); + EXPECT_TRUE(identity); + EXPECT_EQ(kECDSA_PRIVATE_KEY_PEM, identity->PrivateKeyToPEMString()); + EXPECT_EQ(kECDSA_PUBLIC_KEY_PEM, identity->PublicKeyToPEMString()); + EXPECT_EQ(kECDSA_CERT_PEM, identity->certificate().ToPEMString()); +} + +TEST_F(SSLIdentityTest, FromPEMChainStrings) { + // This doesn't form a valid certificate chain, but that doesn't matter for + // the purposes of the test + std::string chain(kRSA_CERT_PEM); + chain.append(kTestCertificate); + std::unique_ptr<SSLIdentity> identity( + SSLIdentity::CreateFromPEMChainStrings(kRSA_PRIVATE_KEY_PEM, chain)); + EXPECT_TRUE(identity); + EXPECT_EQ(kRSA_PRIVATE_KEY_PEM, identity->PrivateKeyToPEMString()); + EXPECT_EQ(kRSA_PUBLIC_KEY_PEM, identity->PublicKeyToPEMString()); + ASSERT_EQ(2u, identity->cert_chain().GetSize()); + EXPECT_EQ(kRSA_CERT_PEM, identity->cert_chain().Get(0).ToPEMString()); + EXPECT_EQ(kTestCertificate, identity->cert_chain().Get(1).ToPEMString()); +} + +TEST_F(SSLIdentityTest, CloneIdentityRSA) { + TestCloningIdentity(*identity_rsa1_); + TestCloningIdentity(*identity_rsa2_); +} + +TEST_F(SSLIdentityTest, CloneIdentityECDSA) { + TestCloningIdentity(*identity_ecdsa1_); + TestCloningIdentity(*identity_ecdsa2_); +} + +TEST_F(SSLIdentityTest, PemDerConversion) { + std::string der; + EXPECT_TRUE(SSLIdentity::PemToDer("CERTIFICATE", kTestCertificate, &der)); + + EXPECT_EQ( + kTestCertificate, + SSLIdentity::DerToPem("CERTIFICATE", + reinterpret_cast<const unsigned char*>(der.data()), + der.length())); +} + +TEST_F(SSLIdentityTest, GetSignatureDigestAlgorithm) { + TestGetSignatureDigestAlgorithm(); +} + +TEST_F(SSLIdentityTest, SSLCertificateGetStatsRSA) { + std::unique_ptr<SSLIdentity> identity( + SSLIdentity::CreateFromPEMStrings(kRSA_PRIVATE_KEY_PEM, kRSA_CERT_PEM)); + std::unique_ptr<rtc::SSLCertificateStats> stats = + identity->certificate().GetStats(); + EXPECT_EQ(stats->fingerprint, kRSA_FINGERPRINT); + EXPECT_EQ(stats->fingerprint_algorithm, kRSA_FINGERPRINT_ALGORITHM); + EXPECT_EQ(stats->base64_certificate, kRSA_BASE64_CERTIFICATE); + EXPECT_FALSE(stats->issuer); +} + +TEST_F(SSLIdentityTest, SSLCertificateGetStatsECDSA) { + std::unique_ptr<SSLIdentity> identity(SSLIdentity::CreateFromPEMStrings( + kECDSA_PRIVATE_KEY_PEM, kECDSA_CERT_PEM)); + std::unique_ptr<rtc::SSLCertificateStats> stats = + identity->certificate().GetStats(); + EXPECT_EQ(stats->fingerprint, kECDSA_FINGERPRINT); + EXPECT_EQ(stats->fingerprint_algorithm, kECDSA_FINGERPRINT_ALGORITHM); + EXPECT_EQ(stats->base64_certificate, kECDSA_BASE64_CERTIFICATE); + EXPECT_FALSE(stats->issuer); +} + +TEST_F(SSLIdentityTest, SSLCertificateGetStatsWithChain) { + std::vector<std::string> ders; + ders.push_back("every der results in"); + ders.push_back("an identity + certificate"); + ders.push_back("in a certificate chain"); + IdentityAndInfo info = CreateFakeIdentityAndInfoFromDers(ders); + EXPECT_TRUE(info.identity); + EXPECT_EQ(info.ders, ders); + EXPECT_EQ(info.pems.size(), info.ders.size()); + EXPECT_EQ(info.fingerprints.size(), info.ders.size()); + + std::unique_ptr<rtc::SSLCertificateStats> first_stats = + info.identity->cert_chain().GetStats(); + rtc::SSLCertificateStats* cert_stats = first_stats.get(); + for (size_t i = 0; i < info.ders.size(); ++i) { + EXPECT_EQ(cert_stats->fingerprint, info.fingerprints[i]); + EXPECT_EQ(cert_stats->fingerprint_algorithm, "sha-1"); + EXPECT_EQ(cert_stats->base64_certificate, info.pems[i]); + cert_stats = cert_stats->issuer.get(); + EXPECT_EQ(static_cast<bool>(cert_stats), i + 1 < info.ders.size()); + } +} + +class SSLIdentityExpirationTest : public ::testing::Test { + public: + SSLIdentityExpirationTest() { + // Set use of the test RNG to get deterministic expiration timestamp. + rtc::SetRandomTestMode(true); + } + ~SSLIdentityExpirationTest() override { + // Put it back for the next test. + rtc::SetRandomTestMode(false); + } + + void TestASN1TimeToSec() { + struct asn_example { + const char* string; + bool long_format; + int64_t want; + } static const data[] = { + // clang-format off + // clang formatting breaks this nice alignment + + // Valid examples. + {"19700101000000Z", true, 0}, + {"700101000000Z", false, 0}, + {"19700101000001Z", true, 1}, + {"700101000001Z", false, 1}, + {"19700101000100Z", true, 60}, + {"19700101000101Z", true, 61}, + {"19700101010000Z", true, 3600}, + {"19700101010001Z", true, 3601}, + {"19700101010100Z", true, 3660}, + {"19700101010101Z", true, 3661}, + {"710911012345Z", false, 53400225}, + {"20000101000000Z", true, 946684800}, + {"20000101000000Z", true, 946684800}, + {"20151130140156Z", true, 1448892116}, + {"151130140156Z", false, 1448892116}, + {"20491231235959Z", true, 2524607999}, + {"491231235959Z", false, 2524607999}, + {"20500101000000Z", true, 2524607999+1}, + {"20700101000000Z", true, 3155760000}, + {"21000101000000Z", true, 4102444800}, + {"24000101000000Z", true, 13569465600}, + + // Invalid examples. + {"19700101000000", true, -1}, // missing Z long format + {"19700101000000X", true, -1}, // X instead of Z long format + {"197001010000000", true, -1}, // 0 instead of Z long format + {"1970010100000000Z", true, -1}, // excess digits long format + {"700101000000", false, -1}, // missing Z short format + {"700101000000X", false, -1}, // X instead of Z short format + {"7001010000000", false, -1}, // 0 instead of Z short format + {"70010100000000Z", false, -1}, // excess digits short format + {":9700101000000Z", true, -1}, // invalid character + {"1:700101000001Z", true, -1}, // invalid character + {"19:00101000100Z", true, -1}, // invalid character + {"197:0101000101Z", true, -1}, // invalid character + {"1970:101010000Z", true, -1}, // invalid character + {"19700:01010001Z", true, -1}, // invalid character + {"197001:1010100Z", true, -1}, // invalid character + {"1970010:010101Z", true, -1}, // invalid character + {"70010100:000Z", false, -1}, // invalid character + {"700101000:01Z", false, -1}, // invalid character + {"2000010100:000Z", true, -1}, // invalid character + {"21000101000:00Z", true, -1}, // invalid character + {"240001010000:0Z", true, -1}, // invalid character + {"500101000000Z", false, -1}, // but too old for epoch + {"691231235959Z", false, -1}, // too old for epoch + {"19611118043000Z", false, -1}, // way too old for epoch + + // clang-format off + }; + + unsigned char buf[20]; + + // Run all examples and check for the expected result. + for (const auto& entry : data) { + size_t length = strlen(entry.string); + memcpy(buf, entry.string, length); // Copy the ASN1 string... + buf[length] = rtc::CreateRandomId(); // ...and terminate it with junk. + int64_t res = rtc::ASN1TimeToSec(buf, length, entry.long_format); + RTC_LOG(LS_VERBOSE) << entry.string; + ASSERT_EQ(entry.want, res); + } + // Run all examples again, but with an invalid length. + for (const auto& entry : data) { + size_t length = strlen(entry.string); + memcpy(buf, entry.string, length); // Copy the ASN1 string... + buf[length] = rtc::CreateRandomId(); // ...and terminate it with junk. + int64_t res = rtc::ASN1TimeToSec(buf, length - 1, entry.long_format); + RTC_LOG(LS_VERBOSE) << entry.string; + ASSERT_EQ(-1, res); + } + } + + void TestExpireTime(int times) { + // We test just ECDSA here since what we're out to exercise is the + // interfaces for expiration setting and reading. + for (int i = 0; i < times; i++) { + // We limit the time to < 2^31 here, i.e., we stay before 2038, since else + // we hit time offset limitations in OpenSSL on some 32-bit systems. + time_t time_before_generation = time(nullptr); + time_t lifetime = + rtc::CreateRandomId() % (0x80000000 - time_before_generation); + rtc::KeyParams key_params = rtc::KeyParams::ECDSA(rtc::EC_NIST_P256); + auto identity = + rtc::SSLIdentity::Create("", key_params, lifetime); + time_t time_after_generation = time(nullptr); + EXPECT_LE(time_before_generation + lifetime, + identity->certificate().CertificateExpirationTime()); + EXPECT_GE(time_after_generation + lifetime, + identity->certificate().CertificateExpirationTime()); + } + } +}; + +TEST_F(SSLIdentityExpirationTest, TestASN1TimeToSec) { + TestASN1TimeToSec(); +} + +TEST_F(SSLIdentityExpirationTest, TestExpireTime) { + TestExpireTime(500); +} diff --git a/third_party/libwebrtc/rtc_base/ssl_roots.h b/third_party/libwebrtc/rtc_base/ssl_roots.h new file mode 100644 index 0000000000..c3f2701b04 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/ssl_roots.h @@ -0,0 +1,2485 @@ +/* + * Copyright 2023 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 RTC_BASE_SSL_ROOTS_H_ +#define RTC_BASE_SSL_ROOTS_H_ + +// This file is the root certificates in C form. + +// It was generated at 2023-05-09T15:05:10+00:00 by the following script: +// `tools_webrtc/sslroots/generate_sslroots.py https://pki.goog/roots.pem` + +// clang-format off +// Don't bother formatting generated code, +// also it would breaks subject/issuer lines. + +// Source bundle `https://pki.goog/roots.pem` digest is [sha256:9c9b9685ad319b9747c3fe69b46a61c11a0efabdfa09ca6a8b0c3da421036d27] + +/* subject: Common Name: Baltimore CyberTrust Root, Organizational Unit: CyberTrust, Organization: Baltimore, Country: IE */ +/* issuer: Common Name: Baltimore CyberTrust Root, Organizational Unit: CyberTrust, Organization: Baltimore, Country: IE */ +/* link: https://crt.sh/?q=16af57a9f676b0ab126095aa5ebadef22ab31119d644ac95cd4b93dbf3f26aeb */ +const unsigned char kCertificateWithFingerprint_16af57a9f676b0ab126095aa5ebadef22ab31119d644ac95cd4b93dbf3f26aeb_certificate[891]={ +0x30,0x82,0x03,0x77,0x30,0x82,0x02,0x5F,0xA0,0x03,0x02,0x01,0x02,0x02,0x04,0x02, +0x00,0x00,0xB9,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05, +0x05,0x00,0x30,0x5A,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x49, +0x45,0x31,0x12,0x30,0x10,0x06,0x03,0x55,0x04,0x0A,0x13,0x09,0x42,0x61,0x6C,0x74, +0x69,0x6D,0x6F,0x72,0x65,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0B,0x13,0x0A, +0x43,0x79,0x62,0x65,0x72,0x54,0x72,0x75,0x73,0x74,0x31,0x22,0x30,0x20,0x06,0x03, +0x55,0x04,0x03,0x13,0x19,0x42,0x61,0x6C,0x74,0x69,0x6D,0x6F,0x72,0x65,0x20,0x43, +0x79,0x62,0x65,0x72,0x54,0x72,0x75,0x73,0x74,0x20,0x52,0x6F,0x6F,0x74,0x30,0x1E, +0x17,0x0D,0x30,0x30,0x30,0x35,0x31,0x32,0x31,0x38,0x34,0x36,0x30,0x30,0x5A,0x17, +0x0D,0x32,0x35,0x30,0x35,0x31,0x32,0x32,0x33,0x35,0x39,0x30,0x30,0x5A,0x30,0x5A, +0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x49,0x45,0x31,0x12,0x30, +0x10,0x06,0x03,0x55,0x04,0x0A,0x13,0x09,0x42,0x61,0x6C,0x74,0x69,0x6D,0x6F,0x72, +0x65,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0B,0x13,0x0A,0x43,0x79,0x62,0x65, +0x72,0x54,0x72,0x75,0x73,0x74,0x31,0x22,0x30,0x20,0x06,0x03,0x55,0x04,0x03,0x13, +0x19,0x42,0x61,0x6C,0x74,0x69,0x6D,0x6F,0x72,0x65,0x20,0x43,0x79,0x62,0x65,0x72, +0x54,0x72,0x75,0x73,0x74,0x20,0x52,0x6F,0x6F,0x74,0x30,0x82,0x01,0x22,0x30,0x0D, +0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01, +0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xA3,0x04,0xBB,0x22,0xAB, +0x98,0x3D,0x57,0xE8,0x26,0x72,0x9A,0xB5,0x79,0xD4,0x29,0xE2,0xE1,0xE8,0x95,0x80, +0xB1,0xB0,0xE3,0x5B,0x8E,0x2B,0x29,0x9A,0x64,0xDF,0xA1,0x5D,0xED,0xB0,0x09,0x05, +0x6D,0xDB,0x28,0x2E,0xCE,0x62,0xA2,0x62,0xFE,0xB4,0x88,0xDA,0x12,0xEB,0x38,0xEB, +0x21,0x9D,0xC0,0x41,0x2B,0x01,0x52,0x7B,0x88,0x77,0xD3,0x1C,0x8F,0xC7,0xBA,0xB9, +0x88,0xB5,0x6A,0x09,0xE7,0x73,0xE8,0x11,0x40,0xA7,0xD1,0xCC,0xCA,0x62,0x8D,0x2D, +0xE5,0x8F,0x0B,0xA6,0x50,0xD2,0xA8,0x50,0xC3,0x28,0xEA,0xF5,0xAB,0x25,0x87,0x8A, +0x9A,0x96,0x1C,0xA9,0x67,0xB8,0x3F,0x0C,0xD5,0xF7,0xF9,0x52,0x13,0x2F,0xC2,0x1B, +0xD5,0x70,0x70,0xF0,0x8F,0xC0,0x12,0xCA,0x06,0xCB,0x9A,0xE1,0xD9,0xCA,0x33,0x7A, +0x77,0xD6,0xF8,0xEC,0xB9,0xF1,0x68,0x44,0x42,0x48,0x13,0xD2,0xC0,0xC2,0xA4,0xAE, +0x5E,0x60,0xFE,0xB6,0xA6,0x05,0xFC,0xB4,0xDD,0x07,0x59,0x02,0xD4,0x59,0x18,0x98, +0x63,0xF5,0xA5,0x63,0xE0,0x90,0x0C,0x7D,0x5D,0xB2,0x06,0x7A,0xF3,0x85,0xEA,0xEB, +0xD4,0x03,0xAE,0x5E,0x84,0x3E,0x5F,0xFF,0x15,0xED,0x69,0xBC,0xF9,0x39,0x36,0x72, +0x75,0xCF,0x77,0x52,0x4D,0xF3,0xC9,0x90,0x2C,0xB9,0x3D,0xE5,0xC9,0x23,0x53,0x3F, +0x1F,0x24,0x98,0x21,0x5C,0x07,0x99,0x29,0xBD,0xC6,0x3A,0xEC,0xE7,0x6E,0x86,0x3A, +0x6B,0x97,0x74,0x63,0x33,0xBD,0x68,0x18,0x31,0xF0,0x78,0x8D,0x76,0xBF,0xFC,0x9E, +0x8E,0x5D,0x2A,0x86,0xA7,0x4D,0x90,0xDC,0x27,0x1A,0x39,0x02,0x03,0x01,0x00,0x01, +0xA3,0x45,0x30,0x43,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0xE5, +0x9D,0x59,0x30,0x82,0x47,0x58,0xCC,0xAC,0xFA,0x08,0x54,0x36,0x86,0x7B,0x3A,0xB5, +0x04,0x4D,0xF0,0x30,0x12,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x08,0x30, +0x06,0x01,0x01,0xFF,0x02,0x01,0x03,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01, +0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7, +0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x85,0x0C,0x5D,0x8E,0xE4, +0x6F,0x51,0x68,0x42,0x05,0xA0,0xDD,0xBB,0x4F,0x27,0x25,0x84,0x03,0xBD,0xF7,0x64, +0xFD,0x2D,0xD7,0x30,0xE3,0xA4,0x10,0x17,0xEB,0xDA,0x29,0x29,0xB6,0x79,0x3F,0x76, +0xF6,0x19,0x13,0x23,0xB8,0x10,0x0A,0xF9,0x58,0xA4,0xD4,0x61,0x70,0xBD,0x04,0x61, +0x6A,0x12,0x8A,0x17,0xD5,0x0A,0xBD,0xC5,0xBC,0x30,0x7C,0xD6,0xE9,0x0C,0x25,0x8D, +0x86,0x40,0x4F,0xEC,0xCC,0xA3,0x7E,0x38,0xC6,0x37,0x11,0x4F,0xED,0xDD,0x68,0x31, +0x8E,0x4C,0xD2,0xB3,0x01,0x74,0xEE,0xBE,0x75,0x5E,0x07,0x48,0x1A,0x7F,0x70,0xFF, +0x16,0x5C,0x84,0xC0,0x79,0x85,0xB8,0x05,0xFD,0x7F,0xBE,0x65,0x11,0xA3,0x0F,0xC0, +0x02,0xB4,0xF8,0x52,0x37,0x39,0x04,0xD5,0xA9,0x31,0x7A,0x18,0xBF,0xA0,0x2A,0xF4, +0x12,0x99,0xF7,0xA3,0x45,0x82,0xE3,0x3C,0x5E,0xF5,0x9D,0x9E,0xB5,0xC8,0x9E,0x7C, +0x2E,0xC8,0xA4,0x9E,0x4E,0x08,0x14,0x4B,0x6D,0xFD,0x70,0x6D,0x6B,0x1A,0x63,0xBD, +0x64,0xE6,0x1F,0xB7,0xCE,0xF0,0xF2,0x9F,0x2E,0xBB,0x1B,0xB7,0xF2,0x50,0x88,0x73, +0x92,0xC2,0xE2,0xE3,0x16,0x8D,0x9A,0x32,0x02,0xAB,0x8E,0x18,0xDD,0xE9,0x10,0x11, +0xEE,0x7E,0x35,0xAB,0x90,0xAF,0x3E,0x30,0x94,0x7A,0xD0,0x33,0x3D,0xA7,0x65,0x0F, +0xF5,0xFC,0x8E,0x9E,0x62,0xCF,0x47,0x44,0x2C,0x01,0x5D,0xBB,0x1D,0xB5,0x32,0xD2, +0x47,0xD2,0x38,0x2E,0xD0,0xFE,0x81,0xDC,0x32,0x6A,0x1E,0xB5,0xEE,0x3C,0xD5,0xFC, +0xE7,0x81,0x1D,0x19,0xC3,0x24,0x42,0xEA,0x63,0x39,0xA9, +}; + +/* subject: Common Name: DigiCert Assured ID Root CA, Organizational Unit: www.digicert.com, Organization: DigiCert Inc, Country: US */ +/* issuer: Common Name: DigiCert Assured ID Root CA, Organizational Unit: www.digicert.com, Organization: DigiCert Inc, Country: US */ +/* link: https://crt.sh/?q=3e9099b5015e8f486c00bcea9d111ee721faba355a89bcf1df69561e3dc6325c */ +const unsigned char kCertificateWithFingerprint_3e9099b5015e8f486c00bcea9d111ee721faba355a89bcf1df69561e3dc6325c_certificate[955]={ +0x30,0x82,0x03,0xB7,0x30,0x82,0x02,0x9F,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x0C, +0xE7,0xE0,0xE5,0x17,0xD8,0x46,0xFE,0x8F,0xE5,0x60,0xFC,0x1B,0xF0,0x30,0x39,0x30, +0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x65, +0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x15,0x30, +0x13,0x06,0x03,0x55,0x04,0x0A,0x13,0x0C,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74, +0x20,0x49,0x6E,0x63,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04,0x0B,0x13,0x10,0x77, +0x77,0x77,0x2E,0x64,0x69,0x67,0x69,0x63,0x65,0x72,0x74,0x2E,0x63,0x6F,0x6D,0x31, +0x24,0x30,0x22,0x06,0x03,0x55,0x04,0x03,0x13,0x1B,0x44,0x69,0x67,0x69,0x43,0x65, +0x72,0x74,0x20,0x41,0x73,0x73,0x75,0x72,0x65,0x64,0x20,0x49,0x44,0x20,0x52,0x6F, +0x6F,0x74,0x20,0x43,0x41,0x30,0x1E,0x17,0x0D,0x30,0x36,0x31,0x31,0x31,0x30,0x30, +0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x33,0x31,0x31,0x31,0x31,0x30,0x30,0x30, +0x30,0x30,0x30,0x30,0x5A,0x30,0x65,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06, +0x13,0x02,0x55,0x53,0x31,0x15,0x30,0x13,0x06,0x03,0x55,0x04,0x0A,0x13,0x0C,0x44, +0x69,0x67,0x69,0x43,0x65,0x72,0x74,0x20,0x49,0x6E,0x63,0x31,0x19,0x30,0x17,0x06, +0x03,0x55,0x04,0x0B,0x13,0x10,0x77,0x77,0x77,0x2E,0x64,0x69,0x67,0x69,0x63,0x65, +0x72,0x74,0x2E,0x63,0x6F,0x6D,0x31,0x24,0x30,0x22,0x06,0x03,0x55,0x04,0x03,0x13, +0x1B,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74,0x20,0x41,0x73,0x73,0x75,0x72,0x65, +0x64,0x20,0x49,0x44,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x41,0x30,0x82,0x01,0x22, +0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03, +0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xAD,0x0E,0x15, +0xCE,0xE4,0x43,0x80,0x5C,0xB1,0x87,0xF3,0xB7,0x60,0xF9,0x71,0x12,0xA5,0xAE,0xDC, +0x26,0x94,0x88,0xAA,0xF4,0xCE,0xF5,0x20,0x39,0x28,0x58,0x60,0x0C,0xF8,0x80,0xDA, +0xA9,0x15,0x95,0x32,0x61,0x3C,0xB5,0xB1,0x28,0x84,0x8A,0x8A,0xDC,0x9F,0x0A,0x0C, +0x83,0x17,0x7A,0x8F,0x90,0xAC,0x8A,0xE7,0x79,0x53,0x5C,0x31,0x84,0x2A,0xF6,0x0F, +0x98,0x32,0x36,0x76,0xCC,0xDE,0xDD,0x3C,0xA8,0xA2,0xEF,0x6A,0xFB,0x21,0xF2,0x52, +0x61,0xDF,0x9F,0x20,0xD7,0x1F,0xE2,0xB1,0xD9,0xFE,0x18,0x64,0xD2,0x12,0x5B,0x5F, +0xF9,0x58,0x18,0x35,0xBC,0x47,0xCD,0xA1,0x36,0xF9,0x6B,0x7F,0xD4,0xB0,0x38,0x3E, +0xC1,0x1B,0xC3,0x8C,0x33,0xD9,0xD8,0x2F,0x18,0xFE,0x28,0x0F,0xB3,0xA7,0x83,0xD6, +0xC3,0x6E,0x44,0xC0,0x61,0x35,0x96,0x16,0xFE,0x59,0x9C,0x8B,0x76,0x6D,0xD7,0xF1, +0xA2,0x4B,0x0D,0x2B,0xFF,0x0B,0x72,0xDA,0x9E,0x60,0xD0,0x8E,0x90,0x35,0xC6,0x78, +0x55,0x87,0x20,0xA1,0xCF,0xE5,0x6D,0x0A,0xC8,0x49,0x7C,0x31,0x98,0x33,0x6C,0x22, +0xE9,0x87,0xD0,0x32,0x5A,0xA2,0xBA,0x13,0x82,0x11,0xED,0x39,0x17,0x9D,0x99,0x3A, +0x72,0xA1,0xE6,0xFA,0xA4,0xD9,0xD5,0x17,0x31,0x75,0xAE,0x85,0x7D,0x22,0xAE,0x3F, +0x01,0x46,0x86,0xF6,0x28,0x79,0xC8,0xB1,0xDA,0xE4,0x57,0x17,0xC4,0x7E,0x1C,0x0E, +0xB0,0xB4,0x92,0xA6,0x56,0xB3,0xBD,0xB2,0x97,0xED,0xAA,0xA7,0xF0,0xB7,0xC5,0xA8, +0x3F,0x95,0x16,0xD0,0xFF,0xA1,0x96,0xEB,0x08,0x5F,0x18,0x77,0x4F,0x02,0x03,0x01, +0x00,0x01,0xA3,0x63,0x30,0x61,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF, +0x04,0x04,0x03,0x02,0x01,0x86,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF, +0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16, +0x04,0x14,0x45,0xEB,0xA2,0xAF,0xF4,0x92,0xCB,0x82,0x31,0x2D,0x51,0x8B,0xA7,0xA7, +0x21,0x9D,0xF3,0x6D,0xC8,0x0F,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30, +0x16,0x80,0x14,0x45,0xEB,0xA2,0xAF,0xF4,0x92,0xCB,0x82,0x31,0x2D,0x51,0x8B,0xA7, +0xA7,0x21,0x9D,0xF3,0x6D,0xC8,0x0F,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7, +0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0xA2,0x0E,0xBC,0xDF,0xE2, +0xED,0xF0,0xE3,0x72,0x73,0x7A,0x64,0x94,0xBF,0xF7,0x72,0x66,0xD8,0x32,0xE4,0x42, +0x75,0x62,0xAE,0x87,0xEB,0xF2,0xD5,0xD9,0xDE,0x56,0xB3,0x9F,0xCC,0xCE,0x14,0x28, +0xB9,0x0D,0x97,0x60,0x5C,0x12,0x4C,0x58,0xE4,0xD3,0x3D,0x83,0x49,0x45,0x58,0x97, +0x35,0x69,0x1A,0xA8,0x47,0xEA,0x56,0xC6,0x79,0xAB,0x12,0xD8,0x67,0x81,0x84,0xDF, +0x7F,0x09,0x3C,0x94,0xE6,0xB8,0x26,0x2C,0x20,0xBD,0x3D,0xB3,0x28,0x89,0xF7,0x5F, +0xFF,0x22,0xE2,0x97,0x84,0x1F,0xE9,0x65,0xEF,0x87,0xE0,0xDF,0xC1,0x67,0x49,0xB3, +0x5D,0xEB,0xB2,0x09,0x2A,0xEB,0x26,0xED,0x78,0xBE,0x7D,0x3F,0x2B,0xF3,0xB7,0x26, +0x35,0x6D,0x5F,0x89,0x01,0xB6,0x49,0x5B,0x9F,0x01,0x05,0x9B,0xAB,0x3D,0x25,0xC1, +0xCC,0xB6,0x7F,0xC2,0xF1,0x6F,0x86,0xC6,0xFA,0x64,0x68,0xEB,0x81,0x2D,0x94,0xEB, +0x42,0xB7,0xFA,0x8C,0x1E,0xDD,0x62,0xF1,0xBE,0x50,0x67,0xB7,0x6C,0xBD,0xF3,0xF1, +0x1F,0x6B,0x0C,0x36,0x07,0x16,0x7F,0x37,0x7C,0xA9,0x5B,0x6D,0x7A,0xF1,0x12,0x46, +0x60,0x83,0xD7,0x27,0x04,0xBE,0x4B,0xCE,0x97,0xBE,0xC3,0x67,0x2A,0x68,0x11,0xDF, +0x80,0xE7,0x0C,0x33,0x66,0xBF,0x13,0x0D,0x14,0x6E,0xF3,0x7F,0x1F,0x63,0x10,0x1E, +0xFA,0x8D,0x1B,0x25,0x6D,0x6C,0x8F,0xA5,0xB7,0x61,0x01,0xB1,0xD2,0xA3,0x26,0xA1, +0x10,0x71,0x9D,0xAD,0xE2,0xC3,0xF9,0xC3,0x99,0x51,0xB7,0x2B,0x07,0x08,0xCE,0x2E, +0xE6,0x50,0xB2,0xA7,0xFA,0x0A,0x45,0x2F,0xA2,0xF0,0xF2, +}; + +/* subject: Common Name: DigiCert Assured ID Root G2, Organizational Unit: www.digicert.com, Organization: DigiCert Inc, Country: US */ +/* issuer: Common Name: DigiCert Assured ID Root G2, Organizational Unit: www.digicert.com, Organization: DigiCert Inc, Country: US */ +/* link: https://crt.sh/?q=7d05ebb682339f8c9451ee094eebfefa7953a114edb2f44949452fab7d2fc185 */ +const unsigned char kCertificateWithFingerprint_7d05ebb682339f8c9451ee094eebfefa7953a114edb2f44949452fab7d2fc185_certificate[922]={ +0x30,0x82,0x03,0x96,0x30,0x82,0x02,0x7E,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x0B, +0x93,0x1C,0x3A,0xD6,0x39,0x67,0xEA,0x67,0x23,0xBF,0xC3,0xAF,0x9A,0xF4,0x4B,0x30, +0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x30,0x65, +0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x15,0x30, +0x13,0x06,0x03,0x55,0x04,0x0A,0x13,0x0C,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74, +0x20,0x49,0x6E,0x63,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04,0x0B,0x13,0x10,0x77, +0x77,0x77,0x2E,0x64,0x69,0x67,0x69,0x63,0x65,0x72,0x74,0x2E,0x63,0x6F,0x6D,0x31, +0x24,0x30,0x22,0x06,0x03,0x55,0x04,0x03,0x13,0x1B,0x44,0x69,0x67,0x69,0x43,0x65, +0x72,0x74,0x20,0x41,0x73,0x73,0x75,0x72,0x65,0x64,0x20,0x49,0x44,0x20,0x52,0x6F, +0x6F,0x74,0x20,0x47,0x32,0x30,0x1E,0x17,0x0D,0x31,0x33,0x30,0x38,0x30,0x31,0x31, +0x32,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x33,0x38,0x30,0x31,0x31,0x35,0x31,0x32, +0x30,0x30,0x30,0x30,0x5A,0x30,0x65,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06, +0x13,0x02,0x55,0x53,0x31,0x15,0x30,0x13,0x06,0x03,0x55,0x04,0x0A,0x13,0x0C,0x44, +0x69,0x67,0x69,0x43,0x65,0x72,0x74,0x20,0x49,0x6E,0x63,0x31,0x19,0x30,0x17,0x06, +0x03,0x55,0x04,0x0B,0x13,0x10,0x77,0x77,0x77,0x2E,0x64,0x69,0x67,0x69,0x63,0x65, +0x72,0x74,0x2E,0x63,0x6F,0x6D,0x31,0x24,0x30,0x22,0x06,0x03,0x55,0x04,0x03,0x13, +0x1B,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74,0x20,0x41,0x73,0x73,0x75,0x72,0x65, +0x64,0x20,0x49,0x44,0x20,0x52,0x6F,0x6F,0x74,0x20,0x47,0x32,0x30,0x82,0x01,0x22, +0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03, +0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xD9,0xE7,0x28, +0x2F,0x52,0x3F,0x36,0x72,0x49,0x88,0x93,0x34,0xF3,0xF8,0x6A,0x1E,0x31,0x54,0x80, +0x9F,0xAD,0x54,0x41,0xB5,0x47,0xDF,0x96,0xA8,0xD4,0xAF,0x80,0x2D,0xB9,0x0A,0xCF, +0x75,0xFD,0x89,0xA5,0x7D,0x24,0xFA,0xE3,0x22,0x0C,0x2B,0xBC,0x95,0x17,0x0B,0x33, +0xBF,0x19,0x4D,0x41,0x06,0x90,0x00,0xBD,0x0C,0x4D,0x10,0xFE,0x07,0xB5,0xE7,0x1C, +0x6E,0x22,0x55,0x31,0x65,0x97,0xBD,0xD3,0x17,0xD2,0x1E,0x62,0xF3,0xDB,0xEA,0x6C, +0x50,0x8C,0x3F,0x84,0x0C,0x96,0xCF,0xB7,0xCB,0x03,0xE0,0xCA,0x6D,0xA1,0x14,0x4C, +0x1B,0x89,0xDD,0xED,0x00,0xB0,0x52,0x7C,0xAF,0x91,0x6C,0xB1,0x38,0x13,0xD1,0xE9, +0x12,0x08,0xC0,0x00,0xB0,0x1C,0x2B,0x11,0xDA,0x77,0x70,0x36,0x9B,0xAE,0xCE,0x79, +0x87,0xDC,0x82,0x70,0xE6,0x09,0x74,0x70,0x55,0x69,0xAF,0xA3,0x68,0x9F,0xBF,0xDD, +0xB6,0x79,0xB3,0xF2,0x9D,0x70,0x29,0x55,0xF4,0xAB,0xFF,0x95,0x61,0xF3,0xC9,0x40, +0x6F,0x1D,0xD1,0xBE,0x93,0xBB,0xD3,0x88,0x2A,0xBB,0x9D,0xBF,0x72,0x5A,0x56,0x71, +0x3B,0x3F,0xD4,0xF3,0xD1,0x0A,0xFE,0x28,0xEF,0xA3,0xEE,0xD9,0x99,0xAF,0x03,0xD3, +0x8F,0x60,0xB7,0xF2,0x92,0xA1,0xB1,0xBD,0x89,0x89,0x1F,0x30,0xCD,0xC3,0xA6,0x2E, +0x62,0x33,0xAE,0x16,0x02,0x77,0x44,0x5A,0xE7,0x81,0x0A,0x3C,0xA7,0x44,0x2E,0x79, +0xB8,0x3F,0x04,0xBC,0x5C,0xA0,0x87,0xE1,0x1B,0xAF,0x51,0x8E,0xCD,0xEC,0x2C,0xFA, +0xF8,0xFE,0x6D,0xF0,0x3A,0x7C,0xAA,0x8B,0xE4,0x67,0x95,0x31,0x8D,0x02,0x03,0x01, +0x00,0x01,0xA3,0x42,0x30,0x40,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF, +0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01, +0xFF,0x04,0x04,0x03,0x02,0x01,0x86,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16, +0x04,0x14,0xCE,0xC3,0x4A,0xB9,0x99,0x55,0xF2,0xB8,0xDB,0x60,0xBF,0xA9,0x7E,0xBD, +0x56,0xB5,0x97,0x36,0xA7,0xD6,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D, +0x01,0x01,0x0B,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0xCA,0xA5,0x55,0x8C,0xE3,0xC8, +0x41,0x6E,0x69,0x27,0xA7,0x75,0x11,0xEF,0x3C,0x86,0x36,0x6F,0xD2,0x9D,0xC6,0x78, +0x38,0x1D,0x69,0x96,0xA2,0x92,0x69,0x2E,0x38,0x6C,0x9B,0x7D,0x04,0xD4,0x89,0xA5, +0xB1,0x31,0x37,0x8A,0xC9,0x21,0xCC,0xAB,0x6C,0xCD,0x8B,0x1C,0x9A,0xD6,0xBF,0x48, +0xD2,0x32,0x66,0xC1,0x8A,0xC0,0xF3,0x2F,0x3A,0xEF,0xC0,0xE3,0xD4,0x91,0x86,0xD1, +0x50,0xE3,0x03,0xDB,0x73,0x77,0x6F,0x4A,0x39,0x53,0xED,0xDE,0x26,0xC7,0xB5,0x7D, +0xAF,0x2B,0x42,0xD1,0x75,0x62,0xE3,0x4A,0x2B,0x02,0xC7,0x50,0x4B,0xE0,0x69,0xE2, +0x96,0x6C,0x0E,0x44,0x66,0x10,0x44,0x8F,0xAD,0x05,0xEB,0xF8,0x79,0xAC,0xA6,0x1B, +0xE8,0x37,0x34,0x9D,0x53,0xC9,0x61,0xAA,0xA2,0x52,0xAF,0x4A,0x70,0x16,0x86,0xC2, +0x3A,0xC8,0xB1,0x13,0x70,0x36,0xD8,0xCF,0xEE,0xF4,0x0A,0x34,0xD5,0x5B,0x4C,0xFD, +0x07,0x9C,0xA2,0xBA,0xD9,0x01,0x72,0x5C,0xF3,0x4D,0xC1,0xDD,0x0E,0xB1,0x1C,0x0D, +0xC4,0x63,0xBE,0xAD,0xF4,0x14,0xFB,0x89,0xEC,0xA2,0x41,0x0E,0x4C,0xCC,0xC8,0x57, +0x40,0xD0,0x6E,0x03,0xAA,0xCD,0x0C,0x8E,0x89,0x99,0x99,0x6C,0xF0,0x3C,0x30,0xAF, +0x38,0xDF,0x6F,0xBC,0xA3,0xBE,0x29,0x20,0x27,0xAB,0x74,0xFF,0x13,0x22,0x78,0xDE, +0x97,0x52,0x55,0x1E,0x83,0xB5,0x54,0x20,0x03,0xEE,0xAE,0xC0,0x4F,0x56,0xDE,0x37, +0xCC,0xC3,0x7F,0xAA,0x04,0x27,0xBB,0xD3,0x77,0xB8,0x62,0xDB,0x17,0x7C,0x9C,0x28, +0x22,0x13,0x73,0x6C,0xCF,0x26,0xF5,0x8A,0x29,0xE7, +}; + +/* subject: Common Name: DigiCert Assured ID Root G3, Organizational Unit: www.digicert.com, Organization: DigiCert Inc, Country: US */ +/* issuer: Common Name: DigiCert Assured ID Root G3, Organizational Unit: www.digicert.com, Organization: DigiCert Inc, Country: US */ +/* link: https://crt.sh/?q=7e37cb8b4c47090cab36551ba6f45db840680fba166a952db100717f43053fc2 */ +const unsigned char kCertificateWithFingerprint_7e37cb8b4c47090cab36551ba6f45db840680fba166a952db100717f43053fc2_certificate[586]={ +0x30,0x82,0x02,0x46,0x30,0x82,0x01,0xCD,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x0B, +0xA1,0x5A,0xFA,0x1D,0xDF,0xA0,0xB5,0x49,0x44,0xAF,0xCD,0x24,0xA0,0x6C,0xEC,0x30, +0x0A,0x06,0x08,0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x03,0x30,0x65,0x31,0x0B,0x30, +0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x15,0x30,0x13,0x06,0x03, +0x55,0x04,0x0A,0x13,0x0C,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74,0x20,0x49,0x6E, +0x63,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04,0x0B,0x13,0x10,0x77,0x77,0x77,0x2E, +0x64,0x69,0x67,0x69,0x63,0x65,0x72,0x74,0x2E,0x63,0x6F,0x6D,0x31,0x24,0x30,0x22, +0x06,0x03,0x55,0x04,0x03,0x13,0x1B,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74,0x20, +0x41,0x73,0x73,0x75,0x72,0x65,0x64,0x20,0x49,0x44,0x20,0x52,0x6F,0x6F,0x74,0x20, +0x47,0x33,0x30,0x1E,0x17,0x0D,0x31,0x33,0x30,0x38,0x30,0x31,0x31,0x32,0x30,0x30, +0x30,0x30,0x5A,0x17,0x0D,0x33,0x38,0x30,0x31,0x31,0x35,0x31,0x32,0x30,0x30,0x30, +0x30,0x5A,0x30,0x65,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55, +0x53,0x31,0x15,0x30,0x13,0x06,0x03,0x55,0x04,0x0A,0x13,0x0C,0x44,0x69,0x67,0x69, +0x43,0x65,0x72,0x74,0x20,0x49,0x6E,0x63,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04, +0x0B,0x13,0x10,0x77,0x77,0x77,0x2E,0x64,0x69,0x67,0x69,0x63,0x65,0x72,0x74,0x2E, +0x63,0x6F,0x6D,0x31,0x24,0x30,0x22,0x06,0x03,0x55,0x04,0x03,0x13,0x1B,0x44,0x69, +0x67,0x69,0x43,0x65,0x72,0x74,0x20,0x41,0x73,0x73,0x75,0x72,0x65,0x64,0x20,0x49, +0x44,0x20,0x52,0x6F,0x6F,0x74,0x20,0x47,0x33,0x30,0x76,0x30,0x10,0x06,0x07,0x2A, +0x86,0x48,0xCE,0x3D,0x02,0x01,0x06,0x05,0x2B,0x81,0x04,0x00,0x22,0x03,0x62,0x00, +0x04,0x19,0xE7,0xBC,0xAC,0x44,0x65,0xED,0xCD,0xB8,0x3F,0x58,0xFB,0x8D,0xB1,0x57, +0xA9,0x44,0x2D,0x05,0x15,0xF2,0xEF,0x0B,0xFF,0x10,0x74,0x9F,0xB5,0x62,0x52,0x5F, +0x66,0x7E,0x1F,0xE5,0xDC,0x1B,0x45,0x79,0x0B,0xCC,0xC6,0x53,0x0A,0x9D,0x8D,0x5D, +0x02,0xD9,0xA9,0x59,0xDE,0x02,0x5A,0xF6,0x95,0x2A,0x0E,0x8D,0x38,0x4A,0x8A,0x49, +0xC6,0xBC,0xC6,0x03,0x38,0x07,0x5F,0x55,0xDA,0x7E,0x09,0x6E,0xE2,0x7F,0x5E,0xD0, +0x45,0x20,0x0F,0x59,0x76,0x10,0xD6,0xA0,0x24,0xF0,0x2D,0xDE,0x36,0xF2,0x6C,0x29, +0x39,0xA3,0x42,0x30,0x40,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04, +0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF, +0x04,0x04,0x03,0x02,0x01,0x86,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04, +0x14,0xCB,0xD0,0xBD,0xA9,0xE1,0x98,0x05,0x51,0xA1,0x4D,0x37,0xA2,0x83,0x79,0xCE, +0x8D,0x1D,0x2A,0xE4,0x84,0x30,0x0A,0x06,0x08,0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03, +0x03,0x03,0x67,0x00,0x30,0x64,0x02,0x30,0x25,0xA4,0x81,0x45,0x02,0x6B,0x12,0x4B, +0x75,0x74,0x4F,0xC8,0x23,0xE3,0x70,0xF2,0x75,0x72,0xDE,0x7C,0x89,0xF0,0xCF,0x91, +0x72,0x61,0x9E,0x5E,0x10,0x92,0x59,0x56,0xB9,0x83,0xC7,0x10,0xE7,0x38,0xE9,0x58, +0x26,0x36,0x7D,0xD5,0xE4,0x34,0x86,0x39,0x02,0x30,0x7C,0x36,0x53,0xF0,0x30,0xE5, +0x62,0x63,0x3A,0x99,0xE2,0xB6,0xA3,0x3B,0x9B,0x34,0xFA,0x1E,0xDA,0x10,0x92,0x71, +0x5E,0x91,0x13,0xA7,0xDD,0xA4,0x6E,0x92,0xCC,0x32,0xD6,0xF5,0x21,0x66,0xC7,0x2F, +0xEA,0x96,0x63,0x6A,0x65,0x45,0x92,0x95,0x01,0xB4, +}; + +/* subject: Common Name: DigiCert Global Root CA, Organizational Unit: www.digicert.com, Organization: DigiCert Inc, Country: US */ +/* issuer: Common Name: DigiCert Global Root CA, Organizational Unit: www.digicert.com, Organization: DigiCert Inc, Country: US */ +/* link: https://crt.sh/?q=4348a0e9444c78cb265e058d5e8944b4d84f9662bd26db257f8934a443c70161 */ +const unsigned char kCertificateWithFingerprint_4348a0e9444c78cb265e058d5e8944b4d84f9662bd26db257f8934a443c70161_certificate[947]={ +0x30,0x82,0x03,0xAF,0x30,0x82,0x02,0x97,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x08, +0x3B,0xE0,0x56,0x90,0x42,0x46,0xB1,0xA1,0x75,0x6A,0xC9,0x59,0x91,0xC7,0x4A,0x30, +0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x61, +0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x15,0x30, +0x13,0x06,0x03,0x55,0x04,0x0A,0x13,0x0C,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74, +0x20,0x49,0x6E,0x63,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04,0x0B,0x13,0x10,0x77, +0x77,0x77,0x2E,0x64,0x69,0x67,0x69,0x63,0x65,0x72,0x74,0x2E,0x63,0x6F,0x6D,0x31, +0x20,0x30,0x1E,0x06,0x03,0x55,0x04,0x03,0x13,0x17,0x44,0x69,0x67,0x69,0x43,0x65, +0x72,0x74,0x20,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43, +0x41,0x30,0x1E,0x17,0x0D,0x30,0x36,0x31,0x31,0x31,0x30,0x30,0x30,0x30,0x30,0x30, +0x30,0x5A,0x17,0x0D,0x33,0x31,0x31,0x31,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x30, +0x5A,0x30,0x61,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53, +0x31,0x15,0x30,0x13,0x06,0x03,0x55,0x04,0x0A,0x13,0x0C,0x44,0x69,0x67,0x69,0x43, +0x65,0x72,0x74,0x20,0x49,0x6E,0x63,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04,0x0B, +0x13,0x10,0x77,0x77,0x77,0x2E,0x64,0x69,0x67,0x69,0x63,0x65,0x72,0x74,0x2E,0x63, +0x6F,0x6D,0x31,0x20,0x30,0x1E,0x06,0x03,0x55,0x04,0x03,0x13,0x17,0x44,0x69,0x67, +0x69,0x43,0x65,0x72,0x74,0x20,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x20,0x52,0x6F,0x6F, +0x74,0x20,0x43,0x41,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86, +0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A, +0x02,0x82,0x01,0x01,0x00,0xE2,0x3B,0xE1,0x11,0x72,0xDE,0xA8,0xA4,0xD3,0xA3,0x57, +0xAA,0x50,0xA2,0x8F,0x0B,0x77,0x90,0xC9,0xA2,0xA5,0xEE,0x12,0xCE,0x96,0x5B,0x01, +0x09,0x20,0xCC,0x01,0x93,0xA7,0x4E,0x30,0xB7,0x53,0xF7,0x43,0xC4,0x69,0x00,0x57, +0x9D,0xE2,0x8D,0x22,0xDD,0x87,0x06,0x40,0x00,0x81,0x09,0xCE,0xCE,0x1B,0x83,0xBF, +0xDF,0xCD,0x3B,0x71,0x46,0xE2,0xD6,0x66,0xC7,0x05,0xB3,0x76,0x27,0x16,0x8F,0x7B, +0x9E,0x1E,0x95,0x7D,0xEE,0xB7,0x48,0xA3,0x08,0xDA,0xD6,0xAF,0x7A,0x0C,0x39,0x06, +0x65,0x7F,0x4A,0x5D,0x1F,0xBC,0x17,0xF8,0xAB,0xBE,0xEE,0x28,0xD7,0x74,0x7F,0x7A, +0x78,0x99,0x59,0x85,0x68,0x6E,0x5C,0x23,0x32,0x4B,0xBF,0x4E,0xC0,0xE8,0x5A,0x6D, +0xE3,0x70,0xBF,0x77,0x10,0xBF,0xFC,0x01,0xF6,0x85,0xD9,0xA8,0x44,0x10,0x58,0x32, +0xA9,0x75,0x18,0xD5,0xD1,0xA2,0xBE,0x47,0xE2,0x27,0x6A,0xF4,0x9A,0x33,0xF8,0x49, +0x08,0x60,0x8B,0xD4,0x5F,0xB4,0x3A,0x84,0xBF,0xA1,0xAA,0x4A,0x4C,0x7D,0x3E,0xCF, +0x4F,0x5F,0x6C,0x76,0x5E,0xA0,0x4B,0x37,0x91,0x9E,0xDC,0x22,0xE6,0x6D,0xCE,0x14, +0x1A,0x8E,0x6A,0xCB,0xFE,0xCD,0xB3,0x14,0x64,0x17,0xC7,0x5B,0x29,0x9E,0x32,0xBF, +0xF2,0xEE,0xFA,0xD3,0x0B,0x42,0xD4,0xAB,0xB7,0x41,0x32,0xDA,0x0C,0xD4,0xEF,0xF8, +0x81,0xD5,0xBB,0x8D,0x58,0x3F,0xB5,0x1B,0xE8,0x49,0x28,0xA2,0x70,0xDA,0x31,0x04, +0xDD,0xF7,0xB2,0x16,0xF2,0x4C,0x0A,0x4E,0x07,0xA8,0xED,0x4A,0x3D,0x5E,0xB5,0x7F, +0xA3,0x90,0xC3,0xAF,0x27,0x02,0x03,0x01,0x00,0x01,0xA3,0x63,0x30,0x61,0x30,0x0E, +0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x86,0x30,0x0F, +0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30, +0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x03,0xDE,0x50,0x35,0x56,0xD1, +0x4C,0xBB,0x66,0xF0,0xA3,0xE2,0x1B,0x1B,0xC3,0x97,0xB2,0x3D,0xD1,0x55,0x30,0x1F, +0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0x03,0xDE,0x50,0x35,0x56, +0xD1,0x4C,0xBB,0x66,0xF0,0xA3,0xE2,0x1B,0x1B,0xC3,0x97,0xB2,0x3D,0xD1,0x55,0x30, +0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82, +0x01,0x01,0x00,0xCB,0x9C,0x37,0xAA,0x48,0x13,0x12,0x0A,0xFA,0xDD,0x44,0x9C,0x4F, +0x52,0xB0,0xF4,0xDF,0xAE,0x04,0xF5,0x79,0x79,0x08,0xA3,0x24,0x18,0xFC,0x4B,0x2B, +0x84,0xC0,0x2D,0xB9,0xD5,0xC7,0xFE,0xF4,0xC1,0x1F,0x58,0xCB,0xB8,0x6D,0x9C,0x7A, +0x74,0xE7,0x98,0x29,0xAB,0x11,0xB5,0xE3,0x70,0xA0,0xA1,0xCD,0x4C,0x88,0x99,0x93, +0x8C,0x91,0x70,0xE2,0xAB,0x0F,0x1C,0xBE,0x93,0xA9,0xFF,0x63,0xD5,0xE4,0x07,0x60, +0xD3,0xA3,0xBF,0x9D,0x5B,0x09,0xF1,0xD5,0x8E,0xE3,0x53,0xF4,0x8E,0x63,0xFA,0x3F, +0xA7,0xDB,0xB4,0x66,0xDF,0x62,0x66,0xD6,0xD1,0x6E,0x41,0x8D,0xF2,0x2D,0xB5,0xEA, +0x77,0x4A,0x9F,0x9D,0x58,0xE2,0x2B,0x59,0xC0,0x40,0x23,0xED,0x2D,0x28,0x82,0x45, +0x3E,0x79,0x54,0x92,0x26,0x98,0xE0,0x80,0x48,0xA8,0x37,0xEF,0xF0,0xD6,0x79,0x60, +0x16,0xDE,0xAC,0xE8,0x0E,0xCD,0x6E,0xAC,0x44,0x17,0x38,0x2F,0x49,0xDA,0xE1,0x45, +0x3E,0x2A,0xB9,0x36,0x53,0xCF,0x3A,0x50,0x06,0xF7,0x2E,0xE8,0xC4,0x57,0x49,0x6C, +0x61,0x21,0x18,0xD5,0x04,0xAD,0x78,0x3C,0x2C,0x3A,0x80,0x6B,0xA7,0xEB,0xAF,0x15, +0x14,0xE9,0xD8,0x89,0xC1,0xB9,0x38,0x6C,0xE2,0x91,0x6C,0x8A,0xFF,0x64,0xB9,0x77, +0x25,0x57,0x30,0xC0,0x1B,0x24,0xA3,0xE1,0xDC,0xE9,0xDF,0x47,0x7C,0xB5,0xB4,0x24, +0x08,0x05,0x30,0xEC,0x2D,0xBD,0x0B,0xBF,0x45,0xBF,0x50,0xB9,0xA9,0xF3,0xEB,0x98, +0x01,0x12,0xAD,0xC8,0x88,0xC6,0x98,0x34,0x5F,0x8D,0x0A,0x3C,0xC6,0xE9,0xD5,0x95, +0x95,0x6D,0xDE, +}; + +/* subject: Common Name: DigiCert Global Root G2, Organizational Unit: www.digicert.com, Organization: DigiCert Inc, Country: US */ +/* issuer: Common Name: DigiCert Global Root G2, Organizational Unit: www.digicert.com, Organization: DigiCert Inc, Country: US */ +/* link: https://crt.sh/?q=cb3ccbb76031e5e0138f8dd39a23f9de47ffc35e43c1144cea27d46a5ab1cb5f */ +const unsigned char kCertificateWithFingerprint_cb3ccbb76031e5e0138f8dd39a23f9de47ffc35e43c1144cea27d46a5ab1cb5f_certificate[914]={ +0x30,0x82,0x03,0x8E,0x30,0x82,0x02,0x76,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x03, +0x3A,0xF1,0xE6,0xA7,0x11,0xA9,0xA0,0xBB,0x28,0x64,0xB1,0x1D,0x09,0xFA,0xE5,0x30, +0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x30,0x61, +0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x15,0x30, +0x13,0x06,0x03,0x55,0x04,0x0A,0x13,0x0C,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74, +0x20,0x49,0x6E,0x63,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04,0x0B,0x13,0x10,0x77, +0x77,0x77,0x2E,0x64,0x69,0x67,0x69,0x63,0x65,0x72,0x74,0x2E,0x63,0x6F,0x6D,0x31, +0x20,0x30,0x1E,0x06,0x03,0x55,0x04,0x03,0x13,0x17,0x44,0x69,0x67,0x69,0x43,0x65, +0x72,0x74,0x20,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x20,0x52,0x6F,0x6F,0x74,0x20,0x47, +0x32,0x30,0x1E,0x17,0x0D,0x31,0x33,0x30,0x38,0x30,0x31,0x31,0x32,0x30,0x30,0x30, +0x30,0x5A,0x17,0x0D,0x33,0x38,0x30,0x31,0x31,0x35,0x31,0x32,0x30,0x30,0x30,0x30, +0x5A,0x30,0x61,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53, +0x31,0x15,0x30,0x13,0x06,0x03,0x55,0x04,0x0A,0x13,0x0C,0x44,0x69,0x67,0x69,0x43, +0x65,0x72,0x74,0x20,0x49,0x6E,0x63,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04,0x0B, +0x13,0x10,0x77,0x77,0x77,0x2E,0x64,0x69,0x67,0x69,0x63,0x65,0x72,0x74,0x2E,0x63, +0x6F,0x6D,0x31,0x20,0x30,0x1E,0x06,0x03,0x55,0x04,0x03,0x13,0x17,0x44,0x69,0x67, +0x69,0x43,0x65,0x72,0x74,0x20,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x20,0x52,0x6F,0x6F, +0x74,0x20,0x47,0x32,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86, +0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A, +0x02,0x82,0x01,0x01,0x00,0xBB,0x37,0xCD,0x34,0xDC,0x7B,0x6B,0xC9,0xB2,0x68,0x90, +0xAD,0x4A,0x75,0xFF,0x46,0xBA,0x21,0x0A,0x08,0x8D,0xF5,0x19,0x54,0xC9,0xFB,0x88, +0xDB,0xF3,0xAE,0xF2,0x3A,0x89,0x91,0x3C,0x7A,0xE6,0xAB,0x06,0x1A,0x6B,0xCF,0xAC, +0x2D,0xE8,0x5E,0x09,0x24,0x44,0xBA,0x62,0x9A,0x7E,0xD6,0xA3,0xA8,0x7E,0xE0,0x54, +0x75,0x20,0x05,0xAC,0x50,0xB7,0x9C,0x63,0x1A,0x6C,0x30,0xDC,0xDA,0x1F,0x19,0xB1, +0xD7,0x1E,0xDE,0xFD,0xD7,0xE0,0xCB,0x94,0x83,0x37,0xAE,0xEC,0x1F,0x43,0x4E,0xDD, +0x7B,0x2C,0xD2,0xBD,0x2E,0xA5,0x2F,0xE4,0xA9,0xB8,0xAD,0x3A,0xD4,0x99,0xA4,0xB6, +0x25,0xE9,0x9B,0x6B,0x00,0x60,0x92,0x60,0xFF,0x4F,0x21,0x49,0x18,0xF7,0x67,0x90, +0xAB,0x61,0x06,0x9C,0x8F,0xF2,0xBA,0xE9,0xB4,0xE9,0x92,0x32,0x6B,0xB5,0xF3,0x57, +0xE8,0x5D,0x1B,0xCD,0x8C,0x1D,0xAB,0x95,0x04,0x95,0x49,0xF3,0x35,0x2D,0x96,0xE3, +0x49,0x6D,0xDD,0x77,0xE3,0xFB,0x49,0x4B,0xB4,0xAC,0x55,0x07,0xA9,0x8F,0x95,0xB3, +0xB4,0x23,0xBB,0x4C,0x6D,0x45,0xF0,0xF6,0xA9,0xB2,0x95,0x30,0xB4,0xFD,0x4C,0x55, +0x8C,0x27,0x4A,0x57,0x14,0x7C,0x82,0x9D,0xCD,0x73,0x92,0xD3,0x16,0x4A,0x06,0x0C, +0x8C,0x50,0xD1,0x8F,0x1E,0x09,0xBE,0x17,0xA1,0xE6,0x21,0xCA,0xFD,0x83,0xE5,0x10, +0xBC,0x83,0xA5,0x0A,0xC4,0x67,0x28,0xF6,0x73,0x14,0x14,0x3D,0x46,0x76,0xC3,0x87, +0x14,0x89,0x21,0x34,0x4D,0xAF,0x0F,0x45,0x0C,0xA6,0x49,0xA1,0xBA,0xBB,0x9C,0xC5, +0xB1,0x33,0x83,0x29,0x85,0x02,0x03,0x01,0x00,0x01,0xA3,0x42,0x30,0x40,0x30,0x0F, +0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30, +0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x86,0x30, +0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x4E,0x22,0x54,0x20,0x18,0x95, +0xE6,0xE3,0x6E,0xE6,0x0F,0xFA,0xFA,0xB9,0x12,0xED,0x06,0x17,0x8F,0x39,0x30,0x0D, +0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x03,0x82,0x01, +0x01,0x00,0x60,0x67,0x28,0x94,0x6F,0x0E,0x48,0x63,0xEB,0x31,0xDD,0xEA,0x67,0x18, +0xD5,0x89,0x7D,0x3C,0xC5,0x8B,0x4A,0x7F,0xE9,0xBE,0xDB,0x2B,0x17,0xDF,0xB0,0x5F, +0x73,0x77,0x2A,0x32,0x13,0x39,0x81,0x67,0x42,0x84,0x23,0xF2,0x45,0x67,0x35,0xEC, +0x88,0xBF,0xF8,0x8F,0xB0,0x61,0x0C,0x34,0xA4,0xAE,0x20,0x4C,0x84,0xC6,0xDB,0xF8, +0x35,0xE1,0x76,0xD9,0xDF,0xA6,0x42,0xBB,0xC7,0x44,0x08,0x86,0x7F,0x36,0x74,0x24, +0x5A,0xDA,0x6C,0x0D,0x14,0x59,0x35,0xBD,0xF2,0x49,0xDD,0xB6,0x1F,0xC9,0xB3,0x0D, +0x47,0x2A,0x3D,0x99,0x2F,0xBB,0x5C,0xBB,0xB5,0xD4,0x20,0xE1,0x99,0x5F,0x53,0x46, +0x15,0xDB,0x68,0x9B,0xF0,0xF3,0x30,0xD5,0x3E,0x31,0xE2,0x8D,0x84,0x9E,0xE3,0x8A, +0xDA,0xDA,0x96,0x3E,0x35,0x13,0xA5,0x5F,0xF0,0xF9,0x70,0x50,0x70,0x47,0x41,0x11, +0x57,0x19,0x4E,0xC0,0x8F,0xAE,0x06,0xC4,0x95,0x13,0x17,0x2F,0x1B,0x25,0x9F,0x75, +0xF2,0xB1,0x8E,0x99,0xA1,0x6F,0x13,0xB1,0x41,0x71,0xFE,0x88,0x2A,0xC8,0x4F,0x10, +0x20,0x55,0xD7,0xF3,0x14,0x45,0xE5,0xE0,0x44,0xF4,0xEA,0x87,0x95,0x32,0x93,0x0E, +0xFE,0x53,0x46,0xFA,0x2C,0x9D,0xFF,0x8B,0x22,0xB9,0x4B,0xD9,0x09,0x45,0xA4,0xDE, +0xA4,0xB8,0x9A,0x58,0xDD,0x1B,0x7D,0x52,0x9F,0x8E,0x59,0x43,0x88,0x81,0xA4,0x9E, +0x26,0xD5,0x6F,0xAD,0xDD,0x0D,0xC6,0x37,0x7D,0xED,0x03,0x92,0x1B,0xE5,0x77,0x5F, +0x76,0xEE,0x3C,0x8D,0xC4,0x5D,0x56,0x5B,0xA2,0xD9,0x66,0x6E,0xB3,0x35,0x37,0xE5, +0x32,0xB6, +}; + +/* subject: Common Name: DigiCert Global Root G3, Organizational Unit: www.digicert.com, Organization: DigiCert Inc, Country: US */ +/* issuer: Common Name: DigiCert Global Root G3, Organizational Unit: www.digicert.com, Organization: DigiCert Inc, Country: US */ +/* link: https://crt.sh/?q=31ad6648f8104138c738f39ea4320133393e3a18cc02296ef97c2ac9ef6731d0 */ +const unsigned char kCertificateWithFingerprint_31ad6648f8104138c738f39ea4320133393e3a18cc02296ef97c2ac9ef6731d0_certificate[579]={ +0x30,0x82,0x02,0x3F,0x30,0x82,0x01,0xC5,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x05, +0x55,0x56,0xBC,0xF2,0x5E,0xA4,0x35,0x35,0xC3,0xA4,0x0F,0xD5,0xAB,0x45,0x72,0x30, +0x0A,0x06,0x08,0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x03,0x30,0x61,0x31,0x0B,0x30, +0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x15,0x30,0x13,0x06,0x03, +0x55,0x04,0x0A,0x13,0x0C,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74,0x20,0x49,0x6E, +0x63,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04,0x0B,0x13,0x10,0x77,0x77,0x77,0x2E, +0x64,0x69,0x67,0x69,0x63,0x65,0x72,0x74,0x2E,0x63,0x6F,0x6D,0x31,0x20,0x30,0x1E, +0x06,0x03,0x55,0x04,0x03,0x13,0x17,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74,0x20, +0x47,0x6C,0x6F,0x62,0x61,0x6C,0x20,0x52,0x6F,0x6F,0x74,0x20,0x47,0x33,0x30,0x1E, +0x17,0x0D,0x31,0x33,0x30,0x38,0x30,0x31,0x31,0x32,0x30,0x30,0x30,0x30,0x5A,0x17, +0x0D,0x33,0x38,0x30,0x31,0x31,0x35,0x31,0x32,0x30,0x30,0x30,0x30,0x5A,0x30,0x61, +0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x15,0x30, +0x13,0x06,0x03,0x55,0x04,0x0A,0x13,0x0C,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74, +0x20,0x49,0x6E,0x63,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04,0x0B,0x13,0x10,0x77, +0x77,0x77,0x2E,0x64,0x69,0x67,0x69,0x63,0x65,0x72,0x74,0x2E,0x63,0x6F,0x6D,0x31, +0x20,0x30,0x1E,0x06,0x03,0x55,0x04,0x03,0x13,0x17,0x44,0x69,0x67,0x69,0x43,0x65, +0x72,0x74,0x20,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x20,0x52,0x6F,0x6F,0x74,0x20,0x47, +0x33,0x30,0x76,0x30,0x10,0x06,0x07,0x2A,0x86,0x48,0xCE,0x3D,0x02,0x01,0x06,0x05, +0x2B,0x81,0x04,0x00,0x22,0x03,0x62,0x00,0x04,0xDD,0xA7,0xD9,0xBB,0x8A,0xB8,0x0B, +0xFB,0x0B,0x7F,0x21,0xD2,0xF0,0xBE,0xBE,0x73,0xF3,0x33,0x5D,0x1A,0xBC,0x34,0xEA, +0xDE,0xC6,0x9B,0xBC,0xD0,0x95,0xF6,0xF0,0xCC,0xD0,0x0B,0xBA,0x61,0x5B,0x51,0x46, +0x7E,0x9E,0x2D,0x9F,0xEE,0x8E,0x63,0x0C,0x17,0xEC,0x07,0x70,0xF5,0xCF,0x84,0x2E, +0x40,0x83,0x9C,0xE8,0x3F,0x41,0x6D,0x3B,0xAD,0xD3,0xA4,0x14,0x59,0x36,0x78,0x9D, +0x03,0x43,0xEE,0x10,0x13,0x6C,0x72,0xDE,0xAE,0x88,0xA7,0xA1,0x6B,0xB5,0x43,0xCE, +0x67,0xDC,0x23,0xFF,0x03,0x1C,0xA3,0xE2,0x3E,0xA3,0x42,0x30,0x40,0x30,0x0F,0x06, +0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0E, +0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x86,0x30,0x1D, +0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0xB3,0xDB,0x48,0xA4,0xF9,0xA1,0xC5, +0xD8,0xAE,0x36,0x41,0xCC,0x11,0x63,0x69,0x62,0x29,0xBC,0x4B,0xC6,0x30,0x0A,0x06, +0x08,0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x03,0x03,0x68,0x00,0x30,0x65,0x02,0x31, +0x00,0xAD,0xBC,0xF2,0x6C,0x3F,0x12,0x4A,0xD1,0x2D,0x39,0xC3,0x0A,0x09,0x97,0x73, +0xF4,0x88,0x36,0x8C,0x88,0x27,0xBB,0xE6,0x88,0x8D,0x50,0x85,0xA7,0x63,0xF9,0x9E, +0x32,0xDE,0x66,0x93,0x0F,0xF1,0xCC,0xB1,0x09,0x8F,0xDD,0x6C,0xAB,0xFA,0x6B,0x7F, +0xA0,0x02,0x30,0x39,0x66,0x5B,0xC2,0x64,0x8D,0xB8,0x9E,0x50,0xDC,0xA8,0xD5,0x49, +0xA2,0xED,0xC7,0xDC,0xD1,0x49,0x7F,0x17,0x01,0xB8,0xC8,0x86,0x8F,0x4E,0x8C,0x88, +0x2B,0xA8,0x9A,0xA9,0x8A,0xC5,0xD1,0x00,0xBD,0xF8,0x54,0xE2,0x9A,0xE5,0x5B,0x7C, +0xB3,0x27,0x17, +}; + +/* subject: Common Name: DigiCert High Assurance EV Root CA, Organizational Unit: www.digicert.com, Organization: DigiCert Inc, Country: US */ +/* issuer: Common Name: DigiCert High Assurance EV Root CA, Organizational Unit: www.digicert.com, Organization: DigiCert Inc, Country: US */ +/* link: https://crt.sh/?q=7431e5f4c3c1ce4690774f0b61e05440883ba9a01ed00ba6abd7806ed3b118cf */ +const unsigned char kCertificateWithFingerprint_7431e5f4c3c1ce4690774f0b61e05440883ba9a01ed00ba6abd7806ed3b118cf_certificate[969]={ +0x30,0x82,0x03,0xC5,0x30,0x82,0x02,0xAD,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x02, +0xAC,0x5C,0x26,0x6A,0x0B,0x40,0x9B,0x8F,0x0B,0x79,0xF2,0xAE,0x46,0x25,0x77,0x30, +0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x6C, +0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x15,0x30, +0x13,0x06,0x03,0x55,0x04,0x0A,0x13,0x0C,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74, +0x20,0x49,0x6E,0x63,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04,0x0B,0x13,0x10,0x77, +0x77,0x77,0x2E,0x64,0x69,0x67,0x69,0x63,0x65,0x72,0x74,0x2E,0x63,0x6F,0x6D,0x31, +0x2B,0x30,0x29,0x06,0x03,0x55,0x04,0x03,0x13,0x22,0x44,0x69,0x67,0x69,0x43,0x65, +0x72,0x74,0x20,0x48,0x69,0x67,0x68,0x20,0x41,0x73,0x73,0x75,0x72,0x61,0x6E,0x63, +0x65,0x20,0x45,0x56,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x41,0x30,0x1E,0x17,0x0D, +0x30,0x36,0x31,0x31,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x33, +0x31,0x31,0x31,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x30,0x6C,0x31,0x0B, +0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x15,0x30,0x13,0x06, +0x03,0x55,0x04,0x0A,0x13,0x0C,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74,0x20,0x49, +0x6E,0x63,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04,0x0B,0x13,0x10,0x77,0x77,0x77, +0x2E,0x64,0x69,0x67,0x69,0x63,0x65,0x72,0x74,0x2E,0x63,0x6F,0x6D,0x31,0x2B,0x30, +0x29,0x06,0x03,0x55,0x04,0x03,0x13,0x22,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74, +0x20,0x48,0x69,0x67,0x68,0x20,0x41,0x73,0x73,0x75,0x72,0x61,0x6E,0x63,0x65,0x20, +0x45,0x56,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x41,0x30,0x82,0x01,0x22,0x30,0x0D, +0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01, +0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xC6,0xCC,0xE5,0x73,0xE6, +0xFB,0xD4,0xBB,0xE5,0x2D,0x2D,0x32,0xA6,0xDF,0xE5,0x81,0x3F,0xC9,0xCD,0x25,0x49, +0xB6,0x71,0x2A,0xC3,0xD5,0x94,0x34,0x67,0xA2,0x0A,0x1C,0xB0,0x5F,0x69,0xA6,0x40, +0xB1,0xC4,0xB7,0xB2,0x8F,0xD0,0x98,0xA4,0xA9,0x41,0x59,0x3A,0xD3,0xDC,0x94,0xD6, +0x3C,0xDB,0x74,0x38,0xA4,0x4A,0xCC,0x4D,0x25,0x82,0xF7,0x4A,0xA5,0x53,0x12,0x38, +0xEE,0xF3,0x49,0x6D,0x71,0x91,0x7E,0x63,0xB6,0xAB,0xA6,0x5F,0xC3,0xA4,0x84,0xF8, +0x4F,0x62,0x51,0xBE,0xF8,0xC5,0xEC,0xDB,0x38,0x92,0xE3,0x06,0xE5,0x08,0x91,0x0C, +0xC4,0x28,0x41,0x55,0xFB,0xCB,0x5A,0x89,0x15,0x7E,0x71,0xE8,0x35,0xBF,0x4D,0x72, +0x09,0x3D,0xBE,0x3A,0x38,0x50,0x5B,0x77,0x31,0x1B,0x8D,0xB3,0xC7,0x24,0x45,0x9A, +0xA7,0xAC,0x6D,0x00,0x14,0x5A,0x04,0xB7,0xBA,0x13,0xEB,0x51,0x0A,0x98,0x41,0x41, +0x22,0x4E,0x65,0x61,0x87,0x81,0x41,0x50,0xA6,0x79,0x5C,0x89,0xDE,0x19,0x4A,0x57, +0xD5,0x2E,0xE6,0x5D,0x1C,0x53,0x2C,0x7E,0x98,0xCD,0x1A,0x06,0x16,0xA4,0x68,0x73, +0xD0,0x34,0x04,0x13,0x5C,0xA1,0x71,0xD3,0x5A,0x7C,0x55,0xDB,0x5E,0x64,0xE1,0x37, +0x87,0x30,0x56,0x04,0xE5,0x11,0xB4,0x29,0x80,0x12,0xF1,0x79,0x39,0x88,0xA2,0x02, +0x11,0x7C,0x27,0x66,0xB7,0x88,0xB7,0x78,0xF2,0xCA,0x0A,0xA8,0x38,0xAB,0x0A,0x64, +0xC2,0xBF,0x66,0x5D,0x95,0x84,0xC1,0xA1,0x25,0x1E,0x87,0x5D,0x1A,0x50,0x0B,0x20, +0x12,0xCC,0x41,0xBB,0x6E,0x0B,0x51,0x38,0xB8,0x4B,0xCB,0x02,0x03,0x01,0x00,0x01, +0xA3,0x63,0x30,0x61,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04, +0x03,0x02,0x01,0x86,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05, +0x30,0x03,0x01,0x01,0xFF,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14, +0xB1,0x3E,0xC3,0x69,0x03,0xF8,0xBF,0x47,0x01,0xD4,0x98,0x26,0x1A,0x08,0x02,0xEF, +0x63,0x64,0x2B,0xC3,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80, +0x14,0xB1,0x3E,0xC3,0x69,0x03,0xF8,0xBF,0x47,0x01,0xD4,0x98,0x26,0x1A,0x08,0x02, +0xEF,0x63,0x64,0x2B,0xC3,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01, +0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x1C,0x1A,0x06,0x97,0xDC,0xD7,0x9C, +0x9F,0x3C,0x88,0x66,0x06,0x08,0x57,0x21,0xDB,0x21,0x47,0xF8,0x2A,0x67,0xAA,0xBF, +0x18,0x32,0x76,0x40,0x10,0x57,0xC1,0x8A,0xF3,0x7A,0xD9,0x11,0x65,0x8E,0x35,0xFA, +0x9E,0xFC,0x45,0xB5,0x9E,0xD9,0x4C,0x31,0x4B,0xB8,0x91,0xE8,0x43,0x2C,0x8E,0xB3, +0x78,0xCE,0xDB,0xE3,0x53,0x79,0x71,0xD6,0xE5,0x21,0x94,0x01,0xDA,0x55,0x87,0x9A, +0x24,0x64,0xF6,0x8A,0x66,0xCC,0xDE,0x9C,0x37,0xCD,0xA8,0x34,0xB1,0x69,0x9B,0x23, +0xC8,0x9E,0x78,0x22,0x2B,0x70,0x43,0xE3,0x55,0x47,0x31,0x61,0x19,0xEF,0x58,0xC5, +0x85,0x2F,0x4E,0x30,0xF6,0xA0,0x31,0x16,0x23,0xC8,0xE7,0xE2,0x65,0x16,0x33,0xCB, +0xBF,0x1A,0x1B,0xA0,0x3D,0xF8,0xCA,0x5E,0x8B,0x31,0x8B,0x60,0x08,0x89,0x2D,0x0C, +0x06,0x5C,0x52,0xB7,0xC4,0xF9,0x0A,0x98,0xD1,0x15,0x5F,0x9F,0x12,0xBE,0x7C,0x36, +0x63,0x38,0xBD,0x44,0xA4,0x7F,0xE4,0x26,0x2B,0x0A,0xC4,0x97,0x69,0x0D,0xE9,0x8C, +0xE2,0xC0,0x10,0x57,0xB8,0xC8,0x76,0x12,0x91,0x55,0xF2,0x48,0x69,0xD8,0xBC,0x2A, +0x02,0x5B,0x0F,0x44,0xD4,0x20,0x31,0xDB,0xF4,0xBA,0x70,0x26,0x5D,0x90,0x60,0x9E, +0xBC,0x4B,0x17,0x09,0x2F,0xB4,0xCB,0x1E,0x43,0x68,0xC9,0x07,0x27,0xC1,0xD2,0x5C, +0xF7,0xEA,0x21,0xB9,0x68,0x12,0x9C,0x3C,0x9C,0xBF,0x9E,0xFC,0x80,0x5C,0x9B,0x63, +0xCD,0xEC,0x47,0xAA,0x25,0x27,0x67,0xA0,0x37,0xF3,0x00,0x82,0x7D,0x54,0xD7,0xA9, +0xF8,0xE9,0x2E,0x13,0xA3,0x77,0xE8,0x1F,0x4A, +}; + +/* subject: Common Name: DigiCert Trusted Root G4, Organizational Unit: www.digicert.com, Organization: DigiCert Inc, Country: US */ +/* issuer: Common Name: DigiCert Trusted Root G4, Organizational Unit: www.digicert.com, Organization: DigiCert Inc, Country: US */ +/* link: https://crt.sh/?q=552f7bdcf1a7af9e6ce672017f4f12abf77240c78e761ac203d1d9d20ac89988 */ +const unsigned char kCertificateWithFingerprint_552f7bdcf1a7af9e6ce672017f4f12abf77240c78e761ac203d1d9d20ac89988_certificate[1428]={ +0x30,0x82,0x05,0x90,0x30,0x82,0x03,0x78,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x05, +0x9B,0x1B,0x57,0x9E,0x8E,0x21,0x32,0xE2,0x39,0x07,0xBD,0xA7,0x77,0x75,0x5C,0x30, +0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0C,0x05,0x00,0x30,0x62, +0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x15,0x30, +0x13,0x06,0x03,0x55,0x04,0x0A,0x13,0x0C,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74, +0x20,0x49,0x6E,0x63,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04,0x0B,0x13,0x10,0x77, +0x77,0x77,0x2E,0x64,0x69,0x67,0x69,0x63,0x65,0x72,0x74,0x2E,0x63,0x6F,0x6D,0x31, +0x21,0x30,0x1F,0x06,0x03,0x55,0x04,0x03,0x13,0x18,0x44,0x69,0x67,0x69,0x43,0x65, +0x72,0x74,0x20,0x54,0x72,0x75,0x73,0x74,0x65,0x64,0x20,0x52,0x6F,0x6F,0x74,0x20, +0x47,0x34,0x30,0x1E,0x17,0x0D,0x31,0x33,0x30,0x38,0x30,0x31,0x31,0x32,0x30,0x30, +0x30,0x30,0x5A,0x17,0x0D,0x33,0x38,0x30,0x31,0x31,0x35,0x31,0x32,0x30,0x30,0x30, +0x30,0x5A,0x30,0x62,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55, +0x53,0x31,0x15,0x30,0x13,0x06,0x03,0x55,0x04,0x0A,0x13,0x0C,0x44,0x69,0x67,0x69, +0x43,0x65,0x72,0x74,0x20,0x49,0x6E,0x63,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04, +0x0B,0x13,0x10,0x77,0x77,0x77,0x2E,0x64,0x69,0x67,0x69,0x63,0x65,0x72,0x74,0x2E, +0x63,0x6F,0x6D,0x31,0x21,0x30,0x1F,0x06,0x03,0x55,0x04,0x03,0x13,0x18,0x44,0x69, +0x67,0x69,0x43,0x65,0x72,0x74,0x20,0x54,0x72,0x75,0x73,0x74,0x65,0x64,0x20,0x52, +0x6F,0x6F,0x74,0x20,0x47,0x34,0x30,0x82,0x02,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86, +0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x02,0x0F,0x00,0x30,0x82, +0x02,0x0A,0x02,0x82,0x02,0x01,0x00,0xBF,0xE6,0x90,0x73,0x68,0xDE,0xBB,0xE4,0x5D, +0x4A,0x3C,0x30,0x22,0x30,0x69,0x33,0xEC,0xC2,0xA7,0x25,0x2E,0xC9,0x21,0x3D,0xF2, +0x8A,0xD8,0x59,0xC2,0xE1,0x29,0xA7,0x3D,0x58,0xAB,0x76,0x9A,0xCD,0xAE,0x7B,0x1B, +0x84,0x0D,0xC4,0x30,0x1F,0xF3,0x1B,0xA4,0x38,0x16,0xEB,0x56,0xC6,0x97,0x6D,0x1D, +0xAB,0xB2,0x79,0xF2,0xCA,0x11,0xD2,0xE4,0x5F,0xD6,0x05,0x3C,0x52,0x0F,0x52,0x1F, +0xC6,0x9E,0x15,0xA5,0x7E,0xBE,0x9F,0xA9,0x57,0x16,0x59,0x55,0x72,0xAF,0x68,0x93, +0x70,0xC2,0xB2,0xBA,0x75,0x99,0x6A,0x73,0x32,0x94,0xD1,0x10,0x44,0x10,0x2E,0xDF, +0x82,0xF3,0x07,0x84,0xE6,0x74,0x3B,0x6D,0x71,0xE2,0x2D,0x0C,0x1B,0xEE,0x20,0xD5, +0xC9,0x20,0x1D,0x63,0x29,0x2D,0xCE,0xEC,0x5E,0x4E,0xC8,0x93,0xF8,0x21,0x61,0x9B, +0x34,0xEB,0x05,0xC6,0x5E,0xEC,0x5B,0x1A,0xBC,0xEB,0xC9,0xCF,0xCD,0xAC,0x34,0x40, +0x5F,0xB1,0x7A,0x66,0xEE,0x77,0xC8,0x48,0xA8,0x66,0x57,0x57,0x9F,0x54,0x58,0x8E, +0x0C,0x2B,0xB7,0x4F,0xA7,0x30,0xD9,0x56,0xEE,0xCA,0x7B,0x5D,0xE3,0xAD,0xC9,0x4F, +0x5E,0xE5,0x35,0xE7,0x31,0xCB,0xDA,0x93,0x5E,0xDC,0x8E,0x8F,0x80,0xDA,0xB6,0x91, +0x98,0x40,0x90,0x79,0xC3,0x78,0xC7,0xB6,0xB1,0xC4,0xB5,0x6A,0x18,0x38,0x03,0x10, +0x8D,0xD8,0xD4,0x37,0xA4,0x2E,0x05,0x7D,0x88,0xF5,0x82,0x3E,0x10,0x91,0x70,0xAB, +0x55,0x82,0x41,0x32,0xD7,0xDB,0x04,0x73,0x2A,0x6E,0x91,0x01,0x7C,0x21,0x4C,0xD4, +0xBC,0xAE,0x1B,0x03,0x75,0x5D,0x78,0x66,0xD9,0x3A,0x31,0x44,0x9A,0x33,0x40,0xBF, +0x08,0xD7,0x5A,0x49,0xA4,0xC2,0xE6,0xA9,0xA0,0x67,0xDD,0xA4,0x27,0xBC,0xA1,0x4F, +0x39,0xB5,0x11,0x58,0x17,0xF7,0x24,0x5C,0x46,0x8F,0x64,0xF7,0xC1,0x69,0x88,0x76, +0x98,0x76,0x3D,0x59,0x5D,0x42,0x76,0x87,0x89,0x97,0x69,0x7A,0x48,0xF0,0xE0,0xA2, +0x12,0x1B,0x66,0x9A,0x74,0xCA,0xDE,0x4B,0x1E,0xE7,0x0E,0x63,0xAE,0xE6,0xD4,0xEF, +0x92,0x92,0x3A,0x9E,0x3D,0xDC,0x00,0xE4,0x45,0x25,0x89,0xB6,0x9A,0x44,0x19,0x2B, +0x7E,0xC0,0x94,0xB4,0xD2,0x61,0x6D,0xEB,0x33,0xD9,0xC5,0xDF,0x4B,0x04,0x00,0xCC, +0x7D,0x1C,0x95,0xC3,0x8F,0xF7,0x21,0xB2,0xB2,0x11,0xB7,0xBB,0x7F,0xF2,0xD5,0x8C, +0x70,0x2C,0x41,0x60,0xAA,0xB1,0x63,0x18,0x44,0x95,0x1A,0x76,0x62,0x7E,0xF6,0x80, +0xB0,0xFB,0xE8,0x64,0xA6,0x33,0xD1,0x89,0x07,0xE1,0xBD,0xB7,0xE6,0x43,0xA4,0x18, +0xB8,0xA6,0x77,0x01,0xE1,0x0F,0x94,0x0C,0x21,0x1D,0xB2,0x54,0x29,0x25,0x89,0x6C, +0xE5,0x0E,0x52,0x51,0x47,0x74,0xBE,0x26,0xAC,0xB6,0x41,0x75,0xDE,0x7A,0xAC,0x5F, +0x8D,0x3F,0xC9,0xBC,0xD3,0x41,0x11,0x12,0x5B,0xE5,0x10,0x50,0xEB,0x31,0xC5,0xCA, +0x72,0x16,0x22,0x09,0xDF,0x7C,0x4C,0x75,0x3F,0x63,0xEC,0x21,0x5F,0xC4,0x20,0x51, +0x6B,0x6F,0xB1,0xAB,0x86,0x8B,0x4F,0xC2,0xD6,0x45,0x5F,0x9D,0x20,0xFC,0xA1,0x1E, +0xC5,0xC0,0x8F,0xA2,0xB1,0x7E,0x0A,0x26,0x99,0xF5,0xE4,0x69,0x2F,0x98,0x1D,0x2D, +0xF5,0xD9,0xA9,0xB2,0x1D,0xE5,0x1B,0x02,0x03,0x01,0x00,0x01,0xA3,0x42,0x30,0x40, +0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01, +0xFF,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01, +0x86,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0xEC,0xD7,0xE3,0x82, +0xD2,0x71,0x5D,0x64,0x4C,0xDF,0x2E,0x67,0x3F,0xE7,0xBA,0x98,0xAE,0x1C,0x0F,0x4F, +0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0C,0x05,0x00,0x03, +0x82,0x02,0x01,0x00,0xBB,0x61,0xD9,0x7D,0xA9,0x6C,0xBE,0x17,0xC4,0x91,0x1B,0xC3, +0xA1,0xA2,0x00,0x8D,0xE3,0x64,0x68,0x0F,0x56,0xCF,0x77,0xAE,0x70,0xF9,0xFD,0x9A, +0x4A,0x99,0xB9,0xC9,0x78,0x5C,0x0C,0x0C,0x5F,0xE4,0xE6,0x14,0x29,0x56,0x0B,0x36, +0x49,0x5D,0x44,0x63,0xE0,0xAD,0x9C,0x96,0x18,0x66,0x1B,0x23,0x0D,0x3D,0x79,0xE9, +0x6D,0x6B,0xD6,0x54,0xF8,0xD2,0x3C,0xC1,0x43,0x40,0xAE,0x1D,0x50,0xF5,0x52,0xFC, +0x90,0x3B,0xBB,0x98,0x99,0x69,0x6B,0xC7,0xC1,0xA7,0xA8,0x68,0xA4,0x27,0xDC,0x9D, +0xF9,0x27,0xAE,0x30,0x85,0xB9,0xF6,0x67,0x4D,0x3A,0x3E,0x8F,0x59,0x39,0x22,0x53, +0x44,0xEB,0xC8,0x5D,0x03,0xCA,0xED,0x50,0x7A,0x7D,0x62,0x21,0x0A,0x80,0xC8,0x73, +0x66,0xD1,0xA0,0x05,0x60,0x5F,0xE8,0xA5,0xB4,0xA7,0xAF,0xA8,0xF7,0x6D,0x35,0x9C, +0x7C,0x5A,0x8A,0xD6,0xA2,0x38,0x99,0xF3,0x78,0x8B,0xF4,0x4D,0xD2,0x20,0x0B,0xDE, +0x04,0xEE,0x8C,0x9B,0x47,0x81,0x72,0x0D,0xC0,0x14,0x32,0xEF,0x30,0x59,0x2E,0xAE, +0xE0,0x71,0xF2,0x56,0xE4,0x6A,0x97,0x6F,0x92,0x50,0x6D,0x96,0x8D,0x68,0x7A,0x9A, +0xB2,0x36,0x14,0x7A,0x06,0xF2,0x24,0xB9,0x09,0x11,0x50,0xD7,0x08,0xB1,0xB8,0x89, +0x7A,0x84,0x23,0x61,0x42,0x29,0xE5,0xA3,0xCD,0xA2,0x20,0x41,0xD7,0xD1,0x9C,0x64, +0xD9,0xEA,0x26,0xA1,0x8B,0x14,0xD7,0x4C,0x19,0xB2,0x50,0x41,0x71,0x3D,0x3F,0x4D, +0x70,0x23,0x86,0x0C,0x4A,0xDC,0x81,0xD2,0xCC,0x32,0x94,0x84,0x0D,0x08,0x09,0x97, +0x1C,0x4F,0xC0,0xEE,0x6B,0x20,0x74,0x30,0xD2,0xE0,0x39,0x34,0x10,0x85,0x21,0x15, +0x01,0x08,0xE8,0x55,0x32,0xDE,0x71,0x49,0xD9,0x28,0x17,0x50,0x4D,0xE6,0xBE,0x4D, +0xD1,0x75,0xAC,0xD0,0xCA,0xFB,0x41,0xB8,0x43,0xA5,0xAA,0xD3,0xC3,0x05,0x44,0x4F, +0x2C,0x36,0x9B,0xE2,0xFA,0xE2,0x45,0xB8,0x23,0x53,0x6C,0x06,0x6F,0x67,0x55,0x7F, +0x46,0xB5,0x4C,0x3F,0x6E,0x28,0x5A,0x79,0x26,0xD2,0xA4,0xA8,0x62,0x97,0xD2,0x1E, +0xE2,0xED,0x4A,0x8B,0xBC,0x1B,0xFD,0x47,0x4A,0x0D,0xDF,0x67,0x66,0x7E,0xB2,0x5B, +0x41,0xD0,0x3B,0xE4,0xF4,0x3B,0xF4,0x04,0x63,0xE9,0xEF,0xC2,0x54,0x00,0x51,0xA0, +0x8A,0x2A,0xC9,0xCE,0x78,0xCC,0xD5,0xEA,0x87,0x04,0x18,0xB3,0xCE,0xAF,0x49,0x88, +0xAF,0xF3,0x92,0x99,0xB6,0xB3,0xE6,0x61,0x0F,0xD2,0x85,0x00,0xE7,0x50,0x1A,0xE4, +0x1B,0x95,0x9D,0x19,0xA1,0xB9,0x9C,0xB1,0x9B,0xB1,0x00,0x1E,0xEF,0xD0,0x0F,0x4F, +0x42,0x6C,0xC9,0x0A,0xBC,0xEE,0x43,0xFA,0x3A,0x71,0xA5,0xC8,0x4D,0x26,0xA5,0x35, +0xFD,0x89,0x5D,0xBC,0x85,0x62,0x1D,0x32,0xD2,0xA0,0x2B,0x54,0xED,0x9A,0x57,0xC1, +0xDB,0xFA,0x10,0xCF,0x19,0xB7,0x8B,0x4A,0x1B,0x8F,0x01,0xB6,0x27,0x95,0x53,0xE8, +0xB6,0x89,0x6D,0x5B,0xBC,0x68,0xD4,0x23,0xE8,0x8B,0x51,0xA2,0x56,0xF9,0xF0,0xA6, +0x80,0xA0,0xD6,0x1E,0xB3,0xBC,0x0F,0x0F,0x53,0x75,0x29,0xAA,0xEA,0x13,0x77,0xE4, +0xDE,0x8C,0x81,0x21,0xAD,0x07,0x10,0x47,0x11,0xAD,0x87,0x3D,0x07,0xD1,0x75,0xBC, +0xCF,0xF3,0x66,0x7E, +}; + +/* subject: Common Name: Entrust Root Certification Authority; Organizational Unit: (c) 2006 Entrust, Inc., www.entrust.net/CPS is incorporated by reference; Organization: Entrust, Inc.; Country: US */ +/* issuer: Common Name: Entrust Root Certification Authority; Organizational Unit: (c) 2006 Entrust, Inc., www.entrust.net/CPS is incorporated by reference; Organization: Entrust, Inc.; Country: US */ +/* link: https://crt.sh/?q=73c176434f1bc6d5adf45b0e76e727287c8de57616c1e6e6141a2b2cbc7d8e4c */ +const unsigned char kCertificateWithFingerprint_73c176434f1bc6d5adf45b0e76e727287c8de57616c1e6e6141a2b2cbc7d8e4c_certificate[1173]={ +0x30,0x82,0x04,0x91,0x30,0x82,0x03,0x79,0xA0,0x03,0x02,0x01,0x02,0x02,0x04,0x45, +0x6B,0x50,0x54,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05, +0x05,0x00,0x30,0x81,0xB0,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02, +0x55,0x53,0x31,0x16,0x30,0x14,0x06,0x03,0x55,0x04,0x0A,0x13,0x0D,0x45,0x6E,0x74, +0x72,0x75,0x73,0x74,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x39,0x30,0x37,0x06,0x03, +0x55,0x04,0x0B,0x13,0x30,0x77,0x77,0x77,0x2E,0x65,0x6E,0x74,0x72,0x75,0x73,0x74, +0x2E,0x6E,0x65,0x74,0x2F,0x43,0x50,0x53,0x20,0x69,0x73,0x20,0x69,0x6E,0x63,0x6F, +0x72,0x70,0x6F,0x72,0x61,0x74,0x65,0x64,0x20,0x62,0x79,0x20,0x72,0x65,0x66,0x65, +0x72,0x65,0x6E,0x63,0x65,0x31,0x1F,0x30,0x1D,0x06,0x03,0x55,0x04,0x0B,0x13,0x16, +0x28,0x63,0x29,0x20,0x32,0x30,0x30,0x36,0x20,0x45,0x6E,0x74,0x72,0x75,0x73,0x74, +0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x2D,0x30,0x2B,0x06,0x03,0x55,0x04,0x03,0x13, +0x24,0x45,0x6E,0x74,0x72,0x75,0x73,0x74,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x65, +0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68, +0x6F,0x72,0x69,0x74,0x79,0x30,0x1E,0x17,0x0D,0x30,0x36,0x31,0x31,0x32,0x37,0x32, +0x30,0x32,0x33,0x34,0x32,0x5A,0x17,0x0D,0x32,0x36,0x31,0x31,0x32,0x37,0x32,0x30, +0x35,0x33,0x34,0x32,0x5A,0x30,0x81,0xB0,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04, +0x06,0x13,0x02,0x55,0x53,0x31,0x16,0x30,0x14,0x06,0x03,0x55,0x04,0x0A,0x13,0x0D, +0x45,0x6E,0x74,0x72,0x75,0x73,0x74,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x39,0x30, +0x37,0x06,0x03,0x55,0x04,0x0B,0x13,0x30,0x77,0x77,0x77,0x2E,0x65,0x6E,0x74,0x72, +0x75,0x73,0x74,0x2E,0x6E,0x65,0x74,0x2F,0x43,0x50,0x53,0x20,0x69,0x73,0x20,0x69, +0x6E,0x63,0x6F,0x72,0x70,0x6F,0x72,0x61,0x74,0x65,0x64,0x20,0x62,0x79,0x20,0x72, +0x65,0x66,0x65,0x72,0x65,0x6E,0x63,0x65,0x31,0x1F,0x30,0x1D,0x06,0x03,0x55,0x04, +0x0B,0x13,0x16,0x28,0x63,0x29,0x20,0x32,0x30,0x30,0x36,0x20,0x45,0x6E,0x74,0x72, +0x75,0x73,0x74,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x2D,0x30,0x2B,0x06,0x03,0x55, +0x04,0x03,0x13,0x24,0x45,0x6E,0x74,0x72,0x75,0x73,0x74,0x20,0x52,0x6F,0x6F,0x74, +0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41, +0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09, +0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00, +0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xB6,0x95,0xB6,0x43,0x42,0xFA,0xC6, +0x6D,0x2A,0x6F,0x48,0xDF,0x94,0x4C,0x39,0x57,0x05,0xEE,0xC3,0x79,0x11,0x41,0x68, +0x36,0xED,0xEC,0xFE,0x9A,0x01,0x8F,0xA1,0x38,0x28,0xFC,0xF7,0x10,0x46,0x66,0x2E, +0x4D,0x1E,0x1A,0xB1,0x1A,0x4E,0xC6,0xD1,0xC0,0x95,0x88,0xB0,0xC9,0xFF,0x31,0x8B, +0x33,0x03,0xDB,0xB7,0x83,0x7B,0x3E,0x20,0x84,0x5E,0xED,0xB2,0x56,0x28,0xA7,0xF8, +0xE0,0xB9,0x40,0x71,0x37,0xC5,0xCB,0x47,0x0E,0x97,0x2A,0x68,0xC0,0x22,0x95,0x62, +0x15,0xDB,0x47,0xD9,0xF5,0xD0,0x2B,0xFF,0x82,0x4B,0xC9,0xAD,0x3E,0xDE,0x4C,0xDB, +0x90,0x80,0x50,0x3F,0x09,0x8A,0x84,0x00,0xEC,0x30,0x0A,0x3D,0x18,0xCD,0xFB,0xFD, +0x2A,0x59,0x9A,0x23,0x95,0x17,0x2C,0x45,0x9E,0x1F,0x6E,0x43,0x79,0x6D,0x0C,0x5C, +0x98,0xFE,0x48,0xA7,0xC5,0x23,0x47,0x5C,0x5E,0xFD,0x6E,0xE7,0x1E,0xB4,0xF6,0x68, +0x45,0xD1,0x86,0x83,0x5B,0xA2,0x8A,0x8D,0xB1,0xE3,0x29,0x80,0xFE,0x25,0x71,0x88, +0xAD,0xBE,0xBC,0x8F,0xAC,0x52,0x96,0x4B,0xAA,0x51,0x8D,0xE4,0x13,0x31,0x19,0xE8, +0x4E,0x4D,0x9F,0xDB,0xAC,0xB3,0x6A,0xD5,0xBC,0x39,0x54,0x71,0xCA,0x7A,0x7A,0x7F, +0x90,0xDD,0x7D,0x1D,0x80,0xD9,0x81,0xBB,0x59,0x26,0xC2,0x11,0xFE,0xE6,0x93,0xE2, +0xF7,0x80,0xE4,0x65,0xFB,0x34,0x37,0x0E,0x29,0x80,0x70,0x4D,0xAF,0x38,0x86,0x2E, +0x9E,0x7F,0x57,0xAF,0x9E,0x17,0xAE,0xEB,0x1C,0xCB,0x28,0x21,0x5F,0xB6,0x1C,0xD8, +0xE7,0xA2,0x04,0x22,0xF9,0xD3,0xDA,0xD8,0xCB,0x02,0x03,0x01,0x00,0x01,0xA3,0x81, +0xB0,0x30,0x81,0xAD,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04, +0x03,0x02,0x01,0x06,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05, +0x30,0x03,0x01,0x01,0xFF,0x30,0x2B,0x06,0x03,0x55,0x1D,0x10,0x04,0x24,0x30,0x22, +0x80,0x0F,0x32,0x30,0x30,0x36,0x31,0x31,0x32,0x37,0x32,0x30,0x32,0x33,0x34,0x32, +0x5A,0x81,0x0F,0x32,0x30,0x32,0x36,0x31,0x31,0x32,0x37,0x32,0x30,0x35,0x33,0x34, +0x32,0x5A,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0x68, +0x90,0xE4,0x67,0xA4,0xA6,0x53,0x80,0xC7,0x86,0x66,0xA4,0xF1,0xF7,0x4B,0x43,0xFB, +0x84,0xBD,0x6D,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x68,0x90, +0xE4,0x67,0xA4,0xA6,0x53,0x80,0xC7,0x86,0x66,0xA4,0xF1,0xF7,0x4B,0x43,0xFB,0x84, +0xBD,0x6D,0x30,0x1D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF6,0x7D,0x07,0x41,0x00,0x04, +0x10,0x30,0x0E,0x1B,0x08,0x56,0x37,0x2E,0x31,0x3A,0x34,0x2E,0x30,0x03,0x02,0x04, +0x90,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00, +0x03,0x82,0x01,0x01,0x00,0x93,0xD4,0x30,0xB0,0xD7,0x03,0x20,0x2A,0xD0,0xF9,0x63, +0xE8,0x91,0x0C,0x05,0x20,0xA9,0x5F,0x19,0xCA,0x7B,0x72,0x4E,0xD4,0xB1,0xDB,0xD0, +0x96,0xFB,0x54,0x5A,0x19,0x2C,0x0C,0x08,0xF7,0xB2,0xBC,0x85,0xA8,0x9D,0x7F,0x6D, +0x3B,0x52,0xB3,0x2A,0xDB,0xE7,0xD4,0x84,0x8C,0x63,0xF6,0x0F,0xCB,0x26,0x01,0x91, +0x50,0x6C,0xF4,0x5F,0x14,0xE2,0x93,0x74,0xC0,0x13,0x9E,0x30,0x3A,0x50,0xE3,0xB4, +0x60,0xC5,0x1C,0xF0,0x22,0x44,0x8D,0x71,0x47,0xAC,0xC8,0x1A,0xC9,0xE9,0x9B,0x9A, +0x00,0x60,0x13,0xFF,0x70,0x7E,0x5F,0x11,0x4D,0x49,0x1B,0xB3,0x15,0x52,0x7B,0xC9, +0x54,0xDA,0xBF,0x9D,0x95,0xAF,0x6B,0x9A,0xD8,0x9E,0xE9,0xF1,0xE4,0x43,0x8D,0xE2, +0x11,0x44,0x3A,0xBF,0xAF,0xBD,0x83,0x42,0x73,0x52,0x8B,0xAA,0xBB,0xA7,0x29,0xCF, +0xF5,0x64,0x1C,0x0A,0x4D,0xD1,0xBC,0xAA,0xAC,0x9F,0x2A,0xD0,0xFF,0x7F,0x7F,0xDA, +0x7D,0xEA,0xB1,0xED,0x30,0x25,0xC1,0x84,0xDA,0x34,0xD2,0x5B,0x78,0x83,0x56,0xEC, +0x9C,0x36,0xC3,0x26,0xE2,0x11,0xF6,0x67,0x49,0x1D,0x92,0xAB,0x8C,0xFB,0xEB,0xFF, +0x7A,0xEE,0x85,0x4A,0xA7,0x50,0x80,0xF0,0xA7,0x5C,0x4A,0x94,0x2E,0x5F,0x05,0x99, +0x3C,0x52,0x41,0xE0,0xCD,0xB4,0x63,0xCF,0x01,0x43,0xBA,0x9C,0x83,0xDC,0x8F,0x60, +0x3B,0xF3,0x5A,0xB4,0xB4,0x7B,0xAE,0xDA,0x0B,0x90,0x38,0x75,0xEF,0x81,0x1D,0x66, +0xD2,0xF7,0x57,0x70,0x36,0xB3,0xBF,0xFC,0x28,0xAF,0x71,0x25,0x85,0x5B,0x13,0xFE, +0x1E,0x7F,0x5A,0xB4,0x3C, +}; + +/* subject: Common Name: Entrust Root Certification Authority - EC1; Organizational Unit: (c) 2012 Entrust, Inc. - for authorized use only, See www.entrust.net/legal-terms; Organization: Entrust, Inc.; Country: US */ +/* issuer: Common Name: Entrust Root Certification Authority - EC1; Organizational Unit: (c) 2012 Entrust, Inc. - for authorized use only, See www.entrust.net/legal-terms; Organization: Entrust, Inc.; Country: US */ +/* link: https://crt.sh/?q=02ed0eb28c14da45165c566791700d6451d7fb56f0b2ab1d3b8eb070e56edff5 */ +const unsigned char kCertificateWithFingerprint_02ed0eb28c14da45165c566791700d6451d7fb56f0b2ab1d3b8eb070e56edff5_certificate[765]={ +0x30,0x82,0x02,0xF9,0x30,0x82,0x02,0x80,0xA0,0x03,0x02,0x01,0x02,0x02,0x0D,0x00, +0xA6,0x8B,0x79,0x29,0x00,0x00,0x00,0x00,0x50,0xD0,0x91,0xF9,0x30,0x0A,0x06,0x08, +0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x03,0x30,0x81,0xBF,0x31,0x0B,0x30,0x09,0x06, +0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x16,0x30,0x14,0x06,0x03,0x55,0x04, +0x0A,0x13,0x0D,0x45,0x6E,0x74,0x72,0x75,0x73,0x74,0x2C,0x20,0x49,0x6E,0x63,0x2E, +0x31,0x28,0x30,0x26,0x06,0x03,0x55,0x04,0x0B,0x13,0x1F,0x53,0x65,0x65,0x20,0x77, +0x77,0x77,0x2E,0x65,0x6E,0x74,0x72,0x75,0x73,0x74,0x2E,0x6E,0x65,0x74,0x2F,0x6C, +0x65,0x67,0x61,0x6C,0x2D,0x74,0x65,0x72,0x6D,0x73,0x31,0x39,0x30,0x37,0x06,0x03, +0x55,0x04,0x0B,0x13,0x30,0x28,0x63,0x29,0x20,0x32,0x30,0x31,0x32,0x20,0x45,0x6E, +0x74,0x72,0x75,0x73,0x74,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x20,0x2D,0x20,0x66,0x6F, +0x72,0x20,0x61,0x75,0x74,0x68,0x6F,0x72,0x69,0x7A,0x65,0x64,0x20,0x75,0x73,0x65, +0x20,0x6F,0x6E,0x6C,0x79,0x31,0x33,0x30,0x31,0x06,0x03,0x55,0x04,0x03,0x13,0x2A, +0x45,0x6E,0x74,0x72,0x75,0x73,0x74,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x65,0x72, +0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F, +0x72,0x69,0x74,0x79,0x20,0x2D,0x20,0x45,0x43,0x31,0x30,0x1E,0x17,0x0D,0x31,0x32, +0x31,0x32,0x31,0x38,0x31,0x35,0x32,0x35,0x33,0x36,0x5A,0x17,0x0D,0x33,0x37,0x31, +0x32,0x31,0x38,0x31,0x35,0x35,0x35,0x33,0x36,0x5A,0x30,0x81,0xBF,0x31,0x0B,0x30, +0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x16,0x30,0x14,0x06,0x03, +0x55,0x04,0x0A,0x13,0x0D,0x45,0x6E,0x74,0x72,0x75,0x73,0x74,0x2C,0x20,0x49,0x6E, +0x63,0x2E,0x31,0x28,0x30,0x26,0x06,0x03,0x55,0x04,0x0B,0x13,0x1F,0x53,0x65,0x65, +0x20,0x77,0x77,0x77,0x2E,0x65,0x6E,0x74,0x72,0x75,0x73,0x74,0x2E,0x6E,0x65,0x74, +0x2F,0x6C,0x65,0x67,0x61,0x6C,0x2D,0x74,0x65,0x72,0x6D,0x73,0x31,0x39,0x30,0x37, +0x06,0x03,0x55,0x04,0x0B,0x13,0x30,0x28,0x63,0x29,0x20,0x32,0x30,0x31,0x32,0x20, +0x45,0x6E,0x74,0x72,0x75,0x73,0x74,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x20,0x2D,0x20, +0x66,0x6F,0x72,0x20,0x61,0x75,0x74,0x68,0x6F,0x72,0x69,0x7A,0x65,0x64,0x20,0x75, +0x73,0x65,0x20,0x6F,0x6E,0x6C,0x79,0x31,0x33,0x30,0x31,0x06,0x03,0x55,0x04,0x03, +0x13,0x2A,0x45,0x6E,0x74,0x72,0x75,0x73,0x74,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43, +0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74, +0x68,0x6F,0x72,0x69,0x74,0x79,0x20,0x2D,0x20,0x45,0x43,0x31,0x30,0x76,0x30,0x10, +0x06,0x07,0x2A,0x86,0x48,0xCE,0x3D,0x02,0x01,0x06,0x05,0x2B,0x81,0x04,0x00,0x22, +0x03,0x62,0x00,0x04,0x84,0x13,0xC9,0xD0,0xBA,0x6D,0x41,0x7B,0xE2,0x6C,0xD0,0xEB, +0x55,0x5F,0x66,0x02,0x1A,0x24,0xF4,0x5B,0x89,0x69,0x47,0xE3,0xB8,0xC2,0x7D,0xF1, +0xF2,0x02,0xC5,0x9F,0xA0,0xF6,0x5B,0xD5,0x8B,0x06,0x19,0x86,0x4F,0x53,0x10,0x6D, +0x07,0x24,0x27,0xA1,0xA0,0xF8,0xD5,0x47,0x19,0x61,0x4C,0x7D,0xCA,0x93,0x27,0xEA, +0x74,0x0C,0xEF,0x6F,0x96,0x09,0xFE,0x63,0xEC,0x70,0x5D,0x36,0xAD,0x67,0x77,0xAE, +0xC9,0x9D,0x7C,0x55,0x44,0x3A,0xA2,0x63,0x51,0x1F,0xF5,0xE3,0x62,0xD4,0xA9,0x47, +0x07,0x3E,0xCC,0x20,0xA3,0x42,0x30,0x40,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01, +0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01, +0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E, +0x04,0x16,0x04,0x14,0xB7,0x63,0xE7,0x1A,0xDD,0x8D,0xE9,0x08,0xA6,0x55,0x83,0xA4, +0xE0,0x6A,0x50,0x41,0x65,0x11,0x42,0x49,0x30,0x0A,0x06,0x08,0x2A,0x86,0x48,0xCE, +0x3D,0x04,0x03,0x03,0x03,0x67,0x00,0x30,0x64,0x02,0x30,0x61,0x79,0xD8,0xE5,0x42, +0x47,0xDF,0x1C,0xAE,0x53,0x99,0x17,0xB6,0x6F,0x1C,0x7D,0xE1,0xBF,0x11,0x94,0xD1, +0x03,0x88,0x75,0xE4,0x8D,0x89,0xA4,0x8A,0x77,0x46,0xDE,0x6D,0x61,0xEF,0x02,0xF5, +0xFB,0xB5,0xDF,0xCC,0xFE,0x4E,0xFF,0xFE,0xA9,0xE6,0xA7,0x02,0x30,0x5B,0x99,0xD7, +0x85,0x37,0x06,0xB5,0x7B,0x08,0xFD,0xEB,0x27,0x8B,0x4A,0x94,0xF9,0xE1,0xFA,0xA7, +0x8E,0x26,0x08,0xE8,0x7C,0x92,0x68,0x6D,0x73,0xD8,0x6F,0x26,0xAC,0x21,0x02,0xB8, +0x99,0xB7,0x26,0x41,0x5B,0x25,0x60,0xAE,0xD0,0x48,0x1A,0xEE,0x06, +}; + +/* subject: Common Name: Entrust Root Certification Authority - G2; Organizational Unit: (c) 2009 Entrust, Inc. - for authorized use only, See www.entrust.net/legal-terms; Organization: Entrust, Inc.; Country: US */ +/* issuer: Common Name: Entrust Root Certification Authority - G2; Organizational Unit: (c) 2009 Entrust, Inc. - for authorized use only, See www.entrust.net/legal-terms; Organization: Entrust, Inc.; Country: US */ +/* link: https://crt.sh/?q=43df5774b03e7fef5fe40d931a7bedf1bb2e6b42738c4e6d3841103d3aa7f339 */ +const unsigned char kCertificateWithFingerprint_43df5774b03e7fef5fe40d931a7bedf1bb2e6b42738c4e6d3841103d3aa7f339_certificate[1090]={ +0x30,0x82,0x04,0x3E,0x30,0x82,0x03,0x26,0xA0,0x03,0x02,0x01,0x02,0x02,0x04,0x4A, +0x53,0x8C,0x28,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B, +0x05,0x00,0x30,0x81,0xBE,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02, +0x55,0x53,0x31,0x16,0x30,0x14,0x06,0x03,0x55,0x04,0x0A,0x13,0x0D,0x45,0x6E,0x74, +0x72,0x75,0x73,0x74,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x28,0x30,0x26,0x06,0x03, +0x55,0x04,0x0B,0x13,0x1F,0x53,0x65,0x65,0x20,0x77,0x77,0x77,0x2E,0x65,0x6E,0x74, +0x72,0x75,0x73,0x74,0x2E,0x6E,0x65,0x74,0x2F,0x6C,0x65,0x67,0x61,0x6C,0x2D,0x74, +0x65,0x72,0x6D,0x73,0x31,0x39,0x30,0x37,0x06,0x03,0x55,0x04,0x0B,0x13,0x30,0x28, +0x63,0x29,0x20,0x32,0x30,0x30,0x39,0x20,0x45,0x6E,0x74,0x72,0x75,0x73,0x74,0x2C, +0x20,0x49,0x6E,0x63,0x2E,0x20,0x2D,0x20,0x66,0x6F,0x72,0x20,0x61,0x75,0x74,0x68, +0x6F,0x72,0x69,0x7A,0x65,0x64,0x20,0x75,0x73,0x65,0x20,0x6F,0x6E,0x6C,0x79,0x31, +0x32,0x30,0x30,0x06,0x03,0x55,0x04,0x03,0x13,0x29,0x45,0x6E,0x74,0x72,0x75,0x73, +0x74,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61, +0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x20,0x2D, +0x20,0x47,0x32,0x30,0x1E,0x17,0x0D,0x30,0x39,0x30,0x37,0x30,0x37,0x31,0x37,0x32, +0x35,0x35,0x34,0x5A,0x17,0x0D,0x33,0x30,0x31,0x32,0x30,0x37,0x31,0x37,0x35,0x35, +0x35,0x34,0x5A,0x30,0x81,0xBE,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13, +0x02,0x55,0x53,0x31,0x16,0x30,0x14,0x06,0x03,0x55,0x04,0x0A,0x13,0x0D,0x45,0x6E, +0x74,0x72,0x75,0x73,0x74,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x28,0x30,0x26,0x06, +0x03,0x55,0x04,0x0B,0x13,0x1F,0x53,0x65,0x65,0x20,0x77,0x77,0x77,0x2E,0x65,0x6E, +0x74,0x72,0x75,0x73,0x74,0x2E,0x6E,0x65,0x74,0x2F,0x6C,0x65,0x67,0x61,0x6C,0x2D, +0x74,0x65,0x72,0x6D,0x73,0x31,0x39,0x30,0x37,0x06,0x03,0x55,0x04,0x0B,0x13,0x30, +0x28,0x63,0x29,0x20,0x32,0x30,0x30,0x39,0x20,0x45,0x6E,0x74,0x72,0x75,0x73,0x74, +0x2C,0x20,0x49,0x6E,0x63,0x2E,0x20,0x2D,0x20,0x66,0x6F,0x72,0x20,0x61,0x75,0x74, +0x68,0x6F,0x72,0x69,0x7A,0x65,0x64,0x20,0x75,0x73,0x65,0x20,0x6F,0x6E,0x6C,0x79, +0x31,0x32,0x30,0x30,0x06,0x03,0x55,0x04,0x03,0x13,0x29,0x45,0x6E,0x74,0x72,0x75, +0x73,0x74,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63, +0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x20, +0x2D,0x20,0x47,0x32,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86, +0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A, +0x02,0x82,0x01,0x01,0x00,0xBA,0x84,0xB6,0x72,0xDB,0x9E,0x0C,0x6B,0xE2,0x99,0xE9, +0x30,0x01,0xA7,0x76,0xEA,0x32,0xB8,0x95,0x41,0x1A,0xC9,0xDA,0x61,0x4E,0x58,0x72, +0xCF,0xFE,0xF6,0x82,0x79,0xBF,0x73,0x61,0x06,0x0A,0xA5,0x27,0xD8,0xB3,0x5F,0xD3, +0x45,0x4E,0x1C,0x72,0xD6,0x4E,0x32,0xF2,0x72,0x8A,0x0F,0xF7,0x83,0x19,0xD0,0x6A, +0x80,0x80,0x00,0x45,0x1E,0xB0,0xC7,0xE7,0x9A,0xBF,0x12,0x57,0x27,0x1C,0xA3,0x68, +0x2F,0x0A,0x87,0xBD,0x6A,0x6B,0x0E,0x5E,0x65,0xF3,0x1C,0x77,0xD5,0xD4,0x85,0x8D, +0x70,0x21,0xB4,0xB3,0x32,0xE7,0x8B,0xA2,0xD5,0x86,0x39,0x02,0xB1,0xB8,0xD2,0x47, +0xCE,0xE4,0xC9,0x49,0xC4,0x3B,0xA7,0xDE,0xFB,0x54,0x7D,0x57,0xBE,0xF0,0xE8,0x6E, +0xC2,0x79,0xB2,0x3A,0x0B,0x55,0xE2,0x50,0x98,0x16,0x32,0x13,0x5C,0x2F,0x78,0x56, +0xC1,0xC2,0x94,0xB3,0xF2,0x5A,0xE4,0x27,0x9A,0x9F,0x24,0xD7,0xC6,0xEC,0xD0,0x9B, +0x25,0x82,0xE3,0xCC,0xC2,0xC4,0x45,0xC5,0x8C,0x97,0x7A,0x06,0x6B,0x2A,0x11,0x9F, +0xA9,0x0A,0x6E,0x48,0x3B,0x6F,0xDB,0xD4,0x11,0x19,0x42,0xF7,0x8F,0x07,0xBF,0xF5, +0x53,0x5F,0x9C,0x3E,0xF4,0x17,0x2C,0xE6,0x69,0xAC,0x4E,0x32,0x4C,0x62,0x77,0xEA, +0xB7,0xE8,0xE5,0xBB,0x34,0xBC,0x19,0x8B,0xAE,0x9C,0x51,0xE7,0xB7,0x7E,0xB5,0x53, +0xB1,0x33,0x22,0xE5,0x6D,0xCF,0x70,0x3C,0x1A,0xFA,0xE2,0x9B,0x67,0xB6,0x83,0xF4, +0x8D,0xA5,0xAF,0x62,0x4C,0x4D,0xE0,0x58,0xAC,0x64,0x34,0x12,0x03,0xF8,0xB6,0x8D, +0x94,0x63,0x24,0xA4,0x71,0x02,0x03,0x01,0x00,0x01,0xA3,0x42,0x30,0x40,0x30,0x0E, +0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x0F, +0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30, +0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x6A,0x72,0x26,0x7A,0xD0,0x1E, +0xEF,0x7D,0xE7,0x3B,0x69,0x51,0xD4,0x6C,0x8D,0x9F,0x90,0x12,0x66,0xAB,0x30,0x0D, +0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x03,0x82,0x01, +0x01,0x00,0x79,0x9F,0x1D,0x96,0xC6,0xB6,0x79,0x3F,0x22,0x8D,0x87,0xD3,0x87,0x03, +0x04,0x60,0x6A,0x6B,0x9A,0x2E,0x59,0x89,0x73,0x11,0xAC,0x43,0xD1,0xF5,0x13,0xFF, +0x8D,0x39,0x2B,0xC0,0xF2,0xBD,0x4F,0x70,0x8C,0xA9,0x2F,0xEA,0x17,0xC4,0x0B,0x54, +0x9E,0xD4,0x1B,0x96,0x98,0x33,0x3C,0xA8,0xAD,0x62,0xA2,0x00,0x76,0xAB,0x59,0x69, +0x6E,0x06,0x1D,0x7E,0xC4,0xB9,0x44,0x8D,0x98,0xAF,0x12,0xD4,0x61,0xDB,0x0A,0x19, +0x46,0x47,0xF3,0xEB,0xF7,0x63,0xC1,0x40,0x05,0x40,0xA5,0xD2,0xB7,0xF4,0xB5,0x9A, +0x36,0xBF,0xA9,0x88,0x76,0x88,0x04,0x55,0x04,0x2B,0x9C,0x87,0x7F,0x1A,0x37,0x3C, +0x7E,0x2D,0xA5,0x1A,0xD8,0xD4,0x89,0x5E,0xCA,0xBD,0xAC,0x3D,0x6C,0xD8,0x6D,0xAF, +0xD5,0xF3,0x76,0x0F,0xCD,0x3B,0x88,0x38,0x22,0x9D,0x6C,0x93,0x9A,0xC4,0x3D,0xBF, +0x82,0x1B,0x65,0x3F,0xA6,0x0F,0x5D,0xAA,0xFC,0xE5,0xB2,0x15,0xCA,0xB5,0xAD,0xC6, +0xBC,0x3D,0xD0,0x84,0xE8,0xEA,0x06,0x72,0xB0,0x4D,0x39,0x32,0x78,0xBF,0x3E,0x11, +0x9C,0x0B,0xA4,0x9D,0x9A,0x21,0xF3,0xF0,0x9B,0x0B,0x30,0x78,0xDB,0xC1,0xDC,0x87, +0x43,0xFE,0xBC,0x63,0x9A,0xCA,0xC5,0xC2,0x1C,0xC9,0xC7,0x8D,0xFF,0x3B,0x12,0x58, +0x08,0xE6,0xB6,0x3D,0xEC,0x7A,0x2C,0x4E,0xFB,0x83,0x96,0xCE,0x0C,0x3C,0x69,0x87, +0x54,0x73,0xA4,0x73,0xC2,0x93,0xFF,0x51,0x10,0xAC,0x15,0x54,0x01,0xD8,0xFC,0x05, +0xB1,0x89,0xA1,0x7F,0x74,0x83,0x9A,0x49,0xD7,0xDC,0x4E,0x7B,0x8A,0x48,0x6F,0x8B, +0x45,0xF6, +}; + +/* subject: Common Name: Entrust.net Certification Authority (2048); Organizational Unit: (c) 1999 Entrust.net Limited, www.entrust.net/CPS_2048 incorp. by ref. (limits liab.); Organization: Entrust.net */ +/* issuer: Common Name: Entrust.net Certification Authority (2048); Organizational Unit: (c) 1999 Entrust.net Limited, www.entrust.net/CPS_2048 incorp. by ref. (limits liab.); Organization: Entrust.net */ +/* link: https://crt.sh/?q=6dc47172e01cbcb0bf62580d895fe2b8ac9ad4f873801e0c10b9c837d21eb177 */ +const unsigned char kCertificateWithFingerprint_6dc47172e01cbcb0bf62580d895fe2b8ac9ad4f873801e0c10b9c837d21eb177_certificate[1070]={ +0x30,0x82,0x04,0x2A,0x30,0x82,0x03,0x12,0xA0,0x03,0x02,0x01,0x02,0x02,0x04,0x38, +0x63,0xDE,0xF8,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05, +0x05,0x00,0x30,0x81,0xB4,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x0A,0x13,0x0B, +0x45,0x6E,0x74,0x72,0x75,0x73,0x74,0x2E,0x6E,0x65,0x74,0x31,0x40,0x30,0x3E,0x06, +0x03,0x55,0x04,0x0B,0x14,0x37,0x77,0x77,0x77,0x2E,0x65,0x6E,0x74,0x72,0x75,0x73, +0x74,0x2E,0x6E,0x65,0x74,0x2F,0x43,0x50,0x53,0x5F,0x32,0x30,0x34,0x38,0x20,0x69, +0x6E,0x63,0x6F,0x72,0x70,0x2E,0x20,0x62,0x79,0x20,0x72,0x65,0x66,0x2E,0x20,0x28, +0x6C,0x69,0x6D,0x69,0x74,0x73,0x20,0x6C,0x69,0x61,0x62,0x2E,0x29,0x31,0x25,0x30, +0x23,0x06,0x03,0x55,0x04,0x0B,0x13,0x1C,0x28,0x63,0x29,0x20,0x31,0x39,0x39,0x39, +0x20,0x45,0x6E,0x74,0x72,0x75,0x73,0x74,0x2E,0x6E,0x65,0x74,0x20,0x4C,0x69,0x6D, +0x69,0x74,0x65,0x64,0x31,0x33,0x30,0x31,0x06,0x03,0x55,0x04,0x03,0x13,0x2A,0x45, +0x6E,0x74,0x72,0x75,0x73,0x74,0x2E,0x6E,0x65,0x74,0x20,0x43,0x65,0x72,0x74,0x69, +0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69, +0x74,0x79,0x20,0x28,0x32,0x30,0x34,0x38,0x29,0x30,0x1E,0x17,0x0D,0x39,0x39,0x31, +0x32,0x32,0x34,0x31,0x37,0x35,0x30,0x35,0x31,0x5A,0x17,0x0D,0x32,0x39,0x30,0x37, +0x32,0x34,0x31,0x34,0x31,0x35,0x31,0x32,0x5A,0x30,0x81,0xB4,0x31,0x14,0x30,0x12, +0x06,0x03,0x55,0x04,0x0A,0x13,0x0B,0x45,0x6E,0x74,0x72,0x75,0x73,0x74,0x2E,0x6E, +0x65,0x74,0x31,0x40,0x30,0x3E,0x06,0x03,0x55,0x04,0x0B,0x14,0x37,0x77,0x77,0x77, +0x2E,0x65,0x6E,0x74,0x72,0x75,0x73,0x74,0x2E,0x6E,0x65,0x74,0x2F,0x43,0x50,0x53, +0x5F,0x32,0x30,0x34,0x38,0x20,0x69,0x6E,0x63,0x6F,0x72,0x70,0x2E,0x20,0x62,0x79, +0x20,0x72,0x65,0x66,0x2E,0x20,0x28,0x6C,0x69,0x6D,0x69,0x74,0x73,0x20,0x6C,0x69, +0x61,0x62,0x2E,0x29,0x31,0x25,0x30,0x23,0x06,0x03,0x55,0x04,0x0B,0x13,0x1C,0x28, +0x63,0x29,0x20,0x31,0x39,0x39,0x39,0x20,0x45,0x6E,0x74,0x72,0x75,0x73,0x74,0x2E, +0x6E,0x65,0x74,0x20,0x4C,0x69,0x6D,0x69,0x74,0x65,0x64,0x31,0x33,0x30,0x31,0x06, +0x03,0x55,0x04,0x03,0x13,0x2A,0x45,0x6E,0x74,0x72,0x75,0x73,0x74,0x2E,0x6E,0x65, +0x74,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20, +0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x20,0x28,0x32,0x30,0x34,0x38,0x29, +0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01, +0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01, +0x00,0xAD,0x4D,0x4B,0xA9,0x12,0x86,0xB2,0xEA,0xA3,0x20,0x07,0x15,0x16,0x64,0x2A, +0x2B,0x4B,0xD1,0xBF,0x0B,0x4A,0x4D,0x8E,0xED,0x80,0x76,0xA5,0x67,0xB7,0x78,0x40, +0xC0,0x73,0x42,0xC8,0x68,0xC0,0xDB,0x53,0x2B,0xDD,0x5E,0xB8,0x76,0x98,0x35,0x93, +0x8B,0x1A,0x9D,0x7C,0x13,0x3A,0x0E,0x1F,0x5B,0xB7,0x1E,0xCF,0xE5,0x24,0x14,0x1E, +0xB1,0x81,0xA9,0x8D,0x7D,0xB8,0xCC,0x6B,0x4B,0x03,0xF1,0x02,0x0C,0xDC,0xAB,0xA5, +0x40,0x24,0x00,0x7F,0x74,0x94,0xA1,0x9D,0x08,0x29,0xB3,0x88,0x0B,0xF5,0x87,0x77, +0x9D,0x55,0xCD,0xE4,0xC3,0x7E,0xD7,0x6A,0x64,0xAB,0x85,0x14,0x86,0x95,0x5B,0x97, +0x32,0x50,0x6F,0x3D,0xC8,0xBA,0x66,0x0C,0xE3,0xFC,0xBD,0xB8,0x49,0xC1,0x76,0x89, +0x49,0x19,0xFD,0xC0,0xA8,0xBD,0x89,0xA3,0x67,0x2F,0xC6,0x9F,0xBC,0x71,0x19,0x60, +0xB8,0x2D,0xE9,0x2C,0xC9,0x90,0x76,0x66,0x7B,0x94,0xE2,0xAF,0x78,0xD6,0x65,0x53, +0x5D,0x3C,0xD6,0x9C,0xB2,0xCF,0x29,0x03,0xF9,0x2F,0xA4,0x50,0xB2,0xD4,0x48,0xCE, +0x05,0x32,0x55,0x8A,0xFD,0xB2,0x64,0x4C,0x0E,0xE4,0x98,0x07,0x75,0xDB,0x7F,0xDF, +0xB9,0x08,0x55,0x60,0x85,0x30,0x29,0xF9,0x7B,0x48,0xA4,0x69,0x86,0xE3,0x35,0x3F, +0x1E,0x86,0x5D,0x7A,0x7A,0x15,0xBD,0xEF,0x00,0x8E,0x15,0x22,0x54,0x17,0x00,0x90, +0x26,0x93,0xBC,0x0E,0x49,0x68,0x91,0xBF,0xF8,0x47,0xD3,0x9D,0x95,0x42,0xC1,0x0E, +0x4D,0xDF,0x6F,0x26,0xCF,0xC3,0x18,0x21,0x62,0x66,0x43,0x70,0xD6,0xD5,0xC0,0x07, +0xE1,0x02,0x03,0x01,0x00,0x01,0xA3,0x42,0x30,0x40,0x30,0x0E,0x06,0x03,0x55,0x1D, +0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x0F,0x06,0x03,0x55,0x1D, +0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x1D,0x06,0x03,0x55, +0x1D,0x0E,0x04,0x16,0x04,0x14,0x55,0xE4,0x81,0xD1,0x11,0x80,0xBE,0xD8,0x89,0xB9, +0x08,0xA3,0x31,0xF9,0xA1,0x24,0x09,0x16,0xB9,0x70,0x30,0x0D,0x06,0x09,0x2A,0x86, +0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x3B,0x9B, +0x8F,0x56,0x9B,0x30,0xE7,0x53,0x99,0x7C,0x7A,0x79,0xA7,0x4D,0x97,0xD7,0x19,0x95, +0x90,0xFB,0x06,0x1F,0xCA,0x33,0x7C,0x46,0x63,0x8F,0x96,0x66,0x24,0xFA,0x40,0x1B, +0x21,0x27,0xCA,0xE6,0x72,0x73,0xF2,0x4F,0xFE,0x31,0x99,0xFD,0xC8,0x0C,0x4C,0x68, +0x53,0xC6,0x80,0x82,0x13,0x98,0xFA,0xB6,0xAD,0xDA,0x5D,0x3D,0xF1,0xCE,0x6E,0xF6, +0x15,0x11,0x94,0x82,0x0C,0xEE,0x3F,0x95,0xAF,0x11,0xAB,0x0F,0xD7,0x2F,0xDE,0x1F, +0x03,0x8F,0x57,0x2C,0x1E,0xC9,0xBB,0x9A,0x1A,0x44,0x95,0xEB,0x18,0x4F,0xA6,0x1F, +0xCD,0x7D,0x57,0x10,0x2F,0x9B,0x04,0x09,0x5A,0x84,0xB5,0x6E,0xD8,0x1D,0x3A,0xE1, +0xD6,0x9E,0xD1,0x6C,0x79,0x5E,0x79,0x1C,0x14,0xC5,0xE3,0xD0,0x4C,0x93,0x3B,0x65, +0x3C,0xED,0xDF,0x3D,0xBE,0xA6,0xE5,0x95,0x1A,0xC3,0xB5,0x19,0xC3,0xBD,0x5E,0x5B, +0xBB,0xFF,0x23,0xEF,0x68,0x19,0xCB,0x12,0x93,0x27,0x5C,0x03,0x2D,0x6F,0x30,0xD0, +0x1E,0xB6,0x1A,0xAC,0xDE,0x5A,0xF7,0xD1,0xAA,0xA8,0x27,0xA6,0xFE,0x79,0x81,0xC4, +0x79,0x99,0x33,0x57,0xBA,0x12,0xB0,0xA9,0xE0,0x42,0x6C,0x93,0xCA,0x56,0xDE,0xFE, +0x6D,0x84,0x0B,0x08,0x8B,0x7E,0x8D,0xEA,0xD7,0x98,0x21,0xC6,0xF3,0xE7,0x3C,0x79, +0x2F,0x5E,0x9C,0xD1,0x4C,0x15,0x8D,0xE1,0xEC,0x22,0x37,0xCC,0x9A,0x43,0x0B,0x97, +0xDC,0x80,0x90,0x8D,0xB3,0x67,0x9B,0x6F,0x48,0x08,0x15,0x56,0xCF,0xBF,0xF1,0x2B, +0x7C,0x5E,0x9A,0x76,0xE9,0x59,0x90,0xC5,0x7C,0x83,0x35,0x11,0x65,0x51, +}; + +/* subject: Common Name: AffirmTrust Commercial, Organization: AffirmTrust, Country: US */ +/* issuer: Common Name: AffirmTrust Commercial, Organization: AffirmTrust, Country: US */ +/* link: https://crt.sh/?q=0376ab1d54c5f9803ce4b2e201a0ee7eef7b57b636e8a93c9b8d4860c96f5fa7 */ +const unsigned char kCertificateWithFingerprint_0376ab1d54c5f9803ce4b2e201a0ee7eef7b57b636e8a93c9b8d4860c96f5fa7_certificate[848]={ +0x30,0x82,0x03,0x4C,0x30,0x82,0x02,0x34,0xA0,0x03,0x02,0x01,0x02,0x02,0x08,0x77, +0x77,0x06,0x27,0x26,0xA9,0xB1,0x7C,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7, +0x0D,0x01,0x01,0x0B,0x05,0x00,0x30,0x44,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04, +0x06,0x13,0x02,0x55,0x53,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0B, +0x41,0x66,0x66,0x69,0x72,0x6D,0x54,0x72,0x75,0x73,0x74,0x31,0x1F,0x30,0x1D,0x06, +0x03,0x55,0x04,0x03,0x0C,0x16,0x41,0x66,0x66,0x69,0x72,0x6D,0x54,0x72,0x75,0x73, +0x74,0x20,0x43,0x6F,0x6D,0x6D,0x65,0x72,0x63,0x69,0x61,0x6C,0x30,0x1E,0x17,0x0D, +0x31,0x30,0x30,0x31,0x32,0x39,0x31,0x34,0x30,0x36,0x30,0x36,0x5A,0x17,0x0D,0x33, +0x30,0x31,0x32,0x33,0x31,0x31,0x34,0x30,0x36,0x30,0x36,0x5A,0x30,0x44,0x31,0x0B, +0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x14,0x30,0x12,0x06, +0x03,0x55,0x04,0x0A,0x0C,0x0B,0x41,0x66,0x66,0x69,0x72,0x6D,0x54,0x72,0x75,0x73, +0x74,0x31,0x1F,0x30,0x1D,0x06,0x03,0x55,0x04,0x03,0x0C,0x16,0x41,0x66,0x66,0x69, +0x72,0x6D,0x54,0x72,0x75,0x73,0x74,0x20,0x43,0x6F,0x6D,0x6D,0x65,0x72,0x63,0x69, +0x61,0x6C,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D, +0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82, +0x01,0x01,0x00,0xF6,0x1B,0x4F,0x67,0x07,0x2B,0xA1,0x15,0xF5,0x06,0x22,0xCB,0x1F, +0x01,0xB2,0xE3,0x73,0x45,0x06,0x44,0x49,0x2C,0xBB,0x49,0x25,0x14,0xD6,0xCE,0xC3, +0xB7,0xAB,0x2C,0x4F,0xC6,0x41,0x32,0x94,0x57,0xFA,0x12,0xA7,0x5B,0x0E,0xE2,0x8F, +0x1F,0x1E,0x86,0x19,0xA7,0xAA,0xB5,0x2D,0xB9,0x5F,0x0D,0x8A,0xC2,0xAF,0x85,0x35, +0x79,0x32,0x2D,0xBB,0x1C,0x62,0x37,0xF2,0xB1,0x5B,0x4A,0x3D,0xCA,0xCD,0x71,0x5F, +0xE9,0x42,0xBE,0x94,0xE8,0xC8,0xDE,0xF9,0x22,0x48,0x64,0xC6,0xE5,0xAB,0xC6,0x2B, +0x6D,0xAD,0x05,0xF0,0xFA,0xD5,0x0B,0xCF,0x9A,0xE5,0xF0,0x50,0xA4,0x8B,0x3B,0x47, +0xA5,0x23,0x5B,0x7A,0x7A,0xF8,0x33,0x3F,0xB8,0xEF,0x99,0x97,0xE3,0x20,0xC1,0xD6, +0x28,0x89,0xCF,0x94,0xFB,0xB9,0x45,0xED,0xE3,0x40,0x17,0x11,0xD4,0x74,0xF0,0x0B, +0x31,0xE2,0x2B,0x26,0x6A,0x9B,0x4C,0x57,0xAE,0xAC,0x20,0x3E,0xBA,0x45,0x7A,0x05, +0xF3,0xBD,0x9B,0x69,0x15,0xAE,0x7D,0x4E,0x20,0x63,0xC4,0x35,0x76,0x3A,0x07,0x02, +0xC9,0x37,0xFD,0xC7,0x47,0xEE,0xE8,0xF1,0x76,0x1D,0x73,0x15,0xF2,0x97,0xA4,0xB5, +0xC8,0x7A,0x79,0xD9,0x42,0xAA,0x2B,0x7F,0x5C,0xFE,0xCE,0x26,0x4F,0xA3,0x66,0x81, +0x35,0xAF,0x44,0xBA,0x54,0x1E,0x1C,0x30,0x32,0x65,0x9D,0xE6,0x3C,0x93,0x5E,0x50, +0x4E,0x7A,0xE3,0x3A,0xD4,0x6E,0xCC,0x1A,0xFB,0xF9,0xD2,0x37,0xAE,0x24,0x2A,0xAB, +0x57,0x03,0x22,0x28,0x0D,0x49,0x75,0x7F,0xB7,0x28,0xDA,0x75,0xBF,0x8E,0xE3,0xDC, +0x0E,0x79,0x31,0x02,0x03,0x01,0x00,0x01,0xA3,0x42,0x30,0x40,0x30,0x1D,0x06,0x03, +0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x9D,0x93,0xC6,0x53,0x8B,0x5E,0xCA,0xAF,0x3F, +0x9F,0x1E,0x0F,0xE5,0x99,0x95,0xBC,0x24,0xF6,0x94,0x8F,0x30,0x0F,0x06,0x03,0x55, +0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0E,0x06,0x03, +0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x0D,0x06,0x09, +0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x03,0x82,0x01,0x01,0x00, +0x58,0xAC,0xF4,0x04,0x0E,0xCD,0xC0,0x0D,0xFF,0x0A,0xFD,0xD4,0xBA,0x16,0x5F,0x29, +0xBD,0x7B,0x68,0x99,0x58,0x49,0xD2,0xB4,0x1D,0x37,0x4D,0x7F,0x27,0x7D,0x46,0x06, +0x5D,0x43,0xC6,0x86,0x2E,0x3E,0x73,0xB2,0x26,0x7D,0x4F,0x93,0xA9,0xB6,0xC4,0x2A, +0x9A,0xAB,0x21,0x97,0x14,0xB1,0xDE,0x8C,0xD3,0xAB,0x89,0x15,0xD8,0x6B,0x24,0xD4, +0xF1,0x16,0xAE,0xD8,0xA4,0x5C,0xD4,0x7F,0x51,0x8E,0xED,0x18,0x01,0xB1,0x93,0x63, +0xBD,0xBC,0xF8,0x61,0x80,0x9A,0x9E,0xB1,0xCE,0x42,0x70,0xE2,0xA9,0x7D,0x06,0x25, +0x7D,0x27,0xA1,0xFE,0x6F,0xEC,0xB3,0x1E,0x24,0xDA,0xE3,0x4B,0x55,0x1A,0x00,0x3B, +0x35,0xB4,0x3B,0xD9,0xD7,0x5D,0x30,0xFD,0x81,0x13,0x89,0xF2,0xC2,0x06,0x2B,0xED, +0x67,0xC4,0x8E,0xC9,0x43,0xB2,0x5C,0x6B,0x15,0x89,0x02,0xBC,0x62,0xFC,0x4E,0xF2, +0xB5,0x33,0xAA,0xB2,0x6F,0xD3,0x0A,0xA2,0x50,0xE3,0xF6,0x3B,0xE8,0x2E,0x44,0xC2, +0xDB,0x66,0x38,0xA9,0x33,0x56,0x48,0xF1,0x6D,0x1B,0x33,0x8D,0x0D,0x8C,0x3F,0x60, +0x37,0x9D,0xD3,0xCA,0x6D,0x7E,0x34,0x7E,0x0D,0x9F,0x72,0x76,0x8B,0x1B,0x9F,0x72, +0xFD,0x52,0x35,0x41,0x45,0x02,0x96,0x2F,0x1C,0xB2,0x9A,0x73,0x49,0x21,0xB1,0x49, +0x47,0x45,0x47,0xB4,0xEF,0x6A,0x34,0x11,0xC9,0x4D,0x9A,0xCC,0x59,0xB7,0xD6,0x02, +0x9E,0x5A,0x4E,0x65,0xB5,0x94,0xAE,0x1B,0xDF,0x29,0xB0,0x16,0xF1,0xBF,0x00,0x9E, +0x07,0x3A,0x17,0x64,0xB5,0x04,0xB5,0x23,0x21,0x99,0x0A,0x95,0x3B,0x97,0x7C,0xEF, +}; + +/* subject: Common Name: AffirmTrust Networking, Organization: AffirmTrust, Country: US */ +/* issuer: Common Name: AffirmTrust Networking, Organization: AffirmTrust, Country: US */ +/* link: https://crt.sh/?q=0a81ec5a929777f145904af38d5d509f66b5e2c58fcdb531058b0e17f3f0b41b */ +const unsigned char kCertificateWithFingerprint_0a81ec5a929777f145904af38d5d509f66b5e2c58fcdb531058b0e17f3f0b41b_certificate[848]={ +0x30,0x82,0x03,0x4C,0x30,0x82,0x02,0x34,0xA0,0x03,0x02,0x01,0x02,0x02,0x08,0x7C, +0x4F,0x04,0x39,0x1C,0xD4,0x99,0x2D,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7, +0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x44,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04, +0x06,0x13,0x02,0x55,0x53,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0B, +0x41,0x66,0x66,0x69,0x72,0x6D,0x54,0x72,0x75,0x73,0x74,0x31,0x1F,0x30,0x1D,0x06, +0x03,0x55,0x04,0x03,0x0C,0x16,0x41,0x66,0x66,0x69,0x72,0x6D,0x54,0x72,0x75,0x73, +0x74,0x20,0x4E,0x65,0x74,0x77,0x6F,0x72,0x6B,0x69,0x6E,0x67,0x30,0x1E,0x17,0x0D, +0x31,0x30,0x30,0x31,0x32,0x39,0x31,0x34,0x30,0x38,0x32,0x34,0x5A,0x17,0x0D,0x33, +0x30,0x31,0x32,0x33,0x31,0x31,0x34,0x30,0x38,0x32,0x34,0x5A,0x30,0x44,0x31,0x0B, +0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x14,0x30,0x12,0x06, +0x03,0x55,0x04,0x0A,0x0C,0x0B,0x41,0x66,0x66,0x69,0x72,0x6D,0x54,0x72,0x75,0x73, +0x74,0x31,0x1F,0x30,0x1D,0x06,0x03,0x55,0x04,0x03,0x0C,0x16,0x41,0x66,0x66,0x69, +0x72,0x6D,0x54,0x72,0x75,0x73,0x74,0x20,0x4E,0x65,0x74,0x77,0x6F,0x72,0x6B,0x69, +0x6E,0x67,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D, +0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82, +0x01,0x01,0x00,0xB4,0x84,0xCC,0x33,0x17,0x2E,0x6B,0x94,0x6C,0x6B,0x61,0x52,0xA0, +0xEB,0xA3,0xCF,0x79,0x94,0x4C,0xE5,0x94,0x80,0x99,0xCB,0x55,0x64,0x44,0x65,0x8F, +0x67,0x64,0xE2,0x06,0xE3,0x5C,0x37,0x49,0xF6,0x2F,0x9B,0x84,0x84,0x1E,0x2D,0xF2, +0x60,0x9D,0x30,0x4E,0xCC,0x84,0x85,0xE2,0x2C,0xCF,0x1E,0x9E,0xFE,0x36,0xAB,0x33, +0x77,0x35,0x44,0xD8,0x35,0x96,0x1A,0x3D,0x36,0xE8,0x7A,0x0E,0xD8,0xD5,0x47,0xA1, +0x6A,0x69,0x8B,0xD9,0xFC,0xBB,0x3A,0xAE,0x79,0x5A,0xD5,0xF4,0xD6,0x71,0xBB,0x9A, +0x90,0x23,0x6B,0x9A,0xB7,0x88,0x74,0x87,0x0C,0x1E,0x5F,0xB9,0x9E,0x2D,0xFA,0xAB, +0x53,0x2B,0xDC,0xBB,0x76,0x3E,0x93,0x4C,0x08,0x08,0x8C,0x1E,0xA2,0x23,0x1C,0xD4, +0x6A,0xAD,0x22,0xBA,0x99,0x01,0x2E,0x6D,0x65,0xCB,0xBE,0x24,0x66,0x55,0x24,0x4B, +0x40,0x44,0xB1,0x1B,0xD7,0xE1,0xC2,0x85,0xC0,0xDE,0x10,0x3F,0x3D,0xED,0xB8,0xFC, +0xF1,0xF1,0x23,0x53,0xDC,0xBF,0x65,0x97,0x6F,0xD9,0xF9,0x40,0x71,0x8D,0x7D,0xBD, +0x95,0xD4,0xCE,0xBE,0xA0,0x5E,0x27,0x23,0xDE,0xFD,0xA6,0xD0,0x26,0x0E,0x00,0x29, +0xEB,0x3C,0x46,0xF0,0x3D,0x60,0xBF,0x3F,0x50,0xD2,0xDC,0x26,0x41,0x51,0x9E,0x14, +0x37,0x42,0x04,0xA3,0x70,0x57,0xA8,0x1B,0x87,0xED,0x2D,0xFA,0x7B,0xEE,0x8C,0x0A, +0xE3,0xA9,0x66,0x89,0x19,0xCB,0x41,0xF9,0xDD,0x44,0x36,0x61,0xCF,0xE2,0x77,0x46, +0xC8,0x7D,0xF6,0xF4,0x92,0x81,0x36,0xFD,0xDB,0x34,0xF1,0x72,0x7E,0xF3,0x0C,0x16, +0xBD,0xB4,0x15,0x02,0x03,0x01,0x00,0x01,0xA3,0x42,0x30,0x40,0x30,0x1D,0x06,0x03, +0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x07,0x1F,0xD2,0xE7,0x9C,0xDA,0xC2,0x6E,0xA2, +0x40,0xB4,0xB0,0x7A,0x50,0x10,0x50,0x74,0xC4,0xC8,0xBD,0x30,0x0F,0x06,0x03,0x55, +0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0E,0x06,0x03, +0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x0D,0x06,0x09, +0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00, +0x89,0x57,0xB2,0x16,0x7A,0xA8,0xC2,0xFD,0xD6,0xD9,0x9B,0x9B,0x34,0xC2,0x9C,0xB4, +0x32,0x14,0x4D,0xA7,0xA4,0xDF,0xEC,0xBE,0xA7,0xBE,0xF8,0x43,0xDB,0x91,0x37,0xCE, +0xB4,0x32,0x2E,0x50,0x55,0x1A,0x35,0x4E,0x76,0x43,0x71,0x20,0xEF,0x93,0x77,0x4E, +0x15,0x70,0x2E,0x87,0xC3,0xC1,0x1D,0x6D,0xDC,0xCB,0xB5,0x27,0xD4,0x2C,0x56,0xD1, +0x52,0x53,0x3A,0x44,0xD2,0x73,0xC8,0xC4,0x1B,0x05,0x65,0x5A,0x62,0x92,0x9C,0xEE, +0x41,0x8D,0x31,0xDB,0xE7,0x34,0xEA,0x59,0x21,0xD5,0x01,0x7A,0xD7,0x64,0xB8,0x64, +0x39,0xCD,0xC9,0xED,0xAF,0xED,0x4B,0x03,0x48,0xA7,0xA0,0x99,0x01,0x80,0xDC,0x65, +0xA3,0x36,0xAE,0x65,0x59,0x48,0x4F,0x82,0x4B,0xC8,0x65,0xF1,0x57,0x1D,0xE5,0x59, +0x2E,0x0A,0x3F,0x6C,0xD8,0xD1,0xF5,0xE5,0x09,0xB4,0x6C,0x54,0x00,0x0A,0xE0,0x15, +0x4D,0x87,0x75,0x6D,0xB7,0x58,0x96,0x5A,0xDD,0x6D,0xD2,0x00,0xA0,0xF4,0x9B,0x48, +0xBE,0xC3,0x37,0xA4,0xBA,0x36,0xE0,0x7C,0x87,0x85,0x97,0x1A,0x15,0xA2,0xDE,0x2E, +0xA2,0x5B,0xBD,0xAF,0x18,0xF9,0x90,0x50,0xCD,0x70,0x59,0xF8,0x27,0x67,0x47,0xCB, +0xC7,0xA0,0x07,0x3A,0x7D,0xD1,0x2C,0x5D,0x6C,0x19,0x3A,0x66,0xB5,0x7D,0xFD,0x91, +0x6F,0x82,0xB1,0xBE,0x08,0x93,0xDB,0x14,0x47,0xF1,0xA2,0x37,0xC7,0x45,0x9E,0x3C, +0xC7,0x77,0xAF,0x64,0xA8,0x93,0xDF,0xF6,0x69,0x83,0x82,0x60,0xF2,0x49,0x42,0x34, +0xED,0x5A,0x00,0x54,0x85,0x1C,0x16,0x36,0x92,0x0C,0x5C,0xFA,0xA6,0xAD,0xBF,0xDB, +}; + +/* subject: Common Name: AffirmTrust Premium, Organization: AffirmTrust, Country: US */ +/* issuer: Common Name: AffirmTrust Premium, Organization: AffirmTrust, Country: US */ +/* link: https://crt.sh/?q=70a73f7f376b60074248904534b11482d5bf0e698ecc498df52577ebf2e93b9a */ +const unsigned char kCertificateWithFingerprint_70a73f7f376b60074248904534b11482d5bf0e698ecc498df52577ebf2e93b9a_certificate[1354]={ +0x30,0x82,0x05,0x46,0x30,0x82,0x03,0x2E,0xA0,0x03,0x02,0x01,0x02,0x02,0x08,0x6D, +0x8C,0x14,0x46,0xB1,0xA6,0x0A,0xEE,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7, +0x0D,0x01,0x01,0x0C,0x05,0x00,0x30,0x41,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04, +0x06,0x13,0x02,0x55,0x53,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0B, +0x41,0x66,0x66,0x69,0x72,0x6D,0x54,0x72,0x75,0x73,0x74,0x31,0x1C,0x30,0x1A,0x06, +0x03,0x55,0x04,0x03,0x0C,0x13,0x41,0x66,0x66,0x69,0x72,0x6D,0x54,0x72,0x75,0x73, +0x74,0x20,0x50,0x72,0x65,0x6D,0x69,0x75,0x6D,0x30,0x1E,0x17,0x0D,0x31,0x30,0x30, +0x31,0x32,0x39,0x31,0x34,0x31,0x30,0x33,0x36,0x5A,0x17,0x0D,0x34,0x30,0x31,0x32, +0x33,0x31,0x31,0x34,0x31,0x30,0x33,0x36,0x5A,0x30,0x41,0x31,0x0B,0x30,0x09,0x06, +0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04, +0x0A,0x0C,0x0B,0x41,0x66,0x66,0x69,0x72,0x6D,0x54,0x72,0x75,0x73,0x74,0x31,0x1C, +0x30,0x1A,0x06,0x03,0x55,0x04,0x03,0x0C,0x13,0x41,0x66,0x66,0x69,0x72,0x6D,0x54, +0x72,0x75,0x73,0x74,0x20,0x50,0x72,0x65,0x6D,0x69,0x75,0x6D,0x30,0x82,0x02,0x22, +0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03, +0x82,0x02,0x0F,0x00,0x30,0x82,0x02,0x0A,0x02,0x82,0x02,0x01,0x00,0xC4,0x12,0xDF, +0xA9,0x5F,0xFE,0x41,0xDD,0xDD,0xF5,0x9F,0x8A,0xE3,0xF6,0xAC,0xE1,0x3C,0x78,0x9A, +0xBC,0xD8,0xF0,0x7F,0x7A,0xA0,0x33,0x2A,0xDC,0x8D,0x20,0x5B,0xAE,0x2D,0x6F,0xE7, +0x93,0xD9,0x36,0x70,0x6A,0x68,0xCF,0x8E,0x51,0xA3,0x85,0x5B,0x67,0x04,0xA0,0x10, +0x24,0x6F,0x5D,0x28,0x82,0xC1,0x97,0x57,0xD8,0x48,0x29,0x13,0xB6,0xE1,0xBE,0x91, +0x4D,0xDF,0x85,0x0C,0x53,0x18,0x9A,0x1E,0x24,0xA2,0x4F,0x8F,0xF0,0xA2,0x85,0x0B, +0xCB,0xF4,0x29,0x7F,0xD2,0xA4,0x58,0xEE,0x26,0x4D,0xC9,0xAA,0xA8,0x7B,0x9A,0xD9, +0xFA,0x38,0xDE,0x44,0x57,0x15,0xE5,0xF8,0x8C,0xC8,0xD9,0x48,0xE2,0x0D,0x16,0x27, +0x1D,0x1E,0xC8,0x83,0x85,0x25,0xB7,0xBA,0xAA,0x55,0x41,0xCC,0x03,0x22,0x4B,0x2D, +0x91,0x8D,0x8B,0xE6,0x89,0xAF,0x66,0xC7,0xE9,0xFF,0x2B,0xE9,0x3C,0xAC,0xDA,0xD2, +0xB3,0xC3,0xE1,0x68,0x9C,0x89,0xF8,0x7A,0x00,0x56,0xDE,0xF4,0x55,0x95,0x6C,0xFB, +0xBA,0x64,0xDD,0x62,0x8B,0xDF,0x0B,0x77,0x32,0xEB,0x62,0xCC,0x26,0x9A,0x9B,0xBB, +0xAA,0x62,0x83,0x4C,0xB4,0x06,0x7A,0x30,0xC8,0x29,0xBF,0xED,0x06,0x4D,0x97,0xB9, +0x1C,0xC4,0x31,0x2B,0xD5,0x5F,0xBC,0x53,0x12,0x17,0x9C,0x99,0x57,0x29,0x66,0x77, +0x61,0x21,0x31,0x07,0x2E,0x25,0x49,0x9D,0x18,0xF2,0xEE,0xF3,0x2B,0x71,0x8C,0xB5, +0xBA,0x39,0x07,0x49,0x77,0xFC,0xEF,0x2E,0x92,0x90,0x05,0x8D,0x2D,0x2F,0x77,0x7B, +0xEF,0x43,0xBF,0x35,0xBB,0x9A,0xD8,0xF9,0x73,0xA7,0x2C,0xF2,0xD0,0x57,0xEE,0x28, +0x4E,0x26,0x5F,0x8F,0x90,0x68,0x09,0x2F,0xB8,0xF8,0xDC,0x06,0xE9,0x2E,0x9A,0x3E, +0x51,0xA7,0xD1,0x22,0xC4,0x0A,0xA7,0x38,0x48,0x6C,0xB3,0xF9,0xFF,0x7D,0xAB,0x86, +0x57,0xE3,0xBA,0xD6,0x85,0x78,0x77,0xBA,0x43,0xEA,0x48,0x7F,0xF6,0xD8,0xBE,0x23, +0x6D,0x1E,0xBF,0xD1,0x36,0x6C,0x58,0x5C,0xF1,0xEE,0xA4,0x19,0x54,0x1A,0xF5,0x03, +0xD2,0x76,0xE6,0xE1,0x8C,0xBD,0x3C,0xB3,0xD3,0x48,0x4B,0xE2,0xC8,0xF8,0x7F,0x92, +0xA8,0x76,0x46,0x9C,0x42,0x65,0x3E,0xA4,0x1E,0xC1,0x07,0x03,0x5A,0x46,0x2D,0xB8, +0x97,0xF3,0xB7,0xD5,0xB2,0x55,0x21,0xEF,0xBA,0xDC,0x4C,0x00,0x97,0xFB,0x14,0x95, +0x27,0x33,0xBF,0xE8,0x43,0x47,0x46,0xD2,0x08,0x99,0x16,0x60,0x3B,0x9A,0x7E,0xD2, +0xE6,0xED,0x38,0xEA,0xEC,0x01,0x1E,0x3C,0x48,0x56,0x49,0x09,0xC7,0x4C,0x37,0x00, +0x9E,0x88,0x0E,0xC0,0x73,0xE1,0x6F,0x66,0xE9,0x72,0x47,0x30,0x3E,0x10,0xE5,0x0B, +0x03,0xC9,0x9A,0x42,0x00,0x6C,0xC5,0x94,0x7E,0x61,0xC4,0x8A,0xDF,0x7F,0x82,0x1A, +0x0B,0x59,0xC4,0x59,0x32,0x77,0xB3,0xBC,0x60,0x69,0x56,0x39,0xFD,0xB4,0x06,0x7B, +0x2C,0xD6,0x64,0x36,0xD9,0xBD,0x48,0xED,0x84,0x1F,0x7E,0xA5,0x22,0x8F,0x2A,0xB8, +0x42,0xF4,0x82,0xB7,0xD4,0x53,0x90,0x78,0x4E,0x2D,0x1A,0xFD,0x81,0x6F,0x44,0xD7, +0x3B,0x01,0x74,0x96,0x42,0xE0,0x00,0xE2,0x2E,0x6B,0xEA,0xC5,0xEE,0x72,0xAC,0xBB, +0xBF,0xFE,0xEA,0xAA,0xA8,0xF8,0xDC,0xF6,0xB2,0x79,0x8A,0xB6,0x67,0x02,0x03,0x01, +0x00,0x01,0xA3,0x42,0x30,0x40,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04, +0x14,0x9D,0xC0,0x67,0xA6,0x0C,0x22,0xD9,0x26,0xF5,0x45,0xAB,0xA6,0x65,0x52,0x11, +0x27,0xD8,0x45,0xAC,0x63,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04, +0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF, +0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D, +0x01,0x01,0x0C,0x05,0x00,0x03,0x82,0x02,0x01,0x00,0xB3,0x57,0x4D,0x10,0x62,0x4E, +0x3A,0xE4,0xAC,0xEA,0xB8,0x1C,0xAF,0x32,0x23,0xC8,0xB3,0x49,0x5A,0x51,0x9C,0x76, +0x28,0x8D,0x79,0xAA,0x57,0x46,0x17,0xD5,0xF5,0x52,0xF6,0xB7,0x44,0xE8,0x08,0x44, +0xBF,0x18,0x84,0xD2,0x0B,0x80,0xCD,0xC5,0x12,0xFD,0x00,0x55,0x05,0x61,0x87,0x41, +0xDC,0xB5,0x24,0x9E,0x3C,0xC4,0xD8,0xC8,0xFB,0x70,0x9E,0x2F,0x78,0x96,0x83,0x20, +0x36,0xDE,0x7C,0x0F,0x69,0x13,0x88,0xA5,0x75,0x36,0x98,0x08,0xA6,0xC6,0xDF,0xAC, +0xCE,0xE3,0x58,0xD6,0xB7,0x3E,0xDE,0xBA,0xF3,0xEB,0x34,0x40,0xD8,0xA2,0x81,0xF5, +0x78,0x3F,0x2F,0xD5,0xA5,0xFC,0xD9,0xA2,0xD4,0x5E,0x04,0x0E,0x17,0xAD,0xFE,0x41, +0xF0,0xE5,0xB2,0x72,0xFA,0x44,0x82,0x33,0x42,0xE8,0x2D,0x58,0xF7,0x56,0x8C,0x62, +0x3F,0xBA,0x42,0xB0,0x9C,0x0C,0x5C,0x7E,0x2E,0x65,0x26,0x5C,0x53,0x4F,0x00,0xB2, +0x78,0x7E,0xA1,0x0D,0x99,0x2D,0x8D,0xB8,0x1D,0x8E,0xA2,0xC4,0xB0,0xFD,0x60,0xD0, +0x30,0xA4,0x8E,0xC8,0x04,0x62,0xA9,0xC4,0xED,0x35,0xDE,0x7A,0x97,0xED,0x0E,0x38, +0x5E,0x92,0x2F,0x93,0x70,0xA5,0xA9,0x9C,0x6F,0xA7,0x7D,0x13,0x1D,0x7E,0xC6,0x08, +0x48,0xB1,0x5E,0x67,0xEB,0x51,0x08,0x25,0xE9,0xE6,0x25,0x6B,0x52,0x29,0x91,0x9C, +0xD2,0x39,0x73,0x08,0x57,0xDE,0x99,0x06,0xB4,0x5B,0x9D,0x10,0x06,0xE1,0xC2,0x00, +0xA8,0xB8,0x1C,0x4A,0x02,0x0A,0x14,0xD0,0xC1,0x41,0xCA,0xFB,0x8C,0x35,0x21,0x7D, +0x82,0x38,0xF2,0xA9,0x54,0x91,0x19,0x35,0x93,0x94,0x6D,0x6A,0x3A,0xC5,0xB2,0xD0, +0xBB,0x89,0x86,0x93,0xE8,0x9B,0xC9,0x0F,0x3A,0xA7,0x7A,0xB8,0xA1,0xF0,0x78,0x46, +0xFA,0xFC,0x37,0x2F,0xE5,0x8A,0x84,0xF3,0xDF,0xFE,0x04,0xD9,0xA1,0x68,0xA0,0x2F, +0x24,0xE2,0x09,0x95,0x06,0xD5,0x95,0xCA,0xE1,0x24,0x96,0xEB,0x7C,0xF6,0x93,0x05, +0xBB,0xED,0x73,0xE9,0x2D,0xD1,0x75,0x39,0xD7,0xE7,0x24,0xDB,0xD8,0x4E,0x5F,0x43, +0x8F,0x9E,0xD0,0x14,0x39,0xBF,0x55,0x70,0x48,0x99,0x57,0x31,0xB4,0x9C,0xEE,0x4A, +0x98,0x03,0x96,0x30,0x1F,0x60,0x06,0xEE,0x1B,0x23,0xFE,0x81,0x60,0x23,0x1A,0x47, +0x62,0x85,0xA5,0xCC,0x19,0x34,0x80,0x6F,0xB3,0xAC,0x1A,0xE3,0x9F,0xF0,0x7B,0x48, +0xAD,0xD5,0x01,0xD9,0x67,0xB6,0xA9,0x72,0x93,0xEA,0x2D,0x66,0xB5,0xB2,0xB8,0xE4, +0x3D,0x3C,0xB2,0xEF,0x4C,0x8C,0xEA,0xEB,0x07,0xBF,0xAB,0x35,0x9A,0x55,0x86,0xBC, +0x18,0xA6,0xB5,0xA8,0x5E,0xB4,0x83,0x6C,0x6B,0x69,0x40,0xD3,0x9F,0xDC,0xF1,0xC3, +0x69,0x6B,0xB9,0xE1,0x6D,0x09,0xF4,0xF1,0xAA,0x50,0x76,0x0A,0x7A,0x7D,0x7A,0x17, +0xA1,0x55,0x96,0x42,0x99,0x31,0x09,0xDD,0x60,0x11,0x8D,0x05,0x30,0x7E,0xE6,0x8E, +0x46,0xD1,0x9D,0x14,0xDA,0xC7,0x17,0xE4,0x05,0x96,0x8C,0xC4,0x24,0xB5,0x1B,0xCF, +0x14,0x07,0xB2,0x40,0xF8,0xA3,0x9E,0x41,0x86,0xBC,0x04,0xD0,0x6B,0x96,0xC8,0x2A, +0x80,0x34,0xFD,0xBF,0xEF,0x06,0xA3,0xDD,0x58,0xC5,0x85,0x3D,0x3E,0x8F,0xFE,0x9E, +0x29,0xE0,0xB6,0xB8,0x09,0x68,0x19,0x1C,0x18,0x43, +}; + +/* subject: Common Name: AffirmTrust Premium ECC, Organization: AffirmTrust, Country: US */ +/* issuer: Common Name: AffirmTrust Premium ECC, Organization: AffirmTrust, Country: US */ +/* link: https://crt.sh/?q=bd71fdf6da97e4cf62d1647add2581b07d79adf8397eb4ecba9c5e8488821423 */ +const unsigned char kCertificateWithFingerprint_bd71fdf6da97e4cf62d1647add2581b07d79adf8397eb4ecba9c5e8488821423_certificate[514]={ +0x30,0x82,0x01,0xFE,0x30,0x82,0x01,0x85,0xA0,0x03,0x02,0x01,0x02,0x02,0x08,0x74, +0x97,0x25,0x8A,0xC7,0x3F,0x7A,0x54,0x30,0x0A,0x06,0x08,0x2A,0x86,0x48,0xCE,0x3D, +0x04,0x03,0x03,0x30,0x45,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02, +0x55,0x53,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0B,0x41,0x66,0x66, +0x69,0x72,0x6D,0x54,0x72,0x75,0x73,0x74,0x31,0x20,0x30,0x1E,0x06,0x03,0x55,0x04, +0x03,0x0C,0x17,0x41,0x66,0x66,0x69,0x72,0x6D,0x54,0x72,0x75,0x73,0x74,0x20,0x50, +0x72,0x65,0x6D,0x69,0x75,0x6D,0x20,0x45,0x43,0x43,0x30,0x1E,0x17,0x0D,0x31,0x30, +0x30,0x31,0x32,0x39,0x31,0x34,0x32,0x30,0x32,0x34,0x5A,0x17,0x0D,0x34,0x30,0x31, +0x32,0x33,0x31,0x31,0x34,0x32,0x30,0x32,0x34,0x5A,0x30,0x45,0x31,0x0B,0x30,0x09, +0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x14,0x30,0x12,0x06,0x03,0x55, +0x04,0x0A,0x0C,0x0B,0x41,0x66,0x66,0x69,0x72,0x6D,0x54,0x72,0x75,0x73,0x74,0x31, +0x20,0x30,0x1E,0x06,0x03,0x55,0x04,0x03,0x0C,0x17,0x41,0x66,0x66,0x69,0x72,0x6D, +0x54,0x72,0x75,0x73,0x74,0x20,0x50,0x72,0x65,0x6D,0x69,0x75,0x6D,0x20,0x45,0x43, +0x43,0x30,0x76,0x30,0x10,0x06,0x07,0x2A,0x86,0x48,0xCE,0x3D,0x02,0x01,0x06,0x05, +0x2B,0x81,0x04,0x00,0x22,0x03,0x62,0x00,0x04,0x0D,0x30,0x5E,0x1B,0x15,0x9D,0x03, +0xD0,0xA1,0x79,0x35,0xB7,0x3A,0x3C,0x92,0x7A,0xCA,0x15,0x1C,0xCD,0x62,0xF3,0x9C, +0x26,0x5C,0x07,0x3D,0xE5,0x54,0xFA,0xA3,0xD6,0xCC,0x12,0xEA,0xF4,0x14,0x5F,0xE8, +0x8E,0x19,0xAB,0x2F,0x2E,0x48,0xE6,0xAC,0x18,0x43,0x78,0xAC,0xD0,0x37,0xC3,0xBD, +0xB2,0xCD,0x2C,0xE6,0x47,0xE2,0x1A,0xE6,0x63,0xB8,0x3D,0x2E,0x2F,0x78,0xC4,0x4F, +0xDB,0xF4,0x0F,0xA4,0x68,0x4C,0x55,0x72,0x6B,0x95,0x1D,0x4E,0x18,0x42,0x95,0x78, +0xCC,0x37,0x3C,0x91,0xE2,0x9B,0x65,0x2B,0x29,0xA3,0x42,0x30,0x40,0x30,0x1D,0x06, +0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x9A,0xAF,0x29,0x7A,0xC0,0x11,0x35,0x35, +0x26,0x51,0x30,0x00,0xC3,0x6A,0xFE,0x40,0xD5,0xAE,0xD6,0x3C,0x30,0x0F,0x06,0x03, +0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0E,0x06, +0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x0A,0x06, +0x08,0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x03,0x03,0x67,0x00,0x30,0x64,0x02,0x30, +0x17,0x09,0xF3,0x87,0x88,0x50,0x5A,0xAF,0xC8,0xC0,0x42,0xBF,0x47,0x5F,0xF5,0x6C, +0x6A,0x86,0xE0,0xC4,0x27,0x74,0xE4,0x38,0x53,0xD7,0x05,0x7F,0x1B,0x34,0xE3,0xC6, +0x2F,0xB3,0xCA,0x09,0x3C,0x37,0x9D,0xD7,0xE7,0xB8,0x46,0xF1,0xFD,0xA1,0xE2,0x71, +0x02,0x30,0x42,0x59,0x87,0x43,0xD4,0x51,0xDF,0xBA,0xD3,0x09,0x32,0x5A,0xCE,0x88, +0x7E,0x57,0x3D,0x9C,0x5F,0x42,0x6B,0xF5,0x07,0x2D,0xB5,0xF0,0x82,0x93,0xF9,0x59, +0x6F,0xAE,0x64,0xFA,0x58,0xE5,0x8B,0x1E,0xE3,0x63,0xBE,0xB5,0x81,0xCD,0x6F,0x02, +0x8C,0x79, +}; + +/* subject: Common Name: GlobalSign Root CA, Organizational Unit: Root CA, Organization: GlobalSign nv-sa, Country: BE */ +/* issuer: Common Name: GlobalSign Root CA, Organizational Unit: Root CA, Organization: GlobalSign nv-sa, Country: BE */ +/* link: https://crt.sh/?q=ebd41040e4bb3ec742c9e381d31ef2a41a48b6685c96e7cef3c1df6cd4331c99 */ +const unsigned char kCertificateWithFingerprint_ebd41040e4bb3ec742c9e381d31ef2a41a48b6685c96e7cef3c1df6cd4331c99_certificate[889]={ +0x30,0x82,0x03,0x75,0x30,0x82,0x02,0x5D,0xA0,0x03,0x02,0x01,0x02,0x02,0x0B,0x04, +0x00,0x00,0x00,0x00,0x01,0x15,0x4B,0x5A,0xC3,0x94,0x30,0x0D,0x06,0x09,0x2A,0x86, +0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x57,0x31,0x0B,0x30,0x09,0x06, +0x03,0x55,0x04,0x06,0x13,0x02,0x42,0x45,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04, +0x0A,0x13,0x10,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x53,0x69,0x67,0x6E,0x20,0x6E,0x76, +0x2D,0x73,0x61,0x31,0x10,0x30,0x0E,0x06,0x03,0x55,0x04,0x0B,0x13,0x07,0x52,0x6F, +0x6F,0x74,0x20,0x43,0x41,0x31,0x1B,0x30,0x19,0x06,0x03,0x55,0x04,0x03,0x13,0x12, +0x47,0x6C,0x6F,0x62,0x61,0x6C,0x53,0x69,0x67,0x6E,0x20,0x52,0x6F,0x6F,0x74,0x20, +0x43,0x41,0x30,0x1E,0x17,0x0D,0x39,0x38,0x30,0x39,0x30,0x31,0x31,0x32,0x30,0x30, +0x30,0x30,0x5A,0x17,0x0D,0x32,0x38,0x30,0x31,0x32,0x38,0x31,0x32,0x30,0x30,0x30, +0x30,0x5A,0x30,0x57,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x42, +0x45,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04,0x0A,0x13,0x10,0x47,0x6C,0x6F,0x62, +0x61,0x6C,0x53,0x69,0x67,0x6E,0x20,0x6E,0x76,0x2D,0x73,0x61,0x31,0x10,0x30,0x0E, +0x06,0x03,0x55,0x04,0x0B,0x13,0x07,0x52,0x6F,0x6F,0x74,0x20,0x43,0x41,0x31,0x1B, +0x30,0x19,0x06,0x03,0x55,0x04,0x03,0x13,0x12,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x53, +0x69,0x67,0x6E,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x41,0x30,0x82,0x01,0x22,0x30, +0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82, +0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xDA,0x0E,0xE6,0x99, +0x8D,0xCE,0xA3,0xE3,0x4F,0x8A,0x7E,0xFB,0xF1,0x8B,0x83,0x25,0x6B,0xEA,0x48,0x1F, +0xF1,0x2A,0xB0,0xB9,0x95,0x11,0x04,0xBD,0xF0,0x63,0xD1,0xE2,0x67,0x66,0xCF,0x1C, +0xDD,0xCF,0x1B,0x48,0x2B,0xEE,0x8D,0x89,0x8E,0x9A,0xAF,0x29,0x80,0x65,0xAB,0xE9, +0xC7,0x2D,0x12,0xCB,0xAB,0x1C,0x4C,0x70,0x07,0xA1,0x3D,0x0A,0x30,0xCD,0x15,0x8D, +0x4F,0xF8,0xDD,0xD4,0x8C,0x50,0x15,0x1C,0xEF,0x50,0xEE,0xC4,0x2E,0xF7,0xFC,0xE9, +0x52,0xF2,0x91,0x7D,0xE0,0x6D,0xD5,0x35,0x30,0x8E,0x5E,0x43,0x73,0xF2,0x41,0xE9, +0xD5,0x6A,0xE3,0xB2,0x89,0x3A,0x56,0x39,0x38,0x6F,0x06,0x3C,0x88,0x69,0x5B,0x2A, +0x4D,0xC5,0xA7,0x54,0xB8,0x6C,0x89,0xCC,0x9B,0xF9,0x3C,0xCA,0xE5,0xFD,0x89,0xF5, +0x12,0x3C,0x92,0x78,0x96,0xD6,0xDC,0x74,0x6E,0x93,0x44,0x61,0xD1,0x8D,0xC7,0x46, +0xB2,0x75,0x0E,0x86,0xE8,0x19,0x8A,0xD5,0x6D,0x6C,0xD5,0x78,0x16,0x95,0xA2,0xE9, +0xC8,0x0A,0x38,0xEB,0xF2,0x24,0x13,0x4F,0x73,0x54,0x93,0x13,0x85,0x3A,0x1B,0xBC, +0x1E,0x34,0xB5,0x8B,0x05,0x8C,0xB9,0x77,0x8B,0xB1,0xDB,0x1F,0x20,0x91,0xAB,0x09, +0x53,0x6E,0x90,0xCE,0x7B,0x37,0x74,0xB9,0x70,0x47,0x91,0x22,0x51,0x63,0x16,0x79, +0xAE,0xB1,0xAE,0x41,0x26,0x08,0xC8,0x19,0x2B,0xD1,0x46,0xAA,0x48,0xD6,0x64,0x2A, +0xD7,0x83,0x34,0xFF,0x2C,0x2A,0xC1,0x6C,0x19,0x43,0x4A,0x07,0x85,0xE7,0xD3,0x7C, +0xF6,0x21,0x68,0xEF,0xEA,0xF2,0x52,0x9F,0x7F,0x93,0x90,0xCF,0x02,0x03,0x01,0x00, +0x01,0xA3,0x42,0x30,0x40,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04, +0x04,0x03,0x02,0x01,0x06,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04, +0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04, +0x14,0x60,0x7B,0x66,0x1A,0x45,0x0D,0x97,0xCA,0x89,0x50,0x2F,0x7D,0x04,0xCD,0x34, +0xA8,0xFF,0xFC,0xFD,0x4B,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01, +0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0xD6,0x73,0xE7,0x7C,0x4F,0x76,0xD0, +0x8D,0xBF,0xEC,0xBA,0xA2,0xBE,0x34,0xC5,0x28,0x32,0xB5,0x7C,0xFC,0x6C,0x9C,0x2C, +0x2B,0xBD,0x09,0x9E,0x53,0xBF,0x6B,0x5E,0xAA,0x11,0x48,0xB6,0xE5,0x08,0xA3,0xB3, +0xCA,0x3D,0x61,0x4D,0xD3,0x46,0x09,0xB3,0x3E,0xC3,0xA0,0xE3,0x63,0x55,0x1B,0xF2, +0xBA,0xEF,0xAD,0x39,0xE1,0x43,0xB9,0x38,0xA3,0xE6,0x2F,0x8A,0x26,0x3B,0xEF,0xA0, +0x50,0x56,0xF9,0xC6,0x0A,0xFD,0x38,0xCD,0xC4,0x0B,0x70,0x51,0x94,0x97,0x98,0x04, +0xDF,0xC3,0x5F,0x94,0xD5,0x15,0xC9,0x14,0x41,0x9C,0xC4,0x5D,0x75,0x64,0x15,0x0D, +0xFF,0x55,0x30,0xEC,0x86,0x8F,0xFF,0x0D,0xEF,0x2C,0xB9,0x63,0x46,0xF6,0xAA,0xFC, +0xDF,0xBC,0x69,0xFD,0x2E,0x12,0x48,0x64,0x9A,0xE0,0x95,0xF0,0xA6,0xEF,0x29,0x8F, +0x01,0xB1,0x15,0xB5,0x0C,0x1D,0xA5,0xFE,0x69,0x2C,0x69,0x24,0x78,0x1E,0xB3,0xA7, +0x1C,0x71,0x62,0xEE,0xCA,0xC8,0x97,0xAC,0x17,0x5D,0x8A,0xC2,0xF8,0x47,0x86,0x6E, +0x2A,0xC4,0x56,0x31,0x95,0xD0,0x67,0x89,0x85,0x2B,0xF9,0x6C,0xA6,0x5D,0x46,0x9D, +0x0C,0xAA,0x82,0xE4,0x99,0x51,0xDD,0x70,0xB7,0xDB,0x56,0x3D,0x61,0xE4,0x6A,0xE1, +0x5C,0xD6,0xF6,0xFE,0x3D,0xDE,0x41,0xCC,0x07,0xAE,0x63,0x52,0xBF,0x53,0x53,0xF4, +0x2B,0xE9,0xC7,0xFD,0xB6,0xF7,0x82,0x5F,0x85,0xD2,0x41,0x18,0xDB,0x81,0xB3,0x04, +0x1C,0xC5,0x1F,0xA4,0x80,0x6F,0x15,0x20,0xC9,0xDE,0x0C,0x88,0x0A,0x1D,0xD6,0x66, +0x55,0xE2,0xFC,0x48,0xC9,0x29,0x26,0x69,0xE0, +}; + +/* subject: Common Name: GlobalSign, Organization: GlobalSign, Organizational Unit: GlobalSign Root CA - R3 */ +/* issuer: Common Name: GlobalSign, Organization: GlobalSign, Organizational Unit: GlobalSign Root CA - R3 */ +/* link: https://crt.sh/?q=cbb522d7b7f127ad6a0113865bdf1cd4102e7d0759af635a7cf4720dc963c53b */ +const unsigned char kCertificateWithFingerprint_cbb522d7b7f127ad6a0113865bdf1cd4102e7d0759af635a7cf4720dc963c53b_certificate[867]={ +0x30,0x82,0x03,0x5F,0x30,0x82,0x02,0x47,0xA0,0x03,0x02,0x01,0x02,0x02,0x0B,0x04, +0x00,0x00,0x00,0x00,0x01,0x21,0x58,0x53,0x08,0xA2,0x30,0x0D,0x06,0x09,0x2A,0x86, +0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x30,0x4C,0x31,0x20,0x30,0x1E,0x06, +0x03,0x55,0x04,0x0B,0x13,0x17,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x53,0x69,0x67,0x6E, +0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x41,0x20,0x2D,0x20,0x52,0x33,0x31,0x13,0x30, +0x11,0x06,0x03,0x55,0x04,0x0A,0x13,0x0A,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x53,0x69, +0x67,0x6E,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0A,0x47,0x6C,0x6F, +0x62,0x61,0x6C,0x53,0x69,0x67,0x6E,0x30,0x1E,0x17,0x0D,0x30,0x39,0x30,0x33,0x31, +0x38,0x31,0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x32,0x39,0x30,0x33,0x31,0x38, +0x31,0x30,0x30,0x30,0x30,0x30,0x5A,0x30,0x4C,0x31,0x20,0x30,0x1E,0x06,0x03,0x55, +0x04,0x0B,0x13,0x17,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x53,0x69,0x67,0x6E,0x20,0x52, +0x6F,0x6F,0x74,0x20,0x43,0x41,0x20,0x2D,0x20,0x52,0x33,0x31,0x13,0x30,0x11,0x06, +0x03,0x55,0x04,0x0A,0x13,0x0A,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x53,0x69,0x67,0x6E, +0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0A,0x47,0x6C,0x6F,0x62,0x61, +0x6C,0x53,0x69,0x67,0x6E,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48, +0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01, +0x0A,0x02,0x82,0x01,0x01,0x00,0xCC,0x25,0x76,0x90,0x79,0x06,0x78,0x22,0x16,0xF5, +0xC0,0x83,0xB6,0x84,0xCA,0x28,0x9E,0xFD,0x05,0x76,0x11,0xC5,0xAD,0x88,0x72,0xFC, +0x46,0x02,0x43,0xC7,0xB2,0x8A,0x9D,0x04,0x5F,0x24,0xCB,0x2E,0x4B,0xE1,0x60,0x82, +0x46,0xE1,0x52,0xAB,0x0C,0x81,0x47,0x70,0x6C,0xDD,0x64,0xD1,0xEB,0xF5,0x2C,0xA3, +0x0F,0x82,0x3D,0x0C,0x2B,0xAE,0x97,0xD7,0xB6,0x14,0x86,0x10,0x79,0xBB,0x3B,0x13, +0x80,0x77,0x8C,0x08,0xE1,0x49,0xD2,0x6A,0x62,0x2F,0x1F,0x5E,0xFA,0x96,0x68,0xDF, +0x89,0x27,0x95,0x38,0x9F,0x06,0xD7,0x3E,0xC9,0xCB,0x26,0x59,0x0D,0x73,0xDE,0xB0, +0xC8,0xE9,0x26,0x0E,0x83,0x15,0xC6,0xEF,0x5B,0x8B,0xD2,0x04,0x60,0xCA,0x49,0xA6, +0x28,0xF6,0x69,0x3B,0xF6,0xCB,0xC8,0x28,0x91,0xE5,0x9D,0x8A,0x61,0x57,0x37,0xAC, +0x74,0x14,0xDC,0x74,0xE0,0x3A,0xEE,0x72,0x2F,0x2E,0x9C,0xFB,0xD0,0xBB,0xBF,0xF5, +0x3D,0x00,0xE1,0x06,0x33,0xE8,0x82,0x2B,0xAE,0x53,0xA6,0x3A,0x16,0x73,0x8C,0xDD, +0x41,0x0E,0x20,0x3A,0xC0,0xB4,0xA7,0xA1,0xE9,0xB2,0x4F,0x90,0x2E,0x32,0x60,0xE9, +0x57,0xCB,0xB9,0x04,0x92,0x68,0x68,0xE5,0x38,0x26,0x60,0x75,0xB2,0x9F,0x77,0xFF, +0x91,0x14,0xEF,0xAE,0x20,0x49,0xFC,0xAD,0x40,0x15,0x48,0xD1,0x02,0x31,0x61,0x19, +0x5E,0xB8,0x97,0xEF,0xAD,0x77,0xB7,0x64,0x9A,0x7A,0xBF,0x5F,0xC1,0x13,0xEF,0x9B, +0x62,0xFB,0x0D,0x6C,0xE0,0x54,0x69,0x16,0xA9,0x03,0xDA,0x6E,0xE9,0x83,0x93,0x71, +0x76,0xC6,0x69,0x85,0x82,0x17,0x02,0x03,0x01,0x00,0x01,0xA3,0x42,0x30,0x40,0x30, +0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30, +0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF, +0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x8F,0xF0,0x4B,0x7F,0xA8, +0x2E,0x45,0x24,0xAE,0x4D,0x50,0xFA,0x63,0x9A,0x8B,0xDE,0xE2,0xDD,0x1B,0xBC,0x30, +0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x03,0x82, +0x01,0x01,0x00,0x4B,0x40,0xDB,0xC0,0x50,0xAA,0xFE,0xC8,0x0C,0xEF,0xF7,0x96,0x54, +0x45,0x49,0xBB,0x96,0x00,0x09,0x41,0xAC,0xB3,0x13,0x86,0x86,0x28,0x07,0x33,0xCA, +0x6B,0xE6,0x74,0xB9,0xBA,0x00,0x2D,0xAE,0xA4,0x0A,0xD3,0xF5,0xF1,0xF1,0x0F,0x8A, +0xBF,0x73,0x67,0x4A,0x83,0xC7,0x44,0x7B,0x78,0xE0,0xAF,0x6E,0x6C,0x6F,0x03,0x29, +0x8E,0x33,0x39,0x45,0xC3,0x8E,0xE4,0xB9,0x57,0x6C,0xAA,0xFC,0x12,0x96,0xEC,0x53, +0xC6,0x2D,0xE4,0x24,0x6C,0xB9,0x94,0x63,0xFB,0xDC,0x53,0x68,0x67,0x56,0x3E,0x83, +0xB8,0xCF,0x35,0x21,0xC3,0xC9,0x68,0xFE,0xCE,0xDA,0xC2,0x53,0xAA,0xCC,0x90,0x8A, +0xE9,0xF0,0x5D,0x46,0x8C,0x95,0xDD,0x7A,0x58,0x28,0x1A,0x2F,0x1D,0xDE,0xCD,0x00, +0x37,0x41,0x8F,0xED,0x44,0x6D,0xD7,0x53,0x28,0x97,0x7E,0xF3,0x67,0x04,0x1E,0x15, +0xD7,0x8A,0x96,0xB4,0xD3,0xDE,0x4C,0x27,0xA4,0x4C,0x1B,0x73,0x73,0x76,0xF4,0x17, +0x99,0xC2,0x1F,0x7A,0x0E,0xE3,0x2D,0x08,0xAD,0x0A,0x1C,0x2C,0xFF,0x3C,0xAB,0x55, +0x0E,0x0F,0x91,0x7E,0x36,0xEB,0xC3,0x57,0x49,0xBE,0xE1,0x2E,0x2D,0x7C,0x60,0x8B, +0xC3,0x41,0x51,0x13,0x23,0x9D,0xCE,0xF7,0x32,0x6B,0x94,0x01,0xA8,0x99,0xE7,0x2C, +0x33,0x1F,0x3A,0x3B,0x25,0xD2,0x86,0x40,0xCE,0x3B,0x2C,0x86,0x78,0xC9,0x61,0x2F, +0x14,0xBA,0xEE,0xDB,0x55,0x6F,0xDF,0x84,0xEE,0x05,0x09,0x4D,0xBD,0x28,0xD8,0x72, +0xCE,0xD3,0x62,0x50,0x65,0x1E,0xEB,0x92,0x97,0x83,0x31,0xD9,0xB3,0xB5,0xCA,0x47, +0x58,0x3F,0x5F, +}; + +/* subject: Common Name: GlobalSign, Organization: GlobalSign, Organizational Unit: GlobalSign ECC Root CA - R5 */ +/* issuer: Common Name: GlobalSign, Organization: GlobalSign, Organizational Unit: GlobalSign ECC Root CA - R5 */ +/* link: https://crt.sh/?q=179fbc148a3dd00fd24ea13458cc43bfa7f59c8182d783a513f6ebec100c8924 */ +const unsigned char kCertificateWithFingerprint_179fbc148a3dd00fd24ea13458cc43bfa7f59c8182d783a513f6ebec100c8924_certificate[546]={ +0x30,0x82,0x02,0x1E,0x30,0x82,0x01,0xA4,0xA0,0x03,0x02,0x01,0x02,0x02,0x11,0x60, +0x59,0x49,0xE0,0x26,0x2E,0xBB,0x55,0xF9,0x0A,0x77,0x8A,0x71,0xF9,0x4A,0xD8,0x6C, +0x30,0x0A,0x06,0x08,0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x03,0x30,0x50,0x31,0x24, +0x30,0x22,0x06,0x03,0x55,0x04,0x0B,0x13,0x1B,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x53, +0x69,0x67,0x6E,0x20,0x45,0x43,0x43,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x41,0x20, +0x2D,0x20,0x52,0x35,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0A,0x13,0x0A,0x47, +0x6C,0x6F,0x62,0x61,0x6C,0x53,0x69,0x67,0x6E,0x31,0x13,0x30,0x11,0x06,0x03,0x55, +0x04,0x03,0x13,0x0A,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x53,0x69,0x67,0x6E,0x30,0x1E, +0x17,0x0D,0x31,0x32,0x31,0x31,0x31,0x33,0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x17, +0x0D,0x33,0x38,0x30,0x31,0x31,0x39,0x30,0x33,0x31,0x34,0x30,0x37,0x5A,0x30,0x50, +0x31,0x24,0x30,0x22,0x06,0x03,0x55,0x04,0x0B,0x13,0x1B,0x47,0x6C,0x6F,0x62,0x61, +0x6C,0x53,0x69,0x67,0x6E,0x20,0x45,0x43,0x43,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43, +0x41,0x20,0x2D,0x20,0x52,0x35,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0A,0x13, +0x0A,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x53,0x69,0x67,0x6E,0x31,0x13,0x30,0x11,0x06, +0x03,0x55,0x04,0x03,0x13,0x0A,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x53,0x69,0x67,0x6E, +0x30,0x76,0x30,0x10,0x06,0x07,0x2A,0x86,0x48,0xCE,0x3D,0x02,0x01,0x06,0x05,0x2B, +0x81,0x04,0x00,0x22,0x03,0x62,0x00,0x04,0x47,0x45,0x0E,0x96,0xFB,0x7D,0x5D,0xBF, +0xE9,0x39,0xD1,0x21,0xF8,0x9F,0x0B,0xB6,0xD5,0x7B,0x1E,0x92,0x3A,0x48,0x59,0x1C, +0xF0,0x62,0x31,0x2D,0xC0,0x7A,0x28,0xFE,0x1A,0xA7,0x5C,0xB3,0xB6,0xCC,0x97,0xE7, +0x45,0xD4,0x58,0xFA,0xD1,0x77,0x6D,0x43,0xA2,0xC0,0x87,0x65,0x34,0x0A,0x1F,0x7A, +0xDD,0xEB,0x3C,0x33,0xA1,0xC5,0x9D,0x4D,0xA4,0x6F,0x41,0x95,0x38,0x7F,0xC9,0x1E, +0x84,0xEB,0xD1,0x9E,0x49,0x92,0x87,0x94,0x87,0x0C,0x3A,0x85,0x4A,0x66,0x9F,0x9D, +0x59,0x93,0x4D,0x97,0x61,0x06,0x86,0x4A,0xA3,0x42,0x30,0x40,0x30,0x0E,0x06,0x03, +0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x0F,0x06,0x03, +0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x1D,0x06, +0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x3D,0xE6,0x29,0x48,0x9B,0xEA,0x07,0xCA, +0x21,0x44,0x4A,0x26,0xDE,0x6E,0xDE,0xD2,0x83,0xD0,0x9F,0x59,0x30,0x0A,0x06,0x08, +0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x03,0x03,0x68,0x00,0x30,0x65,0x02,0x31,0x00, +0xE5,0x69,0x12,0xC9,0x6E,0xDB,0xC6,0x31,0xBA,0x09,0x41,0xE1,0x97,0xF8,0xFB,0xFD, +0x9A,0xE2,0x7D,0x12,0xC9,0xED,0x7C,0x64,0xD3,0xCB,0x05,0x25,0x8B,0x56,0xD9,0xA0, +0xE7,0x5E,0x5D,0x4E,0x0B,0x83,0x9C,0x5B,0x76,0x29,0xA0,0x09,0x26,0x21,0x6A,0x62, +0x02,0x30,0x71,0xD2,0xB5,0x8F,0x5C,0xEA,0x3B,0xE1,0x78,0x09,0x85,0xA8,0x75,0x92, +0x3B,0xC8,0x5C,0xFD,0x48,0xEF,0x0D,0x74,0x22,0xA8,0x08,0xE2,0x6E,0xC5,0x49,0xCE, +0xC7,0x0C,0xBC,0xA7,0x61,0x69,0xF1,0xF7,0x3B,0xE1,0x2A,0xCB,0xF9,0x2B,0xF3,0x66, +0x90,0x37, +}; + +/* subject: Common Name: GlobalSign, Organization: GlobalSign, Organizational Unit: GlobalSign Root CA - R6 */ +/* issuer: Common Name: GlobalSign, Organization: GlobalSign, Organizational Unit: GlobalSign Root CA - R6 */ +/* link: https://crt.sh/?q=2cabeafe37d06ca22aba7391c0033d25982952c453647349763a3ab5ad6ccf69 */ +const unsigned char kCertificateWithFingerprint_2cabeafe37d06ca22aba7391c0033d25982952c453647349763a3ab5ad6ccf69_certificate[1415]={ +0x30,0x82,0x05,0x83,0x30,0x82,0x03,0x6B,0xA0,0x03,0x02,0x01,0x02,0x02,0x0E,0x45, +0xE6,0xBB,0x03,0x83,0x33,0xC3,0x85,0x65,0x48,0xE6,0xFF,0x45,0x51,0x30,0x0D,0x06, +0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0C,0x05,0x00,0x30,0x4C,0x31,0x20, +0x30,0x1E,0x06,0x03,0x55,0x04,0x0B,0x13,0x17,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x53, +0x69,0x67,0x6E,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x41,0x20,0x2D,0x20,0x52,0x36, +0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0A,0x13,0x0A,0x47,0x6C,0x6F,0x62,0x61, +0x6C,0x53,0x69,0x67,0x6E,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0A, +0x47,0x6C,0x6F,0x62,0x61,0x6C,0x53,0x69,0x67,0x6E,0x30,0x1E,0x17,0x0D,0x31,0x34, +0x31,0x32,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x33,0x34,0x31, +0x32,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x30,0x4C,0x31,0x20,0x30,0x1E, +0x06,0x03,0x55,0x04,0x0B,0x13,0x17,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x53,0x69,0x67, +0x6E,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x41,0x20,0x2D,0x20,0x52,0x36,0x31,0x13, +0x30,0x11,0x06,0x03,0x55,0x04,0x0A,0x13,0x0A,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x53, +0x69,0x67,0x6E,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0A,0x47,0x6C, +0x6F,0x62,0x61,0x6C,0x53,0x69,0x67,0x6E,0x30,0x82,0x02,0x22,0x30,0x0D,0x06,0x09, +0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x02,0x0F,0x00, +0x30,0x82,0x02,0x0A,0x02,0x82,0x02,0x01,0x00,0x95,0x07,0xE8,0x73,0xCA,0x66,0xF9, +0xEC,0x14,0xCA,0x7B,0x3C,0xF7,0x0D,0x08,0xF1,0xB4,0x45,0x0B,0x2C,0x82,0xB4,0x48, +0xC6,0xEB,0x5B,0x3C,0xAE,0x83,0xB8,0x41,0x92,0x33,0x14,0xA4,0x6F,0x7F,0xE9,0x2A, +0xCC,0xC6,0xB0,0x88,0x6B,0xC5,0xB6,0x89,0xD1,0xC6,0xB2,0xFF,0x14,0xCE,0x51,0x14, +0x21,0xEC,0x4A,0xDD,0x1B,0x5A,0xC6,0xD6,0x87,0xEE,0x4D,0x3A,0x15,0x06,0xED,0x64, +0x66,0x0B,0x92,0x80,0xCA,0x44,0xDE,0x73,0x94,0x4E,0xF3,0xA7,0x89,0x7F,0x4F,0x78, +0x63,0x08,0xC8,0x12,0x50,0x6D,0x42,0x66,0x2F,0x4D,0xB9,0x79,0x28,0x4D,0x52,0x1A, +0x8A,0x1A,0x80,0xB7,0x19,0x81,0x0E,0x7E,0xC4,0x8A,0xBC,0x64,0x4C,0x21,0x1C,0x43, +0x68,0xD7,0x3D,0x3C,0x8A,0xC5,0xB2,0x66,0xD5,0x90,0x9A,0xB7,0x31,0x06,0xC5,0xBE, +0xE2,0x6D,0x32,0x06,0xA6,0x1E,0xF9,0xB9,0xEB,0xAA,0xA3,0xB8,0xBF,0xBE,0x82,0x63, +0x50,0xD0,0xF0,0x18,0x89,0xDF,0xE4,0x0F,0x79,0xF5,0xEA,0xA2,0x1F,0x2A,0xD2,0x70, +0x2E,0x7B,0xE7,0xBC,0x93,0xBB,0x6D,0x53,0xE2,0x48,0x7C,0x8C,0x10,0x07,0x38,0xFF, +0x66,0xB2,0x77,0x61,0x7E,0xE0,0xEA,0x8C,0x3C,0xAA,0xB4,0xA4,0xF6,0xF3,0x95,0x4A, +0x12,0x07,0x6D,0xFD,0x8C,0xB2,0x89,0xCF,0xD0,0xA0,0x61,0x77,0xC8,0x58,0x74,0xB0, +0xD4,0x23,0x3A,0xF7,0x5D,0x3A,0xCA,0xA2,0xDB,0x9D,0x09,0xDE,0x5D,0x44,0x2D,0x90, +0xF1,0x81,0xCD,0x57,0x92,0xFA,0x7E,0xBC,0x50,0x04,0x63,0x34,0xDF,0x6B,0x93,0x18, +0xBE,0x6B,0x36,0xB2,0x39,0xE4,0xAC,0x24,0x36,0xB7,0xF0,0xEF,0xB6,0x1C,0x13,0x57, +0x93,0xB6,0xDE,0xB2,0xF8,0xE2,0x85,0xB7,0x73,0xA2,0xB8,0x35,0xAA,0x45,0xF2,0xE0, +0x9D,0x36,0xA1,0x6F,0x54,0x8A,0xF1,0x72,0x56,0x6E,0x2E,0x88,0xC5,0x51,0x42,0x44, +0x15,0x94,0xEE,0xA3,0xC5,0x38,0x96,0x9B,0x4E,0x4E,0x5A,0x0B,0x47,0xF3,0x06,0x36, +0x49,0x77,0x30,0xBC,0x71,0x37,0xE5,0xA6,0xEC,0x21,0x08,0x75,0xFC,0xE6,0x61,0x16, +0x3F,0x77,0xD5,0xD9,0x91,0x97,0x84,0x0A,0x6C,0xD4,0x02,0x4D,0x74,0xC0,0x14,0xED, +0xFD,0x39,0xFB,0x83,0xF2,0x5E,0x14,0xA1,0x04,0xB0,0x0B,0xE9,0xFE,0xEE,0x8F,0xE1, +0x6E,0x0B,0xB2,0x08,0xB3,0x61,0x66,0x09,0x6A,0xB1,0x06,0x3A,0x65,0x96,0x59,0xC0, +0xF0,0x35,0xFD,0xC9,0xDA,0x28,0x8D,0x1A,0x11,0x87,0x70,0x81,0x0A,0xA8,0x9A,0x75, +0x1D,0x9E,0x3A,0x86,0x05,0x00,0x9E,0xDB,0x80,0xD6,0x25,0xF9,0xDC,0x05,0x9E,0x27, +0x59,0x4C,0x76,0x39,0x5B,0xEA,0xF9,0xA5,0xA1,0xD8,0x83,0x0F,0xD1,0xFF,0xDF,0x30, +0x11,0xF9,0x85,0xCF,0x33,0x48,0xF5,0xCA,0x6D,0x64,0x14,0x2C,0x7A,0x58,0x4F,0xD3, +0x4B,0x08,0x49,0xC5,0x95,0x64,0x1A,0x63,0x0E,0x79,0x3D,0xF5,0xB3,0x8C,0xCA,0x58, +0xAD,0x9C,0x42,0x45,0x79,0x6E,0x0E,0x87,0x19,0x5C,0x54,0xB1,0x65,0xB6,0xBF,0x8C, +0x9B,0xDC,0x13,0xE9,0x0D,0x6F,0xB8,0x2E,0xDC,0x67,0x6E,0xC9,0x8B,0x11,0xB5,0x84, +0x14,0x8A,0x00,0x19,0x70,0x83,0x79,0x91,0x97,0x91,0xD4,0x1A,0x27,0xBF,0x37,0x1E, +0x32,0x07,0xD8,0x14,0x63,0x3C,0x28,0x4C,0xAF,0x02,0x03,0x01,0x00,0x01,0xA3,0x63, +0x30,0x61,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02, +0x01,0x06,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03, +0x01,0x01,0xFF,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0xAE,0x6C, +0x05,0xA3,0x93,0x13,0xE2,0xA2,0xE7,0xE2,0xD7,0x1C,0xD6,0xC7,0xF0,0x7F,0xC8,0x67, +0x53,0xA0,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0xAE, +0x6C,0x05,0xA3,0x93,0x13,0xE2,0xA2,0xE7,0xE2,0xD7,0x1C,0xD6,0xC7,0xF0,0x7F,0xC8, +0x67,0x53,0xA0,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0C, +0x05,0x00,0x03,0x82,0x02,0x01,0x00,0x83,0x25,0xED,0xE8,0xD1,0xFD,0x95,0x52,0xCD, +0x9E,0xC0,0x04,0xA0,0x91,0x69,0xE6,0x5C,0xD0,0x84,0xDE,0xDC,0xAD,0xA2,0x4F,0xE8, +0x47,0x78,0xD6,0x65,0x98,0xA9,0x5B,0xA8,0x3C,0x87,0x7C,0x02,0x8A,0xD1,0x6E,0xB7, +0x16,0x73,0xE6,0x5F,0xC0,0x54,0x98,0xD5,0x74,0xBE,0xC1,0xCD,0xE2,0x11,0x91,0xAD, +0x23,0x18,0x3D,0xDD,0xE1,0x72,0x44,0x96,0xB4,0x95,0x5E,0xC0,0x7B,0x8E,0x99,0x78, +0x16,0x43,0x13,0x56,0x57,0xB3,0xA2,0xB3,0x3B,0xB5,0x77,0xDC,0x40,0x72,0xAC,0xA3, +0xEB,0x9B,0x35,0x3E,0xB1,0x08,0x21,0xA1,0xE7,0xC4,0x43,0x37,0x79,0x32,0xBE,0xB5, +0xE7,0x9C,0x2C,0x4C,0xBC,0x43,0x29,0x99,0x8E,0x30,0xD3,0xAC,0x21,0xE0,0xE3,0x1D, +0xFA,0xD8,0x07,0x33,0x76,0x54,0x00,0x22,0x2A,0xB9,0x4D,0x20,0x2E,0x70,0x68,0xDA, +0xE5,0x53,0xFC,0x83,0x5C,0xD3,0x9D,0xF2,0xFF,0x44,0x0C,0x44,0x66,0xF2,0xD2,0xE3, +0xBD,0x46,0x00,0x1A,0x6D,0x02,0xBA,0x25,0x5D,0x8D,0xA1,0x31,0x51,0xDD,0x54,0x46, +0x1C,0x4D,0xDB,0x99,0x96,0xEF,0x1A,0x1C,0x04,0x5C,0xA6,0x15,0xEF,0x78,0xE0,0x79, +0xFE,0x5D,0xDB,0x3E,0xAA,0x4C,0x55,0xFD,0x9A,0x15,0xA9,0x6F,0xE1,0xA6,0xFB,0xDF, +0x70,0x30,0xE9,0xC3,0xEE,0x42,0x46,0xED,0xC2,0x93,0x05,0x89,0xFA,0x7D,0x63,0x7B, +0x3F,0xD0,0x71,0x81,0x7C,0x00,0xE8,0x98,0xAE,0x0E,0x78,0x34,0xC3,0x25,0xFB,0xAF, +0x0A,0x9F,0x20,0x6B,0xDD,0x3B,0x13,0x8F,0x12,0x8C,0xE2,0x41,0x1A,0x48,0x7A,0x73, +0xA0,0x77,0x69,0xC7,0xB6,0x5C,0x7F,0x82,0xC8,0x1E,0xFE,0x58,0x1B,0x28,0x2B,0xA8, +0x6C,0xAD,0x5E,0x6D,0xC0,0x05,0xD2,0x7B,0xB7,0xEB,0x80,0xFE,0x25,0x37,0xFE,0x02, +0x9B,0x68,0xAC,0x42,0x5D,0xC3,0xEE,0xF5,0xCC,0xDC,0xF0,0x50,0x75,0xD2,0x36,0x69, +0x9C,0xE6,0x7B,0x04,0xDF,0x6E,0x06,0x69,0xB6,0xDE,0x0A,0x09,0x48,0x59,0x87,0xEB, +0x7B,0x14,0x60,0x7A,0x64,0xAA,0x69,0x43,0xEF,0x91,0xC7,0x4C,0xEC,0x18,0xDD,0x6C, +0xEF,0x53,0x2D,0x8C,0x99,0xE1,0x5E,0xF2,0x72,0x3E,0xCF,0x54,0xC8,0xBD,0x67,0xEC, +0xA4,0x0F,0x4C,0x45,0xFF,0xD3,0xB9,0x30,0x23,0x07,0x4C,0x8F,0x10,0xBF,0x86,0x96, +0xD9,0x99,0x5A,0xB4,0x99,0x57,0x1C,0xA4,0xCC,0xBB,0x15,0x89,0x53,0xBA,0x2C,0x05, +0x0F,0xE4,0xC4,0x9E,0x19,0xB1,0x18,0x34,0xD5,0x4C,0x9D,0xBA,0xED,0xF7,0x1F,0xAF, +0x24,0x95,0x04,0x78,0xA8,0x03,0xBB,0xEE,0x81,0xE5,0xDA,0x5F,0x7C,0x8B,0x4A,0xA1, +0x90,0x74,0x25,0xA7,0xB3,0x3E,0x4B,0xC8,0x2C,0x56,0xBD,0xC7,0xC8,0xEF,0x38,0xE2, +0x5C,0x92,0xF0,0x79,0xF7,0x9C,0x84,0xBA,0x74,0x2D,0x61,0x01,0x20,0x7E,0x7E,0xD1, +0xF2,0x4F,0x07,0x59,0x5F,0x8B,0x2D,0x43,0x52,0xEB,0x46,0x0C,0x94,0xE1,0xF5,0x66, +0x47,0x79,0x77,0xD5,0x54,0x5B,0x1F,0xAD,0x24,0x37,0xCB,0x45,0x5A,0x4E,0xA0,0x44, +0x48,0xC8,0xD8,0xB0,0x99,0xC5,0x15,0x84,0x09,0xF6,0xD6,0x49,0x49,0xC0,0x65,0xB8, +0xE6,0x1A,0x71,0x6E,0xA0,0xA8,0xF1,0x82,0xE8,0x45,0x3E,0x6C,0xD6,0x02,0xD7,0x0A, +0x67,0x83,0x05,0x5A,0xC9,0xA4,0x10, +}; + +/* subject: Common Name: Go Daddy Root Certificate Authority - G2; Organization: GoDaddy.com, Inc.; Locality: Scottsdale; State/Province: Arizona; Country: US */ +/* issuer: Common Name: Go Daddy Root Certificate Authority - G2; Organization: GoDaddy.com, Inc.; Locality: Scottsdale; State/Province: Arizona; Country: US */ +/* link: https://crt.sh/?q=45140b3247eb9cc8c5b4f0d7b53091f73292089e6e5a63e2749dd3aca9198eda */ +const unsigned char kCertificateWithFingerprint_45140b3247eb9cc8c5b4f0d7b53091f73292089e6e5a63e2749dd3aca9198eda_certificate[969]={ +0x30,0x82,0x03,0xC5,0x30,0x82,0x02,0xAD,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x00, +0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x30, +0x81,0x83,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31, +0x10,0x30,0x0E,0x06,0x03,0x55,0x04,0x08,0x13,0x07,0x41,0x72,0x69,0x7A,0x6F,0x6E, +0x61,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x07,0x13,0x0A,0x53,0x63,0x6F,0x74, +0x74,0x73,0x64,0x61,0x6C,0x65,0x31,0x1A,0x30,0x18,0x06,0x03,0x55,0x04,0x0A,0x13, +0x11,0x47,0x6F,0x44,0x61,0x64,0x64,0x79,0x2E,0x63,0x6F,0x6D,0x2C,0x20,0x49,0x6E, +0x63,0x2E,0x31,0x31,0x30,0x2F,0x06,0x03,0x55,0x04,0x03,0x13,0x28,0x47,0x6F,0x20, +0x44,0x61,0x64,0x64,0x79,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x65,0x72,0x74,0x69, +0x66,0x69,0x63,0x61,0x74,0x65,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79, +0x20,0x2D,0x20,0x47,0x32,0x30,0x1E,0x17,0x0D,0x30,0x39,0x30,0x39,0x30,0x31,0x30, +0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x33,0x37,0x31,0x32,0x33,0x31,0x32,0x33, +0x35,0x39,0x35,0x39,0x5A,0x30,0x81,0x83,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04, +0x06,0x13,0x02,0x55,0x53,0x31,0x10,0x30,0x0E,0x06,0x03,0x55,0x04,0x08,0x13,0x07, +0x41,0x72,0x69,0x7A,0x6F,0x6E,0x61,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x07, +0x13,0x0A,0x53,0x63,0x6F,0x74,0x74,0x73,0x64,0x61,0x6C,0x65,0x31,0x1A,0x30,0x18, +0x06,0x03,0x55,0x04,0x0A,0x13,0x11,0x47,0x6F,0x44,0x61,0x64,0x64,0x79,0x2E,0x63, +0x6F,0x6D,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x31,0x30,0x2F,0x06,0x03,0x55,0x04, +0x03,0x13,0x28,0x47,0x6F,0x20,0x44,0x61,0x64,0x64,0x79,0x20,0x52,0x6F,0x6F,0x74, +0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x20,0x41,0x75,0x74, +0x68,0x6F,0x72,0x69,0x74,0x79,0x20,0x2D,0x20,0x47,0x32,0x30,0x82,0x01,0x22,0x30, +0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82, +0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xBF,0x71,0x62,0x08, +0xF1,0xFA,0x59,0x34,0xF7,0x1B,0xC9,0x18,0xA3,0xF7,0x80,0x49,0x58,0xE9,0x22,0x83, +0x13,0xA6,0xC5,0x20,0x43,0x01,0x3B,0x84,0xF1,0xE6,0x85,0x49,0x9F,0x27,0xEA,0xF6, +0x84,0x1B,0x4E,0xA0,0xB4,0xDB,0x70,0x98,0xC7,0x32,0x01,0xB1,0x05,0x3E,0x07,0x4E, +0xEE,0xF4,0xFA,0x4F,0x2F,0x59,0x30,0x22,0xE7,0xAB,0x19,0x56,0x6B,0xE2,0x80,0x07, +0xFC,0xF3,0x16,0x75,0x80,0x39,0x51,0x7B,0xE5,0xF9,0x35,0xB6,0x74,0x4E,0xA9,0x8D, +0x82,0x13,0xE4,0xB6,0x3F,0xA9,0x03,0x83,0xFA,0xA2,0xBE,0x8A,0x15,0x6A,0x7F,0xDE, +0x0B,0xC3,0xB6,0x19,0x14,0x05,0xCA,0xEA,0xC3,0xA8,0x04,0x94,0x3B,0x46,0x7C,0x32, +0x0D,0xF3,0x00,0x66,0x22,0xC8,0x8D,0x69,0x6D,0x36,0x8C,0x11,0x18,0xB7,0xD3,0xB2, +0x1C,0x60,0xB4,0x38,0xFA,0x02,0x8C,0xCE,0xD3,0xDD,0x46,0x07,0xDE,0x0A,0x3E,0xEB, +0x5D,0x7C,0xC8,0x7C,0xFB,0xB0,0x2B,0x53,0xA4,0x92,0x62,0x69,0x51,0x25,0x05,0x61, +0x1A,0x44,0x81,0x8C,0x2C,0xA9,0x43,0x96,0x23,0xDF,0xAC,0x3A,0x81,0x9A,0x0E,0x29, +0xC5,0x1C,0xA9,0xE9,0x5D,0x1E,0xB6,0x9E,0x9E,0x30,0x0A,0x39,0xCE,0xF1,0x88,0x80, +0xFB,0x4B,0x5D,0xCC,0x32,0xEC,0x85,0x62,0x43,0x25,0x34,0x02,0x56,0x27,0x01,0x91, +0xB4,0x3B,0x70,0x2A,0x3F,0x6E,0xB1,0xE8,0x9C,0x88,0x01,0x7D,0x9F,0xD4,0xF9,0xDB, +0x53,0x6D,0x60,0x9D,0xBF,0x2C,0xE7,0x58,0xAB,0xB8,0x5F,0x46,0xFC,0xCE,0xC4,0x1B, +0x03,0x3C,0x09,0xEB,0x49,0x31,0x5C,0x69,0x46,0xB3,0xE0,0x47,0x02,0x03,0x01,0x00, +0x01,0xA3,0x42,0x30,0x40,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04, +0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF, +0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04, +0x14,0x3A,0x9A,0x85,0x07,0x10,0x67,0x28,0xB6,0xEF,0xF6,0xBD,0x05,0x41,0x6E,0x20, +0xC1,0x94,0xDA,0x0F,0xDE,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01, +0x01,0x0B,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x99,0xDB,0x5D,0x79,0xD5,0xF9,0x97, +0x59,0x67,0x03,0x61,0xF1,0x7E,0x3B,0x06,0x31,0x75,0x2D,0xA1,0x20,0x8E,0x4F,0x65, +0x87,0xB4,0xF7,0xA6,0x9C,0xBC,0xD8,0xE9,0x2F,0xD0,0xDB,0x5A,0xEE,0xCF,0x74,0x8C, +0x73,0xB4,0x38,0x42,0xDA,0x05,0x7B,0xF8,0x02,0x75,0xB8,0xFD,0xA5,0xB1,0xD7,0xAE, +0xF6,0xD7,0xDE,0x13,0xCB,0x53,0x10,0x7E,0x8A,0x46,0xD1,0x97,0xFA,0xB7,0x2E,0x2B, +0x11,0xAB,0x90,0xB0,0x27,0x80,0xF9,0xE8,0x9F,0x5A,0xE9,0x37,0x9F,0xAB,0xE4,0xDF, +0x6C,0xB3,0x85,0x17,0x9D,0x3D,0xD9,0x24,0x4F,0x79,0x91,0x35,0xD6,0x5F,0x04,0xEB, +0x80,0x83,0xAB,0x9A,0x02,0x2D,0xB5,0x10,0xF4,0xD8,0x90,0xC7,0x04,0x73,0x40,0xED, +0x72,0x25,0xA0,0xA9,0x9F,0xEC,0x9E,0xAB,0x68,0x12,0x99,0x57,0xC6,0x8F,0x12,0x3A, +0x09,0xA4,0xBD,0x44,0xFD,0x06,0x15,0x37,0xC1,0x9B,0xE4,0x32,0xA3,0xED,0x38,0xE8, +0xD8,0x64,0xF3,0x2C,0x7E,0x14,0xFC,0x02,0xEA,0x9F,0xCD,0xFF,0x07,0x68,0x17,0xDB, +0x22,0x90,0x38,0x2D,0x7A,0x8D,0xD1,0x54,0xF1,0x69,0xE3,0x5F,0x33,0xCA,0x7A,0x3D, +0x7B,0x0A,0xE3,0xCA,0x7F,0x5F,0x39,0xE5,0xE2,0x75,0xBA,0xC5,0x76,0x18,0x33,0xCE, +0x2C,0xF0,0x2F,0x4C,0xAD,0xF7,0xB1,0xE7,0xCE,0x4F,0xA8,0xC4,0x9B,0x4A,0x54,0x06, +0xC5,0x7F,0x7D,0xD5,0x08,0x0F,0xE2,0x1C,0xFE,0x7E,0x17,0xB8,0xAC,0x5E,0xF6,0xD4, +0x16,0xB2,0x43,0x09,0x0C,0x4D,0xF6,0xA7,0x6B,0xB4,0x99,0x84,0x65,0xCA,0x7A,0x88, +0xE2,0xE2,0x44,0xBE,0x5C,0xF7,0xEA,0x1C,0xF5, +}; + +/* subject: Common Name: Starfield Root Certificate Authority - G2; Organization: Starfield Technologies, Inc.; Locality: Scottsdale; State/Province: Arizona; Country: US */ +/* issuer: Common Name: Starfield Root Certificate Authority - G2; Organization: Starfield Technologies, Inc.; Locality: Scottsdale; State/Province: Arizona; Country: US */ +/* link: https://crt.sh/?q=2ce1cb0bf9d2f9e102993fbe215152c3b2dd0cabde1c68e5319b839154dbb7f5 */ +const unsigned char kCertificateWithFingerprint_2ce1cb0bf9d2f9e102993fbe215152c3b2dd0cabde1c68e5319b839154dbb7f5_certificate[993]={ +0x30,0x82,0x03,0xDD,0x30,0x82,0x02,0xC5,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x00, +0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x30, +0x81,0x8F,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31, +0x10,0x30,0x0E,0x06,0x03,0x55,0x04,0x08,0x13,0x07,0x41,0x72,0x69,0x7A,0x6F,0x6E, +0x61,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x07,0x13,0x0A,0x53,0x63,0x6F,0x74, +0x74,0x73,0x64,0x61,0x6C,0x65,0x31,0x25,0x30,0x23,0x06,0x03,0x55,0x04,0x0A,0x13, +0x1C,0x53,0x74,0x61,0x72,0x66,0x69,0x65,0x6C,0x64,0x20,0x54,0x65,0x63,0x68,0x6E, +0x6F,0x6C,0x6F,0x67,0x69,0x65,0x73,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x32,0x30, +0x30,0x06,0x03,0x55,0x04,0x03,0x13,0x29,0x53,0x74,0x61,0x72,0x66,0x69,0x65,0x6C, +0x64,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61, +0x74,0x65,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x20,0x2D,0x20,0x47, +0x32,0x30,0x1E,0x17,0x0D,0x30,0x39,0x30,0x39,0x30,0x31,0x30,0x30,0x30,0x30,0x30, +0x30,0x5A,0x17,0x0D,0x33,0x37,0x31,0x32,0x33,0x31,0x32,0x33,0x35,0x39,0x35,0x39, +0x5A,0x30,0x81,0x8F,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55, +0x53,0x31,0x10,0x30,0x0E,0x06,0x03,0x55,0x04,0x08,0x13,0x07,0x41,0x72,0x69,0x7A, +0x6F,0x6E,0x61,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x07,0x13,0x0A,0x53,0x63, +0x6F,0x74,0x74,0x73,0x64,0x61,0x6C,0x65,0x31,0x25,0x30,0x23,0x06,0x03,0x55,0x04, +0x0A,0x13,0x1C,0x53,0x74,0x61,0x72,0x66,0x69,0x65,0x6C,0x64,0x20,0x54,0x65,0x63, +0x68,0x6E,0x6F,0x6C,0x6F,0x67,0x69,0x65,0x73,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31, +0x32,0x30,0x30,0x06,0x03,0x55,0x04,0x03,0x13,0x29,0x53,0x74,0x61,0x72,0x66,0x69, +0x65,0x6C,0x64,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69, +0x63,0x61,0x74,0x65,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x20,0x2D, +0x20,0x47,0x32,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7, +0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02, +0x82,0x01,0x01,0x00,0xBD,0xED,0xC1,0x03,0xFC,0xF6,0x8F,0xFC,0x02,0xB1,0x6F,0x5B, +0x9F,0x48,0xD9,0x9D,0x79,0xE2,0xA2,0xB7,0x03,0x61,0x56,0x18,0xC3,0x47,0xB6,0xD7, +0xCA,0x3D,0x35,0x2E,0x89,0x43,0xF7,0xA1,0x69,0x9B,0xDE,0x8A,0x1A,0xFD,0x13,0x20, +0x9C,0xB4,0x49,0x77,0x32,0x29,0x56,0xFD,0xB9,0xEC,0x8C,0xDD,0x22,0xFA,0x72,0xDC, +0x27,0x61,0x97,0xEE,0xF6,0x5A,0x84,0xEC,0x6E,0x19,0xB9,0x89,0x2C,0xDC,0x84,0x5B, +0xD5,0x74,0xFB,0x6B,0x5F,0xC5,0x89,0xA5,0x10,0x52,0x89,0x46,0x55,0xF4,0xB8,0x75, +0x1C,0xE6,0x7F,0xE4,0x54,0xAE,0x4B,0xF8,0x55,0x72,0x57,0x02,0x19,0xF8,0x17,0x71, +0x59,0xEB,0x1E,0x28,0x07,0x74,0xC5,0x9D,0x48,0xBE,0x6C,0xB4,0xF4,0xA4,0xB0,0xF3, +0x64,0x37,0x79,0x92,0xC0,0xEC,0x46,0x5E,0x7F,0xE1,0x6D,0x53,0x4C,0x62,0xAF,0xCD, +0x1F,0x0B,0x63,0xBB,0x3A,0x9D,0xFB,0xFC,0x79,0x00,0x98,0x61,0x74,0xCF,0x26,0x82, +0x40,0x63,0xF3,0xB2,0x72,0x6A,0x19,0x0D,0x99,0xCA,0xD4,0x0E,0x75,0xCC,0x37,0xFB, +0x8B,0x89,0xC1,0x59,0xF1,0x62,0x7F,0x5F,0xB3,0x5F,0x65,0x30,0xF8,0xA7,0xB7,0x4D, +0x76,0x5A,0x1E,0x76,0x5E,0x34,0xC0,0xE8,0x96,0x56,0x99,0x8A,0xB3,0xF0,0x7F,0xA4, +0xCD,0xBD,0xDC,0x32,0x31,0x7C,0x91,0xCF,0xE0,0x5F,0x11,0xF8,0x6B,0xAA,0x49,0x5C, +0xD1,0x99,0x94,0xD1,0xA2,0xE3,0x63,0x5B,0x09,0x76,0xB5,0x56,0x62,0xE1,0x4B,0x74, +0x1D,0x96,0xD4,0x26,0xD4,0x08,0x04,0x59,0xD0,0x98,0x0E,0x0E,0xE6,0xDE,0xFC,0xC3, +0xEC,0x1F,0x90,0xF1,0x02,0x03,0x01,0x00,0x01,0xA3,0x42,0x30,0x40,0x30,0x0F,0x06, +0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0E, +0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x1D, +0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x7C,0x0C,0x32,0x1F,0xA7,0xD9,0x30, +0x7F,0xC4,0x7D,0x68,0xA3,0x62,0xA8,0xA1,0xCE,0xAB,0x07,0x5B,0x27,0x30,0x0D,0x06, +0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x03,0x82,0x01,0x01, +0x00,0x11,0x59,0xFA,0x25,0x4F,0x03,0x6F,0x94,0x99,0x3B,0x9A,0x1F,0x82,0x85,0x39, +0xD4,0x76,0x05,0x94,0x5E,0xE1,0x28,0x93,0x6D,0x62,0x5D,0x09,0xC2,0xA0,0xA8,0xD4, +0xB0,0x75,0x38,0xF1,0x34,0x6A,0x9D,0xE4,0x9F,0x8A,0x86,0x26,0x51,0xE6,0x2C,0xD1, +0xC6,0x2D,0x6E,0x95,0x20,0x4A,0x92,0x01,0xEC,0xB8,0x8A,0x67,0x7B,0x31,0xE2,0x67, +0x2E,0x8C,0x95,0x03,0x26,0x2E,0x43,0x9D,0x4A,0x31,0xF6,0x0E,0xB5,0x0C,0xBB,0xB7, +0xE2,0x37,0x7F,0x22,0xBA,0x00,0xA3,0x0E,0x7B,0x52,0xFB,0x6B,0xBB,0x3B,0xC4,0xD3, +0x79,0x51,0x4E,0xCD,0x90,0xF4,0x67,0x07,0x19,0xC8,0x3C,0x46,0x7A,0x0D,0x01,0x7D, +0xC5,0x58,0xE7,0x6D,0xE6,0x85,0x30,0x17,0x9A,0x24,0xC4,0x10,0xE0,0x04,0xF7,0xE0, +0xF2,0x7F,0xD4,0xAA,0x0A,0xFF,0x42,0x1D,0x37,0xED,0x94,0xE5,0x64,0x59,0x12,0x20, +0x77,0x38,0xD3,0x32,0x3E,0x38,0x81,0x75,0x96,0x73,0xFA,0x68,0x8F,0xB1,0xCB,0xCE, +0x1F,0xC5,0xEC,0xFA,0x9C,0x7E,0xCF,0x7E,0xB1,0xF1,0x07,0x2D,0xB6,0xFC,0xBF,0xCA, +0xA4,0xBF,0xD0,0x97,0x05,0x4A,0xBC,0xEA,0x18,0x28,0x02,0x90,0xBD,0x54,0x78,0x09, +0x21,0x71,0xD3,0xD1,0x7D,0x1D,0xD9,0x16,0xB0,0xA9,0x61,0x3D,0xD0,0x0A,0x00,0x22, +0xFC,0xC7,0x7B,0xCB,0x09,0x64,0x45,0x0B,0x3B,0x40,0x81,0xF7,0x7D,0x7C,0x32,0xF5, +0x98,0xCA,0x58,0x8E,0x7D,0x2A,0xEE,0x90,0x59,0x73,0x64,0xF9,0x36,0x74,0x5E,0x25, +0xA1,0xF5,0x66,0x05,0x2E,0x7F,0x39,0x15,0xA9,0x2A,0xFB,0x50,0x8B,0x8E,0x85,0x69, +0xF4, +}; + +/* subject: Organizational Unit: Starfield Class 2 Certification Authority; Organization: Starfield Technologies, Inc.; Country: US */ +/* issuer: Organizational Unit: Starfield Class 2 Certification Authority; Organization: Starfield Technologies, Inc.; Country: US */ +/* link: https://crt.sh/?q=1465fa205397b876faa6f0a9958e5590e40fcc7faa4fb7c2c8677521fb5fb658 */ +const unsigned char kCertificateWithFingerprint_1465fa205397b876faa6f0a9958e5590e40fcc7faa4fb7c2c8677521fb5fb658_certificate[1043]={ +0x30,0x82,0x04,0x0F,0x30,0x82,0x02,0xF7,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x00, +0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30, +0x68,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x25, +0x30,0x23,0x06,0x03,0x55,0x04,0x0A,0x13,0x1C,0x53,0x74,0x61,0x72,0x66,0x69,0x65, +0x6C,0x64,0x20,0x54,0x65,0x63,0x68,0x6E,0x6F,0x6C,0x6F,0x67,0x69,0x65,0x73,0x2C, +0x20,0x49,0x6E,0x63,0x2E,0x31,0x32,0x30,0x30,0x06,0x03,0x55,0x04,0x0B,0x13,0x29, +0x53,0x74,0x61,0x72,0x66,0x69,0x65,0x6C,0x64,0x20,0x43,0x6C,0x61,0x73,0x73,0x20, +0x32,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20, +0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x30,0x1E,0x17,0x0D,0x30,0x34,0x30, +0x36,0x32,0x39,0x31,0x37,0x33,0x39,0x31,0x36,0x5A,0x17,0x0D,0x33,0x34,0x30,0x36, +0x32,0x39,0x31,0x37,0x33,0x39,0x31,0x36,0x5A,0x30,0x68,0x31,0x0B,0x30,0x09,0x06, +0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x25,0x30,0x23,0x06,0x03,0x55,0x04, +0x0A,0x13,0x1C,0x53,0x74,0x61,0x72,0x66,0x69,0x65,0x6C,0x64,0x20,0x54,0x65,0x63, +0x68,0x6E,0x6F,0x6C,0x6F,0x67,0x69,0x65,0x73,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31, +0x32,0x30,0x30,0x06,0x03,0x55,0x04,0x0B,0x13,0x29,0x53,0x74,0x61,0x72,0x66,0x69, +0x65,0x6C,0x64,0x20,0x43,0x6C,0x61,0x73,0x73,0x20,0x32,0x20,0x43,0x65,0x72,0x74, +0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72, +0x69,0x74,0x79,0x30,0x82,0x01,0x20,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7, +0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0D,0x00,0x30,0x82,0x01,0x08,0x02, +0x82,0x01,0x01,0x00,0xB7,0x32,0xC8,0xFE,0xE9,0x71,0xA6,0x04,0x85,0xAD,0x0C,0x11, +0x64,0xDF,0xCE,0x4D,0xEF,0xC8,0x03,0x18,0x87,0x3F,0xA1,0xAB,0xFB,0x3C,0xA6,0x9F, +0xF0,0xC3,0xA1,0xDA,0xD4,0xD8,0x6E,0x2B,0x53,0x90,0xFB,0x24,0xA4,0x3E,0x84,0xF0, +0x9E,0xE8,0x5F,0xEC,0xE5,0x27,0x44,0xF5,0x28,0xA6,0x3F,0x7B,0xDE,0xE0,0x2A,0xF0, +0xC8,0xAF,0x53,0x2F,0x9E,0xCA,0x05,0x01,0x93,0x1E,0x8F,0x66,0x1C,0x39,0xA7,0x4D, +0xFA,0x5A,0xB6,0x73,0x04,0x25,0x66,0xEB,0x77,0x7F,0xE7,0x59,0xC6,0x4A,0x99,0x25, +0x14,0x54,0xEB,0x26,0xC7,0xF3,0x7F,0x19,0xD5,0x30,0x70,0x8F,0xAF,0xB0,0x46,0x2A, +0xFF,0xAD,0xEB,0x29,0xED,0xD7,0x9F,0xAA,0x04,0x87,0xA3,0xD4,0xF9,0x89,0xA5,0x34, +0x5F,0xDB,0x43,0x91,0x82,0x36,0xD9,0x66,0x3C,0xB1,0xB8,0xB9,0x82,0xFD,0x9C,0x3A, +0x3E,0x10,0xC8,0x3B,0xEF,0x06,0x65,0x66,0x7A,0x9B,0x19,0x18,0x3D,0xFF,0x71,0x51, +0x3C,0x30,0x2E,0x5F,0xBE,0x3D,0x77,0x73,0xB2,0x5D,0x06,0x6C,0xC3,0x23,0x56,0x9A, +0x2B,0x85,0x26,0x92,0x1C,0xA7,0x02,0xB3,0xE4,0x3F,0x0D,0xAF,0x08,0x79,0x82,0xB8, +0x36,0x3D,0xEA,0x9C,0xD3,0x35,0xB3,0xBC,0x69,0xCA,0xF5,0xCC,0x9D,0xE8,0xFD,0x64, +0x8D,0x17,0x80,0x33,0x6E,0x5E,0x4A,0x5D,0x99,0xC9,0x1E,0x87,0xB4,0x9D,0x1A,0xC0, +0xD5,0x6E,0x13,0x35,0x23,0x5E,0xDF,0x9B,0x5F,0x3D,0xEF,0xD6,0xF7,0x76,0xC2,0xEA, +0x3E,0xBB,0x78,0x0D,0x1C,0x42,0x67,0x6B,0x04,0xD8,0xF8,0xD6,0xDA,0x6F,0x8B,0xF2, +0x44,0xA0,0x01,0xAB,0x02,0x01,0x03,0xA3,0x81,0xC5,0x30,0x81,0xC2,0x30,0x1D,0x06, +0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0xBF,0x5F,0xB7,0xD1,0xCE,0xDD,0x1F,0x86, +0xF4,0x5B,0x55,0xAC,0xDC,0xD7,0x10,0xC2,0x0E,0xA9,0x88,0xE7,0x30,0x81,0x92,0x06, +0x03,0x55,0x1D,0x23,0x04,0x81,0x8A,0x30,0x81,0x87,0x80,0x14,0xBF,0x5F,0xB7,0xD1, +0xCE,0xDD,0x1F,0x86,0xF4,0x5B,0x55,0xAC,0xDC,0xD7,0x10,0xC2,0x0E,0xA9,0x88,0xE7, +0xA1,0x6C,0xA4,0x6A,0x30,0x68,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13, +0x02,0x55,0x53,0x31,0x25,0x30,0x23,0x06,0x03,0x55,0x04,0x0A,0x13,0x1C,0x53,0x74, +0x61,0x72,0x66,0x69,0x65,0x6C,0x64,0x20,0x54,0x65,0x63,0x68,0x6E,0x6F,0x6C,0x6F, +0x67,0x69,0x65,0x73,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x32,0x30,0x30,0x06,0x03, +0x55,0x04,0x0B,0x13,0x29,0x53,0x74,0x61,0x72,0x66,0x69,0x65,0x6C,0x64,0x20,0x43, +0x6C,0x61,0x73,0x73,0x20,0x32,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61, +0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x82,0x01, +0x00,0x30,0x0C,0x06,0x03,0x55,0x1D,0x13,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30, +0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82, +0x01,0x01,0x00,0x05,0x9D,0x3F,0x88,0x9D,0xD1,0xC9,0x1A,0x55,0xA1,0xAC,0x69,0xF3, +0xF3,0x59,0xDA,0x9B,0x01,0x87,0x1A,0x4F,0x57,0xA9,0xA1,0x79,0x09,0x2A,0xDB,0xF7, +0x2F,0xB2,0x1E,0xCC,0xC7,0x5E,0x6A,0xD8,0x83,0x87,0xA1,0x97,0xEF,0x49,0x35,0x3E, +0x77,0x06,0x41,0x58,0x62,0xBF,0x8E,0x58,0xB8,0x0A,0x67,0x3F,0xEC,0xB3,0xDD,0x21, +0x66,0x1F,0xC9,0x54,0xFA,0x72,0xCC,0x3D,0x4C,0x40,0xD8,0x81,0xAF,0x77,0x9E,0x83, +0x7A,0xBB,0xA2,0xC7,0xF5,0x34,0x17,0x8E,0xD9,0x11,0x40,0xF4,0xFC,0x2C,0x2A,0x4D, +0x15,0x7F,0xA7,0x62,0x5D,0x2E,0x25,0xD3,0x00,0x0B,0x20,0x1A,0x1D,0x68,0xF9,0x17, +0xB8,0xF4,0xBD,0x8B,0xED,0x28,0x59,0xDD,0x4D,0x16,0x8B,0x17,0x83,0xC8,0xB2,0x65, +0xC7,0x2D,0x7A,0xA5,0xAA,0xBC,0x53,0x86,0x6D,0xDD,0x57,0xA4,0xCA,0xF8,0x20,0x41, +0x0B,0x68,0xF0,0xF4,0xFB,0x74,0xBE,0x56,0x5D,0x7A,0x79,0xF5,0xF9,0x1D,0x85,0xE3, +0x2D,0x95,0xBE,0xF5,0x71,0x90,0x43,0xCC,0x8D,0x1F,0x9A,0x00,0x0A,0x87,0x29,0xE9, +0x55,0x22,0x58,0x00,0x23,0xEA,0xE3,0x12,0x43,0x29,0x5B,0x47,0x08,0xDD,0x8C,0x41, +0x6A,0x65,0x06,0xA8,0xE5,0x21,0xAA,0x41,0xB4,0x95,0x21,0x95,0xB9,0x7D,0xD1,0x34, +0xAB,0x13,0xD6,0xAD,0xBC,0xDC,0xE2,0x3D,0x39,0xCD,0xBD,0x3E,0x75,0x70,0xA1,0x18, +0x59,0x03,0xC9,0x22,0xB4,0x8F,0x9C,0xD5,0x5E,0x2A,0xD7,0xA5,0xB6,0xD4,0x0A,0x6D, +0xF8,0xB7,0x40,0x11,0x46,0x9A,0x1F,0x79,0x0E,0x62,0xBF,0x0F,0x97,0xEC,0xE0,0x2F, +0x1F,0x17,0x94, +}; + +/* subject: Organizational Unit: Go Daddy Class 2 Certification Authority; Organization: The Go Daddy Group, Inc.; Country: US */ +/* issuer: Organizational Unit: Go Daddy Class 2 Certification Authority; Organization: The Go Daddy Group, Inc.; Country: US */ +/* link: https://crt.sh/?q=c3846bf24b9e93ca64274c0ec67c1ecc5e024ffcacd2d74019350e81fe546ae4 */ +const unsigned char kCertificateWithFingerprint_c3846bf24b9e93ca64274c0ec67c1ecc5e024ffcacd2d74019350e81fe546ae4_certificate[1028]={ +0x30,0x82,0x04,0x00,0x30,0x82,0x02,0xE8,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x00, +0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30, +0x63,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x21, +0x30,0x1F,0x06,0x03,0x55,0x04,0x0A,0x13,0x18,0x54,0x68,0x65,0x20,0x47,0x6F,0x20, +0x44,0x61,0x64,0x64,0x79,0x20,0x47,0x72,0x6F,0x75,0x70,0x2C,0x20,0x49,0x6E,0x63, +0x2E,0x31,0x31,0x30,0x2F,0x06,0x03,0x55,0x04,0x0B,0x13,0x28,0x47,0x6F,0x20,0x44, +0x61,0x64,0x64,0x79,0x20,0x43,0x6C,0x61,0x73,0x73,0x20,0x32,0x20,0x43,0x65,0x72, +0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F, +0x72,0x69,0x74,0x79,0x30,0x1E,0x17,0x0D,0x30,0x34,0x30,0x36,0x32,0x39,0x31,0x37, +0x30,0x36,0x32,0x30,0x5A,0x17,0x0D,0x33,0x34,0x30,0x36,0x32,0x39,0x31,0x37,0x30, +0x36,0x32,0x30,0x5A,0x30,0x63,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13, +0x02,0x55,0x53,0x31,0x21,0x30,0x1F,0x06,0x03,0x55,0x04,0x0A,0x13,0x18,0x54,0x68, +0x65,0x20,0x47,0x6F,0x20,0x44,0x61,0x64,0x64,0x79,0x20,0x47,0x72,0x6F,0x75,0x70, +0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x31,0x30,0x2F,0x06,0x03,0x55,0x04,0x0B,0x13, +0x28,0x47,0x6F,0x20,0x44,0x61,0x64,0x64,0x79,0x20,0x43,0x6C,0x61,0x73,0x73,0x20, +0x32,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20, +0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x30,0x82,0x01,0x20,0x30,0x0D,0x06, +0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0D, +0x00,0x30,0x82,0x01,0x08,0x02,0x82,0x01,0x01,0x00,0xDE,0x9D,0xD7,0xEA,0x57,0x18, +0x49,0xA1,0x5B,0xEB,0xD7,0x5F,0x48,0x86,0xEA,0xBE,0xDD,0xFF,0xE4,0xEF,0x67,0x1C, +0xF4,0x65,0x68,0xB3,0x57,0x71,0xA0,0x5E,0x77,0xBB,0xED,0x9B,0x49,0xE9,0x70,0x80, +0x3D,0x56,0x18,0x63,0x08,0x6F,0xDA,0xF2,0xCC,0xD0,0x3F,0x7F,0x02,0x54,0x22,0x54, +0x10,0xD8,0xB2,0x81,0xD4,0xC0,0x75,0x3D,0x4B,0x7F,0xC7,0x77,0xC3,0x3E,0x78,0xAB, +0x1A,0x03,0xB5,0x20,0x6B,0x2F,0x6A,0x2B,0xB1,0xC5,0x88,0x7E,0xC4,0xBB,0x1E,0xB0, +0xC1,0xD8,0x45,0x27,0x6F,0xAA,0x37,0x58,0xF7,0x87,0x26,0xD7,0xD8,0x2D,0xF6,0xA9, +0x17,0xB7,0x1F,0x72,0x36,0x4E,0xA6,0x17,0x3F,0x65,0x98,0x92,0xDB,0x2A,0x6E,0x5D, +0xA2,0xFE,0x88,0xE0,0x0B,0xDE,0x7F,0xE5,0x8D,0x15,0xE1,0xEB,0xCB,0x3A,0xD5,0xE2, +0x12,0xA2,0x13,0x2D,0xD8,0x8E,0xAF,0x5F,0x12,0x3D,0xA0,0x08,0x05,0x08,0xB6,0x5C, +0xA5,0x65,0x38,0x04,0x45,0x99,0x1E,0xA3,0x60,0x60,0x74,0xC5,0x41,0xA5,0x72,0x62, +0x1B,0x62,0xC5,0x1F,0x6F,0x5F,0x1A,0x42,0xBE,0x02,0x51,0x65,0xA8,0xAE,0x23,0x18, +0x6A,0xFC,0x78,0x03,0xA9,0x4D,0x7F,0x80,0xC3,0xFA,0xAB,0x5A,0xFC,0xA1,0x40,0xA4, +0xCA,0x19,0x16,0xFE,0xB2,0xC8,0xEF,0x5E,0x73,0x0D,0xEE,0x77,0xBD,0x9A,0xF6,0x79, +0x98,0xBC,0xB1,0x07,0x67,0xA2,0x15,0x0D,0xDD,0xA0,0x58,0xC6,0x44,0x7B,0x0A,0x3E, +0x62,0x28,0x5F,0xBA,0x41,0x07,0x53,0x58,0xCF,0x11,0x7E,0x38,0x74,0xC5,0xF8,0xFF, +0xB5,0x69,0x90,0x8F,0x84,0x74,0xEA,0x97,0x1B,0xAF,0x02,0x01,0x03,0xA3,0x81,0xC0, +0x30,0x81,0xBD,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0xD2,0xC4, +0xB0,0xD2,0x91,0xD4,0x4C,0x11,0x71,0xB3,0x61,0xCB,0x3D,0xA1,0xFE,0xDD,0xA8,0x6A, +0xD4,0xE3,0x30,0x81,0x8D,0x06,0x03,0x55,0x1D,0x23,0x04,0x81,0x85,0x30,0x81,0x82, +0x80,0x14,0xD2,0xC4,0xB0,0xD2,0x91,0xD4,0x4C,0x11,0x71,0xB3,0x61,0xCB,0x3D,0xA1, +0xFE,0xDD,0xA8,0x6A,0xD4,0xE3,0xA1,0x67,0xA4,0x65,0x30,0x63,0x31,0x0B,0x30,0x09, +0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x21,0x30,0x1F,0x06,0x03,0x55, +0x04,0x0A,0x13,0x18,0x54,0x68,0x65,0x20,0x47,0x6F,0x20,0x44,0x61,0x64,0x64,0x79, +0x20,0x47,0x72,0x6F,0x75,0x70,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x31,0x30,0x2F, +0x06,0x03,0x55,0x04,0x0B,0x13,0x28,0x47,0x6F,0x20,0x44,0x61,0x64,0x64,0x79,0x20, +0x43,0x6C,0x61,0x73,0x73,0x20,0x32,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63, +0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x82, +0x01,0x00,0x30,0x0C,0x06,0x03,0x55,0x1D,0x13,0x04,0x05,0x30,0x03,0x01,0x01,0xFF, +0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03, +0x82,0x01,0x01,0x00,0x32,0x4B,0xF3,0xB2,0xCA,0x3E,0x91,0xFC,0x12,0xC6,0xA1,0x07, +0x8C,0x8E,0x77,0xA0,0x33,0x06,0x14,0x5C,0x90,0x1E,0x18,0xF7,0x08,0xA6,0x3D,0x0A, +0x19,0xF9,0x87,0x80,0x11,0x6E,0x69,0xE4,0x96,0x17,0x30,0xFF,0x34,0x91,0x63,0x72, +0x38,0xEE,0xCC,0x1C,0x01,0xA3,0x1D,0x94,0x28,0xA4,0x31,0xF6,0x7A,0xC4,0x54,0xD7, +0xF6,0xE5,0x31,0x58,0x03,0xA2,0xCC,0xCE,0x62,0xDB,0x94,0x45,0x73,0xB5,0xBF,0x45, +0xC9,0x24,0xB5,0xD5,0x82,0x02,0xAD,0x23,0x79,0x69,0x8D,0xB8,0xB6,0x4D,0xCE,0xCF, +0x4C,0xCA,0x33,0x23,0xE8,0x1C,0x88,0xAA,0x9D,0x8B,0x41,0x6E,0x16,0xC9,0x20,0xE5, +0x89,0x9E,0xCD,0x3B,0xDA,0x70,0xF7,0x7E,0x99,0x26,0x20,0x14,0x54,0x25,0xAB,0x6E, +0x73,0x85,0xE6,0x9B,0x21,0x9D,0x0A,0x6C,0x82,0x0E,0xA8,0xF8,0xC2,0x0C,0xFA,0x10, +0x1E,0x6C,0x96,0xEF,0x87,0x0D,0xC4,0x0F,0x61,0x8B,0xAD,0xEE,0x83,0x2B,0x95,0xF8, +0x8E,0x92,0x84,0x72,0x39,0xEB,0x20,0xEA,0x83,0xED,0x83,0xCD,0x97,0x6E,0x08,0xBC, +0xEB,0x4E,0x26,0xB6,0x73,0x2B,0xE4,0xD3,0xF6,0x4C,0xFE,0x26,0x71,0xE2,0x61,0x11, +0x74,0x4A,0xFF,0x57,0x1A,0x87,0x0F,0x75,0x48,0x2E,0xCF,0x51,0x69,0x17,0xA0,0x02, +0x12,0x61,0x95,0xD5,0xD1,0x40,0xB2,0x10,0x4C,0xEE,0xC4,0xAC,0x10,0x43,0xA6,0xA5, +0x9E,0x0A,0xD5,0x95,0x62,0x9A,0x0D,0xCF,0x88,0x82,0xC5,0x32,0x0C,0xE4,0x2B,0x9F, +0x45,0xE6,0x0D,0x9F,0x28,0x9C,0xB1,0xB9,0x2A,0x5A,0x57,0xAD,0x37,0x0F,0xAF,0x1D, +0x7F,0xDB,0xBD,0x9F, +}; + +/* subject: Common Name: AAA Certificate Services, Organization: Comodo CA Limited, Locality: Salford, State/Province: Greater Manchester, Country: GB */ +/* issuer: Common Name: AAA Certificate Services, Organization: Comodo CA Limited, Locality: Salford, State/Province: Greater Manchester, Country: GB */ +/* link: https://crt.sh/?q=d7a7a0fb5d7e2731d771e9484ebcdef71d5f0c3e0a2948782bc83ee0ea699ef4 */ +const unsigned char kCertificateWithFingerprint_d7a7a0fb5d7e2731d771e9484ebcdef71d5f0c3e0a2948782bc83ee0ea699ef4_certificate[1078]={ +0x30,0x82,0x04,0x32,0x30,0x82,0x03,0x1A,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x01, +0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30, +0x7B,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x47,0x42,0x31,0x1B, +0x30,0x19,0x06,0x03,0x55,0x04,0x08,0x0C,0x12,0x47,0x72,0x65,0x61,0x74,0x65,0x72, +0x20,0x4D,0x61,0x6E,0x63,0x68,0x65,0x73,0x74,0x65,0x72,0x31,0x10,0x30,0x0E,0x06, +0x03,0x55,0x04,0x07,0x0C,0x07,0x53,0x61,0x6C,0x66,0x6F,0x72,0x64,0x31,0x1A,0x30, +0x18,0x06,0x03,0x55,0x04,0x0A,0x0C,0x11,0x43,0x6F,0x6D,0x6F,0x64,0x6F,0x20,0x43, +0x41,0x20,0x4C,0x69,0x6D,0x69,0x74,0x65,0x64,0x31,0x21,0x30,0x1F,0x06,0x03,0x55, +0x04,0x03,0x0C,0x18,0x41,0x41,0x41,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63, +0x61,0x74,0x65,0x20,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73,0x30,0x1E,0x17,0x0D, +0x30,0x34,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x32, +0x38,0x31,0x32,0x33,0x31,0x32,0x33,0x35,0x39,0x35,0x39,0x5A,0x30,0x7B,0x31,0x0B, +0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x47,0x42,0x31,0x1B,0x30,0x19,0x06, +0x03,0x55,0x04,0x08,0x0C,0x12,0x47,0x72,0x65,0x61,0x74,0x65,0x72,0x20,0x4D,0x61, +0x6E,0x63,0x68,0x65,0x73,0x74,0x65,0x72,0x31,0x10,0x30,0x0E,0x06,0x03,0x55,0x04, +0x07,0x0C,0x07,0x53,0x61,0x6C,0x66,0x6F,0x72,0x64,0x31,0x1A,0x30,0x18,0x06,0x03, +0x55,0x04,0x0A,0x0C,0x11,0x43,0x6F,0x6D,0x6F,0x64,0x6F,0x20,0x43,0x41,0x20,0x4C, +0x69,0x6D,0x69,0x74,0x65,0x64,0x31,0x21,0x30,0x1F,0x06,0x03,0x55,0x04,0x03,0x0C, +0x18,0x41,0x41,0x41,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65, +0x20,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73,0x30,0x82,0x01,0x22,0x30,0x0D,0x06, +0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F, +0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xBE,0x40,0x9D,0xF4,0x6E,0xE1, +0xEA,0x76,0x87,0x1C,0x4D,0x45,0x44,0x8E,0xBE,0x46,0xC8,0x83,0x06,0x9D,0xC1,0x2A, +0xFE,0x18,0x1F,0x8E,0xE4,0x02,0xFA,0xF3,0xAB,0x5D,0x50,0x8A,0x16,0x31,0x0B,0x9A, +0x06,0xD0,0xC5,0x70,0x22,0xCD,0x49,0x2D,0x54,0x63,0xCC,0xB6,0x6E,0x68,0x46,0x0B, +0x53,0xEA,0xCB,0x4C,0x24,0xC0,0xBC,0x72,0x4E,0xEA,0xF1,0x15,0xAE,0xF4,0x54,0x9A, +0x12,0x0A,0xC3,0x7A,0xB2,0x33,0x60,0xE2,0xDA,0x89,0x55,0xF3,0x22,0x58,0xF3,0xDE, +0xDC,0xCF,0xEF,0x83,0x86,0xA2,0x8C,0x94,0x4F,0x9F,0x68,0xF2,0x98,0x90,0x46,0x84, +0x27,0xC7,0x76,0xBF,0xE3,0xCC,0x35,0x2C,0x8B,0x5E,0x07,0x64,0x65,0x82,0xC0,0x48, +0xB0,0xA8,0x91,0xF9,0x61,0x9F,0x76,0x20,0x50,0xA8,0x91,0xC7,0x66,0xB5,0xEB,0x78, +0x62,0x03,0x56,0xF0,0x8A,0x1A,0x13,0xEA,0x31,0xA3,0x1E,0xA0,0x99,0xFD,0x38,0xF6, +0xF6,0x27,0x32,0x58,0x6F,0x07,0xF5,0x6B,0xB8,0xFB,0x14,0x2B,0xAF,0xB7,0xAA,0xCC, +0xD6,0x63,0x5F,0x73,0x8C,0xDA,0x05,0x99,0xA8,0x38,0xA8,0xCB,0x17,0x78,0x36,0x51, +0xAC,0xE9,0x9E,0xF4,0x78,0x3A,0x8D,0xCF,0x0F,0xD9,0x42,0xE2,0x98,0x0C,0xAB,0x2F, +0x9F,0x0E,0x01,0xDE,0xEF,0x9F,0x99,0x49,0xF1,0x2D,0xDF,0xAC,0x74,0x4D,0x1B,0x98, +0xB5,0x47,0xC5,0xE5,0x29,0xD1,0xF9,0x90,0x18,0xC7,0x62,0x9C,0xBE,0x83,0xC7,0x26, +0x7B,0x3E,0x8A,0x25,0xC7,0xC0,0xDD,0x9D,0xE6,0x35,0x68,0x10,0x20,0x9D,0x8F,0xD8, +0xDE,0xD2,0xC3,0x84,0x9C,0x0D,0x5E,0xE8,0x2F,0xC9,0x02,0x03,0x01,0x00,0x01,0xA3, +0x81,0xC0,0x30,0x81,0xBD,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14, +0xA0,0x11,0x0A,0x23,0x3E,0x96,0xF1,0x07,0xEC,0xE2,0xAF,0x29,0xEF,0x82,0xA5,0x7F, +0xD0,0x30,0xA4,0xB4,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04, +0x03,0x02,0x01,0x06,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05, +0x30,0x03,0x01,0x01,0xFF,0x30,0x7B,0x06,0x03,0x55,0x1D,0x1F,0x04,0x74,0x30,0x72, +0x30,0x38,0xA0,0x36,0xA0,0x34,0x86,0x32,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63, +0x72,0x6C,0x2E,0x63,0x6F,0x6D,0x6F,0x64,0x6F,0x63,0x61,0x2E,0x63,0x6F,0x6D,0x2F, +0x41,0x41,0x41,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x53,0x65, +0x72,0x76,0x69,0x63,0x65,0x73,0x2E,0x63,0x72,0x6C,0x30,0x36,0xA0,0x34,0xA0,0x32, +0x86,0x30,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,0x72,0x6C,0x2E,0x63,0x6F,0x6D, +0x6F,0x64,0x6F,0x2E,0x6E,0x65,0x74,0x2F,0x41,0x41,0x41,0x43,0x65,0x72,0x74,0x69, +0x66,0x69,0x63,0x61,0x74,0x65,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73,0x2E,0x63, +0x72,0x6C,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05, +0x00,0x03,0x82,0x01,0x01,0x00,0x08,0x56,0xFC,0x02,0xF0,0x9B,0xE8,0xFF,0xA4,0xFA, +0xD6,0x7B,0xC6,0x44,0x80,0xCE,0x4F,0xC4,0xC5,0xF6,0x00,0x58,0xCC,0xA6,0xB6,0xBC, +0x14,0x49,0x68,0x04,0x76,0xE8,0xE6,0xEE,0x5D,0xEC,0x02,0x0F,0x60,0xD6,0x8D,0x50, +0x18,0x4F,0x26,0x4E,0x01,0xE3,0xE6,0xB0,0xA5,0xEE,0xBF,0xBC,0x74,0x54,0x41,0xBF, +0xFD,0xFC,0x12,0xB8,0xC7,0x4F,0x5A,0xF4,0x89,0x60,0x05,0x7F,0x60,0xB7,0x05,0x4A, +0xF3,0xF6,0xF1,0xC2,0xBF,0xC4,0xB9,0x74,0x86,0xB6,0x2D,0x7D,0x6B,0xCC,0xD2,0xF3, +0x46,0xDD,0x2F,0xC6,0xE0,0x6A,0xC3,0xC3,0x34,0x03,0x2C,0x7D,0x96,0xDD,0x5A,0xC2, +0x0E,0xA7,0x0A,0x99,0xC1,0x05,0x8B,0xAB,0x0C,0x2F,0xF3,0x5C,0x3A,0xCF,0x6C,0x37, +0x55,0x09,0x87,0xDE,0x53,0x40,0x6C,0x58,0xEF,0xFC,0xB6,0xAB,0x65,0x6E,0x04,0xF6, +0x1B,0xDC,0x3C,0xE0,0x5A,0x15,0xC6,0x9E,0xD9,0xF1,0x59,0x48,0x30,0x21,0x65,0x03, +0x6C,0xEC,0xE9,0x21,0x73,0xEC,0x9B,0x03,0xA1,0xE0,0x37,0xAD,0xA0,0x15,0x18,0x8F, +0xFA,0xBA,0x02,0xCE,0xA7,0x2C,0xA9,0x10,0x13,0x2C,0xD4,0xE5,0x08,0x26,0xAB,0x22, +0x97,0x60,0xF8,0x90,0x5E,0x74,0xD4,0xA2,0x9A,0x53,0xBD,0xF2,0xA9,0x68,0xE0,0xA2, +0x6E,0xC2,0xD7,0x6C,0xB1,0xA3,0x0F,0x9E,0xBF,0xEB,0x68,0xE7,0x56,0xF2,0xAE,0xF2, +0xE3,0x2B,0x38,0x3A,0x09,0x81,0xB5,0x6B,0x85,0xD7,0xBE,0x2D,0xED,0x3F,0x1A,0xB7, +0xB2,0x63,0xE2,0xF5,0x62,0x2C,0x82,0xD4,0x6A,0x00,0x41,0x50,0xF1,0x39,0x83,0x9F, +0x95,0xE9,0x36,0x96,0x98,0x6E, +}; + +/* subject: Common Name: COMODO Certification Authority, Organization: COMODO CA Limited, Locality: Salford, State/Province: Greater Manchester, Country: GB */ +/* issuer: Common Name: COMODO Certification Authority, Organization: COMODO CA Limited, Locality: Salford, State/Province: Greater Manchester, Country: GB */ +/* link: https://crt.sh/?q=0c2cd63df7806fa399ede809116b575bf87989f06518f9808c860503178baf66 */ +const unsigned char kCertificateWithFingerprint_0c2cd63df7806fa399ede809116b575bf87989f06518f9808c860503178baf66_certificate[1057]={ +0x30,0x82,0x04,0x1D,0x30,0x82,0x03,0x05,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x4E, +0x81,0x2D,0x8A,0x82,0x65,0xE0,0x0B,0x02,0xEE,0x3E,0x35,0x02,0x46,0xE5,0x3D,0x30, +0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x81, +0x81,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x47,0x42,0x31,0x1B, +0x30,0x19,0x06,0x03,0x55,0x04,0x08,0x13,0x12,0x47,0x72,0x65,0x61,0x74,0x65,0x72, +0x20,0x4D,0x61,0x6E,0x63,0x68,0x65,0x73,0x74,0x65,0x72,0x31,0x10,0x30,0x0E,0x06, +0x03,0x55,0x04,0x07,0x13,0x07,0x53,0x61,0x6C,0x66,0x6F,0x72,0x64,0x31,0x1A,0x30, +0x18,0x06,0x03,0x55,0x04,0x0A,0x13,0x11,0x43,0x4F,0x4D,0x4F,0x44,0x4F,0x20,0x43, +0x41,0x20,0x4C,0x69,0x6D,0x69,0x74,0x65,0x64,0x31,0x27,0x30,0x25,0x06,0x03,0x55, +0x04,0x03,0x13,0x1E,0x43,0x4F,0x4D,0x4F,0x44,0x4F,0x20,0x43,0x65,0x72,0x74,0x69, +0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69, +0x74,0x79,0x30,0x1E,0x17,0x0D,0x30,0x36,0x31,0x32,0x30,0x31,0x30,0x30,0x30,0x30, +0x30,0x30,0x5A,0x17,0x0D,0x32,0x39,0x31,0x32,0x33,0x31,0x32,0x33,0x35,0x39,0x35, +0x39,0x5A,0x30,0x81,0x81,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02, +0x47,0x42,0x31,0x1B,0x30,0x19,0x06,0x03,0x55,0x04,0x08,0x13,0x12,0x47,0x72,0x65, +0x61,0x74,0x65,0x72,0x20,0x4D,0x61,0x6E,0x63,0x68,0x65,0x73,0x74,0x65,0x72,0x31, +0x10,0x30,0x0E,0x06,0x03,0x55,0x04,0x07,0x13,0x07,0x53,0x61,0x6C,0x66,0x6F,0x72, +0x64,0x31,0x1A,0x30,0x18,0x06,0x03,0x55,0x04,0x0A,0x13,0x11,0x43,0x4F,0x4D,0x4F, +0x44,0x4F,0x20,0x43,0x41,0x20,0x4C,0x69,0x6D,0x69,0x74,0x65,0x64,0x31,0x27,0x30, +0x25,0x06,0x03,0x55,0x04,0x03,0x13,0x1E,0x43,0x4F,0x4D,0x4F,0x44,0x4F,0x20,0x43, +0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74, +0x68,0x6F,0x72,0x69,0x74,0x79,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86, +0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82, +0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xD0,0x40,0x8B,0x8B,0x72,0xE3,0x91,0x1B,0xF7, +0x51,0xC1,0x1B,0x54,0x04,0x98,0xD3,0xA9,0xBF,0xC1,0xE6,0x8A,0x5D,0x3B,0x87,0xFB, +0xBB,0x88,0xCE,0x0D,0xE3,0x2F,0x3F,0x06,0x96,0xF0,0xA2,0x29,0x50,0x99,0xAE,0xDB, +0x3B,0xA1,0x57,0xB0,0x74,0x51,0x71,0xCD,0xED,0x42,0x91,0x4D,0x41,0xFE,0xA9,0xC8, +0xD8,0x6A,0x86,0x77,0x44,0xBB,0x59,0x66,0x97,0x50,0x5E,0xB4,0xD4,0x2C,0x70,0x44, +0xCF,0xDA,0x37,0x95,0x42,0x69,0x3C,0x30,0xC4,0x71,0xB3,0x52,0xF0,0x21,0x4D,0xA1, +0xD8,0xBA,0x39,0x7C,0x1C,0x9E,0xA3,0x24,0x9D,0xF2,0x83,0x16,0x98,0xAA,0x16,0x7C, +0x43,0x9B,0x15,0x5B,0xB7,0xAE,0x34,0x91,0xFE,0xD4,0x62,0x26,0x18,0x46,0x9A,0x3F, +0xEB,0xC1,0xF9,0xF1,0x90,0x57,0xEB,0xAC,0x7A,0x0D,0x8B,0xDB,0x72,0x30,0x6A,0x66, +0xD5,0xE0,0x46,0xA3,0x70,0xDC,0x68,0xD9,0xFF,0x04,0x48,0x89,0x77,0xDE,0xB5,0xE9, +0xFB,0x67,0x6D,0x41,0xE9,0xBC,0x39,0xBD,0x32,0xD9,0x62,0x02,0xF1,0xB1,0xA8,0x3D, +0x6E,0x37,0x9C,0xE2,0x2F,0xE2,0xD3,0xA2,0x26,0x8B,0xC6,0xB8,0x55,0x43,0x88,0xE1, +0x23,0x3E,0xA5,0xD2,0x24,0x39,0x6A,0x47,0xAB,0x00,0xD4,0xA1,0xB3,0xA9,0x25,0xFE, +0x0D,0x3F,0xA7,0x1D,0xBA,0xD3,0x51,0xC1,0x0B,0xA4,0xDA,0xAC,0x38,0xEF,0x55,0x50, +0x24,0x05,0x65,0x46,0x93,0x34,0x4F,0x2D,0x8D,0xAD,0xC6,0xD4,0x21,0x19,0xD2,0x8E, +0xCA,0x05,0x61,0x71,0x07,0x73,0x47,0xE5,0x8A,0x19,0x12,0xBD,0x04,0x4D,0xCE,0x4E, +0x9C,0xA5,0x48,0xAC,0xBB,0x26,0xF7,0x02,0x03,0x01,0x00,0x01,0xA3,0x81,0x8E,0x30, +0x81,0x8B,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x0B,0x58,0xE5, +0x8B,0xC6,0x4C,0x15,0x37,0xA4,0x40,0xA9,0x30,0xA9,0x21,0xBE,0x47,0x36,0x5A,0x56, +0xFF,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01, +0x06,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01, +0x01,0xFF,0x30,0x49,0x06,0x03,0x55,0x1D,0x1F,0x04,0x42,0x30,0x40,0x30,0x3E,0xA0, +0x3C,0xA0,0x3A,0x86,0x38,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,0x72,0x6C,0x2E, +0x63,0x6F,0x6D,0x6F,0x64,0x6F,0x63,0x61,0x2E,0x63,0x6F,0x6D,0x2F,0x43,0x4F,0x4D, +0x4F,0x44,0x4F,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E, +0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x2E,0x63,0x72,0x6C,0x30,0x0D,0x06, +0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01, +0x00,0x3E,0x98,0x9E,0x9B,0xF6,0x1B,0xE9,0xD7,0x39,0xB7,0x78,0xAE,0x1D,0x72,0x18, +0x49,0xD3,0x87,0xE4,0x43,0x82,0xEB,0x3F,0xC9,0xAA,0xF5,0xA8,0xB5,0xEF,0x55,0x7C, +0x21,0x52,0x65,0xF9,0xD5,0x0D,0xE1,0x6C,0xF4,0x3E,0x8C,0x93,0x73,0x91,0x2E,0x02, +0xC4,0x4E,0x07,0x71,0x6F,0xC0,0x8F,0x38,0x61,0x08,0xA8,0x1E,0x81,0x0A,0xC0,0x2F, +0x20,0x2F,0x41,0x8B,0x91,0xDC,0x48,0x45,0xBC,0xF1,0xC6,0xDE,0xBA,0x76,0x6B,0x33, +0xC8,0x00,0x2D,0x31,0x46,0x4C,0xED,0xE7,0x9D,0xCF,0x88,0x94,0xFF,0x33,0xC0,0x56, +0xE8,0x24,0x86,0x26,0xB8,0xD8,0x38,0x38,0xDF,0x2A,0x6B,0xDD,0x12,0xCC,0xC7,0x3F, +0x47,0x17,0x4C,0xA2,0xC2,0x06,0x96,0x09,0xD6,0xDB,0xFE,0x3F,0x3C,0x46,0x41,0xDF, +0x58,0xE2,0x56,0x0F,0x3C,0x3B,0xC1,0x1C,0x93,0x35,0xD9,0x38,0x52,0xAC,0xEE,0xC8, +0xEC,0x2E,0x30,0x4E,0x94,0x35,0xB4,0x24,0x1F,0x4B,0x78,0x69,0xDA,0xF2,0x02,0x38, +0xCC,0x95,0x52,0x93,0xF0,0x70,0x25,0x59,0x9C,0x20,0x67,0xC4,0xEE,0xF9,0x8B,0x57, +0x61,0xF4,0x92,0x76,0x7D,0x3F,0x84,0x8D,0x55,0xB7,0xE8,0xE5,0xAC,0xD5,0xF1,0xF5, +0x19,0x56,0xA6,0x5A,0xFB,0x90,0x1C,0xAF,0x93,0xEB,0xE5,0x1C,0xD4,0x67,0x97,0x5D, +0x04,0x0E,0xBE,0x0B,0x83,0xA6,0x17,0x83,0xB9,0x30,0x12,0xA0,0xC5,0x33,0x15,0x05, +0xB9,0x0D,0xFB,0xC7,0x05,0x76,0xE3,0xD8,0x4A,0x8D,0xFC,0x34,0x17,0xA3,0xC6,0x21, +0x28,0xBE,0x30,0x45,0x31,0x1E,0xC7,0x78,0xBE,0x58,0x61,0x38,0xAC,0x3B,0xE2,0x01, +0x65, +}; + +/* subject: Common Name: COMODO ECC Certification Authority, Organization: COMODO CA Limited, Locality: Salford, State/Province: Greater Manchester, Country: GB */ +/* issuer: Common Name: COMODO ECC Certification Authority, Organization: COMODO CA Limited, Locality: Salford, State/Province: Greater Manchester, Country: GB */ +/* link: https://crt.sh/?q=1793927a0614549789adce2f8f34f7f0b66d0f3ae3a3b84d21ec15dbba4fadc7 */ +const unsigned char kCertificateWithFingerprint_1793927a0614549789adce2f8f34f7f0b66d0f3ae3a3b84d21ec15dbba4fadc7_certificate[653]={ +0x30,0x82,0x02,0x89,0x30,0x82,0x02,0x0F,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x1F, +0x47,0xAF,0xAA,0x62,0x00,0x70,0x50,0x54,0x4C,0x01,0x9E,0x9B,0x63,0x99,0x2A,0x30, +0x0A,0x06,0x08,0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x03,0x30,0x81,0x85,0x31,0x0B, +0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x47,0x42,0x31,0x1B,0x30,0x19,0x06, +0x03,0x55,0x04,0x08,0x13,0x12,0x47,0x72,0x65,0x61,0x74,0x65,0x72,0x20,0x4D,0x61, +0x6E,0x63,0x68,0x65,0x73,0x74,0x65,0x72,0x31,0x10,0x30,0x0E,0x06,0x03,0x55,0x04, +0x07,0x13,0x07,0x53,0x61,0x6C,0x66,0x6F,0x72,0x64,0x31,0x1A,0x30,0x18,0x06,0x03, +0x55,0x04,0x0A,0x13,0x11,0x43,0x4F,0x4D,0x4F,0x44,0x4F,0x20,0x43,0x41,0x20,0x4C, +0x69,0x6D,0x69,0x74,0x65,0x64,0x31,0x2B,0x30,0x29,0x06,0x03,0x55,0x04,0x03,0x13, +0x22,0x43,0x4F,0x4D,0x4F,0x44,0x4F,0x20,0x45,0x43,0x43,0x20,0x43,0x65,0x72,0x74, +0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72, +0x69,0x74,0x79,0x30,0x1E,0x17,0x0D,0x30,0x38,0x30,0x33,0x30,0x36,0x30,0x30,0x30, +0x30,0x30,0x30,0x5A,0x17,0x0D,0x33,0x38,0x30,0x31,0x31,0x38,0x32,0x33,0x35,0x39, +0x35,0x39,0x5A,0x30,0x81,0x85,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13, +0x02,0x47,0x42,0x31,0x1B,0x30,0x19,0x06,0x03,0x55,0x04,0x08,0x13,0x12,0x47,0x72, +0x65,0x61,0x74,0x65,0x72,0x20,0x4D,0x61,0x6E,0x63,0x68,0x65,0x73,0x74,0x65,0x72, +0x31,0x10,0x30,0x0E,0x06,0x03,0x55,0x04,0x07,0x13,0x07,0x53,0x61,0x6C,0x66,0x6F, +0x72,0x64,0x31,0x1A,0x30,0x18,0x06,0x03,0x55,0x04,0x0A,0x13,0x11,0x43,0x4F,0x4D, +0x4F,0x44,0x4F,0x20,0x43,0x41,0x20,0x4C,0x69,0x6D,0x69,0x74,0x65,0x64,0x31,0x2B, +0x30,0x29,0x06,0x03,0x55,0x04,0x03,0x13,0x22,0x43,0x4F,0x4D,0x4F,0x44,0x4F,0x20, +0x45,0x43,0x43,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F, +0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x30,0x76,0x30,0x10,0x06, +0x07,0x2A,0x86,0x48,0xCE,0x3D,0x02,0x01,0x06,0x05,0x2B,0x81,0x04,0x00,0x22,0x03, +0x62,0x00,0x04,0x03,0x47,0x7B,0x2F,0x75,0xC9,0x82,0x15,0x85,0xFB,0x75,0xE4,0x91, +0x16,0xD4,0xAB,0x62,0x99,0xF5,0x3E,0x52,0x0B,0x06,0xCE,0x41,0x00,0x7F,0x97,0xE1, +0x0A,0x24,0x3C,0x1D,0x01,0x04,0xEE,0x3D,0xD2,0x8D,0x09,0x97,0x0C,0xE0,0x75,0xE4, +0xFA,0xFB,0x77,0x8A,0x2A,0xF5,0x03,0x60,0x4B,0x36,0x8B,0x16,0x23,0x16,0xAD,0x09, +0x71,0xF4,0x4A,0xF4,0x28,0x50,0xB4,0xFE,0x88,0x1C,0x6E,0x3F,0x6C,0x2F,0x2F,0x09, +0x59,0x5B,0xA5,0x5B,0x0B,0x33,0x99,0xE2,0xC3,0x3D,0x89,0xF9,0x6A,0x2C,0xEF,0xB2, +0xD3,0x06,0xE9,0xA3,0x42,0x30,0x40,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16, +0x04,0x14,0x75,0x71,0xA7,0x19,0x48,0x19,0xBC,0x9D,0x9D,0xEA,0x41,0x47,0xDF,0x94, +0xC4,0x48,0x77,0x99,0xD3,0x79,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF, +0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF, +0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0A,0x06,0x08,0x2A,0x86,0x48,0xCE,0x3D, +0x04,0x03,0x03,0x03,0x68,0x00,0x30,0x65,0x02,0x31,0x00,0xEF,0x03,0x5B,0x7A,0xAC, +0xB7,0x78,0x0A,0x72,0xB7,0x88,0xDF,0xFF,0xB5,0x46,0x14,0x09,0x0A,0xFA,0xA0,0xE6, +0x7D,0x08,0xC6,0x1A,0x87,0xBD,0x18,0xA8,0x73,0xBD,0x26,0xCA,0x60,0x0C,0x9D,0xCE, +0x99,0x9F,0xCF,0x5C,0x0F,0x30,0xE1,0xBE,0x14,0x31,0xEA,0x02,0x30,0x14,0xF4,0x93, +0x3C,0x49,0xA7,0x33,0x7A,0x90,0x46,0x47,0xB3,0x63,0x7D,0x13,0x9B,0x4E,0xB7,0x6F, +0x18,0x37,0x80,0x53,0xFE,0xDD,0x20,0xE0,0x35,0x9A,0x36,0xD1,0xC7,0x01,0xB9,0xE6, +0xDC,0xDD,0xF3,0xFF,0x1D,0x2C,0x3A,0x16,0x57,0xD9,0x92,0x39,0xD6, +}; + +/* subject: Common Name: COMODO RSA Certification Authority, Organization: COMODO CA Limited, Locality: Salford, State/Province: Greater Manchester, Country: GB */ +/* issuer: Common Name: COMODO RSA Certification Authority, Organization: COMODO CA Limited, Locality: Salford, State/Province: Greater Manchester, Country: GB */ +/* link: https://crt.sh/?q=52f0e1c4e58ec629291b60317f074671b85d7ea80d5b07273463534b32b40234 */ +const unsigned char kCertificateWithFingerprint_52f0e1c4e58ec629291b60317f074671b85d7ea80d5b07273463534b32b40234_certificate[1500]={ +0x30,0x82,0x05,0xD8,0x30,0x82,0x03,0xC0,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x4C, +0xAA,0xF9,0xCA,0xDB,0x63,0x6F,0xE0,0x1F,0xF7,0x4E,0xD8,0x5B,0x03,0x86,0x9D,0x30, +0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0C,0x05,0x00,0x30,0x81, +0x85,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x47,0x42,0x31,0x1B, +0x30,0x19,0x06,0x03,0x55,0x04,0x08,0x13,0x12,0x47,0x72,0x65,0x61,0x74,0x65,0x72, +0x20,0x4D,0x61,0x6E,0x63,0x68,0x65,0x73,0x74,0x65,0x72,0x31,0x10,0x30,0x0E,0x06, +0x03,0x55,0x04,0x07,0x13,0x07,0x53,0x61,0x6C,0x66,0x6F,0x72,0x64,0x31,0x1A,0x30, +0x18,0x06,0x03,0x55,0x04,0x0A,0x13,0x11,0x43,0x4F,0x4D,0x4F,0x44,0x4F,0x20,0x43, +0x41,0x20,0x4C,0x69,0x6D,0x69,0x74,0x65,0x64,0x31,0x2B,0x30,0x29,0x06,0x03,0x55, +0x04,0x03,0x13,0x22,0x43,0x4F,0x4D,0x4F,0x44,0x4F,0x20,0x52,0x53,0x41,0x20,0x43, +0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74, +0x68,0x6F,0x72,0x69,0x74,0x79,0x30,0x1E,0x17,0x0D,0x31,0x30,0x30,0x31,0x31,0x39, +0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x33,0x38,0x30,0x31,0x31,0x38,0x32, +0x33,0x35,0x39,0x35,0x39,0x5A,0x30,0x81,0x85,0x31,0x0B,0x30,0x09,0x06,0x03,0x55, +0x04,0x06,0x13,0x02,0x47,0x42,0x31,0x1B,0x30,0x19,0x06,0x03,0x55,0x04,0x08,0x13, +0x12,0x47,0x72,0x65,0x61,0x74,0x65,0x72,0x20,0x4D,0x61,0x6E,0x63,0x68,0x65,0x73, +0x74,0x65,0x72,0x31,0x10,0x30,0x0E,0x06,0x03,0x55,0x04,0x07,0x13,0x07,0x53,0x61, +0x6C,0x66,0x6F,0x72,0x64,0x31,0x1A,0x30,0x18,0x06,0x03,0x55,0x04,0x0A,0x13,0x11, +0x43,0x4F,0x4D,0x4F,0x44,0x4F,0x20,0x43,0x41,0x20,0x4C,0x69,0x6D,0x69,0x74,0x65, +0x64,0x31,0x2B,0x30,0x29,0x06,0x03,0x55,0x04,0x03,0x13,0x22,0x43,0x4F,0x4D,0x4F, +0x44,0x4F,0x20,0x52,0x53,0x41,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61, +0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x30,0x82, +0x02,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05, +0x00,0x03,0x82,0x02,0x0F,0x00,0x30,0x82,0x02,0x0A,0x02,0x82,0x02,0x01,0x00,0x91, +0xE8,0x54,0x92,0xD2,0x0A,0x56,0xB1,0xAC,0x0D,0x24,0xDD,0xC5,0xCF,0x44,0x67,0x74, +0x99,0x2B,0x37,0xA3,0x7D,0x23,0x70,0x00,0x71,0xBC,0x53,0xDF,0xC4,0xFA,0x2A,0x12, +0x8F,0x4B,0x7F,0x10,0x56,0xBD,0x9F,0x70,0x72,0xB7,0x61,0x7F,0xC9,0x4B,0x0F,0x17, +0xA7,0x3D,0xE3,0xB0,0x04,0x61,0xEE,0xFF,0x11,0x97,0xC7,0xF4,0x86,0x3E,0x0A,0xFA, +0x3E,0x5C,0xF9,0x93,0xE6,0x34,0x7A,0xD9,0x14,0x6B,0xE7,0x9C,0xB3,0x85,0xA0,0x82, +0x7A,0x76,0xAF,0x71,0x90,0xD7,0xEC,0xFD,0x0D,0xFA,0x9C,0x6C,0xFA,0xDF,0xB0,0x82, +0xF4,0x14,0x7E,0xF9,0xBE,0xC4,0xA6,0x2F,0x4F,0x7F,0x99,0x7F,0xB5,0xFC,0x67,0x43, +0x72,0xBD,0x0C,0x00,0xD6,0x89,0xEB,0x6B,0x2C,0xD3,0xED,0x8F,0x98,0x1C,0x14,0xAB, +0x7E,0xE5,0xE3,0x6E,0xFC,0xD8,0xA8,0xE4,0x92,0x24,0xDA,0x43,0x6B,0x62,0xB8,0x55, +0xFD,0xEA,0xC1,0xBC,0x6C,0xB6,0x8B,0xF3,0x0E,0x8D,0x9A,0xE4,0x9B,0x6C,0x69,0x99, +0xF8,0x78,0x48,0x30,0x45,0xD5,0xAD,0xE1,0x0D,0x3C,0x45,0x60,0xFC,0x32,0x96,0x51, +0x27,0xBC,0x67,0xC3,0xCA,0x2E,0xB6,0x6B,0xEA,0x46,0xC7,0xC7,0x20,0xA0,0xB1,0x1F, +0x65,0xDE,0x48,0x08,0xBA,0xA4,0x4E,0xA9,0xF2,0x83,0x46,0x37,0x84,0xEB,0xE8,0xCC, +0x81,0x48,0x43,0x67,0x4E,0x72,0x2A,0x9B,0x5C,0xBD,0x4C,0x1B,0x28,0x8A,0x5C,0x22, +0x7B,0xB4,0xAB,0x98,0xD9,0xEE,0xE0,0x51,0x83,0xC3,0x09,0x46,0x4E,0x6D,0x3E,0x99, +0xFA,0x95,0x17,0xDA,0x7C,0x33,0x57,0x41,0x3C,0x8D,0x51,0xED,0x0B,0xB6,0x5C,0xAF, +0x2C,0x63,0x1A,0xDF,0x57,0xC8,0x3F,0xBC,0xE9,0x5D,0xC4,0x9B,0xAF,0x45,0x99,0xE2, +0xA3,0x5A,0x24,0xB4,0xBA,0xA9,0x56,0x3D,0xCF,0x6F,0xAA,0xFF,0x49,0x58,0xBE,0xF0, +0xA8,0xFF,0xF4,0xB8,0xAD,0xE9,0x37,0xFB,0xBA,0xB8,0xF4,0x0B,0x3A,0xF9,0xE8,0x43, +0x42,0x1E,0x89,0xD8,0x84,0xCB,0x13,0xF1,0xD9,0xBB,0xE1,0x89,0x60,0xB8,0x8C,0x28, +0x56,0xAC,0x14,0x1D,0x9C,0x0A,0xE7,0x71,0xEB,0xCF,0x0E,0xDD,0x3D,0xA9,0x96,0xA1, +0x48,0xBD,0x3C,0xF7,0xAF,0xB5,0x0D,0x22,0x4C,0xC0,0x11,0x81,0xEC,0x56,0x3B,0xF6, +0xD3,0xA2,0xE2,0x5B,0xB7,0xB2,0x04,0x22,0x52,0x95,0x80,0x93,0x69,0xE8,0x8E,0x4C, +0x65,0xF1,0x91,0x03,0x2D,0x70,0x74,0x02,0xEA,0x8B,0x67,0x15,0x29,0x69,0x52,0x02, +0xBB,0xD7,0xDF,0x50,0x6A,0x55,0x46,0xBF,0xA0,0xA3,0x28,0x61,0x7F,0x70,0xD0,0xC3, +0xA2,0xAA,0x2C,0x21,0xAA,0x47,0xCE,0x28,0x9C,0x06,0x45,0x76,0xBF,0x82,0x18,0x27, +0xB4,0xD5,0xAE,0xB4,0xCB,0x50,0xE6,0x6B,0xF4,0x4C,0x86,0x71,0x30,0xE9,0xA6,0xDF, +0x16,0x86,0xE0,0xD8,0xFF,0x40,0xDD,0xFB,0xD0,0x42,0x88,0x7F,0xA3,0x33,0x3A,0x2E, +0x5C,0x1E,0x41,0x11,0x81,0x63,0xCE,0x18,0x71,0x6B,0x2B,0xEC,0xA6,0x8A,0xB7,0x31, +0x5C,0x3A,0x6A,0x47,0xE0,0xC3,0x79,0x59,0xD6,0x20,0x1A,0xAF,0xF2,0x6A,0x98,0xAA, +0x72,0xBC,0x57,0x4A,0xD2,0x4B,0x9D,0xBB,0x10,0xFC,0xB0,0x4C,0x41,0xE5,0xED,0x1D, +0x3D,0x5E,0x28,0x9D,0x9C,0xCC,0xBF,0xB3,0x51,0xDA,0xA7,0x47,0xE5,0x84,0x53,0x02, +0x03,0x01,0x00,0x01,0xA3,0x42,0x30,0x40,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04, +0x16,0x04,0x14,0xBB,0xAF,0x7E,0x02,0x3D,0xFA,0xA6,0xF1,0x3C,0x84,0x8E,0xAD,0xEE, +0x38,0x98,0xEC,0xD9,0x32,0x32,0xD4,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01, +0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01, +0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86, +0xF7,0x0D,0x01,0x01,0x0C,0x05,0x00,0x03,0x82,0x02,0x01,0x00,0x0A,0xF1,0xD5,0x46, +0x84,0xB7,0xAE,0x51,0xBB,0x6C,0xB2,0x4D,0x41,0x14,0x00,0x93,0x4C,0x9C,0xCB,0xE5, +0xC0,0x54,0xCF,0xA0,0x25,0x8E,0x02,0xF9,0xFD,0xB0,0xA2,0x0D,0xF5,0x20,0x98,0x3C, +0x13,0x2D,0xAC,0x56,0xA2,0xB0,0xD6,0x7E,0x11,0x92,0xE9,0x2E,0xBA,0x9E,0x2E,0x9A, +0x72,0xB1,0xBD,0x19,0x44,0x6C,0x61,0x35,0xA2,0x9A,0xB4,0x16,0x12,0x69,0x5A,0x8C, +0xE1,0xD7,0x3E,0xA4,0x1A,0xE8,0x2F,0x03,0xF4,0xAE,0x61,0x1D,0x10,0x1B,0x2A,0xA4, +0x8B,0x7A,0xC5,0xFE,0x05,0xA6,0xE1,0xC0,0xD6,0xC8,0xFE,0x9E,0xAE,0x8F,0x2B,0xBA, +0x3D,0x99,0xF8,0xD8,0x73,0x09,0x58,0x46,0x6E,0xA6,0x9C,0xF4,0xD7,0x27,0xD3,0x95, +0xDA,0x37,0x83,0x72,0x1C,0xD3,0x73,0xE0,0xA2,0x47,0x99,0x03,0x38,0x5D,0xD5,0x49, +0x79,0x00,0x29,0x1C,0xC7,0xEC,0x9B,0x20,0x1C,0x07,0x24,0x69,0x57,0x78,0xB2,0x39, +0xFC,0x3A,0x84,0xA0,0xB5,0x9C,0x7C,0x8D,0xBF,0x2E,0x93,0x62,0x27,0xB7,0x39,0xDA, +0x17,0x18,0xAE,0xBD,0x3C,0x09,0x68,0xFF,0x84,0x9B,0x3C,0xD5,0xD6,0x0B,0x03,0xE3, +0x57,0x9E,0x14,0xF7,0xD1,0xEB,0x4F,0xC8,0xBD,0x87,0x23,0xB7,0xB6,0x49,0x43,0x79, +0x85,0x5C,0xBA,0xEB,0x92,0x0B,0xA1,0xC6,0xE8,0x68,0xA8,0x4C,0x16,0xB1,0x1A,0x99, +0x0A,0xE8,0x53,0x2C,0x92,0xBB,0xA1,0x09,0x18,0x75,0x0C,0x65,0xA8,0x7B,0xCB,0x23, +0xB7,0x1A,0xC2,0x28,0x85,0xC3,0x1B,0xFF,0xD0,0x2B,0x62,0xEF,0xA4,0x7B,0x09,0x91, +0x98,0x67,0x8C,0x14,0x01,0xCD,0x68,0x06,0x6A,0x63,0x21,0x75,0x03,0x80,0x88,0x8A, +0x6E,0x81,0xC6,0x85,0xF2,0xA9,0xA4,0x2D,0xE7,0xF4,0xA5,0x24,0x10,0x47,0x83,0xCA, +0xCD,0xF4,0x8D,0x79,0x58,0xB1,0x06,0x9B,0xE7,0x1A,0x2A,0xD9,0x9D,0x01,0xD7,0x94, +0x7D,0xED,0x03,0x4A,0xCA,0xF0,0xDB,0xE8,0xA9,0x01,0x3E,0xF5,0x56,0x99,0xC9,0x1E, +0x8E,0x49,0x3D,0xBB,0xE5,0x09,0xB9,0xE0,0x4F,0x49,0x92,0x3D,0x16,0x82,0x40,0xCC, +0xCC,0x59,0xC6,0xE6,0x3A,0xED,0x12,0x2E,0x69,0x3C,0x6C,0x95,0xB1,0xFD,0xAA,0x1D, +0x7B,0x7F,0x86,0xBE,0x1E,0x0E,0x32,0x46,0xFB,0xFB,0x13,0x8F,0x75,0x7F,0x4C,0x8B, +0x4B,0x46,0x63,0xFE,0x00,0x34,0x40,0x70,0xC1,0xC3,0xB9,0xA1,0xDD,0xA6,0x70,0xE2, +0x04,0xB3,0x41,0xBC,0xE9,0x80,0x91,0xEA,0x64,0x9C,0x7A,0xE1,0x22,0x03,0xA9,0x9C, +0x6E,0x6F,0x0E,0x65,0x4F,0x6C,0x87,0x87,0x5E,0xF3,0x6E,0xA0,0xF9,0x75,0xA5,0x9B, +0x40,0xE8,0x53,0xB2,0x27,0x9D,0x4A,0xB9,0xC0,0x77,0x21,0x8D,0xFF,0x87,0xF2,0xDE, +0xBC,0x8C,0xEF,0x17,0xDF,0xB7,0x49,0x0B,0xD1,0xF2,0x6E,0x30,0x0B,0x1A,0x0E,0x4E, +0x76,0xED,0x11,0xFC,0xF5,0xE9,0x56,0xB2,0x7D,0xBF,0xC7,0x6D,0x0A,0x93,0x8C,0xA5, +0xD0,0xC0,0xB6,0x1D,0xBE,0x3A,0x4E,0x94,0xA2,0xD7,0x6E,0x6C,0x0B,0xC2,0x8A,0x7C, +0xFA,0x20,0xF3,0xC4,0xE4,0xE5,0xCD,0x0D,0xA8,0xCB,0x91,0x92,0xB1,0x7C,0x85,0xEC, +0xB5,0x14,0x69,0x66,0x0E,0x82,0xE7,0xCD,0xCE,0xC8,0x2D,0xA6,0x51,0x7F,0x21,0xC1, +0x35,0x53,0x85,0x06,0x4A,0x5D,0x9F,0xAD,0xBB,0x1B,0x5F,0x74, +}; + +/* subject: Common Name: USERTrust ECC Certification Authority, Organization: The USERTRUST Network, Locality: Jersey City, State/Province: New Jersey, Country: US */ +/* issuer: Common Name: USERTrust ECC Certification Authority, Organization: The USERTRUST Network, Locality: Jersey City, State/Province: New Jersey, Country: US */ +/* link: https://crt.sh/?q=4ff460d54b9c86dabfbcfc5712e0400d2bed3fbc4d4fbdaa86e06adcd2a9ad7a */ +const unsigned char kCertificateWithFingerprint_4ff460d54b9c86dabfbcfc5712e0400d2bed3fbc4d4fbdaa86e06adcd2a9ad7a_certificate[659]={ +0x30,0x82,0x02,0x8F,0x30,0x82,0x02,0x15,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x5C, +0x8B,0x99,0xC5,0x5A,0x94,0xC5,0xD2,0x71,0x56,0xDE,0xCD,0x89,0x80,0xCC,0x26,0x30, +0x0A,0x06,0x08,0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x03,0x30,0x81,0x88,0x31,0x0B, +0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x13,0x30,0x11,0x06, +0x03,0x55,0x04,0x08,0x13,0x0A,0x4E,0x65,0x77,0x20,0x4A,0x65,0x72,0x73,0x65,0x79, +0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x07,0x13,0x0B,0x4A,0x65,0x72,0x73,0x65, +0x79,0x20,0x43,0x69,0x74,0x79,0x31,0x1E,0x30,0x1C,0x06,0x03,0x55,0x04,0x0A,0x13, +0x15,0x54,0x68,0x65,0x20,0x55,0x53,0x45,0x52,0x54,0x52,0x55,0x53,0x54,0x20,0x4E, +0x65,0x74,0x77,0x6F,0x72,0x6B,0x31,0x2E,0x30,0x2C,0x06,0x03,0x55,0x04,0x03,0x13, +0x25,0x55,0x53,0x45,0x52,0x54,0x72,0x75,0x73,0x74,0x20,0x45,0x43,0x43,0x20,0x43, +0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74, +0x68,0x6F,0x72,0x69,0x74,0x79,0x30,0x1E,0x17,0x0D,0x31,0x30,0x30,0x32,0x30,0x31, +0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x33,0x38,0x30,0x31,0x31,0x38,0x32, +0x33,0x35,0x39,0x35,0x39,0x5A,0x30,0x81,0x88,0x31,0x0B,0x30,0x09,0x06,0x03,0x55, +0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x08,0x13, +0x0A,0x4E,0x65,0x77,0x20,0x4A,0x65,0x72,0x73,0x65,0x79,0x31,0x14,0x30,0x12,0x06, +0x03,0x55,0x04,0x07,0x13,0x0B,0x4A,0x65,0x72,0x73,0x65,0x79,0x20,0x43,0x69,0x74, +0x79,0x31,0x1E,0x30,0x1C,0x06,0x03,0x55,0x04,0x0A,0x13,0x15,0x54,0x68,0x65,0x20, +0x55,0x53,0x45,0x52,0x54,0x52,0x55,0x53,0x54,0x20,0x4E,0x65,0x74,0x77,0x6F,0x72, +0x6B,0x31,0x2E,0x30,0x2C,0x06,0x03,0x55,0x04,0x03,0x13,0x25,0x55,0x53,0x45,0x52, +0x54,0x72,0x75,0x73,0x74,0x20,0x45,0x43,0x43,0x20,0x43,0x65,0x72,0x74,0x69,0x66, +0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74, +0x79,0x30,0x76,0x30,0x10,0x06,0x07,0x2A,0x86,0x48,0xCE,0x3D,0x02,0x01,0x06,0x05, +0x2B,0x81,0x04,0x00,0x22,0x03,0x62,0x00,0x04,0x1A,0xAC,0x54,0x5A,0xA9,0xF9,0x68, +0x23,0xE7,0x7A,0xD5,0x24,0x6F,0x53,0xC6,0x5A,0xD8,0x4B,0xAB,0xC6,0xD5,0xB6,0xD1, +0xE6,0x73,0x71,0xAE,0xDD,0x9C,0xD6,0x0C,0x61,0xFD,0xDB,0xA0,0x89,0x03,0xB8,0x05, +0x14,0xEC,0x57,0xCE,0xEE,0x5D,0x3F,0xE2,0x21,0xB3,0xCE,0xF7,0xD4,0x8A,0x79,0xE0, +0xA3,0x83,0x7E,0x2D,0x97,0xD0,0x61,0xC4,0xF1,0x99,0xDC,0x25,0x91,0x63,0xAB,0x7F, +0x30,0xA3,0xB4,0x70,0xE2,0xC7,0xA1,0x33,0x9C,0xF3,0xBF,0x2E,0x5C,0x53,0xB1,0x5F, +0xB3,0x7D,0x32,0x7F,0x8A,0x34,0xE3,0x79,0x79,0xA3,0x42,0x30,0x40,0x30,0x1D,0x06, +0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x3A,0xE1,0x09,0x86,0xD4,0xCF,0x19,0xC2, +0x96,0x76,0x74,0x49,0x76,0xDC,0xE0,0x35,0xC6,0x63,0x63,0x9A,0x30,0x0E,0x06,0x03, +0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x0F,0x06,0x03, +0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0A,0x06, +0x08,0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x03,0x03,0x68,0x00,0x30,0x65,0x02,0x30, +0x36,0x67,0xA1,0x16,0x08,0xDC,0xE4,0x97,0x00,0x41,0x1D,0x4E,0xBE,0xE1,0x63,0x01, +0xCF,0x3B,0xAA,0x42,0x11,0x64,0xA0,0x9D,0x94,0x39,0x02,0x11,0x79,0x5C,0x7B,0x1D, +0xFA,0x64,0xB9,0xEE,0x16,0x42,0xB3,0xBF,0x8A,0xC2,0x09,0xC4,0xEC,0xE4,0xB1,0x4D, +0x02,0x31,0x00,0xE9,0x2A,0x61,0x47,0x8C,0x52,0x4A,0x4B,0x4E,0x18,0x70,0xF6,0xD6, +0x44,0xD6,0x6E,0xF5,0x83,0xBA,0x6D,0x58,0xBD,0x24,0xD9,0x56,0x48,0xEA,0xEF,0xC4, +0xA2,0x46,0x81,0x88,0x6A,0x3A,0x46,0xD1,0xA9,0x9B,0x4D,0xC9,0x61,0xDA,0xD1,0x5D, +0x57,0x6A,0x18, +}; + +/* subject: Common Name: USERTrust RSA Certification Authority, Organization: The USERTRUST Network, Locality: Jersey City, State/Province: New Jersey, Country: US */ +/* issuer: Common Name: USERTrust RSA Certification Authority, Organization: The USERTRUST Network, Locality: Jersey City, State/Province: New Jersey, Country: US */ +/* link: https://crt.sh/?q=e793c9b02fd8aa13e21c31228accb08119643b749c898964b1746d46c3d4cbd2 */ +const unsigned char kCertificateWithFingerprint_e793c9b02fd8aa13e21c31228accb08119643b749c898964b1746d46c3d4cbd2_certificate[1506]={ +0x30,0x82,0x05,0xDE,0x30,0x82,0x03,0xC6,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x01, +0xFD,0x6D,0x30,0xFC,0xA3,0xCA,0x51,0xA8,0x1B,0xBC,0x64,0x0E,0x35,0x03,0x2D,0x30, +0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0C,0x05,0x00,0x30,0x81, +0x88,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x13, +0x30,0x11,0x06,0x03,0x55,0x04,0x08,0x13,0x0A,0x4E,0x65,0x77,0x20,0x4A,0x65,0x72, +0x73,0x65,0x79,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x07,0x13,0x0B,0x4A,0x65, +0x72,0x73,0x65,0x79,0x20,0x43,0x69,0x74,0x79,0x31,0x1E,0x30,0x1C,0x06,0x03,0x55, +0x04,0x0A,0x13,0x15,0x54,0x68,0x65,0x20,0x55,0x53,0x45,0x52,0x54,0x52,0x55,0x53, +0x54,0x20,0x4E,0x65,0x74,0x77,0x6F,0x72,0x6B,0x31,0x2E,0x30,0x2C,0x06,0x03,0x55, +0x04,0x03,0x13,0x25,0x55,0x53,0x45,0x52,0x54,0x72,0x75,0x73,0x74,0x20,0x52,0x53, +0x41,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20, +0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x30,0x1E,0x17,0x0D,0x31,0x30,0x30, +0x32,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x33,0x38,0x30,0x31, +0x31,0x38,0x32,0x33,0x35,0x39,0x35,0x39,0x5A,0x30,0x81,0x88,0x31,0x0B,0x30,0x09, +0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x13,0x30,0x11,0x06,0x03,0x55, +0x04,0x08,0x13,0x0A,0x4E,0x65,0x77,0x20,0x4A,0x65,0x72,0x73,0x65,0x79,0x31,0x14, +0x30,0x12,0x06,0x03,0x55,0x04,0x07,0x13,0x0B,0x4A,0x65,0x72,0x73,0x65,0x79,0x20, +0x43,0x69,0x74,0x79,0x31,0x1E,0x30,0x1C,0x06,0x03,0x55,0x04,0x0A,0x13,0x15,0x54, +0x68,0x65,0x20,0x55,0x53,0x45,0x52,0x54,0x52,0x55,0x53,0x54,0x20,0x4E,0x65,0x74, +0x77,0x6F,0x72,0x6B,0x31,0x2E,0x30,0x2C,0x06,0x03,0x55,0x04,0x03,0x13,0x25,0x55, +0x53,0x45,0x52,0x54,0x72,0x75,0x73,0x74,0x20,0x52,0x53,0x41,0x20,0x43,0x65,0x72, +0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F, +0x72,0x69,0x74,0x79,0x30,0x82,0x02,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86, +0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x02,0x0F,0x00,0x30,0x82,0x02,0x0A, +0x02,0x82,0x02,0x01,0x00,0x80,0x12,0x65,0x17,0x36,0x0E,0xC3,0xDB,0x08,0xB3,0xD0, +0xAC,0x57,0x0D,0x76,0xED,0xCD,0x27,0xD3,0x4C,0xAD,0x50,0x83,0x61,0xE2,0xAA,0x20, +0x4D,0x09,0x2D,0x64,0x09,0xDC,0xCE,0x89,0x9F,0xCC,0x3D,0xA9,0xEC,0xF6,0xCF,0xC1, +0xDC,0xF1,0xD3,0xB1,0xD6,0x7B,0x37,0x28,0x11,0x2B,0x47,0xDA,0x39,0xC6,0xBC,0x3A, +0x19,0xB4,0x5F,0xA6,0xBD,0x7D,0x9D,0xA3,0x63,0x42,0xB6,0x76,0xF2,0xA9,0x3B,0x2B, +0x91,0xF8,0xE2,0x6F,0xD0,0xEC,0x16,0x20,0x90,0x09,0x3E,0xE2,0xE8,0x74,0xC9,0x18, +0xB4,0x91,0xD4,0x62,0x64,0xDB,0x7F,0xA3,0x06,0xF1,0x88,0x18,0x6A,0x90,0x22,0x3C, +0xBC,0xFE,0x13,0xF0,0x87,0x14,0x7B,0xF6,0xE4,0x1F,0x8E,0xD4,0xE4,0x51,0xC6,0x11, +0x67,0x46,0x08,0x51,0xCB,0x86,0x14,0x54,0x3F,0xBC,0x33,0xFE,0x7E,0x6C,0x9C,0xFF, +0x16,0x9D,0x18,0xBD,0x51,0x8E,0x35,0xA6,0xA7,0x66,0xC8,0x72,0x67,0xDB,0x21,0x66, +0xB1,0xD4,0x9B,0x78,0x03,0xC0,0x50,0x3A,0xE8,0xCC,0xF0,0xDC,0xBC,0x9E,0x4C,0xFE, +0xAF,0x05,0x96,0x35,0x1F,0x57,0x5A,0xB7,0xFF,0xCE,0xF9,0x3D,0xB7,0x2C,0xB6,0xF6, +0x54,0xDD,0xC8,0xE7,0x12,0x3A,0x4D,0xAE,0x4C,0x8A,0xB7,0x5C,0x9A,0xB4,0xB7,0x20, +0x3D,0xCA,0x7F,0x22,0x34,0xAE,0x7E,0x3B,0x68,0x66,0x01,0x44,0xE7,0x01,0x4E,0x46, +0x53,0x9B,0x33,0x60,0xF7,0x94,0xBE,0x53,0x37,0x90,0x73,0x43,0xF3,0x32,0xC3,0x53, +0xEF,0xDB,0xAA,0xFE,0x74,0x4E,0x69,0xC7,0x6B,0x8C,0x60,0x93,0xDE,0xC4,0xC7,0x0C, +0xDF,0xE1,0x32,0xAE,0xCC,0x93,0x3B,0x51,0x78,0x95,0x67,0x8B,0xEE,0x3D,0x56,0xFE, +0x0C,0xD0,0x69,0x0F,0x1B,0x0F,0xF3,0x25,0x26,0x6B,0x33,0x6D,0xF7,0x6E,0x47,0xFA, +0x73,0x43,0xE5,0x7E,0x0E,0xA5,0x66,0xB1,0x29,0x7C,0x32,0x84,0x63,0x55,0x89,0xC4, +0x0D,0xC1,0x93,0x54,0x30,0x19,0x13,0xAC,0xD3,0x7D,0x37,0xA7,0xEB,0x5D,0x3A,0x6C, +0x35,0x5C,0xDB,0x41,0xD7,0x12,0xDA,0xA9,0x49,0x0B,0xDF,0xD8,0x80,0x8A,0x09,0x93, +0x62,0x8E,0xB5,0x66,0xCF,0x25,0x88,0xCD,0x84,0xB8,0xB1,0x3F,0xA4,0x39,0x0F,0xD9, +0x02,0x9E,0xEB,0x12,0x4C,0x95,0x7C,0xF3,0x6B,0x05,0xA9,0x5E,0x16,0x83,0xCC,0xB8, +0x67,0xE2,0xE8,0x13,0x9D,0xCC,0x5B,0x82,0xD3,0x4C,0xB3,0xED,0x5B,0xFF,0xDE,0xE5, +0x73,0xAC,0x23,0x3B,0x2D,0x00,0xBF,0x35,0x55,0x74,0x09,0x49,0xD8,0x49,0x58,0x1A, +0x7F,0x92,0x36,0xE6,0x51,0x92,0x0E,0xF3,0x26,0x7D,0x1C,0x4D,0x17,0xBC,0xC9,0xEC, +0x43,0x26,0xD0,0xBF,0x41,0x5F,0x40,0xA9,0x44,0x44,0xF4,0x99,0xE7,0x57,0x87,0x9E, +0x50,0x1F,0x57,0x54,0xA8,0x3E,0xFD,0x74,0x63,0x2F,0xB1,0x50,0x65,0x09,0xE6,0x58, +0x42,0x2E,0x43,0x1A,0x4C,0xB4,0xF0,0x25,0x47,0x59,0xFA,0x04,0x1E,0x93,0xD4,0x26, +0x46,0x4A,0x50,0x81,0xB2,0xDE,0xBE,0x78,0xB7,0xFC,0x67,0x15,0xE1,0xC9,0x57,0x84, +0x1E,0x0F,0x63,0xD6,0xE9,0x62,0xBA,0xD6,0x5F,0x55,0x2E,0xEA,0x5C,0xC6,0x28,0x08, +0x04,0x25,0x39,0xB8,0x0E,0x2B,0xA9,0xF2,0x4C,0x97,0x1C,0x07,0x3F,0x0D,0x52,0xF5, +0xED,0xEF,0x2F,0x82,0x0F,0x02,0x03,0x01,0x00,0x01,0xA3,0x42,0x30,0x40,0x30,0x1D, +0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x53,0x79,0xBF,0x5A,0xAA,0x2B,0x4A, +0xCF,0x54,0x80,0xE1,0xD8,0x9B,0xC0,0x9D,0xF2,0xB2,0x03,0x66,0xCB,0x30,0x0E,0x06, +0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x0F,0x06, +0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0D, +0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0C,0x05,0x00,0x03,0x82,0x02, +0x01,0x00,0x5C,0xD4,0x7C,0x0D,0xCF,0xF7,0x01,0x7D,0x41,0x99,0x65,0x0C,0x73,0xC5, +0x52,0x9F,0xCB,0xF8,0xCF,0x99,0x06,0x7F,0x1B,0xDA,0x43,0x15,0x9F,0x9E,0x02,0x55, +0x57,0x96,0x14,0xF1,0x52,0x3C,0x27,0x87,0x94,0x28,0xED,0x1F,0x3A,0x01,0x37,0xA2, +0x76,0xFC,0x53,0x50,0xC0,0x84,0x9B,0xC6,0x6B,0x4E,0xBA,0x8C,0x21,0x4F,0xA2,0x8E, +0x55,0x62,0x91,0xF3,0x69,0x15,0xD8,0xBC,0x88,0xE3,0xC4,0xAA,0x0B,0xFD,0xEF,0xA8, +0xE9,0x4B,0x55,0x2A,0x06,0x20,0x6D,0x55,0x78,0x29,0x19,0xEE,0x5F,0x30,0x5C,0x4B, +0x24,0x11,0x55,0xFF,0x24,0x9A,0x6E,0x5E,0x2A,0x2B,0xEE,0x0B,0x4D,0x9F,0x7F,0xF7, +0x01,0x38,0x94,0x14,0x95,0x43,0x07,0x09,0xFB,0x60,0xA9,0xEE,0x1C,0xAB,0x12,0x8C, +0xA0,0x9A,0x5E,0xA7,0x98,0x6A,0x59,0x6D,0x8B,0x3F,0x08,0xFB,0xC8,0xD1,0x45,0xAF, +0x18,0x15,0x64,0x90,0x12,0x0F,0x73,0x28,0x2E,0xC5,0xE2,0x24,0x4E,0xFC,0x58,0xEC, +0xF0,0xF4,0x45,0xFE,0x22,0xB3,0xEB,0x2F,0x8E,0xD2,0xD9,0x45,0x61,0x05,0xC1,0x97, +0x6F,0xA8,0x76,0x72,0x8F,0x8B,0x8C,0x36,0xAF,0xBF,0x0D,0x05,0xCE,0x71,0x8D,0xE6, +0xA6,0x6F,0x1F,0x6C,0xA6,0x71,0x62,0xC5,0xD8,0xD0,0x83,0x72,0x0C,0xF1,0x67,0x11, +0x89,0x0C,0x9C,0x13,0x4C,0x72,0x34,0xDF,0xBC,0xD5,0x71,0xDF,0xAA,0x71,0xDD,0xE1, +0xB9,0x6C,0x8C,0x3C,0x12,0x5D,0x65,0xDA,0xBD,0x57,0x12,0xB6,0x43,0x6B,0xFF,0xE5, +0xDE,0x4D,0x66,0x11,0x51,0xCF,0x99,0xAE,0xEC,0x17,0xB6,0xE8,0x71,0x91,0x8C,0xDE, +0x49,0xFE,0xDD,0x35,0x71,0xA2,0x15,0x27,0x94,0x1C,0xCF,0x61,0xE3,0x26,0xBB,0x6F, +0xA3,0x67,0x25,0x21,0x5D,0xE6,0xDD,0x1D,0x0B,0x2E,0x68,0x1B,0x3B,0x82,0xAF,0xEC, +0x83,0x67,0x85,0xD4,0x98,0x51,0x74,0xB1,0xB9,0x99,0x80,0x89,0xFF,0x7F,0x78,0x19, +0x5C,0x79,0x4A,0x60,0x2E,0x92,0x40,0xAE,0x4C,0x37,0x2A,0x2C,0xC9,0xC7,0x62,0xC8, +0x0E,0x5D,0xF7,0x36,0x5B,0xCA,0xE0,0x25,0x25,0x01,0xB4,0xDD,0x1A,0x07,0x9C,0x77, +0x00,0x3F,0xD0,0xDC,0xD5,0xEC,0x3D,0xD4,0xFA,0xBB,0x3F,0xCC,0x85,0xD6,0x6F,0x7F, +0xA9,0x2D,0xDF,0xB9,0x02,0xF7,0xF5,0x97,0x9A,0xB5,0x35,0xDA,0xC3,0x67,0xB0,0x87, +0x4A,0xA9,0x28,0x9E,0x23,0x8E,0xFF,0x5C,0x27,0x6B,0xE1,0xB0,0x4F,0xF3,0x07,0xEE, +0x00,0x2E,0xD4,0x59,0x87,0xCB,0x52,0x41,0x95,0xEA,0xF4,0x47,0xD7,0xEE,0x64,0x41, +0x55,0x7C,0x8D,0x59,0x02,0x95,0xDD,0x62,0x9D,0xC2,0xB9,0xEE,0x5A,0x28,0x74,0x84, +0xA5,0x9B,0xB7,0x90,0xC7,0x0C,0x07,0xDF,0xF5,0x89,0x36,0x74,0x32,0xD6,0x28,0xC1, +0xB0,0xB0,0x0B,0xE0,0x9C,0x4C,0xC3,0x1C,0xD6,0xFC,0xE3,0x69,0xB5,0x47,0x46,0x81, +0x2F,0xA2,0x82,0xAB,0xD3,0x63,0x44,0x70,0xC4,0x8D,0xFF,0x2D,0x33,0xBA,0xAD,0x8F, +0x7B,0xB5,0x70,0x88,0xAE,0x3E,0x19,0xCF,0x40,0x28,0xD8,0xFC,0xC8,0x90,0xBB,0x5D, +0x99,0x22,0xF5,0x52,0xE6,0x58,0xC5,0x1F,0x88,0x31,0x43,0xEE,0x88,0x1D,0xD7,0xC6, +0x8E,0x3C,0x43,0x6A,0x1D,0xA7,0x18,0xDE,0x7D,0x3D,0x16,0xF1,0x62,0xF9,0xCA,0x90, +0xA8,0xFD, +}; + +/* subject: Common Name: GTS Root R1, Organization: Google Trust Services LLC, Country: US */ +/* issuer: Common Name: GTS Root R1, Organization: Google Trust Services LLC, Country: US */ +/* link: https://crt.sh/?q=d947432abde7b7fa90fc2e6b59101b1280e0e1c7e4e40fa3c6887fff57a7f4cf */ +const unsigned char kCertificateWithFingerprint_d947432abde7b7fa90fc2e6b59101b1280e0e1c7e4e40fa3c6887fff57a7f4cf_certificate[1371]={ +0x30,0x82,0x05,0x57,0x30,0x82,0x03,0x3F,0xA0,0x03,0x02,0x01,0x02,0x02,0x0D,0x02, +0x03,0xE5,0x93,0x6F,0x31,0xB0,0x13,0x49,0x88,0x6B,0xA2,0x17,0x30,0x0D,0x06,0x09, +0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0C,0x05,0x00,0x30,0x47,0x31,0x0B,0x30, +0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x22,0x30,0x20,0x06,0x03, +0x55,0x04,0x0A,0x13,0x19,0x47,0x6F,0x6F,0x67,0x6C,0x65,0x20,0x54,0x72,0x75,0x73, +0x74,0x20,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73,0x20,0x4C,0x4C,0x43,0x31,0x14, +0x30,0x12,0x06,0x03,0x55,0x04,0x03,0x13,0x0B,0x47,0x54,0x53,0x20,0x52,0x6F,0x6F, +0x74,0x20,0x52,0x31,0x30,0x1E,0x17,0x0D,0x31,0x36,0x30,0x36,0x32,0x32,0x30,0x30, +0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x33,0x36,0x30,0x36,0x32,0x32,0x30,0x30,0x30, +0x30,0x30,0x30,0x5A,0x30,0x47,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13, +0x02,0x55,0x53,0x31,0x22,0x30,0x20,0x06,0x03,0x55,0x04,0x0A,0x13,0x19,0x47,0x6F, +0x6F,0x67,0x6C,0x65,0x20,0x54,0x72,0x75,0x73,0x74,0x20,0x53,0x65,0x72,0x76,0x69, +0x63,0x65,0x73,0x20,0x4C,0x4C,0x43,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x03, +0x13,0x0B,0x47,0x54,0x53,0x20,0x52,0x6F,0x6F,0x74,0x20,0x52,0x31,0x30,0x82,0x02, +0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00, +0x03,0x82,0x02,0x0F,0x00,0x30,0x82,0x02,0x0A,0x02,0x82,0x02,0x01,0x00,0xB6,0x11, +0x02,0x8B,0x1E,0xE3,0xA1,0x77,0x9B,0x3B,0xDC,0xBF,0x94,0x3E,0xB7,0x95,0xA7,0x40, +0x3C,0xA1,0xFD,0x82,0xF9,0x7D,0x32,0x06,0x82,0x71,0xF6,0xF6,0x8C,0x7F,0xFB,0xE8, +0xDB,0xBC,0x6A,0x2E,0x97,0x97,0xA3,0x8C,0x4B,0xF9,0x2B,0xF6,0xB1,0xF9,0xCE,0x84, +0x1D,0xB1,0xF9,0xC5,0x97,0xDE,0xEF,0xB9,0xF2,0xA3,0xE9,0xBC,0x12,0x89,0x5E,0xA7, +0xAA,0x52,0xAB,0xF8,0x23,0x27,0xCB,0xA4,0xB1,0x9C,0x63,0xDB,0xD7,0x99,0x7E,0xF0, +0x0A,0x5E,0xEB,0x68,0xA6,0xF4,0xC6,0x5A,0x47,0x0D,0x4D,0x10,0x33,0xE3,0x4E,0xB1, +0x13,0xA3,0xC8,0x18,0x6C,0x4B,0xEC,0xFC,0x09,0x90,0xDF,0x9D,0x64,0x29,0x25,0x23, +0x07,0xA1,0xB4,0xD2,0x3D,0x2E,0x60,0xE0,0xCF,0xD2,0x09,0x87,0xBB,0xCD,0x48,0xF0, +0x4D,0xC2,0xC2,0x7A,0x88,0x8A,0xBB,0xBA,0xCF,0x59,0x19,0xD6,0xAF,0x8F,0xB0,0x07, +0xB0,0x9E,0x31,0xF1,0x82,0xC1,0xC0,0xDF,0x2E,0xA6,0x6D,0x6C,0x19,0x0E,0xB5,0xD8, +0x7E,0x26,0x1A,0x45,0x03,0x3D,0xB0,0x79,0xA4,0x94,0x28,0xAD,0x0F,0x7F,0x26,0xE5, +0xA8,0x08,0xFE,0x96,0xE8,0x3C,0x68,0x94,0x53,0xEE,0x83,0x3A,0x88,0x2B,0x15,0x96, +0x09,0xB2,0xE0,0x7A,0x8C,0x2E,0x75,0xD6,0x9C,0xEB,0xA7,0x56,0x64,0x8F,0x96,0x4F, +0x68,0xAE,0x3D,0x97,0xC2,0x84,0x8F,0xC0,0xBC,0x40,0xC0,0x0B,0x5C,0xBD,0xF6,0x87, +0xB3,0x35,0x6C,0xAC,0x18,0x50,0x7F,0x84,0xE0,0x4C,0xCD,0x92,0xD3,0x20,0xE9,0x33, +0xBC,0x52,0x99,0xAF,0x32,0xB5,0x29,0xB3,0x25,0x2A,0xB4,0x48,0xF9,0x72,0xE1,0xCA, +0x64,0xF7,0xE6,0x82,0x10,0x8D,0xE8,0x9D,0xC2,0x8A,0x88,0xFA,0x38,0x66,0x8A,0xFC, +0x63,0xF9,0x01,0xF9,0x78,0xFD,0x7B,0x5C,0x77,0xFA,0x76,0x87,0xFA,0xEC,0xDF,0xB1, +0x0E,0x79,0x95,0x57,0xB4,0xBD,0x26,0xEF,0xD6,0x01,0xD1,0xEB,0x16,0x0A,0xBB,0x8E, +0x0B,0xB5,0xC5,0xC5,0x8A,0x55,0xAB,0xD3,0xAC,0xEA,0x91,0x4B,0x29,0xCC,0x19,0xA4, +0x32,0x25,0x4E,0x2A,0xF1,0x65,0x44,0xD0,0x02,0xCE,0xAA,0xCE,0x49,0xB4,0xEA,0x9F, +0x7C,0x83,0xB0,0x40,0x7B,0xE7,0x43,0xAB,0xA7,0x6C,0xA3,0x8F,0x7D,0x89,0x81,0xFA, +0x4C,0xA5,0xFF,0xD5,0x8E,0xC3,0xCE,0x4B,0xE0,0xB5,0xD8,0xB3,0x8E,0x45,0xCF,0x76, +0xC0,0xED,0x40,0x2B,0xFD,0x53,0x0F,0xB0,0xA7,0xD5,0x3B,0x0D,0xB1,0x8A,0xA2,0x03, +0xDE,0x31,0xAD,0xCC,0x77,0xEA,0x6F,0x7B,0x3E,0xD6,0xDF,0x91,0x22,0x12,0xE6,0xBE, +0xFA,0xD8,0x32,0xFC,0x10,0x63,0x14,0x51,0x72,0xDE,0x5D,0xD6,0x16,0x93,0xBD,0x29, +0x68,0x33,0xEF,0x3A,0x66,0xEC,0x07,0x8A,0x26,0xDF,0x13,0xD7,0x57,0x65,0x78,0x27, +0xDE,0x5E,0x49,0x14,0x00,0xA2,0x00,0x7F,0x9A,0xA8,0x21,0xB6,0xA9,0xB1,0x95,0xB0, +0xA5,0xB9,0x0D,0x16,0x11,0xDA,0xC7,0x6C,0x48,0x3C,0x40,0xE0,0x7E,0x0D,0x5A,0xCD, +0x56,0x3C,0xD1,0x97,0x05,0xB9,0xCB,0x4B,0xED,0x39,0x4B,0x9C,0xC4,0x3F,0xD2,0x55, +0x13,0x6E,0x24,0xB0,0xD6,0x71,0xFA,0xF4,0xC1,0xBA,0xCC,0xED,0x1B,0xF5,0xFE,0x81, +0x41,0xD8,0x00,0x98,0x3D,0x3A,0xC8,0xAE,0x7A,0x98,0x37,0x18,0x05,0x95,0x02,0x03, +0x01,0x00,0x01,0xA3,0x42,0x30,0x40,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01, +0xFF,0x04,0x04,0x03,0x02,0x01,0x86,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01, +0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04, +0x16,0x04,0x14,0xE4,0xAF,0x2B,0x26,0x71,0x1A,0x2B,0x48,0x27,0x85,0x2F,0x52,0x66, +0x2C,0xEF,0xF0,0x89,0x13,0x71,0x3E,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7, +0x0D,0x01,0x01,0x0C,0x05,0x00,0x03,0x82,0x02,0x01,0x00,0x9F,0xAA,0x42,0x26,0xDB, +0x0B,0x9B,0xBE,0xFF,0x1E,0x96,0x92,0x2E,0x3E,0xA2,0x65,0x4A,0x6A,0x98,0xBA,0x22, +0xCB,0x7D,0xC1,0x3A,0xD8,0x82,0x0A,0x06,0xC6,0xF6,0xA5,0xDE,0xC0,0x4E,0x87,0x66, +0x79,0xA1,0xF9,0xA6,0x58,0x9C,0xAA,0xF9,0xB5,0xE6,0x60,0xE7,0xE0,0xE8,0xB1,0x1E, +0x42,0x41,0x33,0x0B,0x37,0x3D,0xCE,0x89,0x70,0x15,0xCA,0xB5,0x24,0xA8,0xCF,0x6B, +0xB5,0xD2,0x40,0x21,0x98,0xCF,0x22,0x34,0xCF,0x3B,0xC5,0x22,0x84,0xE0,0xC5,0x0E, +0x8A,0x7C,0x5D,0x88,0xE4,0x35,0x24,0xCE,0x9B,0x3E,0x1A,0x54,0x1E,0x6E,0xDB,0xB2, +0x87,0xA7,0xFC,0xF3,0xFA,0x81,0x55,0x14,0x62,0x0A,0x59,0xA9,0x22,0x05,0x31,0x3E, +0x82,0xD6,0xEE,0xDB,0x57,0x34,0xBC,0x33,0x95,0xD3,0x17,0x1B,0xE8,0x27,0xA2,0x8B, +0x7B,0x4E,0x26,0x1A,0x7A,0x5A,0x64,0xB6,0xD1,0xAC,0x37,0xF1,0xFD,0xA0,0xF3,0x38, +0xEC,0x72,0xF0,0x11,0x75,0x9D,0xCB,0x34,0x52,0x8D,0xE6,0x76,0x6B,0x17,0xC6,0xDF, +0x86,0xAB,0x27,0x8E,0x49,0x2B,0x75,0x66,0x81,0x10,0x21,0xA6,0xEA,0x3E,0xF4,0xAE, +0x25,0xFF,0x7C,0x15,0xDE,0xCE,0x8C,0x25,0x3F,0xCA,0x62,0x70,0x0A,0xF7,0x2F,0x09, +0x66,0x07,0xC8,0x3F,0x1C,0xFC,0xF0,0xDB,0x45,0x30,0xDF,0x62,0x88,0xC1,0xB5,0x0F, +0x9D,0xC3,0x9F,0x4A,0xDE,0x59,0x59,0x47,0xC5,0x87,0x22,0x36,0xE6,0x82,0xA7,0xED, +0x0A,0xB9,0xE2,0x07,0xA0,0x8D,0x7B,0x7A,0x4A,0x3C,0x71,0xD2,0xE2,0x03,0xA1,0x1F, +0x32,0x07,0xDD,0x1B,0xE4,0x42,0xCE,0x0C,0x00,0x45,0x61,0x80,0xB5,0x0B,0x20,0x59, +0x29,0x78,0xBD,0xF9,0x55,0xCB,0x63,0xC5,0x3C,0x4C,0xF4,0xB6,0xFF,0xDB,0x6A,0x5F, +0x31,0x6B,0x99,0x9E,0x2C,0xC1,0x6B,0x50,0xA4,0xD7,0xE6,0x18,0x14,0xBD,0x85,0x3F, +0x67,0xAB,0x46,0x9F,0xA0,0xFF,0x42,0xA7,0x3A,0x7F,0x5C,0xCB,0x5D,0xB0,0x70,0x1D, +0x2B,0x34,0xF5,0xD4,0x76,0x09,0x0C,0xEB,0x78,0x4C,0x59,0x05,0xF3,0x33,0x42,0xC3, +0x61,0x15,0x10,0x1B,0x77,0x4D,0xCE,0x22,0x8C,0xD4,0x85,0xF2,0x45,0x7D,0xB7,0x53, +0xEA,0xEF,0x40,0x5A,0x94,0x0A,0x5C,0x20,0x5F,0x4E,0x40,0x5D,0x62,0x22,0x76,0xDF, +0xFF,0xCE,0x61,0xBD,0x8C,0x23,0x78,0xD2,0x37,0x02,0xE0,0x8E,0xDE,0xD1,0x11,0x37, +0x89,0xF6,0xBF,0xED,0x49,0x07,0x62,0xAE,0x92,0xEC,0x40,0x1A,0xAF,0x14,0x09,0xD9, +0xD0,0x4E,0xB2,0xA2,0xF7,0xBE,0xEE,0xEE,0xD8,0xFF,0xDC,0x1A,0x2D,0xDE,0xB8,0x36, +0x71,0xE2,0xFC,0x79,0xB7,0x94,0x25,0xD1,0x48,0x73,0x5B,0xA1,0x35,0xE7,0xB3,0x99, +0x67,0x75,0xC1,0x19,0x3A,0x2B,0x47,0x4E,0xD3,0x42,0x8E,0xFD,0x31,0xC8,0x16,0x66, +0xDA,0xD2,0x0C,0x3C,0xDB,0xB3,0x8E,0xC9,0xA1,0x0D,0x80,0x0F,0x7B,0x16,0x77,0x14, +0xBF,0xFF,0xDB,0x09,0x94,0xB2,0x93,0xBC,0x20,0x58,0x15,0xE9,0xDB,0x71,0x43,0xF3, +0xDE,0x10,0xC3,0x00,0xDC,0xA8,0x2A,0x95,0xB6,0xC2,0xD6,0x3F,0x90,0x6B,0x76,0xDB, +0x6C,0xFE,0x8C,0xBC,0xF2,0x70,0x35,0x0C,0xDC,0x99,0x19,0x35,0xDC,0xD7,0xC8,0x46, +0x63,0xD5,0x36,0x71,0xAE,0x57,0xFB,0xB7,0x82,0x6D,0xDC, +}; + +/* subject: Common Name: GTS Root R2, Organization: Google Trust Services LLC, Country: US */ +/* issuer: Common Name: GTS Root R2, Organization: Google Trust Services LLC, Country: US */ +/* link: https://crt.sh/?q=8d25cd97229dbf70356bda4eb3cc734031e24cf00fafcfd32dc76eb5841c7ea8 */ +const unsigned char kCertificateWithFingerprint_8d25cd97229dbf70356bda4eb3cc734031e24cf00fafcfd32dc76eb5841c7ea8_certificate[1371]={ +0x30,0x82,0x05,0x57,0x30,0x82,0x03,0x3F,0xA0,0x03,0x02,0x01,0x02,0x02,0x0D,0x02, +0x03,0xE5,0xAE,0xC5,0x8D,0x04,0x25,0x1A,0xAB,0x11,0x25,0xAA,0x30,0x0D,0x06,0x09, +0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0C,0x05,0x00,0x30,0x47,0x31,0x0B,0x30, +0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x22,0x30,0x20,0x06,0x03, +0x55,0x04,0x0A,0x13,0x19,0x47,0x6F,0x6F,0x67,0x6C,0x65,0x20,0x54,0x72,0x75,0x73, +0x74,0x20,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73,0x20,0x4C,0x4C,0x43,0x31,0x14, +0x30,0x12,0x06,0x03,0x55,0x04,0x03,0x13,0x0B,0x47,0x54,0x53,0x20,0x52,0x6F,0x6F, +0x74,0x20,0x52,0x32,0x30,0x1E,0x17,0x0D,0x31,0x36,0x30,0x36,0x32,0x32,0x30,0x30, +0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x33,0x36,0x30,0x36,0x32,0x32,0x30,0x30,0x30, +0x30,0x30,0x30,0x5A,0x30,0x47,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13, +0x02,0x55,0x53,0x31,0x22,0x30,0x20,0x06,0x03,0x55,0x04,0x0A,0x13,0x19,0x47,0x6F, +0x6F,0x67,0x6C,0x65,0x20,0x54,0x72,0x75,0x73,0x74,0x20,0x53,0x65,0x72,0x76,0x69, +0x63,0x65,0x73,0x20,0x4C,0x4C,0x43,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x03, +0x13,0x0B,0x47,0x54,0x53,0x20,0x52,0x6F,0x6F,0x74,0x20,0x52,0x32,0x30,0x82,0x02, +0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00, +0x03,0x82,0x02,0x0F,0x00,0x30,0x82,0x02,0x0A,0x02,0x82,0x02,0x01,0x00,0xCE,0xDE, +0xFD,0xA6,0xFB,0xEC,0xEC,0x14,0x34,0x3C,0x07,0x06,0x5A,0x6C,0x59,0xF7,0x19,0x35, +0xDD,0xF7,0xC1,0x9D,0x55,0xAA,0xD3,0xCD,0x3B,0xA4,0x93,0x72,0xEF,0x0A,0xFA,0x6D, +0x9D,0xF6,0xF0,0x85,0x80,0x5B,0xA1,0x48,0x52,0x9F,0x39,0xC5,0xB7,0xEE,0x28,0xAC, +0xEF,0xCB,0x76,0x68,0x14,0xB9,0xDF,0xAD,0x01,0x6C,0x99,0x1F,0xC4,0x22,0x1D,0x9F, +0xFE,0x72,0x77,0xE0,0x2C,0x5B,0xAF,0xE4,0x04,0xBF,0x4F,0x72,0xA0,0x1A,0x34,0x98, +0xE8,0x39,0x68,0xEC,0x95,0x25,0x7B,0x76,0xA1,0xE6,0x69,0xB9,0x85,0x19,0xBD,0x89, +0x8C,0xFE,0xAD,0xED,0x36,0xEA,0x73,0xBC,0xFF,0x83,0xE2,0xCB,0x7D,0xC1,0xD2,0xCE, +0x4A,0xB3,0x8D,0x05,0x9E,0x8B,0x49,0x93,0xDF,0xC1,0x5B,0xD0,0x6E,0x5E,0xF0,0x2E, +0x30,0x2E,0x82,0xFC,0xFA,0xBC,0xB4,0x17,0x0A,0x48,0xE5,0x88,0x9B,0xC5,0x9B,0x6B, +0xDE,0xB0,0xCA,0xB4,0x03,0xF0,0xDA,0xF4,0x90,0xB8,0x65,0x64,0xF7,0x5C,0x4C,0xAD, +0xE8,0x7E,0x66,0x5E,0x99,0xD7,0xB8,0xC2,0x3E,0xC8,0xD0,0x13,0x9D,0xAD,0xEE,0xE4, +0x45,0x7B,0x89,0x55,0xF7,0x8A,0x1F,0x62,0x52,0x84,0x12,0xB3,0xC2,0x40,0x97,0xE3, +0x8A,0x1F,0x47,0x91,0xA6,0x74,0x5A,0xD2,0xF8,0xB1,0x63,0x28,0x10,0xB8,0xB3,0x09, +0xB8,0x56,0x77,0x40,0xA2,0x26,0x98,0x79,0xC6,0xFE,0xDF,0x25,0xEE,0x3E,0xE5,0xA0, +0x7F,0xD4,0x61,0x0F,0x51,0x4B,0x3C,0x3F,0x8C,0xDA,0xE1,0x70,0x74,0xD8,0xC2,0x68, +0xA1,0xF9,0xC1,0x0C,0xE9,0xA1,0xE2,0x7F,0xBB,0x55,0x3C,0x76,0x06,0xEE,0x6A,0x4E, +0xCC,0x92,0x88,0x30,0x4D,0x9A,0xBD,0x4F,0x0B,0x48,0x9A,0x84,0xB5,0x98,0xA3,0xD5, +0xFB,0x73,0xC1,0x57,0x61,0xDD,0x28,0x56,0x75,0x13,0xAE,0x87,0x8E,0xE7,0x0C,0x51, +0x09,0x10,0x75,0x88,0x4C,0xBC,0x8D,0xF9,0x7B,0x3C,0xD4,0x22,0x48,0x1F,0x2A,0xDC, +0xEB,0x6B,0xBB,0x44,0xB1,0xCB,0x33,0x71,0x32,0x46,0xAF,0xAD,0x4A,0xF1,0x8C,0xE8, +0x74,0x3A,0xAC,0xE7,0x1A,0x22,0x73,0x80,0xD2,0x30,0xF7,0x25,0x42,0xC7,0x22,0x3B, +0x3B,0x12,0xAD,0x96,0x2E,0xC6,0xC3,0x76,0x07,0xAA,0x20,0xB7,0x35,0x49,0x57,0xE9, +0x92,0x49,0xE8,0x76,0x16,0x72,0x31,0x67,0x2B,0x96,0x7E,0x8A,0xA3,0xC7,0x94,0x56, +0x22,0xBF,0x6A,0x4B,0x7E,0x01,0x21,0xB2,0x23,0x32,0xDF,0xE4,0x9A,0x44,0x6D,0x59, +0x5B,0x5D,0xF5,0x00,0xA0,0x1C,0x9B,0xC6,0x78,0x97,0x8D,0x90,0xFF,0x9B,0xC8,0xAA, +0xB4,0xAF,0x11,0x51,0x39,0x5E,0xD9,0xFB,0x67,0xAD,0xD5,0x5B,0x11,0x9D,0x32,0x9A, +0x1B,0xBD,0xD5,0xBA,0x5B,0xA5,0xC9,0xCB,0x25,0x69,0x53,0x55,0x27,0x5C,0xE0,0xCA, +0x36,0xCB,0x88,0x61,0xFB,0x1E,0xB7,0xD0,0xCB,0xEE,0x16,0xFB,0xD3,0xA6,0x4C,0xDE, +0x92,0xA5,0xD4,0xE2,0xDF,0xF5,0x06,0x54,0xDE,0x2E,0x9D,0x4B,0xB4,0x93,0x30,0xAA, +0x81,0xCE,0xDD,0x1A,0xDC,0x51,0x73,0x0D,0x4F,0x70,0xE9,0xE5,0xB6,0x16,0x21,0x19, +0x79,0xB2,0xE6,0x89,0x0B,0x75,0x64,0xCA,0xD5,0xAB,0xBC,0x09,0xC1,0x18,0xA1,0xFF, +0xD4,0x54,0xA1,0x85,0x3C,0xFD,0x14,0x24,0x03,0xB2,0x87,0xD3,0xA4,0xB7,0x02,0x03, +0x01,0x00,0x01,0xA3,0x42,0x30,0x40,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01, +0xFF,0x04,0x04,0x03,0x02,0x01,0x86,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01, +0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04, +0x16,0x04,0x14,0xBB,0xFF,0xCA,0x8E,0x23,0x9F,0x4F,0x99,0xCA,0xDB,0xE2,0x68,0xA6, +0xA5,0x15,0x27,0x17,0x1E,0xD9,0x0E,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7, +0x0D,0x01,0x01,0x0C,0x05,0x00,0x03,0x82,0x02,0x01,0x00,0x1F,0xCA,0xCE,0xDD,0xC7, +0xBE,0xA1,0x9F,0xD9,0x27,0x4C,0x0B,0xDC,0x17,0x98,0x11,0x6A,0x88,0xDE,0x3D,0xE6, +0x71,0x56,0x72,0xB2,0x9E,0x1A,0x4E,0x9C,0xD5,0x2B,0x98,0x24,0x5D,0x9B,0x6B,0x7B, +0xB0,0x33,0x82,0x09,0xBD,0xDF,0x25,0x46,0xEA,0x98,0x9E,0xB6,0x1B,0xFE,0x83,0x3C, +0xD2,0x62,0x61,0xC1,0x04,0xED,0xCE,0xE0,0xC5,0xC9,0xC8,0x13,0x13,0x55,0xE7,0xA8, +0x63,0xAD,0x8C,0x7B,0x01,0xFE,0x77,0x30,0xE1,0xCE,0x68,0x9B,0x05,0xF8,0x12,0xEE, +0x79,0x31,0xA0,0x41,0x45,0x35,0x28,0x0A,0x71,0xA4,0x24,0x4F,0x8C,0xDC,0x3C,0x82, +0x07,0x5F,0x66,0xDC,0x7D,0x10,0xFE,0x0C,0x61,0xB3,0x05,0x95,0xEE,0xE1,0xAE,0x81, +0x0F,0xA8,0xF8,0xC7,0x8F,0x4D,0xA8,0x23,0x02,0x26,0x6B,0x1D,0x83,0x52,0x55,0xCE, +0xB5,0x2F,0x00,0xCA,0x80,0x40,0xE0,0xE1,0x74,0xAC,0x60,0xF5,0x87,0x80,0x9D,0xAE, +0x36,0x64,0x91,0x5D,0xB0,0x68,0x18,0xEA,0x8A,0x61,0xC9,0x77,0xA8,0x97,0xC4,0xC9, +0xC7,0xA5,0xFC,0x55,0x4B,0xF3,0xF0,0x7F,0xB9,0x65,0x3D,0x27,0x68,0xD0,0xCC,0x6B, +0xFA,0x53,0x9D,0xE1,0x91,0x1A,0xC9,0x5D,0x1A,0x96,0x6D,0x32,0x87,0xED,0x03,0x20, +0xC8,0x02,0xCE,0x5A,0xBE,0xD9,0xEA,0xFD,0xB2,0x4D,0xC4,0x2F,0x1B,0xDF,0x5F,0x7A, +0xF5,0xF8,0x8B,0xC6,0xEE,0x31,0x3A,0x25,0x51,0x55,0x67,0x8D,0x64,0x32,0x7B,0xE9, +0x9E,0xC3,0x82,0xBA,0x2A,0x2D,0xE9,0x1E,0xB4,0xE0,0x48,0x06,0xA2,0xFC,0x67,0xAF, +0x1F,0x22,0x02,0x73,0xFB,0x20,0x0A,0xAF,0x9D,0x54,0x4B,0xA1,0xCD,0xFF,0x60,0x47, +0xB0,0x3F,0x5D,0xEF,0x1B,0x56,0xBD,0x97,0x21,0x96,0x2D,0x0A,0xD1,0x5E,0x9D,0x38, +0x02,0x47,0x6C,0xB9,0xF4,0xF6,0x23,0x25,0xB8,0xA0,0x6A,0x9A,0x2B,0x77,0x08,0xFA, +0xC4,0xB1,0x28,0x90,0x26,0x58,0x08,0x3C,0xE2,0x7E,0xAA,0xD7,0x3D,0x6F,0xBA,0x31, +0x88,0x0A,0x05,0xEB,0x27,0xB5,0xA1,0x49,0xEE,0xA0,0x45,0x54,0x7B,0xE6,0x27,0x65, +0x99,0x20,0x21,0xA8,0xA3,0xBC,0xFB,0x18,0x96,0xBB,0x52,0x6F,0x0C,0xED,0x83,0x51, +0x4C,0xE9,0x59,0xE2,0x20,0x60,0xC5,0xC2,0x65,0x92,0x82,0x8C,0xF3,0x10,0x1F,0x0E, +0x8A,0x97,0xBE,0x77,0x82,0x6D,0x3F,0x8F,0x1D,0x5D,0xBC,0x49,0x27,0xBD,0xCC,0x4F, +0x0F,0xE1,0xCE,0x76,0x86,0x04,0x23,0xC5,0xC0,0x8C,0x12,0x5B,0xFD,0xDB,0x84,0xA0, +0x24,0xF1,0x48,0xFF,0x64,0x7C,0xD0,0xBE,0x5C,0x16,0xD1,0xEF,0x99,0xAD,0xC0,0x1F, +0xFB,0xCB,0xAE,0xBC,0x38,0x22,0x06,0x26,0x64,0xDA,0xDA,0x97,0x0E,0x3F,0x28,0x15, +0x44,0xA8,0x4F,0x00,0xCA,0xF0,0x9A,0xCC,0xCF,0x74,0x6A,0xB4,0x3E,0x3C,0xEB,0x95, +0xEC,0xB5,0xD3,0x5A,0xD8,0x81,0x99,0xE9,0x43,0x18,0x37,0xEB,0xB3,0xBB,0xD1,0x58, +0x62,0x41,0xF3,0x66,0xD2,0x8F,0xAA,0x78,0x95,0x54,0x20,0xC3,0x5A,0x2E,0x74,0x2B, +0xD5,0xD1,0xBE,0x18,0x69,0xC0,0xAC,0xD5,0xA4,0xCF,0x39,0xBA,0x51,0x84,0x03,0x65, +0xE9,0x62,0xC0,0x62,0xFE,0xD8,0x4D,0x55,0x96,0xE2,0xD0,0x11,0xFA,0x48,0x34,0x11, +0xEC,0x9E,0xED,0x05,0x1D,0xE4,0xC8,0xD6,0x1D,0x86,0xCB, +}; + +/* subject: Common Name: GTS Root R3, Organization: Google Trust Services LLC, Country: US */ +/* issuer: Common Name: GTS Root R3, Organization: Google Trust Services LLC, Country: US */ +/* link: https://crt.sh/?q=34d8a73ee208d9bcdb0d956520934b4e40e69482596e8b6f73c8426b010a6f48 */ +const unsigned char kCertificateWithFingerprint_34d8a73ee208d9bcdb0d956520934b4e40e69482596e8b6f73c8426b010a6f48_certificate[525]={ +0x30,0x82,0x02,0x09,0x30,0x82,0x01,0x8E,0xA0,0x03,0x02,0x01,0x02,0x02,0x0D,0x02, +0x03,0xE5,0xB8,0x82,0xEB,0x20,0xF8,0x25,0x27,0x6D,0x3D,0x66,0x30,0x0A,0x06,0x08, +0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x03,0x30,0x47,0x31,0x0B,0x30,0x09,0x06,0x03, +0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x22,0x30,0x20,0x06,0x03,0x55,0x04,0x0A, +0x13,0x19,0x47,0x6F,0x6F,0x67,0x6C,0x65,0x20,0x54,0x72,0x75,0x73,0x74,0x20,0x53, +0x65,0x72,0x76,0x69,0x63,0x65,0x73,0x20,0x4C,0x4C,0x43,0x31,0x14,0x30,0x12,0x06, +0x03,0x55,0x04,0x03,0x13,0x0B,0x47,0x54,0x53,0x20,0x52,0x6F,0x6F,0x74,0x20,0x52, +0x33,0x30,0x1E,0x17,0x0D,0x31,0x36,0x30,0x36,0x32,0x32,0x30,0x30,0x30,0x30,0x30, +0x30,0x5A,0x17,0x0D,0x33,0x36,0x30,0x36,0x32,0x32,0x30,0x30,0x30,0x30,0x30,0x30, +0x5A,0x30,0x47,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53, +0x31,0x22,0x30,0x20,0x06,0x03,0x55,0x04,0x0A,0x13,0x19,0x47,0x6F,0x6F,0x67,0x6C, +0x65,0x20,0x54,0x72,0x75,0x73,0x74,0x20,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73, +0x20,0x4C,0x4C,0x43,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x03,0x13,0x0B,0x47, +0x54,0x53,0x20,0x52,0x6F,0x6F,0x74,0x20,0x52,0x33,0x30,0x76,0x30,0x10,0x06,0x07, +0x2A,0x86,0x48,0xCE,0x3D,0x02,0x01,0x06,0x05,0x2B,0x81,0x04,0x00,0x22,0x03,0x62, +0x00,0x04,0x1F,0x4F,0x33,0x87,0x33,0x29,0x8A,0xA1,0x84,0xDE,0xCB,0xC7,0x21,0x58, +0x41,0x89,0xEA,0x56,0x9D,0x2B,0x4B,0x85,0xC6,0x1D,0x4C,0x27,0xBC,0x7F,0x26,0x51, +0x72,0x6F,0xE2,0x9F,0xD6,0xA3,0xCA,0xCC,0x45,0x14,0x46,0x8B,0xAD,0xEF,0x7E,0x86, +0x8C,0xEC,0xB1,0x7E,0x2F,0xFF,0xA9,0x71,0x9D,0x18,0x84,0x45,0x04,0x41,0x55,0x6E, +0x2B,0xEA,0x26,0x7F,0xBB,0x90,0x01,0xE3,0x4B,0x19,0xBA,0xE4,0x54,0x96,0x45,0x09, +0xB1,0xD5,0x6C,0x91,0x44,0xAD,0x84,0x13,0x8E,0x9A,0x8C,0x0D,0x80,0x0C,0x32,0xF6, +0xE0,0x27,0xA3,0x42,0x30,0x40,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF, +0x04,0x04,0x03,0x02,0x01,0x86,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF, +0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16, +0x04,0x14,0xC1,0xF1,0x26,0xBA,0xA0,0x2D,0xAE,0x85,0x81,0xCF,0xD3,0xF1,0x2A,0x12, +0xBD,0xB8,0x0A,0x67,0xFD,0xBC,0x30,0x0A,0x06,0x08,0x2A,0x86,0x48,0xCE,0x3D,0x04, +0x03,0x03,0x03,0x69,0x00,0x30,0x66,0x02,0x31,0x00,0xF6,0xE1,0x20,0x95,0x14,0x7B, +0x54,0xA3,0x90,0x16,0x11,0xBF,0x84,0xC8,0xEA,0x6F,0x6B,0x17,0x9E,0x1E,0x46,0x98, +0x20,0x9B,0x9F,0xD3,0x0D,0xD9,0xAC,0xD3,0x2F,0xCD,0x7C,0xF8,0x5B,0x2E,0x55,0xBB, +0xBF,0xDD,0x92,0xF7,0xA4,0x0C,0xDC,0x31,0xE1,0xA2,0x02,0x31,0x00,0xFC,0x97,0x66, +0x66,0xE5,0x43,0x16,0x13,0x83,0xDD,0xC7,0xDF,0x2F,0xBE,0x14,0x38,0xED,0x01,0xCE, +0xB1,0x17,0x1A,0x11,0x75,0xE9,0xBD,0x03,0x8F,0x26,0x7E,0x84,0xE5,0xC9,0x60,0xA6, +0x95,0xD7,0x54,0x59,0xB7,0xE7,0x11,0x2C,0x89,0xD4,0xB9,0xEE,0x17, +}; + +/* subject: Common Name: GTS Root R4, Organization: Google Trust Services LLC, Country: US */ +/* issuer: Common Name: GTS Root R4, Organization: Google Trust Services LLC, Country: US */ +/* link: https://crt.sh/?q=349dfa4058c5e263123b398ae795573c4e1313c83fe68f93556cd5e8031b3c7d */ +const unsigned char kCertificateWithFingerprint_349dfa4058c5e263123b398ae795573c4e1313c83fe68f93556cd5e8031b3c7d_certificate[525]={ +0x30,0x82,0x02,0x09,0x30,0x82,0x01,0x8E,0xA0,0x03,0x02,0x01,0x02,0x02,0x0D,0x02, +0x03,0xE5,0xC0,0x68,0xEF,0x63,0x1A,0x9C,0x72,0x90,0x50,0x52,0x30,0x0A,0x06,0x08, +0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x03,0x30,0x47,0x31,0x0B,0x30,0x09,0x06,0x03, +0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x22,0x30,0x20,0x06,0x03,0x55,0x04,0x0A, +0x13,0x19,0x47,0x6F,0x6F,0x67,0x6C,0x65,0x20,0x54,0x72,0x75,0x73,0x74,0x20,0x53, +0x65,0x72,0x76,0x69,0x63,0x65,0x73,0x20,0x4C,0x4C,0x43,0x31,0x14,0x30,0x12,0x06, +0x03,0x55,0x04,0x03,0x13,0x0B,0x47,0x54,0x53,0x20,0x52,0x6F,0x6F,0x74,0x20,0x52, +0x34,0x30,0x1E,0x17,0x0D,0x31,0x36,0x30,0x36,0x32,0x32,0x30,0x30,0x30,0x30,0x30, +0x30,0x5A,0x17,0x0D,0x33,0x36,0x30,0x36,0x32,0x32,0x30,0x30,0x30,0x30,0x30,0x30, +0x5A,0x30,0x47,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53, +0x31,0x22,0x30,0x20,0x06,0x03,0x55,0x04,0x0A,0x13,0x19,0x47,0x6F,0x6F,0x67,0x6C, +0x65,0x20,0x54,0x72,0x75,0x73,0x74,0x20,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73, +0x20,0x4C,0x4C,0x43,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x03,0x13,0x0B,0x47, +0x54,0x53,0x20,0x52,0x6F,0x6F,0x74,0x20,0x52,0x34,0x30,0x76,0x30,0x10,0x06,0x07, +0x2A,0x86,0x48,0xCE,0x3D,0x02,0x01,0x06,0x05,0x2B,0x81,0x04,0x00,0x22,0x03,0x62, +0x00,0x04,0xF3,0x74,0x73,0xA7,0x68,0x8B,0x60,0xAE,0x43,0xB8,0x35,0xC5,0x81,0x30, +0x7B,0x4B,0x49,0x9D,0xFB,0xC1,0x61,0xCE,0xE6,0xDE,0x46,0xBD,0x6B,0xD5,0x61,0x18, +0x35,0xAE,0x40,0xDD,0x73,0xF7,0x89,0x91,0x30,0x5A,0xEB,0x3C,0xEE,0x85,0x7C,0xA2, +0x40,0x76,0x3B,0xA9,0xC6,0xB8,0x47,0xD8,0x2A,0xE7,0x92,0x91,0x6A,0x73,0xE9,0xB1, +0x72,0x39,0x9F,0x29,0x9F,0xA2,0x98,0xD3,0x5F,0x5E,0x58,0x86,0x65,0x0F,0xA1,0x84, +0x65,0x06,0xD1,0xDC,0x8B,0xC9,0xC7,0x73,0xC8,0x8C,0x6A,0x2F,0xE5,0xC4,0xAB,0xD1, +0x1D,0x8A,0xA3,0x42,0x30,0x40,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF, +0x04,0x04,0x03,0x02,0x01,0x86,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF, +0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16, +0x04,0x14,0x80,0x4C,0xD6,0xEB,0x74,0xFF,0x49,0x36,0xA3,0xD5,0xD8,0xFC,0xB5,0x3E, +0xC5,0x6A,0xF0,0x94,0x1D,0x8C,0x30,0x0A,0x06,0x08,0x2A,0x86,0x48,0xCE,0x3D,0x04, +0x03,0x03,0x03,0x69,0x00,0x30,0x66,0x02,0x31,0x00,0xE8,0x40,0xFF,0x83,0xDE,0x03, +0xF4,0x9F,0xAE,0x1D,0x7A,0xA7,0x2E,0xB9,0xAF,0x4F,0xF6,0x83,0x1D,0x0E,0x2D,0x85, +0x01,0x1D,0xD1,0xD9,0x6A,0xEC,0x0F,0xC2,0xAF,0xC7,0x5E,0x56,0x5E,0x5C,0xD5,0x1C, +0x58,0x22,0x28,0x0B,0xF7,0x30,0xB6,0x2F,0xB1,0x7C,0x02,0x31,0x00,0xF0,0x61,0x3C, +0xA7,0xF4,0xA0,0x82,0xE3,0x21,0xD5,0x84,0x1D,0x73,0x86,0x9C,0x2D,0xAF,0xCA,0x34, +0x9B,0xF1,0x9F,0xB9,0x23,0x36,0xE2,0xBC,0x60,0x03,0x9D,0x80,0xB3,0x9A,0x56,0xC8, +0xE1,0xE2,0xBB,0x14,0x79,0xCA,0xCD,0x21,0xD4,0x94,0xB5,0x49,0x43, +}; + +/* subject: Common Name: GlobalSign, Organization: GlobalSign, Organizational Unit: GlobalSign ECC Root CA - R4 */ +/* issuer: Common Name: GlobalSign, Organization: GlobalSign, Organizational Unit: GlobalSign ECC Root CA - R4 */ +/* link: https://crt.sh/?q=b085d70b964f191a73e4af0d54ae7a0e07aafdaf9b71dd0862138ab7325a24a2 */ +const unsigned char kCertificateWithFingerprint_b085d70b964f191a73e4af0d54ae7a0e07aafdaf9b71dd0862138ab7325a24a2_certificate[480]={ +0x30,0x82,0x01,0xDC,0x30,0x82,0x01,0x83,0xA0,0x03,0x02,0x01,0x02,0x02,0x0D,0x02, +0x03,0xE5,0x7E,0xF5,0x3F,0x93,0xFD,0xA5,0x09,0x21,0xB2,0xA6,0x30,0x0A,0x06,0x08, +0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x02,0x30,0x50,0x31,0x24,0x30,0x22,0x06,0x03, +0x55,0x04,0x0B,0x13,0x1B,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x53,0x69,0x67,0x6E,0x20, +0x45,0x43,0x43,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x41,0x20,0x2D,0x20,0x52,0x34, +0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0A,0x13,0x0A,0x47,0x6C,0x6F,0x62,0x61, +0x6C,0x53,0x69,0x67,0x6E,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0A, +0x47,0x6C,0x6F,0x62,0x61,0x6C,0x53,0x69,0x67,0x6E,0x30,0x1E,0x17,0x0D,0x31,0x32, +0x31,0x31,0x31,0x33,0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x33,0x38,0x30, +0x31,0x31,0x39,0x30,0x33,0x31,0x34,0x30,0x37,0x5A,0x30,0x50,0x31,0x24,0x30,0x22, +0x06,0x03,0x55,0x04,0x0B,0x13,0x1B,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x53,0x69,0x67, +0x6E,0x20,0x45,0x43,0x43,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x41,0x20,0x2D,0x20, +0x52,0x34,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0A,0x13,0x0A,0x47,0x6C,0x6F, +0x62,0x61,0x6C,0x53,0x69,0x67,0x6E,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03, +0x13,0x0A,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x53,0x69,0x67,0x6E,0x30,0x59,0x30,0x13, +0x06,0x07,0x2A,0x86,0x48,0xCE,0x3D,0x02,0x01,0x06,0x08,0x2A,0x86,0x48,0xCE,0x3D, +0x03,0x01,0x07,0x03,0x42,0x00,0x04,0xB8,0xC6,0x79,0xD3,0x8F,0x6C,0x25,0x0E,0x9F, +0x2E,0x39,0x19,0x1C,0x03,0xA4,0xAE,0x9A,0xE5,0x39,0x07,0x09,0x16,0xCA,0x63,0xB1, +0xB9,0x86,0xF8,0x8A,0x57,0xC1,0x57,0xCE,0x42,0xFA,0x73,0xA1,0xF7,0x65,0x42,0xFF, +0x1E,0xC1,0x00,0xB2,0x6E,0x73,0x0E,0xFF,0xC7,0x21,0xE5,0x18,0xA4,0xAA,0xD9,0x71, +0x3F,0xA8,0xD4,0xB9,0xCE,0x8C,0x1D,0xA3,0x42,0x30,0x40,0x30,0x0E,0x06,0x03,0x55, +0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x86,0x30,0x0F,0x06,0x03,0x55, +0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x1D,0x06,0x03, +0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x54,0xB0,0x7B,0xAD,0x45,0xB8,0xE2,0x40,0x7F, +0xFB,0x0A,0x6E,0xFB,0xBE,0x33,0xC9,0x3C,0xA3,0x84,0xD5,0x30,0x0A,0x06,0x08,0x2A, +0x86,0x48,0xCE,0x3D,0x04,0x03,0x02,0x03,0x47,0x00,0x30,0x44,0x02,0x20,0x22,0x4F, +0x74,0x72,0xB9,0x60,0xAF,0xF1,0xE6,0x9C,0xA0,0x16,0x05,0x50,0x5F,0xC3,0x5E,0x3B, +0x6E,0x61,0x74,0xEF,0xBE,0x01,0xC4,0xBE,0x18,0x48,0x59,0x61,0x82,0x32,0x02,0x20, +0x26,0x9D,0x54,0x63,0x40,0xDE,0x37,0x60,0x50,0xCF,0xC8,0xD8,0xED,0x9D,0x82,0xAE, +0x37,0x98,0xBC,0xA3,0x8F,0x4C,0x4C,0xA9,0x34,0x2B,0x6C,0xEF,0xFB,0x95,0x9B,0x26, +}; + +const unsigned char* const kSSLCertCertificateList[36]={ +kCertificateWithFingerprint_16af57a9f676b0ab126095aa5ebadef22ab31119d644ac95cd4b93dbf3f26aeb_certificate, +kCertificateWithFingerprint_3e9099b5015e8f486c00bcea9d111ee721faba355a89bcf1df69561e3dc6325c_certificate, +kCertificateWithFingerprint_7d05ebb682339f8c9451ee094eebfefa7953a114edb2f44949452fab7d2fc185_certificate, +kCertificateWithFingerprint_7e37cb8b4c47090cab36551ba6f45db840680fba166a952db100717f43053fc2_certificate, +kCertificateWithFingerprint_4348a0e9444c78cb265e058d5e8944b4d84f9662bd26db257f8934a443c70161_certificate, +kCertificateWithFingerprint_cb3ccbb76031e5e0138f8dd39a23f9de47ffc35e43c1144cea27d46a5ab1cb5f_certificate, +kCertificateWithFingerprint_31ad6648f8104138c738f39ea4320133393e3a18cc02296ef97c2ac9ef6731d0_certificate, +kCertificateWithFingerprint_7431e5f4c3c1ce4690774f0b61e05440883ba9a01ed00ba6abd7806ed3b118cf_certificate, +kCertificateWithFingerprint_552f7bdcf1a7af9e6ce672017f4f12abf77240c78e761ac203d1d9d20ac89988_certificate, +kCertificateWithFingerprint_73c176434f1bc6d5adf45b0e76e727287c8de57616c1e6e6141a2b2cbc7d8e4c_certificate, +kCertificateWithFingerprint_02ed0eb28c14da45165c566791700d6451d7fb56f0b2ab1d3b8eb070e56edff5_certificate, +kCertificateWithFingerprint_43df5774b03e7fef5fe40d931a7bedf1bb2e6b42738c4e6d3841103d3aa7f339_certificate, +kCertificateWithFingerprint_6dc47172e01cbcb0bf62580d895fe2b8ac9ad4f873801e0c10b9c837d21eb177_certificate, +kCertificateWithFingerprint_0376ab1d54c5f9803ce4b2e201a0ee7eef7b57b636e8a93c9b8d4860c96f5fa7_certificate, +kCertificateWithFingerprint_0a81ec5a929777f145904af38d5d509f66b5e2c58fcdb531058b0e17f3f0b41b_certificate, +kCertificateWithFingerprint_70a73f7f376b60074248904534b11482d5bf0e698ecc498df52577ebf2e93b9a_certificate, +kCertificateWithFingerprint_bd71fdf6da97e4cf62d1647add2581b07d79adf8397eb4ecba9c5e8488821423_certificate, +kCertificateWithFingerprint_ebd41040e4bb3ec742c9e381d31ef2a41a48b6685c96e7cef3c1df6cd4331c99_certificate, +kCertificateWithFingerprint_cbb522d7b7f127ad6a0113865bdf1cd4102e7d0759af635a7cf4720dc963c53b_certificate, +kCertificateWithFingerprint_179fbc148a3dd00fd24ea13458cc43bfa7f59c8182d783a513f6ebec100c8924_certificate, +kCertificateWithFingerprint_2cabeafe37d06ca22aba7391c0033d25982952c453647349763a3ab5ad6ccf69_certificate, +kCertificateWithFingerprint_45140b3247eb9cc8c5b4f0d7b53091f73292089e6e5a63e2749dd3aca9198eda_certificate, +kCertificateWithFingerprint_2ce1cb0bf9d2f9e102993fbe215152c3b2dd0cabde1c68e5319b839154dbb7f5_certificate, +kCertificateWithFingerprint_1465fa205397b876faa6f0a9958e5590e40fcc7faa4fb7c2c8677521fb5fb658_certificate, +kCertificateWithFingerprint_c3846bf24b9e93ca64274c0ec67c1ecc5e024ffcacd2d74019350e81fe546ae4_certificate, +kCertificateWithFingerprint_d7a7a0fb5d7e2731d771e9484ebcdef71d5f0c3e0a2948782bc83ee0ea699ef4_certificate, +kCertificateWithFingerprint_0c2cd63df7806fa399ede809116b575bf87989f06518f9808c860503178baf66_certificate, +kCertificateWithFingerprint_1793927a0614549789adce2f8f34f7f0b66d0f3ae3a3b84d21ec15dbba4fadc7_certificate, +kCertificateWithFingerprint_52f0e1c4e58ec629291b60317f074671b85d7ea80d5b07273463534b32b40234_certificate, +kCertificateWithFingerprint_4ff460d54b9c86dabfbcfc5712e0400d2bed3fbc4d4fbdaa86e06adcd2a9ad7a_certificate, +kCertificateWithFingerprint_e793c9b02fd8aa13e21c31228accb08119643b749c898964b1746d46c3d4cbd2_certificate, +kCertificateWithFingerprint_d947432abde7b7fa90fc2e6b59101b1280e0e1c7e4e40fa3c6887fff57a7f4cf_certificate, +kCertificateWithFingerprint_8d25cd97229dbf70356bda4eb3cc734031e24cf00fafcfd32dc76eb5841c7ea8_certificate, +kCertificateWithFingerprint_34d8a73ee208d9bcdb0d956520934b4e40e69482596e8b6f73c8426b010a6f48_certificate, +kCertificateWithFingerprint_349dfa4058c5e263123b398ae795573c4e1313c83fe68f93556cd5e8031b3c7d_certificate, +kCertificateWithFingerprint_b085d70b964f191a73e4af0d54ae7a0e07aafdaf9b71dd0862138ab7325a24a2_certificate, +}; + +const size_t kSSLCertCertificateSizeList[36]={ +891, +955, +922, +586, +947, +914, +579, +969, +1428, +1173, +765, +1090, +1070, +848, +848, +1354, +514, +889, +867, +546, +1415, +969, +993, +1043, +1028, +1078, +1057, +653, +1500, +659, +1506, +1371, +1371, +525, +525, +480, +}; + +// clang-format on + +#endif // RTC_BASE_SSL_ROOTS_H_ diff --git a/third_party/libwebrtc/rtc_base/ssl_stream_adapter.cc b/third_party/libwebrtc/rtc_base/ssl_stream_adapter.cc new file mode 100644 index 0000000000..931d0bf0b6 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/ssl_stream_adapter.cc @@ -0,0 +1,146 @@ +/* + * 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 "rtc_base/ssl_stream_adapter.h" + +#include "absl/memory/memory.h" +#include "absl/strings/string_view.h" +#include "rtc_base/openssl_stream_adapter.h" + +/////////////////////////////////////////////////////////////////////////////// + +namespace rtc { + +// TODO(guoweis): Move this to SDP layer and use int form internally. +// webrtc:5043. +const char kCsAesCm128HmacSha1_80[] = "AES_CM_128_HMAC_SHA1_80"; +const char kCsAesCm128HmacSha1_32[] = "AES_CM_128_HMAC_SHA1_32"; +const char kCsAeadAes128Gcm[] = "AEAD_AES_128_GCM"; +const char kCsAeadAes256Gcm[] = "AEAD_AES_256_GCM"; + +std::string SrtpCryptoSuiteToName(int crypto_suite) { + switch (crypto_suite) { + case kSrtpAes128CmSha1_32: + return kCsAesCm128HmacSha1_32; + case kSrtpAes128CmSha1_80: + return kCsAesCm128HmacSha1_80; + case kSrtpAeadAes128Gcm: + return kCsAeadAes128Gcm; + case kSrtpAeadAes256Gcm: + return kCsAeadAes256Gcm; + default: + return std::string(); + } +} + +int SrtpCryptoSuiteFromName(absl::string_view crypto_suite) { + if (crypto_suite == kCsAesCm128HmacSha1_32) + return kSrtpAes128CmSha1_32; + if (crypto_suite == kCsAesCm128HmacSha1_80) + return kSrtpAes128CmSha1_80; + if (crypto_suite == kCsAeadAes128Gcm) + return kSrtpAeadAes128Gcm; + if (crypto_suite == kCsAeadAes256Gcm) + return kSrtpAeadAes256Gcm; + return kSrtpInvalidCryptoSuite; +} + +bool GetSrtpKeyAndSaltLengths(int crypto_suite, + int* key_length, + int* salt_length) { + switch (crypto_suite) { + case kSrtpAes128CmSha1_32: + case kSrtpAes128CmSha1_80: + // SRTP_AES128_CM_HMAC_SHA1_32 and SRTP_AES128_CM_HMAC_SHA1_80 are defined + // in RFC 5764 to use a 128 bits key and 112 bits salt for the cipher. + *key_length = 16; + *salt_length = 14; + break; + case kSrtpAeadAes128Gcm: + // kSrtpAeadAes128Gcm is defined in RFC 7714 to use a 128 bits key and + // a 96 bits salt for the cipher. + *key_length = 16; + *salt_length = 12; + break; + case kSrtpAeadAes256Gcm: + // kSrtpAeadAes256Gcm is defined in RFC 7714 to use a 256 bits key and + // a 96 bits salt for the cipher. + *key_length = 32; + *salt_length = 12; + break; + default: + return false; + } + return true; +} + +bool IsGcmCryptoSuite(int crypto_suite) { + return (crypto_suite == kSrtpAeadAes256Gcm || + crypto_suite == kSrtpAeadAes128Gcm); +} + +bool IsGcmCryptoSuiteName(absl::string_view crypto_suite) { + return (crypto_suite == kCsAeadAes256Gcm || crypto_suite == kCsAeadAes128Gcm); +} + +std::unique_ptr<SSLStreamAdapter> SSLStreamAdapter::Create( + std::unique_ptr<StreamInterface> stream, + absl::AnyInvocable<void(SSLHandshakeError)> handshake_error) { + return std::make_unique<OpenSSLStreamAdapter>(std::move(stream), + std::move(handshake_error)); +} + +bool SSLStreamAdapter::GetSslCipherSuite(int* cipher_suite) { + return false; +} + +bool SSLStreamAdapter::ExportKeyingMaterial(absl::string_view label, + const uint8_t* context, + size_t context_len, + bool use_context, + uint8_t* result, + size_t result_len) { + return false; // Default is unsupported +} + +bool SSLStreamAdapter::SetDtlsSrtpCryptoSuites( + const std::vector<int>& crypto_suites) { + return false; +} + +bool SSLStreamAdapter::GetDtlsSrtpCryptoSuite(int* crypto_suite) { + return false; +} + +bool SSLStreamAdapter::IsBoringSsl() { + return OpenSSLStreamAdapter::IsBoringSsl(); +} +bool SSLStreamAdapter::IsAcceptableCipher(int cipher, KeyType key_type) { + return OpenSSLStreamAdapter::IsAcceptableCipher(cipher, key_type); +} +bool SSLStreamAdapter::IsAcceptableCipher(absl::string_view cipher, + KeyType key_type) { + return OpenSSLStreamAdapter::IsAcceptableCipher(cipher, key_type); +} +std::string SSLStreamAdapter::SslCipherSuiteToName(int cipher_suite) { + return OpenSSLStreamAdapter::SslCipherSuiteToName(cipher_suite); +} + +/////////////////////////////////////////////////////////////////////////////// +// Test only settings +/////////////////////////////////////////////////////////////////////////////// + +void SSLStreamAdapter::EnableTimeCallbackForTesting() { + OpenSSLStreamAdapter::EnableTimeCallbackForTesting(); +} + +/////////////////////////////////////////////////////////////////////////////// + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/ssl_stream_adapter.h b/third_party/libwebrtc/rtc_base/ssl_stream_adapter.h new file mode 100644 index 0000000000..701cc4437b --- /dev/null +++ b/third_party/libwebrtc/rtc_base/ssl_stream_adapter.h @@ -0,0 +1,281 @@ +/* + * 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 RTC_BASE_SSL_STREAM_ADAPTER_H_ +#define RTC_BASE_SSL_STREAM_ADAPTER_H_ + +#include <stddef.h> +#include <stdint.h> + +#include <memory> +#include <string> +#include <vector> + +#include "absl/functional/any_invocable.h" +#include "absl/memory/memory.h" +#include "absl/strings/string_view.h" +#include "rtc_base/ssl_certificate.h" +#include "rtc_base/ssl_identity.h" +#include "rtc_base/stream.h" + +namespace rtc { + +// Constants for SSL profile. +constexpr int kTlsNullWithNullNull = 0; +constexpr int kSslCipherSuiteMaxValue = 0xFFFF; + +// Constants for SRTP profiles. +constexpr int kSrtpInvalidCryptoSuite = 0; +constexpr int kSrtpAes128CmSha1_80 = 0x0001; +constexpr int kSrtpAes128CmSha1_32 = 0x0002; +constexpr int kSrtpAeadAes128Gcm = 0x0007; +constexpr int kSrtpAeadAes256Gcm = 0x0008; +constexpr int kSrtpCryptoSuiteMaxValue = 0xFFFF; + +// Constants for SSL signature algorithms. +constexpr int kSslSignatureAlgorithmUnknown = 0; +constexpr int kSslSignatureAlgorithmMaxValue = 0xFFFF; + +// Names of SRTP profiles listed above. +// 128-bit AES with 80-bit SHA-1 HMAC. +extern const char kCsAesCm128HmacSha1_80[]; +// 128-bit AES with 32-bit SHA-1 HMAC. +extern const char kCsAesCm128HmacSha1_32[]; +// 128-bit AES GCM with 16 byte AEAD auth tag. +extern const char kCsAeadAes128Gcm[]; +// 256-bit AES GCM with 16 byte AEAD auth tag. +extern const char kCsAeadAes256Gcm[]; + +// Given the DTLS-SRTP protection profile ID, as defined in +// https://tools.ietf.org/html/rfc4568#section-6.2 , return the SRTP profile +// name, as defined in https://tools.ietf.org/html/rfc5764#section-4.1.2. +std::string SrtpCryptoSuiteToName(int crypto_suite); + +// The reverse of above conversion. +int SrtpCryptoSuiteFromName(absl::string_view crypto_suite); + +// Get key length and salt length for given crypto suite. Returns true for +// valid suites, otherwise false. +bool GetSrtpKeyAndSaltLengths(int crypto_suite, + int* key_length, + int* salt_length); + +// Returns true if the given crypto suite id uses a GCM cipher. +bool IsGcmCryptoSuite(int crypto_suite); + +// Returns true if the given crypto suite name uses a GCM cipher. +bool IsGcmCryptoSuiteName(absl::string_view crypto_suite); + +// SSLStreamAdapter : A StreamInterfaceAdapter that does SSL/TLS. +// After SSL has been started, the stream will only open on successful +// SSL verification of certificates, and the communication is +// encrypted of course. +// +// This class was written with SSLAdapter as a starting point. It +// offers a similar interface, with two differences: there is no +// support for a restartable SSL connection, and this class has a +// peer-to-peer mode. +// +// The SSL library requires initialization and cleanup. Static method +// for doing this are in SSLAdapter. They should possibly be moved out +// to a neutral class. + +enum SSLRole { SSL_CLIENT, SSL_SERVER }; +enum SSLMode { SSL_MODE_TLS, SSL_MODE_DTLS }; + +// Note: TLS_10, TLS_11, and DTLS_10 will all be ignored, and only DTLS1_2 will +// be accepted unless the trial flag WebRTC-LegacyTlsProtocols/Enabled/ is +// passed in or an explicit override is used. Support for the legacy protocol +// versions will be completely removed in the future. +// See https://bugs.webrtc.org/10261. +enum SSLProtocolVersion { + SSL_PROTOCOL_NOT_GIVEN = -1, + SSL_PROTOCOL_TLS_10 = 0, + SSL_PROTOCOL_TLS_11, + SSL_PROTOCOL_TLS_12, + SSL_PROTOCOL_DTLS_10 = SSL_PROTOCOL_TLS_11, + SSL_PROTOCOL_DTLS_12 = SSL_PROTOCOL_TLS_12, +}; +enum class SSLPeerCertificateDigestError { + NONE, + UNKNOWN_ALGORITHM, + INVALID_LENGTH, + VERIFICATION_FAILED, +}; + +// Errors for Read -- in the high range so no conflict with OpenSSL. +enum { SSE_MSG_TRUNC = 0xff0001 }; + +// Used to send back UMA histogram value. Logged when Dtls handshake fails. +enum class SSLHandshakeError { UNKNOWN, INCOMPATIBLE_CIPHERSUITE, MAX_VALUE }; + +class SSLStreamAdapter : public StreamInterface { + public: + // Instantiate an SSLStreamAdapter wrapping the given stream, + // (using the selected implementation for the platform). + // Caller is responsible for freeing the returned object. + static std::unique_ptr<SSLStreamAdapter> Create( + std::unique_ptr<StreamInterface> stream, + absl::AnyInvocable<void(SSLHandshakeError)> handshake_error = nullptr); + + SSLStreamAdapter() = default; + ~SSLStreamAdapter() override = default; + + // Specify our SSL identity: key and certificate. SSLStream takes ownership + // of the SSLIdentity object and will free it when appropriate. Should be + // called no more than once on a given SSLStream instance. + virtual void SetIdentity(std::unique_ptr<SSLIdentity> identity) = 0; + virtual SSLIdentity* GetIdentityForTesting() const = 0; + + // Call this to indicate that we are to play the server role (or client role, + // if the default argument is replaced by SSL_CLIENT). + // The default argument is for backward compatibility. + // TODO(ekr@rtfm.com): rename this SetRole to reflect its new function + virtual void SetServerRole(SSLRole role = SSL_SERVER) = 0; + + // Do DTLS or TLS. + virtual void SetMode(SSLMode mode) = 0; + + // Set maximum supported protocol version. The highest version supported by + // both ends will be used for the connection, i.e. if one party supports + // DTLS 1.0 and the other DTLS 1.2, DTLS 1.0 will be used. + // If requested version is not supported by underlying crypto library, the + // next lower will be used. + virtual void SetMaxProtocolVersion(SSLProtocolVersion version) = 0; + + // Set the initial retransmission timeout for DTLS messages. When the timeout + // expires, the message gets retransmitted and the timeout is exponentially + // increased. + // This should only be called before StartSSL(). + virtual void SetInitialRetransmissionTimeout(int timeout_ms) = 0; + + // StartSSL starts negotiation with a peer, whose certificate is verified + // using the certificate digest. Generally, SetIdentity() and possibly + // SetServerRole() should have been called before this. + // SetPeerCertificateDigest() must also be called. It may be called after + // StartSSLWithPeer() but must be called before the underlying stream opens. + // + // Use of the stream prior to calling StartSSL will pass data in clear text. + // Calling StartSSL causes SSL negotiation to begin as soon as possible: right + // away if the underlying wrapped stream is already opened, or else as soon as + // it opens. + // + // StartSSL returns a negative error code on failure. Returning 0 means + // success so far, but negotiation is probably not complete and will continue + // asynchronously. In that case, the exposed stream will open after + // successful negotiation and verification, or an SE_CLOSE event will be + // raised if negotiation fails. + virtual int StartSSL() = 0; + + // Specify the digest of the certificate that our peer is expected to use. + // Only this certificate will be accepted during SSL verification. The + // certificate is assumed to have been obtained through some other secure + // channel (such as the signaling channel). This must specify the terminal + // certificate, not just a CA. SSLStream makes a copy of the digest value. + // + // Returns true if successful. + // `error` is optional and provides more information about the failure. + virtual bool SetPeerCertificateDigest( + absl::string_view digest_alg, + const unsigned char* digest_val, + size_t digest_len, + SSLPeerCertificateDigestError* error = nullptr) = 0; + + // Retrieves the peer's certificate chain including leaf certificate, if a + // connection has been established. + virtual std::unique_ptr<SSLCertChain> GetPeerSSLCertChain() const = 0; + + // Retrieves the IANA registration id of the cipher suite used for the + // connection (e.g. 0x2F for "TLS_RSA_WITH_AES_128_CBC_SHA"). + virtual bool GetSslCipherSuite(int* cipher_suite); + + // Retrieves the enum value for SSL version. + // Will return -1 until the version has been negotiated. + virtual SSLProtocolVersion GetSslVersion() const = 0; + // Retrieves the 2-byte version from the TLS protocol. + // Will return false until the version has been negotiated. + virtual bool GetSslVersionBytes(int* version) const = 0; + + // Key Exporter interface from RFC 5705 + // Arguments are: + // label -- the exporter label. + // part of the RFC defining each exporter + // usage (IN) + // context/context_len -- a context to bind to for this connection; + // optional, can be null, 0 (IN) + // use_context -- whether to use the context value + // (needed to distinguish no context from + // zero-length ones). + // result -- where to put the computed value + // result_len -- the length of the computed value + virtual bool ExportKeyingMaterial(absl::string_view label, + const uint8_t* context, + size_t context_len, + bool use_context, + uint8_t* result, + size_t result_len); + + // Returns the signature algorithm or 0 if not applicable. + virtual uint16_t GetPeerSignatureAlgorithm() const = 0; + + // DTLS-SRTP interface + virtual bool SetDtlsSrtpCryptoSuites(const std::vector<int>& crypto_suites); + virtual bool GetDtlsSrtpCryptoSuite(int* crypto_suite); + + // Returns true if a TLS connection has been established. + // The only difference between this and "GetState() == SE_OPEN" is that if + // the peer certificate digest hasn't been verified, the state will still be + // SS_OPENING but IsTlsConnected should return true. + virtual bool IsTlsConnected() = 0; + + // Capabilities testing. + // Used to have "DTLS supported", "DTLS-SRTP supported" etc. methods, but now + // that's assumed. + static bool IsBoringSsl(); + + // Returns true iff the supplied cipher is deemed to be strong. + // TODO(torbjorng): Consider removing the KeyType argument. + static bool IsAcceptableCipher(int cipher, KeyType key_type); + static bool IsAcceptableCipher(absl::string_view cipher, KeyType key_type); + + // TODO(guoweis): Move this away from a static class method. Currently this is + // introduced such that any caller could depend on sslstreamadapter.h without + // depending on specific SSL implementation. + static std::string SslCipherSuiteToName(int cipher_suite); + + //////////////////////////////////////////////////////////////////////////// + // Testing only member functions + //////////////////////////////////////////////////////////////////////////// + + // Use our timeutils.h source of timing in BoringSSL, allowing us to test + // using a fake clock. + static void EnableTimeCallbackForTesting(); + + // Deprecated. Do not use this API outside of testing. + // Do not set this to false outside of testing. + void SetClientAuthEnabledForTesting(bool enabled) { + client_auth_enabled_ = enabled; + } + + // Deprecated. Do not use this API outside of testing. + // Returns true by default, else false if explicitly set to disable client + // authentication. + bool GetClientAuthEnabled() const { return client_auth_enabled_; } + + private: + // If true (default), the client is required to provide a certificate during + // handshake. If no certificate is given, handshake fails. This applies to + // server mode only. + bool client_auth_enabled_ = true; +}; + +} // namespace rtc + +#endif // RTC_BASE_SSL_STREAM_ADAPTER_H_ diff --git a/third_party/libwebrtc/rtc_base/ssl_stream_adapter_unittest.cc b/third_party/libwebrtc/rtc_base/ssl_stream_adapter_unittest.cc new file mode 100644 index 0000000000..0a99d9b1f0 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/ssl_stream_adapter_unittest.cc @@ -0,0 +1,1853 @@ +/* + * Copyright 2011 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 "rtc_base/ssl_stream_adapter.h" + +#include <algorithm> +#include <memory> +#include <set> +#include <string> + +#include "absl/memory/memory.h" +#include "absl/strings/string_view.h" +#include "api/array_view.h" +#include "api/task_queue/pending_task_safety_flag.h" +#include "rtc_base/buffer_queue.h" +#include "rtc_base/checks.h" +#include "rtc_base/gunit.h" +#include "rtc_base/helpers.h" +#include "rtc_base/memory/fifo_buffer.h" +#include "rtc_base/memory_stream.h" +#include "rtc_base/message_digest.h" +#include "rtc_base/openssl_stream_adapter.h" +#include "rtc_base/ssl_adapter.h" +#include "rtc_base/ssl_identity.h" +#include "rtc_base/stream.h" +#include "test/field_trial.h" + +using ::testing::Combine; +using ::testing::tuple; +using ::testing::Values; +using ::testing::WithParamInterface; +using ::webrtc::SafeTask; + +static const int kBlockSize = 4096; +static const char kExporterLabel[] = "label"; +static const unsigned char kExporterContext[] = "context"; +static int kExporterContextLen = sizeof(kExporterContext); + +// A private key used for testing, broken into pieces in order to avoid +// issues with Git's checks for private keys in repos. +#define RSA_PRIVATE_KEY_HEADER "-----BEGIN RSA PRIVATE KEY-----\n" + +static const char kRSA_PRIVATE_KEY_PEM[] = RSA_PRIVATE_KEY_HEADER + "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMYRkbhmI7kVA/rM\n" + "czsZ+6JDhDvnkF+vn6yCAGuRPV03zuRqZtDy4N4to7PZu9PjqrRl7nDMXrG3YG9y\n" + "rlIAZ72KjcKKFAJxQyAKLCIdawKRyp8RdK3LEySWEZb0AV58IadqPZDTNHHRX8dz\n" + "5aTSMsbbkZ+C/OzTnbiMqLL/vg6jAgMBAAECgYAvgOs4FJcgvp+TuREx7YtiYVsH\n" + "mwQPTum2z/8VzWGwR8BBHBvIpVe1MbD/Y4seyI2aco/7UaisatSgJhsU46/9Y4fq\n" + "2TwXH9QANf4at4d9n/R6rzwpAJOpgwZgKvdQjkfrKTtgLV+/dawvpxUYkRH4JZM1\n" + "CVGukMfKNrSVH4Ap4QJBAOJmGV1ASPnB4r4nc99at7JuIJmd7fmuVUwUgYi4XgaR\n" + "WhScBsgYwZ/JoywdyZJgnbcrTDuVcWG56B3vXbhdpMsCQQDf9zeJrjnPZ3Cqm79y\n" + "kdqANep0uwZciiNiWxsQrCHztywOvbFhdp8iYVFG9EK8DMY41Y5TxUwsHD+67zao\n" + "ZNqJAkEA1suLUP/GvL8IwuRneQd2tWDqqRQ/Td3qq03hP7e77XtF/buya3Ghclo5\n" + "54czUR89QyVfJEC6278nzA7n2h1uVQJAcG6mztNL6ja/dKZjYZye2CY44QjSlLo0\n" + "MTgTSjdfg/28fFn2Jjtqf9Pi/X+50LWI/RcYMC2no606wRk9kyOuIQJBAK6VSAim\n" + "1pOEjsYQn0X5KEIrz1G3bfCbB848Ime3U2/FWlCHMr6ch8kCZ5d1WUeJD3LbwMNG\n" + "UCXiYxSsu20QNVw=\n" + "-----END RSA PRIVATE KEY-----\n"; + +#undef RSA_PRIVATE_KEY_HEADER + +static const char kCERT_PEM[] = + "-----BEGIN CERTIFICATE-----\n" + "MIIBmTCCAQKgAwIBAgIEbzBSAjANBgkqhkiG9w0BAQsFADARMQ8wDQYDVQQDEwZX\n" + "ZWJSVEMwHhcNMTQwMTAyMTgyNDQ3WhcNMTQwMjAxMTgyNDQ3WjARMQ8wDQYDVQQD\n" + "EwZXZWJSVEMwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMYRkbhmI7kVA/rM\n" + "czsZ+6JDhDvnkF+vn6yCAGuRPV03zuRqZtDy4N4to7PZu9PjqrRl7nDMXrG3YG9y\n" + "rlIAZ72KjcKKFAJxQyAKLCIdawKRyp8RdK3LEySWEZb0AV58IadqPZDTNHHRX8dz\n" + "5aTSMsbbkZ+C/OzTnbiMqLL/vg6jAgMBAAEwDQYJKoZIhvcNAQELBQADgYEAUflI\n" + "VUe5Krqf5RVa5C3u/UTAOAUJBiDS3VANTCLBxjuMsvqOG0WvaYWP3HYPgrz0jXK2\n" + "LJE/mGw3MyFHEqi81jh95J+ypl6xKW6Rm8jKLR87gUvCaVYn/Z4/P3AqcQTB7wOv\n" + "UD0A8qfhfDM+LK6rPAnCsVN0NRDY3jvd6rzix9M=\n" + "-----END CERTIFICATE-----\n"; + +static const char kIntCert1[] = + "-----BEGIN CERTIFICATE-----\n" + "MIIEUjCCAjqgAwIBAgIBAjANBgkqhkiG9w0BAQsFADCBljELMAkGA1UEBhMCVVMx\n" + "EzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxFDAS\n" + "BgNVBAoMC0dvb2dsZSwgSW5jMQwwCgYDVQQLDANHVFAxFzAVBgNVBAMMDnRlbGVw\n" + "aG9ueS5nb29nMR0wGwYJKoZIhvcNAQkBFg5ndHBAZ29vZ2xlLmNvbTAeFw0xNzA5\n" + "MjYwNDA5MDNaFw0yMDA2MjIwNDA5MDNaMGQxCzAJBgNVBAYTAlVTMQswCQYDVQQI\n" + "DAJDQTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzEXMBUGA1UECgwOdGVsZXBob255\n" + "Lmdvb2cxFzAVBgNVBAMMDnRlbGVwaG9ueS5nb29nMIGfMA0GCSqGSIb3DQEBAQUA\n" + "A4GNADCBiQKBgQDJXWeeU1v1+wlqkVobzI3aN7Uh2iVQA9YCdq5suuabtiD/qoOD\n" + "NKpmQqsx7WZGGWSZTDFEBaUpvIK7Hb+nzRqk6iioPCFOFuarm6GxO1xVneImMuE6\n" + "tuWb3YZPr+ikChJbl11y5UcSbg0QsbeUc+jHl5umNvrL85Y+z8SP0rxbBwIDAQAB\n" + "o2AwXjAdBgNVHQ4EFgQU7tdZobqlN8R8V72FQnRxmqq8tKswHwYDVR0jBBgwFoAU\n" + "5GgKMUtcxkQ2dJrtNR5YOlIAPDswDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMC\n" + "AQYwDQYJKoZIhvcNAQELBQADggIBADObh9Z+z14FmP9zSenhFtq7hFnmNrSkklk8\n" + "eyYWXKfOuIriEQQBZsz76ZcnzStih8Rj+yQ0AXydk4fJ5LOwC2cUqQBar17g6Pd2\n" + "8g4SIL4azR9WvtiSvpuGlwp25b+yunaacDne6ebnf/MUiiKT5w61Xo3cEPVfl38e\n" + "/Up2l0bioid5enUTmg6LY6RxDO6tnZQkz3XD+nNSwT4ehtkqFpHYWjErj0BbkDM2\n" + "hiVc/JsYOZn3DmuOlHVHU6sKwqh3JEyvHO/d7DGzMGWHpHwv2mCTJq6l/sR95Tc2\n" + "GaQZgGDVNs9pdEouJCDm9e/PbQWRYhnat82PTkXx/6mDAAwdZlIi/pACzq8K4p7e\n" + "6hF0t8uKGnXJubHPXxlnJU6yxZ0yWmivAGjwWK4ur832gKlho4jeMDhiI/T3QPpl\n" + "iMNsIvxRhdD+GxJkQP1ezayw8s+Uc9KwKglrkBSRRDLCJUfPOvMmXLUDSTMX7kp4\n" + "/Ak1CA8dVLJIlfEjLBUuvAttlP7+7lsKNgxAjCxZkWLXIyGULzNPQwVWkGfCbrQs\n" + "XyMvSbFsSIb7blV7eLlmf9a+2RprUUkc2ALXLLCI9YQXmxm2beBfMyNmmebwBJzT\n" + "B0OR+5pFFNTJPoNlqpdrDsGrDu7JlUtk0ZLZzYyKXbgy2qXxfd4OWzXXjxpLMszZ\n" + "LDIpOAkj\n" + "-----END CERTIFICATE-----\n"; + +static const char kCACert[] = + "-----BEGIN CERTIFICATE-----\n" + "MIIGETCCA/mgAwIBAgIJAKN9r/BdbGUJMA0GCSqGSIb3DQEBCwUAMIGWMQswCQYD\n" + "VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4g\n" + "VmlldzEUMBIGA1UECgwLR29vZ2xlLCBJbmMxDDAKBgNVBAsMA0dUUDEXMBUGA1UE\n" + "AwwOdGVsZXBob255Lmdvb2cxHTAbBgkqhkiG9w0BCQEWDmd0cEBnb29nbGUuY29t\n" + "MB4XDTE3MDcyNzIzMDE0NVoXDTE3MDgyNjIzMDE0NVowgZYxCzAJBgNVBAYTAlVT\n" + "MRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1Nb3VudGFpbiBWaWV3MRQw\n" + "EgYDVQQKDAtHb29nbGUsIEluYzEMMAoGA1UECwwDR1RQMRcwFQYDVQQDDA50ZWxl\n" + "cGhvbnkuZ29vZzEdMBsGCSqGSIb3DQEJARYOZ3RwQGdvb2dsZS5jb20wggIiMA0G\n" + "CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCfvpF7aBV5Hp1EHsWoIlL3GeHwh8dS\n" + "lv9VQCegN9rD06Ny7MgcED5AiK2vqXmUmOVS+7NbATkdVYN/eozDhKtN3Q3n87kJ\n" + "Nt/TD/TcZZHOZIGsRPbrf2URK26E/5KzTzbzXVBOA1e+gSj+EBbltGqb01ZO5ErF\n" + "iPGViPM/HpYKdq6mfz2bS5PhU67XZMM2zvToyReQ/Fjm/6PJhwKSRXSgZF5djPhk\n" + "2LfOKMLS0AeZtd2C4DFsCU41lfLUkybioDgFuzTQ3TFi1K8A07KYTMmLY/yQppnf\n" + "SpNX58shlVhM+Ed37K1Z0rU0OfVCZ5P+KKaSSfMranjlU7zeUIhZYjqq/EYrEhbS\n" + "dLnNHwgJrqxzId3kq8uuLM6+VB7JZKnZLfT90GdAbX4+tutNe21smmogF9f80vEy\n" + "gM4tOp9rXrvz9vCwWHXVY9kdKemdLAsREoO6MS9k2ctK4jj80o2dROuFC6Q3e7mz\n" + "RjvZr5Tvi464c2o9o/jNlJ0O6q7V2eQzohD+7VnV5QPpRGXxlIeqpR2zoAg+WtRS\n" + "4OgHOVYiD3M6uAlggJA5pcDjMfkEZ+pkhtVcT4qMCEoruk6GbyPxS565oSHu16bH\n" + "EjeCqbZOVND5T3oA7nz6aQSs8sJabt0jmxUkGVnE+4ZDIuuRtkRma+0P/96Mtqor\n" + "OlpNWY1OBDY64QIDAQABo2AwXjAdBgNVHQ4EFgQU5GgKMUtcxkQ2dJrtNR5YOlIA\n" + "PDswHwYDVR0jBBgwFoAU5GgKMUtcxkQ2dJrtNR5YOlIAPDswDwYDVR0TAQH/BAUw\n" + "AwEB/zALBgNVHQ8EBAMCAQYwDQYJKoZIhvcNAQELBQADggIBAARQly5/bB6VUL2C\n" + "ykDYgWt48go407pAra6tL2kjpdfxV5PdL7iMZRkeht00vj+BVahIqZKrNOa/f5Fx\n" + "vlpahZFu0PDN436aQwRZ9qWut2qDOK0/z9Hhj6NWybquRFwMwqkPG/ivLMDU8Dmj\n" + "CIplpngPYNwXCs0KzdjSXYxqxJbwMjQXELD+/RcurY0oTtJMM1/2vKQMzw24UJqe\n" + "XLJAlsnd2AnWzWNUEviDZY89j9NdkHerBmV2gGzcU+X5lgOO5M8odBv0ZC9D+a6Z\n" + "QPZAOfdGVw60hhGvTW5s/s0dHwCpegRidhs0MD0fTmwwjYFBSmUx3Gztr4JTzOOr\n" + "7e5daJuak2ujQ5DqcGBvt1gePjSudb5brS7JQtN8tI/FyrnR4q/OuOwv1EvlC5RG\n" + "hLX+TXaWqFxB1Hd8ebKRR40mboFG6KcUI3lLBthDvQE7jnq48QfZMjlMQK0ZF1l7\n" + "SrlwRXWA74bU8CLJvnZKKo9p4TsTiDYGSYC6tNHKj5s3TGWL46oqGyZ0KdGNhrtC\n" + "rIGenMhth1vPYjyy0XuGBndXT85yi+IM2l8g8oU845+plxIhgpSI8bbC0oLwnhQ5\n" + "ARfsiYLkXDE7imSS0CSUmye76372mlzAIB1is4bBB/SzpPQtBuB9LDKtONgpSGHn\n" + "dGaXBy+qbVXVyGXaeEbIRjtJ6m92\n" + "-----END CERTIFICATE-----\n"; + +class SSLStreamAdapterTestBase; + +class SSLDummyStreamBase : public rtc::StreamInterface, + public sigslot::has_slots<> { + public: + SSLDummyStreamBase(SSLStreamAdapterTestBase* test, + absl::string_view side, + rtc::StreamInterface* in, + rtc::StreamInterface* out) + : test_base_(test), side_(side), in_(in), out_(out), first_packet_(true) { + in_->SignalEvent.connect(this, &SSLDummyStreamBase::OnEventIn); + out_->SignalEvent.connect(this, &SSLDummyStreamBase::OnEventOut); + } + + rtc::StreamState GetState() const override { return rtc::SS_OPEN; } + + rtc::StreamResult Read(rtc::ArrayView<uint8_t> buffer, + size_t& read, + int& error) override { + rtc::StreamResult r; + + r = in_->Read(buffer, read, error); + if (r == rtc::SR_BLOCK) + return rtc::SR_BLOCK; + if (r == rtc::SR_EOS) + return rtc::SR_EOS; + + if (r != rtc::SR_SUCCESS) { + ADD_FAILURE(); + return rtc::SR_ERROR; + } + + return rtc::SR_SUCCESS; + } + + // Catch readability events on in and pass them up. + void OnEventIn(rtc::StreamInterface* stream, int sig, int err) { + int mask = (rtc::SE_READ | rtc::SE_CLOSE); + + if (sig & mask) { + RTC_LOG(LS_VERBOSE) << "SSLDummyStreamBase::OnEvent side=" << side_ + << " sig=" << sig << " forwarding upward"; + PostEvent(sig & mask, 0); + } + } + + // Catch writeability events on out and pass them up. + void OnEventOut(rtc::StreamInterface* stream, int sig, int err) { + if (sig & rtc::SE_WRITE) { + RTC_LOG(LS_VERBOSE) << "SSLDummyStreamBase::OnEvent side=" << side_ + << " sig=" << sig << " forwarding upward"; + + PostEvent(sig & rtc::SE_WRITE, 0); + } + } + + // Write to the outgoing FifoBuffer + rtc::StreamResult WriteData(rtc::ArrayView<const uint8_t> data, + size_t& written, + int& error) { + return out_->Write(data, written, error); + } + + rtc::StreamResult Write(rtc::ArrayView<const uint8_t> data, + size_t& written, + int& error) override; + + void Close() override { + RTC_LOG(LS_INFO) << "Closing outbound stream"; + out_->Close(); + } + + private: + void PostEvent(int events, int err) { + thread_->PostTask(SafeTask(task_safety_.flag(), [this, events, err]() { + SignalEvent(this, events, err); + })); + } + + webrtc::ScopedTaskSafety task_safety_; + rtc::Thread* const thread_ = rtc::Thread::Current(); + SSLStreamAdapterTestBase* test_base_; + const std::string side_; + rtc::StreamInterface* in_; + rtc::StreamInterface* out_; + bool first_packet_; +}; + +class SSLDummyStreamTLS : public SSLDummyStreamBase { + public: + SSLDummyStreamTLS(SSLStreamAdapterTestBase* test, + absl::string_view side, + rtc::FifoBuffer* in, + rtc::FifoBuffer* out) + : SSLDummyStreamBase(test, side, in, out) {} +}; + +class BufferQueueStream : public rtc::StreamInterface { + public: + BufferQueueStream(size_t capacity, size_t default_size) + : buffer_(capacity, default_size) {} + + // Implementation of abstract StreamInterface methods. + + // A buffer queue stream is always "open". + rtc::StreamState GetState() const override { return rtc::SS_OPEN; } + + // Reading a buffer queue stream will either succeed or block. + rtc::StreamResult Read(rtc::ArrayView<uint8_t> buffer, + size_t& read, + int& error) override { + const bool was_writable = buffer_.is_writable(); + if (!buffer_.ReadFront(buffer.data(), buffer.size(), &read)) + return rtc::SR_BLOCK; + + if (!was_writable) + NotifyWritableForTest(); + + return rtc::SR_SUCCESS; + } + + // Writing to a buffer queue stream will either succeed or block. + rtc::StreamResult Write(rtc::ArrayView<const uint8_t> data, + size_t& written, + int& error) override { + const bool was_readable = buffer_.is_readable(); + if (!buffer_.WriteBack(data.data(), data.size(), &written)) + return rtc::SR_BLOCK; + + if (!was_readable) + NotifyReadableForTest(); + + return rtc::SR_SUCCESS; + } + + // A buffer queue stream can not be closed. + void Close() override {} + + protected: + void NotifyReadableForTest() { PostEvent(rtc::SE_READ, 0); } + void NotifyWritableForTest() { PostEvent(rtc::SE_WRITE, 0); } + + private: + void PostEvent(int events, int err) { + thread_->PostTask(SafeTask(task_safety_.flag(), [this, events, err]() { + SignalEvent(this, events, err); + })); + } + + rtc::Thread* const thread_ = rtc::Thread::Current(); + webrtc::ScopedTaskSafety task_safety_; + rtc::BufferQueue buffer_; +}; + +class SSLDummyStreamDTLS : public SSLDummyStreamBase { + public: + SSLDummyStreamDTLS(SSLStreamAdapterTestBase* test, + absl::string_view side, + BufferQueueStream* in, + BufferQueueStream* out) + : SSLDummyStreamBase(test, side, in, out) {} +}; + +static const int kFifoBufferSize = 4096; +static const int kBufferCapacity = 1; +static const size_t kDefaultBufferSize = 2048; + +class SSLStreamAdapterTestBase : public ::testing::Test, + public sigslot::has_slots<> { + public: + SSLStreamAdapterTestBase( + absl::string_view client_cert_pem, + absl::string_view client_private_key_pem, + bool dtls, + rtc::KeyParams client_key_type = rtc::KeyParams(rtc::KT_DEFAULT), + rtc::KeyParams server_key_type = rtc::KeyParams(rtc::KT_DEFAULT)) + : client_cert_pem_(client_cert_pem), + client_private_key_pem_(client_private_key_pem), + client_key_type_(client_key_type), + server_key_type_(server_key_type), + client_stream_(nullptr), + server_stream_(nullptr), + delay_(0), + mtu_(1460), + loss_(0), + lose_first_packet_(false), + damage_(false), + dtls_(dtls), + handshake_wait_(5000), + identities_set_(false) { + // Set use of the test RNG to get predictable loss patterns. + rtc::SetRandomTestMode(true); + } + + ~SSLStreamAdapterTestBase() override { + // Put it back for the next test. + rtc::SetRandomTestMode(false); + } + + void SetUp() override { + CreateStreams(); + + client_ssl_ = + rtc::SSLStreamAdapter::Create(absl::WrapUnique(client_stream_)); + server_ssl_ = + rtc::SSLStreamAdapter::Create(absl::WrapUnique(server_stream_)); + + // Set up the slots + client_ssl_->SignalEvent.connect(this, &SSLStreamAdapterTestBase::OnEvent); + server_ssl_->SignalEvent.connect(this, &SSLStreamAdapterTestBase::OnEvent); + + std::unique_ptr<rtc::SSLIdentity> client_identity; + if (!client_cert_pem_.empty() && !client_private_key_pem_.empty()) { + client_identity = rtc::SSLIdentity::CreateFromPEMStrings( + client_private_key_pem_, client_cert_pem_); + } else { + client_identity = rtc::SSLIdentity::Create("client", client_key_type_); + } + auto server_identity = rtc::SSLIdentity::Create("server", server_key_type_); + + client_ssl_->SetIdentity(std::move(client_identity)); + server_ssl_->SetIdentity(std::move(server_identity)); + } + + void TearDown() override { + client_ssl_.reset(nullptr); + server_ssl_.reset(nullptr); + } + + virtual void CreateStreams() = 0; + + // Recreate the client/server identities with the specified validity period. + // `not_before` and `not_after` are offsets from the current time in number + // of seconds. + void ResetIdentitiesWithValidity(int not_before, int not_after) { + CreateStreams(); + + client_ssl_ = + rtc::SSLStreamAdapter::Create(absl::WrapUnique(client_stream_)); + server_ssl_ = + rtc::SSLStreamAdapter::Create(absl::WrapUnique(server_stream_)); + + client_ssl_->SignalEvent.connect(this, &SSLStreamAdapterTestBase::OnEvent); + server_ssl_->SignalEvent.connect(this, &SSLStreamAdapterTestBase::OnEvent); + + time_t now = time(nullptr); + + rtc::SSLIdentityParams client_params; + client_params.key_params = rtc::KeyParams(rtc::KT_DEFAULT); + client_params.common_name = "client"; + client_params.not_before = now + not_before; + client_params.not_after = now + not_after; + auto client_identity = rtc::SSLIdentity::CreateForTest(client_params); + + rtc::SSLIdentityParams server_params; + server_params.key_params = rtc::KeyParams(rtc::KT_DEFAULT); + server_params.common_name = "server"; + server_params.not_before = now + not_before; + server_params.not_after = now + not_after; + auto server_identity = rtc::SSLIdentity::CreateForTest(server_params); + + client_ssl_->SetIdentity(std::move(client_identity)); + server_ssl_->SetIdentity(std::move(server_identity)); + } + + virtual void OnEvent(rtc::StreamInterface* stream, int sig, int err) { + RTC_LOG(LS_VERBOSE) << "SSLStreamAdapterTestBase::OnEvent sig=" << sig; + + if (sig & rtc::SE_READ) { + ReadData(stream); + } + + if ((stream == client_ssl_.get()) && (sig & rtc::SE_WRITE)) { + WriteData(); + } + } + + void SetPeerIdentitiesByDigest(bool correct, bool expect_success) { + unsigned char server_digest[20]; + size_t server_digest_len; + unsigned char client_digest[20]; + size_t client_digest_len; + bool rv; + rtc::SSLPeerCertificateDigestError err; + rtc::SSLPeerCertificateDigestError expected_err = + expect_success + ? rtc::SSLPeerCertificateDigestError::NONE + : rtc::SSLPeerCertificateDigestError::VERIFICATION_FAILED; + + RTC_LOG(LS_INFO) << "Setting peer identities by digest"; + + rv = server_identity()->certificate().ComputeDigest( + rtc::DIGEST_SHA_1, server_digest, 20, &server_digest_len); + ASSERT_TRUE(rv); + rv = client_identity()->certificate().ComputeDigest( + rtc::DIGEST_SHA_1, client_digest, 20, &client_digest_len); + ASSERT_TRUE(rv); + + if (!correct) { + RTC_LOG(LS_INFO) << "Setting bogus digest for server cert"; + server_digest[0]++; + } + rv = client_ssl_->SetPeerCertificateDigest(rtc::DIGEST_SHA_1, server_digest, + server_digest_len, &err); + EXPECT_EQ(expected_err, err); + EXPECT_EQ(expect_success, rv); + + if (!correct) { + RTC_LOG(LS_INFO) << "Setting bogus digest for client cert"; + client_digest[0]++; + } + rv = server_ssl_->SetPeerCertificateDigest(rtc::DIGEST_SHA_1, client_digest, + client_digest_len, &err); + EXPECT_EQ(expected_err, err); + EXPECT_EQ(expect_success, rv); + + identities_set_ = true; + } + + void SetupProtocolVersions(rtc::SSLProtocolVersion server_version, + rtc::SSLProtocolVersion client_version) { + server_ssl_->SetMaxProtocolVersion(server_version); + client_ssl_->SetMaxProtocolVersion(client_version); + } + + void TestHandshake(bool expect_success = true) { + server_ssl_->SetMode(dtls_ ? rtc::SSL_MODE_DTLS : rtc::SSL_MODE_TLS); + client_ssl_->SetMode(dtls_ ? rtc::SSL_MODE_DTLS : rtc::SSL_MODE_TLS); + + if (!dtls_) { + // Make sure we simulate a reliable network for TLS. + // This is just a check to make sure that people don't write wrong + // tests. + RTC_CHECK_EQ(1460, mtu_); + RTC_CHECK(!loss_); + RTC_CHECK(!lose_first_packet_); + } + + if (!identities_set_) + SetPeerIdentitiesByDigest(true, true); + + // Start the handshake + int rv; + + server_ssl_->SetServerRole(); + rv = server_ssl_->StartSSL(); + ASSERT_EQ(0, rv); + + rv = client_ssl_->StartSSL(); + ASSERT_EQ(0, rv); + + // Now run the handshake + if (expect_success) { + EXPECT_TRUE_WAIT((client_ssl_->GetState() == rtc::SS_OPEN) && + (server_ssl_->GetState() == rtc::SS_OPEN), + handshake_wait_); + } else { + EXPECT_TRUE_WAIT(client_ssl_->GetState() == rtc::SS_CLOSED, + handshake_wait_); + } + } + + // This tests that we give up after 12 DTLS resends. + void TestHandshakeTimeout() { + rtc::ScopedFakeClock clock; + int64_t time_start = clock.TimeNanos(); + webrtc::TimeDelta time_increment = webrtc::TimeDelta::Millis(1000); + server_ssl_->SetMode(dtls_ ? rtc::SSL_MODE_DTLS : rtc::SSL_MODE_TLS); + client_ssl_->SetMode(dtls_ ? rtc::SSL_MODE_DTLS : rtc::SSL_MODE_TLS); + + if (!dtls_) { + // Make sure we simulate a reliable network for TLS. + // This is just a check to make sure that people don't write wrong + // tests. + RTC_CHECK_EQ(1460, mtu_); + RTC_CHECK(!loss_); + RTC_CHECK(!lose_first_packet_); + } + + if (!identities_set_) + SetPeerIdentitiesByDigest(true, true); + + // Start the handshake + int rv; + + server_ssl_->SetServerRole(); + rv = server_ssl_->StartSSL(); + ASSERT_EQ(0, rv); + + rv = client_ssl_->StartSSL(); + ASSERT_EQ(0, rv); + + // Now wait for the handshake to timeout (or fail after an hour of simulated + // time). + while (client_ssl_->GetState() == rtc::SS_OPENING && + (rtc::TimeDiff(clock.TimeNanos(), time_start) < + 3600 * rtc::kNumNanosecsPerSec)) { + EXPECT_TRUE_WAIT(!((client_ssl_->GetState() == rtc::SS_OPEN) && + (server_ssl_->GetState() == rtc::SS_OPEN)), + 1000); + clock.AdvanceTime(time_increment); + } + RTC_CHECK_EQ(client_ssl_->GetState(), rtc::SS_CLOSED); + } + + // This tests that the handshake can complete before the identity is verified, + // and the identity will be verified after the fact. It also verifies that + // packets can't be read or written before the identity has been verified. + void TestHandshakeWithDelayedIdentity(bool valid_identity) { + server_ssl_->SetMode(dtls_ ? rtc::SSL_MODE_DTLS : rtc::SSL_MODE_TLS); + client_ssl_->SetMode(dtls_ ? rtc::SSL_MODE_DTLS : rtc::SSL_MODE_TLS); + + if (!dtls_) { + // Make sure we simulate a reliable network for TLS. + // This is just a check to make sure that people don't write wrong + // tests. + RTC_CHECK_EQ(1460, mtu_); + RTC_CHECK(!loss_); + RTC_CHECK(!lose_first_packet_); + } + + // Start the handshake + server_ssl_->SetServerRole(); + ASSERT_EQ(0, server_ssl_->StartSSL()); + ASSERT_EQ(0, client_ssl_->StartSSL()); + + // Now run the handshake. + EXPECT_TRUE_WAIT( + client_ssl_->IsTlsConnected() && server_ssl_->IsTlsConnected(), + handshake_wait_); + + // Until the identity has been verified, the state should still be + // SS_OPENING and writes should return SR_BLOCK. + EXPECT_EQ(rtc::SS_OPENING, client_ssl_->GetState()); + EXPECT_EQ(rtc::SS_OPENING, server_ssl_->GetState()); + uint8_t packet[1]; + size_t sent; + int error; + EXPECT_EQ(rtc::SR_BLOCK, client_ssl_->Write(packet, sent, error)); + EXPECT_EQ(rtc::SR_BLOCK, server_ssl_->Write(packet, sent, error)); + + // Collect both of the certificate digests; needs to be done before calling + // SetPeerCertificateDigest as that may reset the identity. + unsigned char server_digest[20]; + size_t server_digest_len; + unsigned char client_digest[20]; + size_t client_digest_len; + bool rv; + + rv = server_identity()->certificate().ComputeDigest( + rtc::DIGEST_SHA_1, server_digest, 20, &server_digest_len); + ASSERT_TRUE(rv); + rv = client_identity()->certificate().ComputeDigest( + rtc::DIGEST_SHA_1, client_digest, 20, &client_digest_len); + ASSERT_TRUE(rv); + + if (!valid_identity) { + RTC_LOG(LS_INFO) << "Setting bogus digest for client/server certs"; + client_digest[0]++; + server_digest[0]++; + } + + // Set the peer certificate digest for the client. + rtc::SSLPeerCertificateDigestError err; + rtc::SSLPeerCertificateDigestError expected_err = + valid_identity + ? rtc::SSLPeerCertificateDigestError::NONE + : rtc::SSLPeerCertificateDigestError::VERIFICATION_FAILED; + rv = client_ssl_->SetPeerCertificateDigest(rtc::DIGEST_SHA_1, server_digest, + server_digest_len, &err); + EXPECT_EQ(expected_err, err); + EXPECT_EQ(valid_identity, rv); + // State should then transition to SS_OPEN or SS_CLOSED based on validation + // of the identity. + if (valid_identity) { + EXPECT_EQ(rtc::SS_OPEN, client_ssl_->GetState()); + // If the client sends a packet while the server still hasn't verified the + // client identity, the server should continue to return SR_BLOCK. + int error; + EXPECT_EQ(rtc::SR_SUCCESS, client_ssl_->Write(packet, sent, error)); + size_t read; + EXPECT_EQ(rtc::SR_BLOCK, server_ssl_->Read(packet, read, error)); + } else { + EXPECT_EQ(rtc::SS_CLOSED, client_ssl_->GetState()); + } + + // Set the peer certificate digest for the server. + rv = server_ssl_->SetPeerCertificateDigest(rtc::DIGEST_SHA_1, client_digest, + client_digest_len, &err); + EXPECT_EQ(expected_err, err); + EXPECT_EQ(valid_identity, rv); + if (valid_identity) { + EXPECT_EQ(rtc::SS_OPEN, server_ssl_->GetState()); + } else { + EXPECT_EQ(rtc::SS_CLOSED, server_ssl_->GetState()); + } + } + + rtc::StreamResult DataWritten(SSLDummyStreamBase* from, + const void* data, + size_t data_len, + size_t& written, + int& error) { + // Randomly drop loss_ percent of packets + if (rtc::CreateRandomId() % 100 < static_cast<uint32_t>(loss_)) { + RTC_LOG(LS_VERBOSE) << "Randomly dropping packet, size=" << data_len; + written = data_len; + return rtc::SR_SUCCESS; + } + if (dtls_ && (data_len > mtu_)) { + RTC_LOG(LS_VERBOSE) << "Dropping packet > mtu, size=" << data_len; + written = data_len; + return rtc::SR_SUCCESS; + } + + // Optionally damage application data (type 23). Note that we don't damage + // handshake packets and we damage the last byte to keep the header + // intact but break the MAC. + if (damage_ && (*static_cast<const unsigned char*>(data) == 23)) { + std::vector<uint8_t> buf(data_len); + + RTC_LOG(LS_VERBOSE) << "Damaging packet"; + + memcpy(&buf[0], data, data_len); + buf[data_len - 1]++; + return from->WriteData(rtc::MakeArrayView(&buf[0], data_len), written, + error); + } + + return from->WriteData( + rtc::MakeArrayView(reinterpret_cast<const uint8_t*>(data), data_len), + written, error); + } + + void SetDelay(int delay) { delay_ = delay; } + int GetDelay() { return delay_; } + + void SetLoseFirstPacket(bool lose) { lose_first_packet_ = lose; } + bool GetLoseFirstPacket() { return lose_first_packet_; } + + void SetLoss(int percent) { loss_ = percent; } + + void SetDamage() { damage_ = true; } + + void SetMtu(size_t mtu) { mtu_ = mtu; } + + void SetHandshakeWait(int wait) { handshake_wait_ = wait; } + + void SetDtlsSrtpCryptoSuites(const std::vector<int>& ciphers, bool client) { + if (client) + client_ssl_->SetDtlsSrtpCryptoSuites(ciphers); + else + server_ssl_->SetDtlsSrtpCryptoSuites(ciphers); + } + + bool GetDtlsSrtpCryptoSuite(bool client, int* retval) { + if (client) + return client_ssl_->GetDtlsSrtpCryptoSuite(retval); + else + return server_ssl_->GetDtlsSrtpCryptoSuite(retval); + } + + std::unique_ptr<rtc::SSLCertificate> GetPeerCertificate(bool client) { + std::unique_ptr<rtc::SSLCertChain> chain; + if (client) + chain = client_ssl_->GetPeerSSLCertChain(); + else + chain = server_ssl_->GetPeerSSLCertChain(); + return (chain && chain->GetSize()) ? chain->Get(0).Clone() : nullptr; + } + + bool GetSslCipherSuite(bool client, int* retval) { + if (client) + return client_ssl_->GetSslCipherSuite(retval); + else + return server_ssl_->GetSslCipherSuite(retval); + } + + int GetSslVersion(bool client) { + if (client) + return client_ssl_->GetSslVersion(); + else + return server_ssl_->GetSslVersion(); + } + + bool ExportKeyingMaterial(absl::string_view label, + const unsigned char* context, + size_t context_len, + bool use_context, + bool client, + unsigned char* result, + size_t result_len) { + if (client) + return client_ssl_->ExportKeyingMaterial(label, context, context_len, + use_context, result, result_len); + else + return server_ssl_->ExportKeyingMaterial(label, context, context_len, + use_context, result, result_len); + } + + // To be implemented by subclasses. + virtual void WriteData() = 0; + virtual void ReadData(rtc::StreamInterface* stream) = 0; + virtual void TestTransfer(int size) = 0; + + protected: + rtc::SSLIdentity* client_identity() const { + if (!client_ssl_) { + return nullptr; + } + return client_ssl_->GetIdentityForTesting(); + } + rtc::SSLIdentity* server_identity() const { + if (!server_ssl_) { + return nullptr; + } + return server_ssl_->GetIdentityForTesting(); + } + + rtc::AutoThread main_thread_; + std::string client_cert_pem_; + std::string client_private_key_pem_; + rtc::KeyParams client_key_type_; + rtc::KeyParams server_key_type_; + SSLDummyStreamBase* client_stream_; // freed by client_ssl_ destructor + SSLDummyStreamBase* server_stream_; // freed by server_ssl_ destructor + std::unique_ptr<rtc::SSLStreamAdapter> client_ssl_; + std::unique_ptr<rtc::SSLStreamAdapter> server_ssl_; + int delay_; + size_t mtu_; + int loss_; + bool lose_first_packet_; + bool damage_; + bool dtls_; + int handshake_wait_; + bool identities_set_; +}; + +class SSLStreamAdapterTestTLS + : public SSLStreamAdapterTestBase, + public WithParamInterface<tuple<rtc::KeyParams, rtc::KeyParams>> { + public: + SSLStreamAdapterTestTLS() + : SSLStreamAdapterTestBase("", + "", + false, + ::testing::get<0>(GetParam()), + ::testing::get<1>(GetParam())), + client_buffer_(kFifoBufferSize), + server_buffer_(kFifoBufferSize) {} + + void CreateStreams() override { + client_stream_ = + new SSLDummyStreamTLS(this, "c2s", &client_buffer_, &server_buffer_); + server_stream_ = + new SSLDummyStreamTLS(this, "s2c", &server_buffer_, &client_buffer_); + } + + // Test data transfer for TLS + void TestTransfer(int size) override { + RTC_LOG(LS_INFO) << "Starting transfer test with " << size << " bytes"; + // Create some dummy data to send. + size_t received; + + send_stream_.ReserveSize(size); + for (int i = 0; i < size; ++i) { + uint8_t ch = static_cast<uint8_t>(i); + size_t written; + int error; + send_stream_.Write(rtc::MakeArrayView(&ch, 1), written, error); + } + send_stream_.Rewind(); + + // Prepare the receive stream. + recv_stream_.ReserveSize(size); + + // Start sending + WriteData(); + + // Wait for the client to close + EXPECT_TRUE_WAIT(server_ssl_->GetState() == rtc::SS_CLOSED, 10000); + + // Now check the data + recv_stream_.GetSize(&received); + + EXPECT_EQ(static_cast<size_t>(size), received); + EXPECT_EQ(0, + memcmp(send_stream_.GetBuffer(), recv_stream_.GetBuffer(), size)); + } + + void WriteData() override { + size_t position, tosend, size; + rtc::StreamResult rv; + size_t sent; + uint8_t block[kBlockSize]; + + send_stream_.GetSize(&size); + if (!size) + return; + + for (;;) { + send_stream_.GetPosition(&position); + int dummy_error; + if (send_stream_.Read(block, tosend, dummy_error) != rtc::SR_EOS) { + int error; + rv = client_ssl_->Write(rtc::MakeArrayView(block, tosend), sent, error); + + if (rv == rtc::SR_SUCCESS) { + send_stream_.SetPosition(position + sent); + RTC_LOG(LS_VERBOSE) << "Sent: " << position + sent; + } else if (rv == rtc::SR_BLOCK) { + RTC_LOG(LS_VERBOSE) << "Blocked..."; + send_stream_.SetPosition(position); + break; + } else { + ADD_FAILURE(); + break; + } + } else { + // Now close + RTC_LOG(LS_INFO) << "Wrote " << position << " bytes. Closing"; + client_ssl_->Close(); + break; + } + } + } + + void ReadData(rtc::StreamInterface* stream) override { + uint8_t buffer[1600]; + size_t bread; + int err2; + rtc::StreamResult r; + + for (;;) { + r = stream->Read(buffer, bread, err2); + + if (r == rtc::SR_ERROR || r == rtc::SR_EOS) { + // Unfortunately, errors are the way that the stream adapter + // signals close in OpenSSL. + stream->Close(); + return; + } + + if (r == rtc::SR_BLOCK) + break; + + ASSERT_EQ(rtc::SR_SUCCESS, r); + RTC_LOG(LS_VERBOSE) << "Read " << bread; + size_t written; + int error; + recv_stream_.Write(rtc::MakeArrayView(buffer, bread), written, error); + } + } + + private: + rtc::FifoBuffer client_buffer_; + rtc::FifoBuffer server_buffer_; + rtc::MemoryStream send_stream_; + rtc::MemoryStream recv_stream_; +}; + +class SSLStreamAdapterTestDTLSBase : public SSLStreamAdapterTestBase { + public: + SSLStreamAdapterTestDTLSBase(rtc::KeyParams param1, rtc::KeyParams param2) + : SSLStreamAdapterTestBase("", "", true, param1, param2), + client_buffer_(kBufferCapacity, kDefaultBufferSize), + server_buffer_(kBufferCapacity, kDefaultBufferSize), + packet_size_(1000), + count_(0), + sent_(0) {} + + SSLStreamAdapterTestDTLSBase(absl::string_view cert_pem, + absl::string_view private_key_pem) + : SSLStreamAdapterTestBase(cert_pem, private_key_pem, true), + client_buffer_(kBufferCapacity, kDefaultBufferSize), + server_buffer_(kBufferCapacity, kDefaultBufferSize), + packet_size_(1000), + count_(0), + sent_(0) {} + + void CreateStreams() override { + client_stream_ = + new SSLDummyStreamDTLS(this, "c2s", &client_buffer_, &server_buffer_); + server_stream_ = + new SSLDummyStreamDTLS(this, "s2c", &server_buffer_, &client_buffer_); + } + + void WriteData() override { + uint8_t* packet = new uint8_t[1600]; + + while (sent_ < count_) { + unsigned int rand_state = sent_; + packet[0] = sent_; + for (size_t i = 1; i < packet_size_; i++) { + // This is a simple LC PRNG. Keep in synch with identical code below. + rand_state = (rand_state * 251 + 19937) >> 7; + packet[i] = rand_state & 0xff; + } + + size_t sent; + int error; + rtc::StreamResult rv = client_ssl_->Write( + rtc::MakeArrayView(packet, packet_size_), sent, error); + if (rv == rtc::SR_SUCCESS) { + RTC_LOG(LS_VERBOSE) << "Sent: " << sent_; + sent_++; + } else if (rv == rtc::SR_BLOCK) { + RTC_LOG(LS_VERBOSE) << "Blocked..."; + break; + } else { + ADD_FAILURE(); + break; + } + } + + delete[] packet; + } + + void ReadData(rtc::StreamInterface* stream) override { + uint8_t buffer[2000]; + size_t bread; + int err2; + rtc::StreamResult r; + + for (;;) { + r = stream->Read(buffer, bread, err2); + + if (r == rtc::SR_ERROR) { + // Unfortunately, errors are the way that the stream adapter + // signals close right now + stream->Close(); + return; + } + + if (r == rtc::SR_BLOCK) + break; + + ASSERT_EQ(rtc::SR_SUCCESS, r); + RTC_LOG(LS_VERBOSE) << "Read " << bread; + + // Now parse the datagram + ASSERT_EQ(packet_size_, bread); + unsigned char packet_num = buffer[0]; + + unsigned int rand_state = packet_num; + for (size_t i = 1; i < packet_size_; i++) { + // This is a simple LC PRNG. Keep in synch with identical code above. + rand_state = (rand_state * 251 + 19937) >> 7; + ASSERT_EQ(rand_state & 0xff, buffer[i]); + } + received_.insert(packet_num); + } + } + + void TestTransfer(int count) override { + count_ = count; + + WriteData(); + + EXPECT_TRUE_WAIT(sent_ == count_, 10000); + RTC_LOG(LS_INFO) << "sent_ == " << sent_; + + if (damage_) { + WAIT(false, 2000); + EXPECT_EQ(0U, received_.size()); + } else if (loss_ == 0) { + EXPECT_EQ_WAIT(static_cast<size_t>(sent_), received_.size(), 1000); + } else { + RTC_LOG(LS_INFO) << "Sent " << sent_ << " packets; received " + << received_.size(); + } + } + + protected: + BufferQueueStream client_buffer_; + BufferQueueStream server_buffer_; + + private: + size_t packet_size_; + int count_; + int sent_; + std::set<int> received_; +}; + +class SSLStreamAdapterTestDTLS + : public SSLStreamAdapterTestDTLSBase, + public WithParamInterface<tuple<rtc::KeyParams, rtc::KeyParams>> { + public: + SSLStreamAdapterTestDTLS() + : SSLStreamAdapterTestDTLSBase(::testing::get<0>(GetParam()), + ::testing::get<1>(GetParam())) {} + + SSLStreamAdapterTestDTLS(absl::string_view cert_pem, + absl::string_view private_key_pem) + : SSLStreamAdapterTestDTLSBase(cert_pem, private_key_pem) {} +}; + +rtc::StreamResult SSLDummyStreamBase::Write(rtc::ArrayView<const uint8_t> data, + size_t& written, + int& error) { + RTC_LOG(LS_VERBOSE) << "Writing to loopback " << data.size(); + + if (first_packet_) { + first_packet_ = false; + if (test_base_->GetLoseFirstPacket()) { + RTC_LOG(LS_INFO) << "Losing initial packet of length " << data.size(); + written = data.size(); // Fake successful writing also to writer. + return rtc::SR_SUCCESS; + } + } + + return test_base_->DataWritten(this, data.data(), data.size(), written, + error); +} + +class SSLStreamAdapterTestDTLSFromPEMStrings : public SSLStreamAdapterTestDTLS { + public: + SSLStreamAdapterTestDTLSFromPEMStrings() + : SSLStreamAdapterTestDTLS(kCERT_PEM, kRSA_PRIVATE_KEY_PEM) {} +}; + +// Test fixture for certificate chaining. Server will push more than one +// certificate. +class SSLStreamAdapterTestDTLSCertChain : public SSLStreamAdapterTestDTLS { + public: + SSLStreamAdapterTestDTLSCertChain() : SSLStreamAdapterTestDTLS("", "") {} + void SetUp() override { + CreateStreams(); + + client_ssl_ = + rtc::SSLStreamAdapter::Create(absl::WrapUnique(client_stream_)); + server_ssl_ = + rtc::SSLStreamAdapter::Create(absl::WrapUnique(server_stream_)); + + // Set up the slots + client_ssl_->SignalEvent.connect( + reinterpret_cast<SSLStreamAdapterTestBase*>(this), + &SSLStreamAdapterTestBase::OnEvent); + server_ssl_->SignalEvent.connect( + reinterpret_cast<SSLStreamAdapterTestBase*>(this), + &SSLStreamAdapterTestBase::OnEvent); + + std::unique_ptr<rtc::SSLIdentity> client_identity; + if (!client_cert_pem_.empty() && !client_private_key_pem_.empty()) { + client_identity = rtc::SSLIdentity::CreateFromPEMStrings( + client_private_key_pem_, client_cert_pem_); + } else { + client_identity = rtc::SSLIdentity::Create("client", client_key_type_); + } + + client_ssl_->SetIdentity(std::move(client_identity)); + } +}; + +// Basic tests: TLS + +// Test that we can make a handshake work +TEST_P(SSLStreamAdapterTestTLS, TestTLSConnect) { + TestHandshake(); +} + +TEST_P(SSLStreamAdapterTestTLS, GetPeerCertChainWithOneCertificate) { + TestHandshake(); + std::unique_ptr<rtc::SSLCertChain> cert_chain = + client_ssl_->GetPeerSSLCertChain(); + ASSERT_NE(nullptr, cert_chain); + EXPECT_EQ(1u, cert_chain->GetSize()); + EXPECT_EQ(cert_chain->Get(0).ToPEMString(), + server_identity()->certificate().ToPEMString()); +} + +TEST_F(SSLStreamAdapterTestDTLSCertChain, TwoCertHandshake) { + auto server_identity = rtc::SSLIdentity::CreateFromPEMChainStrings( + kRSA_PRIVATE_KEY_PEM, std::string(kCERT_PEM) + kCACert); + server_ssl_->SetIdentity(std::move(server_identity)); + TestHandshake(); + std::unique_ptr<rtc::SSLCertChain> peer_cert_chain = + client_ssl_->GetPeerSSLCertChain(); + ASSERT_NE(nullptr, peer_cert_chain); + EXPECT_EQ(kCERT_PEM, peer_cert_chain->Get(0).ToPEMString()); + // TODO(bugs.webrtc.org/15153): Fix peer_cert_chain to return multiple + // certificates under OpenSSL. Today it only works with BoringSSL. +#ifdef OPENSSL_IS_BORINGSSL + ASSERT_EQ(2u, peer_cert_chain->GetSize()); + EXPECT_EQ(kCACert, peer_cert_chain->Get(1).ToPEMString()); +#endif +} + +TEST_F(SSLStreamAdapterTestDTLSCertChain, TwoCertHandshakeWithCopy) { + server_ssl_->SetIdentity(rtc::SSLIdentity::CreateFromPEMChainStrings( + kRSA_PRIVATE_KEY_PEM, std::string(kCERT_PEM) + kCACert)); + TestHandshake(); + std::unique_ptr<rtc::SSLCertChain> peer_cert_chain = + client_ssl_->GetPeerSSLCertChain(); + ASSERT_NE(nullptr, peer_cert_chain); + EXPECT_EQ(kCERT_PEM, peer_cert_chain->Get(0).ToPEMString()); + // TODO(bugs.webrtc.org/15153): Fix peer_cert_chain to return multiple + // certificates under OpenSSL. Today it only works with BoringSSL. +#ifdef OPENSSL_IS_BORINGSSL + ASSERT_EQ(2u, peer_cert_chain->GetSize()); + EXPECT_EQ(kCACert, peer_cert_chain->Get(1).ToPEMString()); +#endif +} + +TEST_F(SSLStreamAdapterTestDTLSCertChain, ThreeCertHandshake) { + server_ssl_->SetIdentity(rtc::SSLIdentity::CreateFromPEMChainStrings( + kRSA_PRIVATE_KEY_PEM, std::string(kCERT_PEM) + kIntCert1 + kCACert)); + TestHandshake(); + std::unique_ptr<rtc::SSLCertChain> peer_cert_chain = + client_ssl_->GetPeerSSLCertChain(); + ASSERT_NE(nullptr, peer_cert_chain); + EXPECT_EQ(kCERT_PEM, peer_cert_chain->Get(0).ToPEMString()); + // TODO(bugs.webrtc.org/15153): Fix peer_cert_chain to return multiple + // certificates under OpenSSL. Today it only works with BoringSSL. +#ifdef OPENSSL_IS_BORINGSSL + ASSERT_EQ(3u, peer_cert_chain->GetSize()); + EXPECT_EQ(kIntCert1, peer_cert_chain->Get(1).ToPEMString()); + EXPECT_EQ(kCACert, peer_cert_chain->Get(2).ToPEMString()); +#endif +} + +// Test that closing the connection on one side updates the other side. +TEST_P(SSLStreamAdapterTestTLS, TestTLSClose) { + TestHandshake(); + client_ssl_->Close(); + EXPECT_EQ_WAIT(rtc::SS_CLOSED, server_ssl_->GetState(), handshake_wait_); +} + +// Test transfer -- trivial +TEST_P(SSLStreamAdapterTestTLS, TestTLSTransfer) { + TestHandshake(); + TestTransfer(100000); +} + +// Test read-write after close. +TEST_P(SSLStreamAdapterTestTLS, ReadWriteAfterClose) { + TestHandshake(); + TestTransfer(100000); + client_ssl_->Close(); + + rtc::StreamResult rv; + uint8_t block[kBlockSize]; + size_t dummy; + int error; + + // It's an error to write after closed. + rv = client_ssl_->Write(block, dummy, error); + ASSERT_EQ(rtc::SR_ERROR, rv); + + // But after closed read gives you EOS. + rv = client_ssl_->Read(block, dummy, error); + ASSERT_EQ(rtc::SR_EOS, rv); +} + +// Test a handshake with a bogus peer digest +TEST_P(SSLStreamAdapterTestTLS, TestTLSBogusDigest) { + SetPeerIdentitiesByDigest(false, true); + TestHandshake(false); +} + +TEST_P(SSLStreamAdapterTestTLS, TestTLSDelayedIdentity) { + TestHandshakeWithDelayedIdentity(true); +} + +TEST_P(SSLStreamAdapterTestTLS, TestTLSDelayedIdentityWithBogusDigest) { + TestHandshakeWithDelayedIdentity(false); +} + +// Test that the correct error is returned when SetPeerCertificateDigest is +// called with an unknown algorithm. +TEST_P(SSLStreamAdapterTestTLS, + TestSetPeerCertificateDigestWithUnknownAlgorithm) { + unsigned char server_digest[20]; + size_t server_digest_len; + bool rv; + rtc::SSLPeerCertificateDigestError err; + + rv = server_identity()->certificate().ComputeDigest( + rtc::DIGEST_SHA_1, server_digest, 20, &server_digest_len); + ASSERT_TRUE(rv); + + rv = client_ssl_->SetPeerCertificateDigest("unknown algorithm", server_digest, + server_digest_len, &err); + EXPECT_EQ(rtc::SSLPeerCertificateDigestError::UNKNOWN_ALGORITHM, err); + EXPECT_FALSE(rv); +} + +// Test that the correct error is returned when SetPeerCertificateDigest is +// called with an invalid digest length. +TEST_P(SSLStreamAdapterTestTLS, TestSetPeerCertificateDigestWithInvalidLength) { + unsigned char server_digest[20]; + size_t server_digest_len; + bool rv; + rtc::SSLPeerCertificateDigestError err; + + rv = server_identity()->certificate().ComputeDigest( + rtc::DIGEST_SHA_1, server_digest, 20, &server_digest_len); + ASSERT_TRUE(rv); + + rv = client_ssl_->SetPeerCertificateDigest(rtc::DIGEST_SHA_1, server_digest, + server_digest_len - 1, &err); + EXPECT_EQ(rtc::SSLPeerCertificateDigestError::INVALID_LENGTH, err); + EXPECT_FALSE(rv); +} + +// Test moving a bunch of data + +// Basic tests: DTLS +// Test that we can make a handshake work +TEST_P(SSLStreamAdapterTestDTLS, TestDTLSConnect) { + TestHandshake(); +} + +// Test that we can make a handshake work if the first packet in +// each direction is lost. This gives us predictable loss +// rather than having to tune random +TEST_P(SSLStreamAdapterTestDTLS, TestDTLSConnectWithLostFirstPacket) { + SetLoseFirstPacket(true); + TestHandshake(); +} + +// Test a handshake with loss and delay +TEST_P(SSLStreamAdapterTestDTLS, TestDTLSConnectWithLostFirstPacketDelay2s) { + SetLoseFirstPacket(true); + SetDelay(2000); + SetHandshakeWait(20000); + TestHandshake(); +} + +// Test a handshake with small MTU +// Disabled due to https://code.google.com/p/webrtc/issues/detail?id=3910 +TEST_P(SSLStreamAdapterTestDTLS, DISABLED_TestDTLSConnectWithSmallMtu) { + SetMtu(700); + SetHandshakeWait(20000); + TestHandshake(); +} + +// Test a handshake with total loss and timing out. +TEST_P(SSLStreamAdapterTestDTLS, TestDTLSConnectTimeout) { + SetLoss(100); + TestHandshakeTimeout(); +} + +// Test transfer -- trivial +TEST_P(SSLStreamAdapterTestDTLS, TestDTLSTransfer) { + TestHandshake(); + TestTransfer(100); +} + +TEST_P(SSLStreamAdapterTestDTLS, TestDTLSTransferWithLoss) { + TestHandshake(); + SetLoss(10); + TestTransfer(100); +} + +TEST_P(SSLStreamAdapterTestDTLS, TestDTLSTransferWithDamage) { + SetDamage(); // Must be called first because first packet + // write happens at end of handshake. + TestHandshake(); + TestTransfer(100); +} + +TEST_P(SSLStreamAdapterTestDTLS, TestDTLSDelayedIdentity) { + TestHandshakeWithDelayedIdentity(true); +} + +TEST_P(SSLStreamAdapterTestDTLS, TestDTLSDelayedIdentityWithBogusDigest) { + TestHandshakeWithDelayedIdentity(false); +} + +// Test DTLS-SRTP with all high ciphers +TEST_P(SSLStreamAdapterTestDTLS, TestDTLSSrtpHigh) { + std::vector<int> high; + high.push_back(rtc::kSrtpAes128CmSha1_80); + SetDtlsSrtpCryptoSuites(high, true); + SetDtlsSrtpCryptoSuites(high, false); + TestHandshake(); + + int client_cipher; + ASSERT_TRUE(GetDtlsSrtpCryptoSuite(true, &client_cipher)); + int server_cipher; + ASSERT_TRUE(GetDtlsSrtpCryptoSuite(false, &server_cipher)); + + ASSERT_EQ(client_cipher, server_cipher); + ASSERT_EQ(client_cipher, rtc::kSrtpAes128CmSha1_80); +} + +// Test DTLS-SRTP with all low ciphers +TEST_P(SSLStreamAdapterTestDTLS, TestDTLSSrtpLow) { + std::vector<int> low; + low.push_back(rtc::kSrtpAes128CmSha1_32); + SetDtlsSrtpCryptoSuites(low, true); + SetDtlsSrtpCryptoSuites(low, false); + TestHandshake(); + + int client_cipher; + ASSERT_TRUE(GetDtlsSrtpCryptoSuite(true, &client_cipher)); + int server_cipher; + ASSERT_TRUE(GetDtlsSrtpCryptoSuite(false, &server_cipher)); + + ASSERT_EQ(client_cipher, server_cipher); + ASSERT_EQ(client_cipher, rtc::kSrtpAes128CmSha1_32); +} + +// Test DTLS-SRTP with a mismatch -- should not converge +TEST_P(SSLStreamAdapterTestDTLS, TestDTLSSrtpHighLow) { + std::vector<int> high; + high.push_back(rtc::kSrtpAes128CmSha1_80); + std::vector<int> low; + low.push_back(rtc::kSrtpAes128CmSha1_32); + SetDtlsSrtpCryptoSuites(high, true); + SetDtlsSrtpCryptoSuites(low, false); + TestHandshake(); + + int client_cipher; + ASSERT_FALSE(GetDtlsSrtpCryptoSuite(true, &client_cipher)); + int server_cipher; + ASSERT_FALSE(GetDtlsSrtpCryptoSuite(false, &server_cipher)); +} + +// Test DTLS-SRTP with each side being mixed -- should select high +TEST_P(SSLStreamAdapterTestDTLS, TestDTLSSrtpMixed) { + std::vector<int> mixed; + mixed.push_back(rtc::kSrtpAes128CmSha1_80); + mixed.push_back(rtc::kSrtpAes128CmSha1_32); + SetDtlsSrtpCryptoSuites(mixed, true); + SetDtlsSrtpCryptoSuites(mixed, false); + TestHandshake(); + + int client_cipher; + ASSERT_TRUE(GetDtlsSrtpCryptoSuite(true, &client_cipher)); + int server_cipher; + ASSERT_TRUE(GetDtlsSrtpCryptoSuite(false, &server_cipher)); + + ASSERT_EQ(client_cipher, server_cipher); + ASSERT_EQ(client_cipher, rtc::kSrtpAes128CmSha1_80); +} + +// Test DTLS-SRTP with all GCM-128 ciphers. +TEST_P(SSLStreamAdapterTestDTLS, TestDTLSSrtpGCM128) { + std::vector<int> gcm128; + gcm128.push_back(rtc::kSrtpAeadAes128Gcm); + SetDtlsSrtpCryptoSuites(gcm128, true); + SetDtlsSrtpCryptoSuites(gcm128, false); + TestHandshake(); + + int client_cipher; + ASSERT_TRUE(GetDtlsSrtpCryptoSuite(true, &client_cipher)); + int server_cipher; + ASSERT_TRUE(GetDtlsSrtpCryptoSuite(false, &server_cipher)); + + ASSERT_EQ(client_cipher, server_cipher); + ASSERT_EQ(client_cipher, rtc::kSrtpAeadAes128Gcm); +} + +// Test DTLS-SRTP with all GCM-256 ciphers. +TEST_P(SSLStreamAdapterTestDTLS, TestDTLSSrtpGCM256) { + std::vector<int> gcm256; + gcm256.push_back(rtc::kSrtpAeadAes256Gcm); + SetDtlsSrtpCryptoSuites(gcm256, true); + SetDtlsSrtpCryptoSuites(gcm256, false); + TestHandshake(); + + int client_cipher; + ASSERT_TRUE(GetDtlsSrtpCryptoSuite(true, &client_cipher)); + int server_cipher; + ASSERT_TRUE(GetDtlsSrtpCryptoSuite(false, &server_cipher)); + + ASSERT_EQ(client_cipher, server_cipher); + ASSERT_EQ(client_cipher, rtc::kSrtpAeadAes256Gcm); +} + +// Test DTLS-SRTP with mixed GCM-128/-256 ciphers -- should not converge. +TEST_P(SSLStreamAdapterTestDTLS, TestDTLSSrtpGCMMismatch) { + std::vector<int> gcm128; + gcm128.push_back(rtc::kSrtpAeadAes128Gcm); + std::vector<int> gcm256; + gcm256.push_back(rtc::kSrtpAeadAes256Gcm); + SetDtlsSrtpCryptoSuites(gcm128, true); + SetDtlsSrtpCryptoSuites(gcm256, false); + TestHandshake(); + + int client_cipher; + ASSERT_FALSE(GetDtlsSrtpCryptoSuite(true, &client_cipher)); + int server_cipher; + ASSERT_FALSE(GetDtlsSrtpCryptoSuite(false, &server_cipher)); +} + +// Test DTLS-SRTP with both GCM-128/-256 ciphers -- should select GCM-256. +TEST_P(SSLStreamAdapterTestDTLS, TestDTLSSrtpGCMMixed) { + std::vector<int> gcmBoth; + gcmBoth.push_back(rtc::kSrtpAeadAes256Gcm); + gcmBoth.push_back(rtc::kSrtpAeadAes128Gcm); + SetDtlsSrtpCryptoSuites(gcmBoth, true); + SetDtlsSrtpCryptoSuites(gcmBoth, false); + TestHandshake(); + + int client_cipher; + ASSERT_TRUE(GetDtlsSrtpCryptoSuite(true, &client_cipher)); + int server_cipher; + ASSERT_TRUE(GetDtlsSrtpCryptoSuite(false, &server_cipher)); + + ASSERT_EQ(client_cipher, server_cipher); + ASSERT_EQ(client_cipher, rtc::kSrtpAeadAes256Gcm); +} + +// Test SRTP cipher suite lengths. +TEST_P(SSLStreamAdapterTestDTLS, TestDTLSSrtpKeyAndSaltLengths) { + int key_len; + int salt_len; + + ASSERT_FALSE(rtc::GetSrtpKeyAndSaltLengths(rtc::kSrtpInvalidCryptoSuite, + &key_len, &salt_len)); + + ASSERT_TRUE(rtc::GetSrtpKeyAndSaltLengths(rtc::kSrtpAes128CmSha1_32, &key_len, + &salt_len)); + ASSERT_EQ(128 / 8, key_len); + ASSERT_EQ(112 / 8, salt_len); + + ASSERT_TRUE(rtc::GetSrtpKeyAndSaltLengths(rtc::kSrtpAes128CmSha1_80, &key_len, + &salt_len)); + ASSERT_EQ(128 / 8, key_len); + ASSERT_EQ(112 / 8, salt_len); + + ASSERT_TRUE(rtc::GetSrtpKeyAndSaltLengths(rtc::kSrtpAeadAes128Gcm, &key_len, + &salt_len)); + ASSERT_EQ(128 / 8, key_len); + ASSERT_EQ(96 / 8, salt_len); + + ASSERT_TRUE(rtc::GetSrtpKeyAndSaltLengths(rtc::kSrtpAeadAes256Gcm, &key_len, + &salt_len)); + ASSERT_EQ(256 / 8, key_len); + ASSERT_EQ(96 / 8, salt_len); +} + +// Test an exporter +TEST_P(SSLStreamAdapterTestDTLS, TestDTLSExporter) { + TestHandshake(); + unsigned char client_out[20]; + unsigned char server_out[20]; + + bool result; + result = ExportKeyingMaterial(kExporterLabel, kExporterContext, + kExporterContextLen, true, true, client_out, + sizeof(client_out)); + ASSERT_TRUE(result); + + result = ExportKeyingMaterial(kExporterLabel, kExporterContext, + kExporterContextLen, true, false, server_out, + sizeof(server_out)); + ASSERT_TRUE(result); + + ASSERT_TRUE(!memcmp(client_out, server_out, sizeof(client_out))); +} + +// Test not yet valid certificates are not rejected. +TEST_P(SSLStreamAdapterTestDTLS, TestCertNotYetValid) { + long one_day = 60 * 60 * 24; + // Make the certificates not valid until one day later. + ResetIdentitiesWithValidity(one_day, one_day); + TestHandshake(); +} + +// Test expired certificates are not rejected. +TEST_P(SSLStreamAdapterTestDTLS, TestCertExpired) { + long one_day = 60 * 60 * 24; + // Make the certificates already expired. + ResetIdentitiesWithValidity(-one_day, -one_day); + TestHandshake(); +} + +// Test data transfer using certs created from strings. +TEST_F(SSLStreamAdapterTestDTLSFromPEMStrings, TestTransfer) { + TestHandshake(); + TestTransfer(100); +} + +// Test getting the remote certificate. +TEST_F(SSLStreamAdapterTestDTLSFromPEMStrings, TestDTLSGetPeerCertificate) { + // Peer certificates haven't been received yet. + ASSERT_FALSE(GetPeerCertificate(true)); + ASSERT_FALSE(GetPeerCertificate(false)); + + TestHandshake(); + + // The client should have a peer certificate after the handshake. + std::unique_ptr<rtc::SSLCertificate> client_peer_cert = + GetPeerCertificate(true); + ASSERT_TRUE(client_peer_cert); + + // It's not kCERT_PEM. + std::string client_peer_string = client_peer_cert->ToPEMString(); + ASSERT_NE(kCERT_PEM, client_peer_string); + + // The server should have a peer certificate after the handshake. + std::unique_ptr<rtc::SSLCertificate> server_peer_cert = + GetPeerCertificate(false); + ASSERT_TRUE(server_peer_cert); + + // It's kCERT_PEM + ASSERT_EQ(kCERT_PEM, server_peer_cert->ToPEMString()); +} + +// Test getting the used DTLS 1.2 ciphers. +// DTLS 1.2 enabled for client and server -> DTLS 1.2 will be used. +TEST_P(SSLStreamAdapterTestDTLS, TestGetSslCipherSuiteDtls12Both) { + SetupProtocolVersions(rtc::SSL_PROTOCOL_DTLS_12, rtc::SSL_PROTOCOL_DTLS_12); + TestHandshake(); + + int client_cipher; + ASSERT_TRUE(GetSslCipherSuite(true, &client_cipher)); + int server_cipher; + ASSERT_TRUE(GetSslCipherSuite(false, &server_cipher)); + + ASSERT_EQ(rtc::SSL_PROTOCOL_DTLS_12, GetSslVersion(true)); + ASSERT_EQ(rtc::SSL_PROTOCOL_DTLS_12, GetSslVersion(false)); + + ASSERT_EQ(client_cipher, server_cipher); + ASSERT_TRUE(rtc::SSLStreamAdapter::IsAcceptableCipher( + server_cipher, ::testing::get<1>(GetParam()).type())); +} + +// Test getting the used DTLS ciphers. +// DTLS 1.2 is max version for client and server. +TEST_P(SSLStreamAdapterTestDTLS, TestGetSslCipherSuite) { + SetupProtocolVersions(rtc::SSL_PROTOCOL_DTLS_12, rtc::SSL_PROTOCOL_DTLS_12); + TestHandshake(); + + int client_cipher; + ASSERT_TRUE(GetSslCipherSuite(true, &client_cipher)); + int server_cipher; + ASSERT_TRUE(GetSslCipherSuite(false, &server_cipher)); + + ASSERT_EQ(rtc::SSL_PROTOCOL_DTLS_12, GetSslVersion(true)); + ASSERT_EQ(rtc::SSL_PROTOCOL_DTLS_12, GetSslVersion(false)); + + ASSERT_EQ(client_cipher, server_cipher); + ASSERT_TRUE(rtc::SSLStreamAdapter::IsAcceptableCipher( + server_cipher, ::testing::get<1>(GetParam()).type())); +} + +// The RSA keysizes here might look strange, why not include the RFC's size +// 2048?. The reason is test case slowness; testing two sizes to exercise +// parametrization is sufficient. +INSTANTIATE_TEST_SUITE_P( + SSLStreamAdapterTestsTLS, + SSLStreamAdapterTestTLS, + Combine(Values(rtc::KeyParams::RSA(1024, 65537), + rtc::KeyParams::RSA(1152, 65537), + rtc::KeyParams::ECDSA(rtc::EC_NIST_P256)), + Values(rtc::KeyParams::RSA(1024, 65537), + rtc::KeyParams::RSA(1152, 65537), + rtc::KeyParams::ECDSA(rtc::EC_NIST_P256)))); +INSTANTIATE_TEST_SUITE_P( + SSLStreamAdapterTestsDTLS, + SSLStreamAdapterTestDTLS, + Combine(Values(rtc::KeyParams::RSA(1024, 65537), + rtc::KeyParams::RSA(1152, 65537), + rtc::KeyParams::ECDSA(rtc::EC_NIST_P256)), + Values(rtc::KeyParams::RSA(1024, 65537), + rtc::KeyParams::RSA(1152, 65537), + rtc::KeyParams::ECDSA(rtc::EC_NIST_P256)))); + +// Tests for enabling / disabling legacy TLS protocols in DTLS. +class SSLStreamAdapterTestDTLSLegacyProtocols + : public SSLStreamAdapterTestDTLSBase { + public: + SSLStreamAdapterTestDTLSLegacyProtocols() + : SSLStreamAdapterTestDTLSBase(rtc::KeyParams::ECDSA(rtc::EC_NIST_P256), + rtc::KeyParams::ECDSA(rtc::EC_NIST_P256)) { + } + + // Do not use the SetUp version from the parent class. + void SetUp() override {} + + // The legacy TLS protocols flag is read when the OpenSSLStreamAdapter is + // initialized, so we set the experiment while creationg client_ssl_ + // and server_ssl_. + + void ConfigureClient(absl::string_view experiment) { + webrtc::test::ScopedFieldTrials trial{std::string(experiment)}; + client_stream_ = + new SSLDummyStreamDTLS(this, "c2s", &client_buffer_, &server_buffer_); + client_ssl_ = + rtc::SSLStreamAdapter::Create(absl::WrapUnique(client_stream_)); + client_ssl_->SignalEvent.connect( + static_cast<SSLStreamAdapterTestBase*>(this), + &SSLStreamAdapterTestBase::OnEvent); + auto client_identity = rtc::SSLIdentity::Create("client", client_key_type_); + client_ssl_->SetIdentity(std::move(client_identity)); + } + + void ConfigureServer(absl::string_view experiment) { + webrtc::test::ScopedFieldTrials trial{std::string(experiment)}; + server_stream_ = + new SSLDummyStreamDTLS(this, "s2c", &server_buffer_, &client_buffer_); + server_ssl_ = + rtc::SSLStreamAdapter::Create(absl::WrapUnique(server_stream_)); + server_ssl_->SignalEvent.connect( + static_cast<SSLStreamAdapterTestBase*>(this), + &SSLStreamAdapterTestBase::OnEvent); + server_ssl_->SetIdentity( + rtc::SSLIdentity::Create("server", server_key_type_)); + } +}; + +// Test getting the used DTLS ciphers. +// DTLS 1.2 enabled for neither client nor server -> DTLS 1.0 will be used. +TEST_F(SSLStreamAdapterTestDTLSLegacyProtocols, TestGetSslCipherSuite) { + ConfigureClient("WebRTC-LegacyTlsProtocols/Enabled/"); + ConfigureServer("WebRTC-LegacyTlsProtocols/Enabled/"); + SetupProtocolVersions(rtc::SSL_PROTOCOL_DTLS_10, rtc::SSL_PROTOCOL_DTLS_10); + TestHandshake(); + + int client_cipher; + ASSERT_TRUE(GetSslCipherSuite(true, &client_cipher)); + int server_cipher; + ASSERT_TRUE(GetSslCipherSuite(false, &server_cipher)); + + ASSERT_EQ(rtc::SSL_PROTOCOL_DTLS_10, GetSslVersion(true)); + ASSERT_EQ(rtc::SSL_PROTOCOL_DTLS_10, GetSslVersion(false)); + + ASSERT_EQ(client_cipher, server_cipher); +} + +// Test getting the used DTLS 1.2 ciphers. +// DTLS 1.2 enabled for client and server -> DTLS 1.2 will be used. +TEST_F(SSLStreamAdapterTestDTLSLegacyProtocols, + TestGetSslCipherSuiteDtls12Both) { + ConfigureClient(""); + ConfigureServer(""); + SetupProtocolVersions(rtc::SSL_PROTOCOL_DTLS_12, rtc::SSL_PROTOCOL_DTLS_12); + TestHandshake(); + + int client_cipher; + ASSERT_TRUE(GetSslCipherSuite(true, &client_cipher)); + int server_cipher; + ASSERT_TRUE(GetSslCipherSuite(false, &server_cipher)); + + ASSERT_EQ(rtc::SSL_PROTOCOL_DTLS_12, GetSslVersion(true)); + ASSERT_EQ(rtc::SSL_PROTOCOL_DTLS_12, GetSslVersion(false)); + + ASSERT_EQ(client_cipher, server_cipher); +} + +// DTLS 1.2 enabled for client only -> DTLS 1.0 will be used. +TEST_F(SSLStreamAdapterTestDTLSLegacyProtocols, + TestGetSslCipherSuiteDtls12Client) { + ConfigureClient("WebRTC-LegacyTlsProtocols/Enabled/"); + ConfigureServer("WebRTC-LegacyTlsProtocols/Enabled/"); + SetupProtocolVersions(rtc::SSL_PROTOCOL_DTLS_10, rtc::SSL_PROTOCOL_DTLS_12); + TestHandshake(); + + int client_cipher; + ASSERT_TRUE(GetSslCipherSuite(true, &client_cipher)); + int server_cipher; + ASSERT_TRUE(GetSslCipherSuite(false, &server_cipher)); + + ASSERT_EQ(rtc::SSL_PROTOCOL_DTLS_10, GetSslVersion(true)); + ASSERT_EQ(rtc::SSL_PROTOCOL_DTLS_10, GetSslVersion(false)); + + ASSERT_EQ(client_cipher, server_cipher); +} + +// DTLS 1.2 enabled for server only -> DTLS 1.0 will be used. +TEST_F(SSLStreamAdapterTestDTLSLegacyProtocols, + TestGetSslCipherSuiteDtls12Server) { + ConfigureClient("WebRTC-LegacyTlsProtocols/Enabled/"); + ConfigureServer("WebRTC-LegacyTlsProtocols/Enabled/"); + SetupProtocolVersions(rtc::SSL_PROTOCOL_DTLS_12, rtc::SSL_PROTOCOL_DTLS_10); + TestHandshake(); + + int client_cipher; + ASSERT_TRUE(GetSslCipherSuite(true, &client_cipher)); + int server_cipher; + ASSERT_TRUE(GetSslCipherSuite(false, &server_cipher)); + + ASSERT_EQ(rtc::SSL_PROTOCOL_DTLS_10, GetSslVersion(true)); + ASSERT_EQ(rtc::SSL_PROTOCOL_DTLS_10, GetSslVersion(false)); + + ASSERT_EQ(client_cipher, server_cipher); +} + +// Client has legacy TLS versions disabled, server has DTLS 1.0 only. +// This is meant to cause a failure. +TEST_F(SSLStreamAdapterTestDTLSLegacyProtocols, + TestGetSslVersionLegacyDisabledServer10) { + ConfigureClient(""); + ConfigureServer("WebRTC-LegacyTlsProtocols/Enabled/"); + SetupProtocolVersions(rtc::SSL_PROTOCOL_DTLS_10, rtc::SSL_PROTOCOL_DTLS_12); + // Handshake should fail. + TestHandshake(false); +} + +// Both client and server have legacy TLS versions disabled and support +// DTLS 1.2. This should work. +TEST_F(SSLStreamAdapterTestDTLSLegacyProtocols, + TestGetSslVersionLegacyDisabledServer12) { + ConfigureClient(""); + ConfigureServer(""); + SetupProtocolVersions(rtc::SSL_PROTOCOL_DTLS_12, rtc::SSL_PROTOCOL_DTLS_12); + TestHandshake(); +} + +// Both client and server have legacy TLS versions enabled and support DTLS 1.0. +// This should work. +TEST_F(SSLStreamAdapterTestDTLSLegacyProtocols, + TestGetSslVersionLegacyEnabledClient10Server10) { + ConfigureClient("WebRTC-LegacyTlsProtocols/Enabled/"); + ConfigureServer("WebRTC-LegacyTlsProtocols/Enabled/"); + SetupProtocolVersions(rtc::SSL_PROTOCOL_DTLS_10, rtc::SSL_PROTOCOL_DTLS_10); + TestHandshake(); +} + +// Legacy protocols are disabled in the client, max TLS version is 1.0 +// This should be a configuration error, and handshake should fail. +TEST_F(SSLStreamAdapterTestDTLSLegacyProtocols, + TestGetSslVersionLegacyDisabledClient10Server10) { + ConfigureClient(""); + ConfigureServer("WebRTC-LegacyTlsProtocols/Enabled/"); + SetupProtocolVersions(rtc::SSL_PROTOCOL_DTLS_10, rtc::SSL_PROTOCOL_DTLS_10); + TestHandshake(false); +} + +// Both client and server have legacy TLS versions enabled and support DTLS 1.0. +// This should work. +TEST_F(SSLStreamAdapterTestDTLSLegacyProtocols, + TestGetSslVersionLegacyOverrideEnabledClient10Server10) { + rtc::SetAllowLegacyTLSProtocols(true); + ConfigureClient(""); + ConfigureServer(""); + // Remove override. + rtc::SetAllowLegacyTLSProtocols(absl::nullopt); + SetupProtocolVersions(rtc::SSL_PROTOCOL_DTLS_10, rtc::SSL_PROTOCOL_DTLS_10); + TestHandshake(); +} + +// Client has legacy TLS disabled and server has legacy TLS enabled via +// override. Handshake for DTLS 1.0 should fail. +TEST_F(SSLStreamAdapterTestDTLSLegacyProtocols, + TestGetSslVersionLegacyOverrideDisabledClient10EnabledServer10) { + rtc::SetAllowLegacyTLSProtocols(false); + ConfigureClient(""); + rtc::SetAllowLegacyTLSProtocols(true); + ConfigureServer(""); + // Remove override. + rtc::SetAllowLegacyTLSProtocols(absl::nullopt); + SetupProtocolVersions(rtc::SSL_PROTOCOL_DTLS_10, rtc::SSL_PROTOCOL_DTLS_10); + TestHandshake(false); +} + +// Client has legacy TLS enabled and server has legacy TLS disabled via +// override. Handshake for DTLS 1.0 should fail. +TEST_F(SSLStreamAdapterTestDTLSLegacyProtocols, + TestGetSslVersionLegacyOverrideEnabledClient10DisabledServer10) { + rtc::SetAllowLegacyTLSProtocols(true); + ConfigureClient(""); + rtc::SetAllowLegacyTLSProtocols(false); + ConfigureServer(""); + // Remove override. + rtc::SetAllowLegacyTLSProtocols(absl::nullopt); + SetupProtocolVersions(rtc::SSL_PROTOCOL_DTLS_10, rtc::SSL_PROTOCOL_DTLS_10); + TestHandshake(false); +} + +// These tests are a no-op under OpenSSL. +#ifdef OPENSSL_IS_BORINGSSL +// TODO(https://bugs.webrtc.org/10261): when removing +// SSLStreamAdapterTestDTLSLegacyProtocols that this class +// inherits from move the code to this class. +class SSLStreamAdapterTestDTLSExtensionPermutation + : public SSLStreamAdapterTestDTLSLegacyProtocols { + public: + SSLStreamAdapterTestDTLSExtensionPermutation() + : SSLStreamAdapterTestDTLSLegacyProtocols() {} +}; + +// Tests for enabling the (D)TLS extension permutation which randomizes the +// order of extensions in the client hello. +TEST_F(SSLStreamAdapterTestDTLSExtensionPermutation, + ClientDefaultServerDefault) { + ConfigureClient(""); + ConfigureServer(""); + TestHandshake(); +} + +TEST_F(SSLStreamAdapterTestDTLSExtensionPermutation, + ClientDefaultServerPermute) { + ConfigureClient(""); + ConfigureServer("WebRTC-PermuteTlsClientHello/Enabled/"); + TestHandshake(); +} + +TEST_F(SSLStreamAdapterTestDTLSExtensionPermutation, + ClientPermuteServerDefault) { + ConfigureClient("WebRTC-PermuteTlsClientHello/Enabled/"); + ConfigureServer(""); + TestHandshake(); +} + +TEST_F(SSLStreamAdapterTestDTLSExtensionPermutation, + ClientPermuteServerPermute) { + ConfigureClient("WebRTC-PermuteTlsClientHello/Enabled/"); + ConfigureServer("WebRTC-PermuteTlsClientHello/Enabled/"); + TestHandshake(); +} +#endif // OPENSSL_IS_BORINGSSL diff --git a/third_party/libwebrtc/rtc_base/stream.cc b/third_party/libwebrtc/rtc_base/stream.cc new file mode 100644 index 0000000000..e6b74b49ac --- /dev/null +++ b/third_party/libwebrtc/rtc_base/stream.cc @@ -0,0 +1,54 @@ +/* + * 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 "rtc_base/stream.h" + +#include <errno.h> +#include <string.h> + +#include <algorithm> +#include <string> + +#include "api/array_view.h" +#include "rtc_base/checks.h" +#include "rtc_base/thread.h" + +namespace rtc { + +/////////////////////////////////////////////////////////////////////////////// +// StreamInterface +/////////////////////////////////////////////////////////////////////////////// + +StreamResult StreamInterface::WriteAll(const void* data, + size_t data_len, + size_t* written, + int* error) { + StreamResult result = SR_SUCCESS; + size_t total_written = 0, current_written; + while (total_written < data_len) { + result = Write(ArrayView<const uint8_t>( + reinterpret_cast<const uint8_t*>(data) + total_written, + data_len - total_written), + current_written, *error); + if (result != SR_SUCCESS) + break; + total_written += current_written; + } + if (written) + *written = total_written; + return result; +} + +bool StreamInterface::Flush() { + return false; +} + +StreamInterface::StreamInterface() {} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/stream.h b/third_party/libwebrtc/rtc_base/stream.h new file mode 100644 index 0000000000..e02349aed3 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/stream.h @@ -0,0 +1,128 @@ +/* + * 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 RTC_BASE_STREAM_H_ +#define RTC_BASE_STREAM_H_ + +#include <memory> + +#include "api/array_view.h" +#include "rtc_base/buffer.h" +#include "rtc_base/system/rtc_export.h" +#include "rtc_base/third_party/sigslot/sigslot.h" +#include "rtc_base/thread.h" + +namespace rtc { + +/////////////////////////////////////////////////////////////////////////////// +// StreamInterface is a generic asynchronous stream interface, supporting read, +// write, and close operations, and asynchronous signalling of state changes. +// The interface is designed with file, memory, and socket implementations in +// mind. Some implementations offer extended operations, such as seeking. +/////////////////////////////////////////////////////////////////////////////// + +// The following enumerations are declared outside of the StreamInterface +// class for brevity in use. + +// The SS_OPENING state indicates that the stream will signal open or closed +// in the future. +enum StreamState { SS_CLOSED, SS_OPENING, SS_OPEN }; + +// Stream read/write methods return this value to indicate various success +// and failure conditions described below. +enum StreamResult { SR_ERROR, SR_SUCCESS, SR_BLOCK, SR_EOS }; + +// StreamEvents are used to asynchronously signal state transitionss. The flags +// may be combined. +// SE_OPEN: The stream has transitioned to the SS_OPEN state +// SE_CLOSE: The stream has transitioned to the SS_CLOSED state +// SE_READ: Data is available, so Read is likely to not return SR_BLOCK +// SE_WRITE: Data can be written, so Write is likely to not return SR_BLOCK +enum StreamEvent { SE_OPEN = 1, SE_READ = 2, SE_WRITE = 4, SE_CLOSE = 8 }; + +class RTC_EXPORT StreamInterface { + public: + virtual ~StreamInterface() {} + + StreamInterface(const StreamInterface&) = delete; + StreamInterface& operator=(const StreamInterface&) = delete; + + virtual StreamState GetState() const = 0; + + // Read attempts to fill buffer of size buffer_len. Write attempts to send + // data_len bytes stored in data. The variables read and write are set only + // on SR_SUCCESS (see below). Likewise, error is only set on SR_ERROR. + // Read and Write return a value indicating: + // SR_ERROR: an error occurred, which is returned in a non-null error + // argument. Interpretation of the error requires knowledge of the + // stream's concrete type, which limits its usefulness. + // SR_SUCCESS: some number of bytes were successfully written, which is + // returned in a non-null read/write argument. + // SR_BLOCK: the stream is in non-blocking mode, and the operation would + // block, or the stream is in SS_OPENING state. + // SR_EOS: the end-of-stream has been reached, or the stream is in the + // SS_CLOSED state. + + virtual StreamResult Read(rtc::ArrayView<uint8_t> buffer, + size_t& read, + int& error) = 0; + virtual StreamResult Write(rtc::ArrayView<const uint8_t> data, + size_t& written, + int& error) = 0; + + // Attempt to transition to the SS_CLOSED state. SE_CLOSE will not be + // signalled as a result of this call. + virtual void Close() = 0; + + // Streams may signal one or more StreamEvents to indicate state changes. + // The first argument identifies the stream on which the state change occured. + // The second argument is a bit-wise combination of StreamEvents. + // If SE_CLOSE is signalled, then the third argument is the associated error + // code. Otherwise, the value is undefined. + // Note: Not all streams will support asynchronous event signalling. However, + // SS_OPENING and SR_BLOCK returned from stream member functions imply that + // certain events will be raised in the future. + sigslot::signal3<StreamInterface*, int, int> SignalEvent; + + // Return true if flush is successful. + virtual bool Flush(); + + // + // CONVENIENCE METHODS + // + // These methods are implemented in terms of other methods, for convenience. + // + + // WriteAll is a helper function which repeatedly calls Write until all the + // data is written, or something other than SR_SUCCESS is returned. Note that + // unlike Write, the argument 'written' is always set, and may be non-zero + // on results other than SR_SUCCESS. The remaining arguments have the + // same semantics as Write. + [[deprecated("Use version with ArrayView")]] StreamResult + WriteAll(const void* data, size_t data_len, size_t* written, int* error); + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + // TODO(bugs.webrc.org/14632): Remove pragmas and change underlying + // implementation when downstream code is converted. + StreamResult WriteAll(ArrayView<const uint8_t> data, + size_t& written, + int& error) { + return WriteAll(data.data(), data.size(), &written, &error); + } +#pragma clang diagnostic pop + + protected: + StreamInterface(); +}; + +} // namespace rtc + +#endif // RTC_BASE_STREAM_H_ diff --git a/third_party/libwebrtc/rtc_base/string_encode.cc b/third_party/libwebrtc/rtc_base/string_encode.cc new file mode 100644 index 0000000000..434d1e6139 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/string_encode.cc @@ -0,0 +1,284 @@ +/* + * 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 "rtc_base/string_encode.h" + +#include <cstdio> + +#include "absl/strings/string_view.h" +#include "api/array_view.h" +#include "rtc_base/arraysize.h" +#include "rtc_base/checks.h" + +namespace rtc { + +///////////////////////////////////////////////////////////////////////////// +// String Encoding Utilities +///////////////////////////////////////////////////////////////////////////// + +namespace { +const char HEX[] = "0123456789abcdef"; + +// Convert an unsigned value from 0 to 15 to the hex character equivalent... +char hex_encode(unsigned char val) { + RTC_DCHECK_LT(val, 16); + return (val < 16) ? HEX[val] : '!'; +} + +// ...and vice-versa. +bool hex_decode(char ch, unsigned char* val) { + if ((ch >= '0') && (ch <= '9')) { + *val = ch - '0'; + } else if ((ch >= 'A') && (ch <= 'F')) { + *val = (ch - 'A') + 10; + } else if ((ch >= 'a') && (ch <= 'f')) { + *val = (ch - 'a') + 10; + } else { + return false; + } + return true; +} + +size_t hex_encode_output_length(size_t srclen, char delimiter) { + return delimiter && srclen > 0 ? (srclen * 3 - 1) : (srclen * 2); +} + +// hex_encode shows the hex representation of binary data in ascii, with +// `delimiter` between bytes, or none if `delimiter` == 0. +void hex_encode_with_delimiter(char* buffer, + absl::string_view source, + char delimiter) { + RTC_DCHECK(buffer); + + // Init and check bounds. + const unsigned char* bsource = + reinterpret_cast<const unsigned char*>(source.data()); + size_t srcpos = 0, bufpos = 0; + + size_t srclen = source.length(); + while (srcpos < srclen) { + unsigned char ch = bsource[srcpos++]; + buffer[bufpos] = hex_encode((ch >> 4) & 0xF); + buffer[bufpos + 1] = hex_encode((ch)&0xF); + bufpos += 2; + + // Don't write a delimiter after the last byte. + if (delimiter && (srcpos < srclen)) { + buffer[bufpos] = delimiter; + ++bufpos; + } + } +} + +} // namespace + +std::string hex_encode(absl::string_view str) { + return hex_encode_with_delimiter(str, 0); +} + +std::string hex_encode_with_delimiter(absl::string_view source, + char delimiter) { + std::string s(hex_encode_output_length(source.length(), delimiter), 0); + hex_encode_with_delimiter(&s[0], source, delimiter); + return s; +} + +size_t hex_decode_with_delimiter(ArrayView<char> cbuffer, + absl::string_view source, + char delimiter) { + if (cbuffer.empty()) + return 0; + + // Init and bounds check. + unsigned char* bbuffer = reinterpret_cast<unsigned char*>(cbuffer.data()); + size_t srcpos = 0, bufpos = 0; + size_t srclen = source.length(); + + size_t needed = (delimiter) ? (srclen + 1) / 3 : srclen / 2; + if (cbuffer.size() < needed) + return 0; + + while (srcpos < srclen) { + if ((srclen - srcpos) < 2) { + // This means we have an odd number of bytes. + return 0; + } + + unsigned char h1, h2; + if (!hex_decode(source[srcpos], &h1) || + !hex_decode(source[srcpos + 1], &h2)) + return 0; + + bbuffer[bufpos++] = (h1 << 4) | h2; + srcpos += 2; + + // Remove the delimiter if needed. + if (delimiter && (srclen - srcpos) > 1) { + if (source[srcpos] != delimiter) + return 0; + ++srcpos; + } + } + + return bufpos; +} + +size_t hex_decode(ArrayView<char> buffer, absl::string_view source) { + return hex_decode_with_delimiter(buffer, source, 0); +} + +size_t tokenize(absl::string_view source, + char delimiter, + std::vector<std::string>* fields) { + fields->clear(); + size_t last = 0; + for (size_t i = 0; i < source.length(); ++i) { + if (source[i] == delimiter) { + if (i != last) { + fields->emplace_back(source.substr(last, i - last)); + } + last = i + 1; + } + } + if (last != source.length()) { + fields->emplace_back(source.substr(last, source.length() - last)); + } + return fields->size(); +} + +bool tokenize_first(absl::string_view source, + const char delimiter, + std::string* token, + std::string* rest) { + // Find the first delimiter + size_t left_pos = source.find(delimiter); + if (left_pos == absl::string_view::npos) { + return false; + } + + // Look for additional occurrances of delimiter. + size_t right_pos = left_pos + 1; + while (right_pos < source.size() && source[right_pos] == delimiter) { + right_pos++; + } + + *token = std::string(source.substr(0, left_pos)); + *rest = std::string(source.substr(right_pos)); + return true; +} + +std::vector<absl::string_view> split(absl::string_view source, char delimiter) { + std::vector<absl::string_view> fields; + size_t last = 0; + for (size_t i = 0; i < source.length(); ++i) { + if (source[i] == delimiter) { + fields.push_back(source.substr(last, i - last)); + last = i + 1; + } + } + fields.push_back(source.substr(last)); + return fields; +} + +std::string ToString(const bool b) { + return b ? "true" : "false"; +} + +std::string ToString(absl::string_view s) { + return std::string(s); +} + +std::string ToString(const char* s) { + return std::string(s); +} + +std::string ToString(const short s) { + char buf[32]; + const int len = std::snprintf(&buf[0], arraysize(buf), "%hd", s); + RTC_DCHECK_LE(len, arraysize(buf)); + return std::string(&buf[0], len); +} +std::string ToString(const unsigned short s) { + char buf[32]; + const int len = std::snprintf(&buf[0], arraysize(buf), "%hu", s); + RTC_DCHECK_LE(len, arraysize(buf)); + return std::string(&buf[0], len); +} +std::string ToString(const int s) { + char buf[32]; + const int len = std::snprintf(&buf[0], arraysize(buf), "%d", s); + RTC_DCHECK_LE(len, arraysize(buf)); + return std::string(&buf[0], len); +} +std::string ToString(const unsigned int s) { + char buf[32]; + const int len = std::snprintf(&buf[0], arraysize(buf), "%u", s); + RTC_DCHECK_LE(len, arraysize(buf)); + return std::string(&buf[0], len); +} +std::string ToString(const long int s) { + char buf[32]; + const int len = std::snprintf(&buf[0], arraysize(buf), "%ld", s); + RTC_DCHECK_LE(len, arraysize(buf)); + return std::string(&buf[0], len); +} +std::string ToString(const unsigned long int s) { + char buf[32]; + const int len = std::snprintf(&buf[0], arraysize(buf), "%lu", s); + RTC_DCHECK_LE(len, arraysize(buf)); + return std::string(&buf[0], len); +} +std::string ToString(const long long int s) { + char buf[32]; + const int len = std::snprintf(&buf[0], arraysize(buf), "%lld", s); + RTC_DCHECK_LE(len, arraysize(buf)); + return std::string(&buf[0], len); +} +std::string ToString(const unsigned long long int s) { + char buf[32]; + const int len = std::snprintf(&buf[0], arraysize(buf), "%llu", s); + RTC_DCHECK_LE(len, arraysize(buf)); + return std::string(&buf[0], len); +} + +std::string ToString(const double d) { + char buf[32]; + const int len = std::snprintf(&buf[0], arraysize(buf), "%g", d); + RTC_DCHECK_LE(len, arraysize(buf)); + return std::string(&buf[0], len); +} + +std::string ToString(const long double d) { + char buf[32]; + const int len = std::snprintf(&buf[0], arraysize(buf), "%Lg", d); + RTC_DCHECK_LE(len, arraysize(buf)); + return std::string(&buf[0], len); +} + +std::string ToString(const void* const p) { + char buf[32]; + const int len = std::snprintf(&buf[0], arraysize(buf), "%p", p); + RTC_DCHECK_LE(len, arraysize(buf)); + return std::string(&buf[0], len); +} + +bool FromString(absl::string_view s, bool* b) { + if (s == "false") { + *b = false; + return true; + } + if (s == "true") { + *b = true; + return true; + } + return false; +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/string_encode.h b/third_party/libwebrtc/rtc_base/string_encode.h new file mode 100644 index 0000000000..82a9dfdb62 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/string_encode.h @@ -0,0 +1,115 @@ +/* + * 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 RTC_BASE_STRING_ENCODE_H_ +#define RTC_BASE_STRING_ENCODE_H_ + +#include <stddef.h> + +#include <string> +#include <type_traits> +#include <vector> + +#include "absl/strings/string_view.h" +#include "absl/types/optional.h" +#include "api/array_view.h" +#include "rtc_base/checks.h" +#include "rtc_base/string_to_number.h" + +namespace rtc { + +////////////////////////////////////////////////////////////////////// +// String Encoding Utilities +////////////////////////////////////////////////////////////////////// + +std::string hex_encode(absl::string_view str); +std::string hex_encode_with_delimiter(absl::string_view source, char delimiter); + +// hex_decode converts ascii hex to binary. +size_t hex_decode(ArrayView<char> buffer, absl::string_view source); + +// hex_decode, assuming that there is a delimiter between every byte +// pair. +// `delimiter` == 0 means no delimiter +// If the buffer is too short or the data is invalid, we return 0. +size_t hex_decode_with_delimiter(ArrayView<char> buffer, + absl::string_view source, + char delimiter); + +// Splits the source string into multiple fields separated by delimiter, +// with duplicates of delimiter creating empty fields. Empty input produces a +// single, empty, field. +std::vector<absl::string_view> split(absl::string_view source, char delimiter); + +// Splits the source string into multiple fields separated by delimiter, +// with duplicates of delimiter ignored. Trailing delimiter ignored. +size_t tokenize(absl::string_view source, + char delimiter, + std::vector<std::string>* fields); + +// Extract the first token from source as separated by delimiter, with +// duplicates of delimiter ignored. Return false if the delimiter could not be +// found, otherwise return true. +bool tokenize_first(absl::string_view source, + char delimiter, + std::string* token, + std::string* rest); + +// Convert arbitrary values to/from a string. +// TODO(jonasolsson): Remove these when absl::StrCat becomes available. +std::string ToString(bool b); + +std::string ToString(absl::string_view s); +// The const char* overload is needed for correct overload resolution because of +// the const void* version of ToString() below. +std::string ToString(const char* s); + +std::string ToString(short s); +std::string ToString(unsigned short s); +std::string ToString(int s); +std::string ToString(unsigned int s); +std::string ToString(long int s); +std::string ToString(unsigned long int s); +std::string ToString(long long int s); +std::string ToString(unsigned long long int s); + +std::string ToString(double t); +std::string ToString(long double t); + +std::string ToString(const void* p); + +template <typename T, + typename std::enable_if<std::is_arithmetic<T>::value && + !std::is_same<T, bool>::value, + int>::type = 0> +static bool FromString(absl::string_view s, T* t) { + RTC_DCHECK(t); + absl::optional<T> result = StringToNumber<T>(s); + + if (result) + *t = *result; + + return result.has_value(); +} + +bool FromString(absl::string_view s, bool* b); + +template <typename T> +static inline T FromString(absl::string_view str) { + T val; + FromString(str, &val); + return val; +} + +////////////////////////////////////////////////////////////////////// + +} // namespace rtc + +#endif // RTC_BASE_STRING_ENCODE_H__ diff --git a/third_party/libwebrtc/rtc_base/string_encode_unittest.cc b/third_party/libwebrtc/rtc_base/string_encode_unittest.cc new file mode 100644 index 0000000000..f277d3a856 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/string_encode_unittest.cc @@ -0,0 +1,335 @@ +/* + * 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 "rtc_base/string_encode.h" + +#include <string.h> + +#include <sstream> // no-presubmit-check TODO(webrtc:8982) + +#include "api/array_view.h" +#include "test/gtest.h" + +namespace rtc { + +class HexEncodeTest : public ::testing::Test { + public: + HexEncodeTest() : dec_res_(0) { + for (size_t i = 0; i < sizeof(data_); ++i) { + data_[i] = (i + 128) & 0xff; + } + memset(decoded_, 0x7f, sizeof(decoded_)); + } + + char data_[10]; + absl::string_view data_view_{data_, sizeof(data_)}; + char decoded_[11]; + size_t dec_res_; +}; + +// Test that we can convert to/from hex with no delimiter. +TEST_F(HexEncodeTest, TestWithNoDelimiter) { + std::string encoded = hex_encode(data_view_); + EXPECT_EQ("80818283848586878889", encoded); + dec_res_ = hex_decode(ArrayView<char>(decoded_), encoded); + ASSERT_EQ(sizeof(data_), dec_res_); + ASSERT_EQ(0, memcmp(data_, decoded_, dec_res_)); +} + +// Test that we can convert to/from hex with a colon delimiter. +TEST_F(HexEncodeTest, TestWithDelimiter) { + std::string encoded = hex_encode_with_delimiter(data_view_, ':'); + EXPECT_EQ("80:81:82:83:84:85:86:87:88:89", encoded); + dec_res_ = hex_decode_with_delimiter(ArrayView<char>(decoded_), encoded, ':'); + ASSERT_EQ(sizeof(data_), dec_res_); + ASSERT_EQ(0, memcmp(data_, decoded_, dec_res_)); +} + +// Test that encoding with one delimiter and decoding with another fails. +TEST_F(HexEncodeTest, TestWithWrongDelimiter) { + std::string encoded = hex_encode_with_delimiter(data_view_, ':'); + dec_res_ = hex_decode_with_delimiter(ArrayView<char>(decoded_), encoded, '/'); + ASSERT_EQ(0U, dec_res_); +} + +// Test that encoding without a delimiter and decoding with one fails. +TEST_F(HexEncodeTest, TestExpectedDelimiter) { + std::string encoded = hex_encode(data_view_); + EXPECT_EQ(sizeof(data_) * 2, encoded.size()); + dec_res_ = hex_decode_with_delimiter(ArrayView<char>(decoded_), encoded, ':'); + ASSERT_EQ(0U, dec_res_); +} + +// Test that encoding with a delimiter and decoding without one fails. +TEST_F(HexEncodeTest, TestExpectedNoDelimiter) { + std::string encoded = hex_encode_with_delimiter(data_view_, ':'); + EXPECT_EQ(sizeof(data_) * 3 - 1, encoded.size()); + dec_res_ = hex_decode(ArrayView<char>(decoded_), encoded); + ASSERT_EQ(0U, dec_res_); +} + +// Test that we handle a zero-length buffer with no delimiter. +TEST_F(HexEncodeTest, TestZeroLengthNoDelimiter) { + std::string encoded = hex_encode(""); + EXPECT_TRUE(encoded.empty()); + dec_res_ = hex_decode(ArrayView<char>(decoded_), encoded); + ASSERT_EQ(0U, dec_res_); +} + +// Test that we handle a zero-length buffer with a delimiter. +TEST_F(HexEncodeTest, TestZeroLengthWithDelimiter) { + std::string encoded = hex_encode_with_delimiter("", ':'); + EXPECT_TRUE(encoded.empty()); + dec_res_ = hex_decode_with_delimiter(ArrayView<char>(decoded_), encoded, ':'); + ASSERT_EQ(0U, dec_res_); +} + +// Test that decoding into a too-small output buffer fails. +TEST_F(HexEncodeTest, TestDecodeTooShort) { + dec_res_ = + hex_decode_with_delimiter(ArrayView<char>(decoded_, 4), "0123456789", 0); + ASSERT_EQ(0U, dec_res_); + ASSERT_EQ(0x7f, decoded_[4]); +} + +// Test that decoding non-hex data fails. +TEST_F(HexEncodeTest, TestDecodeBogusData) { + dec_res_ = hex_decode_with_delimiter(ArrayView<char>(decoded_), "axyz", 0); + ASSERT_EQ(0U, dec_res_); +} + +// Test that decoding an odd number of hex characters fails. +TEST_F(HexEncodeTest, TestDecodeOddHexDigits) { + dec_res_ = hex_decode_with_delimiter(ArrayView<char>(decoded_), "012", 0); + ASSERT_EQ(0U, dec_res_); +} + +// Test that decoding a string with too many delimiters fails. +TEST_F(HexEncodeTest, TestDecodeWithDelimiterTooManyDelimiters) { + dec_res_ = hex_decode_with_delimiter(ArrayView<char>(decoded_, 4), + "01::23::45::67", ':'); + ASSERT_EQ(0U, dec_res_); +} + +// Test that decoding a string with a leading delimiter fails. +TEST_F(HexEncodeTest, TestDecodeWithDelimiterLeadingDelimiter) { + dec_res_ = hex_decode_with_delimiter(ArrayView<char>(decoded_, 4), + ":01:23:45:67", ':'); + ASSERT_EQ(0U, dec_res_); +} + +// Test that decoding a string with a trailing delimiter fails. +TEST_F(HexEncodeTest, TestDecodeWithDelimiterTrailingDelimiter) { + dec_res_ = hex_decode_with_delimiter(ArrayView<char>(decoded_, 4), + "01:23:45:67:", ':'); + ASSERT_EQ(0U, dec_res_); +} + +// Tests counting substrings. +TEST(TokenizeTest, CountSubstrings) { + std::vector<std::string> fields; + + EXPECT_EQ(5ul, tokenize("one two three four five", ' ', &fields)); + fields.clear(); + EXPECT_EQ(1ul, tokenize("one", ' ', &fields)); + + // Extra spaces should be ignored. + fields.clear(); + EXPECT_EQ(5ul, tokenize(" one two three four five ", ' ', &fields)); + fields.clear(); + EXPECT_EQ(1ul, tokenize(" one ", ' ', &fields)); + fields.clear(); + EXPECT_EQ(0ul, tokenize(" ", ' ', &fields)); +} + +// Tests comparing substrings. +TEST(TokenizeTest, CompareSubstrings) { + std::vector<std::string> fields; + + tokenize("find middle one", ' ', &fields); + ASSERT_EQ(3ul, fields.size()); + ASSERT_STREQ("middle", fields.at(1).c_str()); + fields.clear(); + + // Extra spaces should be ignored. + tokenize(" find middle one ", ' ', &fields); + ASSERT_EQ(3ul, fields.size()); + ASSERT_STREQ("middle", fields.at(1).c_str()); + fields.clear(); + tokenize(" ", ' ', &fields); + ASSERT_EQ(0ul, fields.size()); +} + +TEST(TokenizeFirstTest, NoLeadingSpaces) { + std::string token; + std::string rest; + + ASSERT_TRUE(tokenize_first("A &*${}", ' ', &token, &rest)); + ASSERT_STREQ("A", token.c_str()); + ASSERT_STREQ("&*${}", rest.c_str()); + + ASSERT_TRUE(tokenize_first("A B& *${}", ' ', &token, &rest)); + ASSERT_STREQ("A", token.c_str()); + ASSERT_STREQ("B& *${}", rest.c_str()); + + ASSERT_TRUE(tokenize_first("A B& *${} ", ' ', &token, &rest)); + ASSERT_STREQ("A", token.c_str()); + ASSERT_STREQ("B& *${} ", rest.c_str()); +} + +TEST(TokenizeFirstTest, LeadingSpaces) { + std::string token; + std::string rest; + + ASSERT_TRUE(tokenize_first(" A B C", ' ', &token, &rest)); + ASSERT_STREQ("", token.c_str()); + ASSERT_STREQ("A B C", rest.c_str()); + + ASSERT_TRUE(tokenize_first(" A B C ", ' ', &token, &rest)); + ASSERT_STREQ("", token.c_str()); + ASSERT_STREQ("A B C ", rest.c_str()); +} + +TEST(TokenizeFirstTest, SingleToken) { + std::string token; + std::string rest; + + // In the case where we cannot find delimiter the whole string is a token. + ASSERT_FALSE(tokenize_first("ABC", ' ', &token, &rest)); + + ASSERT_TRUE(tokenize_first("ABC ", ' ', &token, &rest)); + ASSERT_STREQ("ABC", token.c_str()); + ASSERT_STREQ("", rest.c_str()); + + ASSERT_TRUE(tokenize_first(" ABC ", ' ', &token, &rest)); + ASSERT_STREQ("", token.c_str()); + ASSERT_STREQ("ABC ", rest.c_str()); +} + +// Tests counting substrings. +TEST(SplitTest, CountSubstrings) { + EXPECT_EQ(5ul, split("one,two,three,four,five", ',').size()); + EXPECT_EQ(1ul, split("one", ',').size()); + + // Empty fields between commas count. + EXPECT_EQ(5ul, split("one,,three,four,five", ',').size()); + EXPECT_EQ(3ul, split(",three,", ',').size()); + EXPECT_EQ(1ul, split("", ',').size()); +} + +// Tests comparing substrings. +TEST(SplitTest, CompareSubstrings) { + std::vector<absl::string_view> fields = split("find,middle,one", ','); + ASSERT_EQ(3ul, fields.size()); + ASSERT_EQ("middle", fields.at(1)); + + // Empty fields between commas count. + fields = split("find,,middle,one", ','); + ASSERT_EQ(4ul, fields.size()); + ASSERT_EQ("middle", fields.at(2)); + fields = split("", ','); + ASSERT_EQ(1ul, fields.size()); + ASSERT_EQ("", fields.at(0)); +} + +TEST(SplitTest, EmptyTokens) { + std::vector<absl::string_view> fields = split("a.b.c", '.'); + ASSERT_EQ(3ul, fields.size()); + EXPECT_EQ("a", fields[0]); + EXPECT_EQ("b", fields[1]); + EXPECT_EQ("c", fields[2]); + + fields = split("..c", '.'); + ASSERT_EQ(3ul, fields.size()); + EXPECT_TRUE(fields[0].empty()); + EXPECT_TRUE(fields[1].empty()); + EXPECT_EQ("c", fields[2]); + + fields = split("", '.'); + ASSERT_EQ(1ul, fields.size()); + EXPECT_TRUE(fields[0].empty()); +} + +TEST(ToString, SanityCheck) { + EXPECT_EQ(ToString(true), "true"); + EXPECT_EQ(ToString(false), "false"); + + const char* c = "message"; + EXPECT_EQ(ToString(c), c); + EXPECT_EQ(ToString(std::string(c)), c); + + EXPECT_EQ(ToString(short{-123}), "-123"); + EXPECT_EQ(ToString((unsigned short)123), "123"); + EXPECT_EQ(ToString(int{-123}), "-123"); + EXPECT_EQ(ToString((unsigned int)123), "123"); + EXPECT_EQ(ToString((long int)-123), "-123"); + EXPECT_EQ(ToString((unsigned long int)123), "123"); + EXPECT_EQ(ToString((long long int)-123), "-123"); + EXPECT_EQ(ToString((unsigned long long int)123), "123"); + + int i = 10; + int* p = &i; + std::ostringstream s; // no-presubmit-check TODO(webrtc:8982) + s << p; + EXPECT_EQ(s.str(), ToString(p)); + + EXPECT_EQ(ToString(0.5), "0.5"); +} + +template <typename T> +void ParsesTo(std::string s, T t) { + T value; + EXPECT_TRUE(FromString(s, &value)); + EXPECT_EQ(value, t); +} + +TEST(FromString, DecodeValid) { + ParsesTo("true", true); + ParsesTo("false", false); + + ParsesTo("105", 105); + ParsesTo("0.25", 0.25); +} + +template <typename T> +void FailsToParse(std::string s) { + T value; + EXPECT_FALSE(FromString(s, &value)) << "[" << s << "]"; +} + +TEST(FromString, DecodeInvalid) { + FailsToParse<bool>("True"); + FailsToParse<bool>("0"); + FailsToParse<bool>("yes"); + + FailsToParse<int>("0.5"); + FailsToParse<int>("XIV"); + FailsToParse<double>(""); + FailsToParse<double>(" "); + FailsToParse<int>("1 2"); +} + +template <typename T> +void RoundTrip(T t) { + std::string s = ToString(t); + T value; + EXPECT_TRUE(FromString(s, &value)); + EXPECT_EQ(value, t); +} + +TEST(FromString, RoundTrip) { + RoundTrip<int>(123); + RoundTrip(false); + RoundTrip(true); + RoundTrip(0.5); + RoundTrip(-15l); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/string_to_number.cc b/third_party/libwebrtc/rtc_base/string_to_number.cc new file mode 100644 index 0000000000..1209eced44 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/string_to_number.cc @@ -0,0 +1,104 @@ +/* + * Copyright 2017 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 "rtc_base/string_to_number.h" + +#include <ctype.h> + +#include <cerrno> +#include <cstdlib> + +#include "rtc_base/checks.h" + +namespace rtc { +namespace string_to_number_internal { + +absl::optional<signed_type> ParseSigned(absl::string_view str, int base) { + if (str.empty()) + return absl::nullopt; + + if (isdigit(static_cast<unsigned char>(str[0])) || str[0] == '-') { + std::string str_str(str); + char* end = nullptr; + errno = 0; + const signed_type value = std::strtoll(str_str.c_str(), &end, base); + // Check for errors and also make sure that there were no embedded nuls in + // the input string. + if (end == str_str.c_str() + str_str.size() && errno == 0) { + return value; + } + } + return absl::nullopt; +} + +absl::optional<unsigned_type> ParseUnsigned(absl::string_view str, int base) { + if (str.empty()) + return absl::nullopt; + + if (isdigit(static_cast<unsigned char>(str[0])) || str[0] == '-') { + std::string str_str(str); + // Explicitly discard negative values. std::strtoull parsing causes unsigned + // wraparound. We cannot just reject values that start with -, though, since + // -0 is perfectly fine, as is -0000000000000000000000000000000. + const bool is_negative = str[0] == '-'; + char* end = nullptr; + errno = 0; + const unsigned_type value = std::strtoull(str_str.c_str(), &end, base); + // Check for errors and also make sure that there were no embedded nuls in + // the input string. + if (end == str_str.c_str() + str_str.size() && errno == 0 && + (value == 0 || !is_negative)) { + return value; + } + } + return absl::nullopt; +} + +template <typename T> +T StrToT(const char* str, char** str_end); + +template <> +inline float StrToT(const char* str, char** str_end) { + return std::strtof(str, str_end); +} + +template <> +inline double StrToT(const char* str, char** str_end) { + return std::strtod(str, str_end); +} + +template <> +inline long double StrToT(const char* str, char** str_end) { + return std::strtold(str, str_end); +} + +template <typename T> +absl::optional<T> ParseFloatingPoint(absl::string_view str) { + if (str.empty()) + return absl::nullopt; + + if (str[0] == '\0') + return absl::nullopt; + std::string str_str(str); + char* end = nullptr; + errno = 0; + const T value = StrToT<T>(str_str.c_str(), &end); + if (end == str_str.c_str() + str_str.size() && errno == 0) { + return value; + } + return absl::nullopt; +} + +template absl::optional<float> ParseFloatingPoint(absl::string_view str); +template absl::optional<double> ParseFloatingPoint(absl::string_view str); +template absl::optional<long double> ParseFloatingPoint(absl::string_view str); + +} // namespace string_to_number_internal +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/string_to_number.h b/third_party/libwebrtc/rtc_base/string_to_number.h new file mode 100644 index 0000000000..1d704ee464 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/string_to_number.h @@ -0,0 +1,105 @@ +/* + * Copyright 2017 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 RTC_BASE_STRING_TO_NUMBER_H_ +#define RTC_BASE_STRING_TO_NUMBER_H_ + +#include <limits> +#include <string> +#include <type_traits> + +#include "absl/strings/string_view.h" +#include "absl/types/optional.h" + +namespace rtc { + +// This file declares a family of functions to parse integers from strings. +// The standard C library functions either fail to indicate errors (atoi, etc.) +// or are a hassle to work with (strtol, sscanf, etc.). The standard C++ library +// functions (std::stoi, etc.) indicate errors by throwing exceptions, which +// are disabled in WebRTC. +// +// Integers are parsed using: +// absl::optional<int-type> StringToNumber(absl::string_view str, +// int base = 10); +// +// These functions parse a value from the beginning of a string into one of the +// fundamental integer types, or returns an empty Optional if parsing +// failed. Values outside of the range supported by the type will be +// rejected. The strings must begin with a digit or a minus sign. No leading +// space nor trailing contents are allowed. +// By setting base to 0, one of octal, decimal or hexadecimal will be +// detected from the string's prefix (0, nothing or 0x, respectively). +// If non-zero, base can be set to a value between 2 and 36 inclusively. + +namespace string_to_number_internal { +// These must be (unsigned) long long, to match the signature of strto(u)ll. +using unsigned_type = unsigned long long; // NOLINT(runtime/int) +using signed_type = long long; // NOLINT(runtime/int) + +absl::optional<signed_type> ParseSigned(absl::string_view str, int base); +absl::optional<unsigned_type> ParseUnsigned(absl::string_view str, int base); + +template <typename T> +absl::optional<T> ParseFloatingPoint(absl::string_view str); +} // namespace string_to_number_internal + +template <typename T> +typename std::enable_if<std::is_integral<T>::value && std::is_signed<T>::value, + absl::optional<T>>::type +StringToNumber(absl::string_view str, int base = 10) { + using string_to_number_internal::signed_type; + static_assert( + std::numeric_limits<T>::max() <= + std::numeric_limits<signed_type>::max() && + std::numeric_limits<T>::lowest() >= + std::numeric_limits<signed_type>::lowest(), + "StringToNumber only supports signed integers as large as long long int"); + absl::optional<signed_type> value = + string_to_number_internal::ParseSigned(str, base); + if (value && *value >= std::numeric_limits<T>::lowest() && + *value <= std::numeric_limits<T>::max()) { + return static_cast<T>(*value); + } + return absl::nullopt; +} + +template <typename T> +typename std::enable_if<std::is_integral<T>::value && + std::is_unsigned<T>::value, + absl::optional<T>>::type +StringToNumber(absl::string_view str, int base = 10) { + using string_to_number_internal::unsigned_type; + static_assert(std::numeric_limits<T>::max() <= + std::numeric_limits<unsigned_type>::max(), + "StringToNumber only supports unsigned integers as large as " + "unsigned long long int"); + absl::optional<unsigned_type> value = + string_to_number_internal::ParseUnsigned(str, base); + if (value && *value <= std::numeric_limits<T>::max()) { + return static_cast<T>(*value); + } + return absl::nullopt; +} + +template <typename T> +typename std::enable_if<std::is_floating_point<T>::value, + absl::optional<T>>::type +StringToNumber(absl::string_view str, int base = 10) { + static_assert( + std::numeric_limits<T>::max() <= std::numeric_limits<long double>::max(), + "StringToNumber only supports floating-point numbers as large " + "as long double"); + return string_to_number_internal::ParseFloatingPoint<T>(str); +} + +} // namespace rtc + +#endif // RTC_BASE_STRING_TO_NUMBER_H_ diff --git a/third_party/libwebrtc/rtc_base/string_to_number_unittest.cc b/third_party/libwebrtc/rtc_base/string_to_number_unittest.cc new file mode 100644 index 0000000000..edfdbf69ff --- /dev/null +++ b/third_party/libwebrtc/rtc_base/string_to_number_unittest.cc @@ -0,0 +1,138 @@ +/* + * Copyright 2017 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 "rtc_base/string_to_number.h" + +#include <stdint.h> + +#include <limits> +#include <string> + +#include "absl/strings/string_view.h" +#include "absl/types/optional.h" +#include "test/gtest.h" + +namespace rtc { + +namespace { +// clang-format off +using IntegerTypes = + ::testing::Types<char, + signed char, unsigned char, // NOLINT(runtime/int) + short, unsigned short, // NOLINT(runtime/int) + int, unsigned int, // NOLINT(runtime/int) + long, unsigned long, // NOLINT(runtime/int) + long long, unsigned long long, // NOLINT(runtime/int) + int8_t, uint8_t, + int16_t, uint16_t, + int32_t, uint32_t, + int64_t, uint64_t>; +// clang-format on + +template <typename T> +class BasicNumberTest : public ::testing::Test {}; + +TYPED_TEST_SUITE_P(BasicNumberTest); + +TYPED_TEST_P(BasicNumberTest, TestValidNumbers) { + using T = TypeParam; + constexpr T min_value = std::numeric_limits<T>::lowest(); + constexpr T max_value = std::numeric_limits<T>::max(); + constexpr T zero_value = 0; + const std::string min_string = std::to_string(min_value); + const std::string max_string = std::to_string(max_value); + EXPECT_EQ(min_value, StringToNumber<T>(min_string)); + EXPECT_EQ(min_value, StringToNumber<T>(min_string.c_str())); + EXPECT_EQ(max_value, StringToNumber<T>(max_string)); + EXPECT_EQ(max_value, StringToNumber<T>(max_string.c_str())); + EXPECT_EQ(zero_value, StringToNumber<T>("0")); + EXPECT_EQ(zero_value, StringToNumber<T>("-0")); + EXPECT_EQ(zero_value, StringToNumber<T>(std::string("-0000000000000"))); +} + +TYPED_TEST_P(BasicNumberTest, TestInvalidNumbers) { + using T = TypeParam; + // Value ranges aren't strictly enforced in this test, since that would either + // require doctoring specific strings for each data type, which is a hassle + // across platforms, or to be able to do addition of values larger than the + // largest type, which is another hassle. + constexpr T min_value = std::numeric_limits<T>::lowest(); + constexpr T max_value = std::numeric_limits<T>::max(); + // If the type supports negative values, make the large negative value + // approximately ten times larger. If the type is unsigned, just use -2. + const std::string too_low_string = + (min_value == 0) ? "-2" : (std::to_string(min_value) + "1"); + // Make the large value approximately ten times larger than the maximum. + const std::string too_large_string = std::to_string(max_value) + "1"; + EXPECT_EQ(absl::nullopt, StringToNumber<T>(too_low_string)); + EXPECT_EQ(absl::nullopt, StringToNumber<T>(too_low_string.c_str())); + EXPECT_EQ(absl::nullopt, StringToNumber<T>(too_large_string)); + EXPECT_EQ(absl::nullopt, StringToNumber<T>(too_large_string.c_str())); +} + +TYPED_TEST_P(BasicNumberTest, TestInvalidInputs) { + using T = TypeParam; + const char kInvalidCharArray[] = "Invalid string containing 47"; + const char kPlusMinusCharArray[] = "+-100"; + const char kNumberFollowedByCruft[] = "640x480"; + const char kEmbeddedNul[] = {'1', '2', '\0', '3', '4'}; + const char kBeginningEmbeddedNul[] = {'\0', '1', '2', '3', '4'}; + const char kTrailingEmbeddedNul[] = {'1', '2', '3', '4', '\0'}; + + EXPECT_EQ(absl::nullopt, StringToNumber<T>(kInvalidCharArray)); + EXPECT_EQ(absl::nullopt, StringToNumber<T>(std::string(kInvalidCharArray))); + EXPECT_EQ(absl::nullopt, StringToNumber<T>(kPlusMinusCharArray)); + EXPECT_EQ(absl::nullopt, StringToNumber<T>(std::string(kPlusMinusCharArray))); + EXPECT_EQ(absl::nullopt, StringToNumber<T>(kNumberFollowedByCruft)); + EXPECT_EQ(absl::nullopt, + StringToNumber<T>(std::string(kNumberFollowedByCruft))); + EXPECT_EQ(absl::nullopt, StringToNumber<T>(" 5")); + EXPECT_EQ(absl::nullopt, StringToNumber<T>(" - 5")); + EXPECT_EQ(absl::nullopt, StringToNumber<T>("- 5")); + EXPECT_EQ(absl::nullopt, StringToNumber<T>(" -5")); + EXPECT_EQ(absl::nullopt, StringToNumber<T>("5 ")); + // Test various types of empty inputs + EXPECT_EQ(absl::nullopt, StringToNumber<T>({nullptr, 0})); + EXPECT_EQ(absl::nullopt, StringToNumber<T>("")); + EXPECT_EQ(absl::nullopt, StringToNumber<T>(std::string())); + EXPECT_EQ(absl::nullopt, StringToNumber<T>(std::string(""))); + EXPECT_EQ(absl::nullopt, StringToNumber<T>(absl::string_view())); + EXPECT_EQ(absl::nullopt, StringToNumber<T>(absl::string_view(nullptr, 0))); + EXPECT_EQ(absl::nullopt, StringToNumber<T>(absl::string_view(""))); + // Test strings with embedded nuls. + EXPECT_EQ(absl::nullopt, StringToNumber<T>(absl::string_view( + kEmbeddedNul, sizeof(kEmbeddedNul)))); + EXPECT_EQ(absl::nullopt, + StringToNumber<T>(absl::string_view( + kBeginningEmbeddedNul, sizeof(kBeginningEmbeddedNul)))); + EXPECT_EQ(absl::nullopt, + StringToNumber<T>(absl::string_view(kTrailingEmbeddedNul, + sizeof(kTrailingEmbeddedNul)))); +} + +REGISTER_TYPED_TEST_SUITE_P(BasicNumberTest, + TestValidNumbers, + TestInvalidNumbers, + TestInvalidInputs); + +} // namespace + +INSTANTIATE_TYPED_TEST_SUITE_P(StringToNumberTest_Integers, + BasicNumberTest, + IntegerTypes); + +TEST(StringToNumberTest, TestSpecificValues) { + EXPECT_EQ(absl::nullopt, StringToNumber<uint8_t>("256")); + EXPECT_EQ(absl::nullopt, StringToNumber<uint8_t>("-256")); + EXPECT_EQ(absl::nullopt, StringToNumber<int8_t>("256")); + EXPECT_EQ(absl::nullopt, StringToNumber<int8_t>("-256")); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/string_utils.cc b/third_party/libwebrtc/rtc_base/string_utils.cc new file mode 100644 index 0000000000..b93e615705 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/string_utils.cc @@ -0,0 +1,37 @@ +/* + * 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 "rtc_base/string_utils.h" + +#include "absl/strings/string_view.h" + +namespace rtc { + +size_t strcpyn(char* buffer, size_t buflen, absl::string_view source) { + if (buflen <= 0) + return 0; + + size_t srclen = source.length(); + if (srclen >= buflen) { + srclen = buflen - 1; + } + memcpy(buffer, source.data(), srclen); + buffer[srclen] = 0; + return srclen; +} + +std::string ToHex(const int i) { + char buffer[50]; + snprintf(buffer, sizeof(buffer), "%x", i); + + return std::string(buffer); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/string_utils.h b/third_party/libwebrtc/rtc_base/string_utils.h new file mode 100644 index 0000000000..9534d59e04 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/string_utils.h @@ -0,0 +1,138 @@ +/* + * 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 RTC_BASE_STRING_UTILS_H_ +#define RTC_BASE_STRING_UTILS_H_ + +#include <stdio.h> +#include <string.h> + +#include "absl/strings/string_view.h" + +#if defined(WEBRTC_WIN) +#include <malloc.h> +#include <wchar.h> +#include <windows.h> + +#endif // WEBRTC_WIN + +#if defined(WEBRTC_POSIX) +#include <stdlib.h> +#include <strings.h> +#endif // WEBRTC_POSIX + +#include <string> + +#include "absl/strings/string_view.h" + +namespace rtc { + +const size_t SIZE_UNKNOWN = static_cast<size_t>(-1); + +// An absl::string_view comparator functor for use with container types such as +// std::map that support heterogenous lookup. +// +// Example usage: +// std::map<std::string, int, rtc::AbslStringViewCmp> my_map; +struct AbslStringViewCmp { + using is_transparent = void; + bool operator()(absl::string_view a, absl::string_view b) const { + return a < b; + } +}; + +// Safe version of strncpy that always nul-terminate. +size_t strcpyn(char* buffer, size_t buflen, absl::string_view source); + +/////////////////////////////////////////////////////////////////////////////// +// UTF helpers (Windows only) +/////////////////////////////////////////////////////////////////////////////// + +#if defined(WEBRTC_WIN) + +inline std::wstring ToUtf16(const char* utf8, size_t len) { + if (len == 0) + return std::wstring(); + int len16 = ::MultiByteToWideChar(CP_UTF8, 0, utf8, static_cast<int>(len), + nullptr, 0); + std::wstring ws(len16, 0); + ::MultiByteToWideChar(CP_UTF8, 0, utf8, static_cast<int>(len), &*ws.begin(), + len16); + return ws; +} + +inline std::wstring ToUtf16(absl::string_view str) { + return ToUtf16(str.data(), str.length()); +} + +inline std::string ToUtf8(const wchar_t* wide, size_t len) { + if (len == 0) + return std::string(); + int len8 = ::WideCharToMultiByte(CP_UTF8, 0, wide, static_cast<int>(len), + nullptr, 0, nullptr, nullptr); + std::string ns(len8, 0); + ::WideCharToMultiByte(CP_UTF8, 0, wide, static_cast<int>(len), &*ns.begin(), + len8, nullptr, nullptr); + return ns; +} + +inline std::string ToUtf8(const wchar_t* wide) { + return ToUtf8(wide, wcslen(wide)); +} + +inline std::string ToUtf8(const std::wstring& wstr) { + return ToUtf8(wstr.data(), wstr.length()); +} + +#endif // WEBRTC_WIN + +// TODO(jonasolsson): replace with absl::Hex when that becomes available. +std::string ToHex(int i); + +// CompileTimeString comprises of a string-like object which can be used as a +// regular const char* in compile time and supports concatenation. Useful for +// concatenating constexpr strings in for example macro declarations. +namespace rtc_base_string_utils_internal { +template <int NPlus1> +struct CompileTimeString { + char string[NPlus1] = {0}; + constexpr CompileTimeString() = default; + template <int MPlus1> + explicit constexpr CompileTimeString(const char (&chars)[MPlus1]) { + char* chars_pointer = string; + for (auto c : chars) + *chars_pointer++ = c; + } + template <int MPlus1> + constexpr auto Concat(CompileTimeString<MPlus1> b) { + CompileTimeString<NPlus1 + MPlus1 - 1> result; + char* chars_pointer = result.string; + for (auto c : string) + *chars_pointer++ = c; + chars_pointer = result.string + NPlus1 - 1; + for (auto c : b.string) + *chars_pointer++ = c; + result.string[NPlus1 + MPlus1 - 2] = 0; + return result; + } + constexpr operator const char*() { return string; } +}; +} // namespace rtc_base_string_utils_internal + +// Makes a constexpr CompileTimeString<X> without having to specify X +// explicitly. +template <int N> +constexpr auto MakeCompileTimeString(const char (&a)[N]) { + return rtc_base_string_utils_internal::CompileTimeString<N>(a); +} + +} // namespace rtc + +#endif // RTC_BASE_STRING_UTILS_H_ diff --git a/third_party/libwebrtc/rtc_base/string_utils_unittest.cc b/third_party/libwebrtc/rtc_base/string_utils_unittest.cc new file mode 100644 index 0000000000..4e4bebdda7 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/string_utils_unittest.cc @@ -0,0 +1,59 @@ +/* + * 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 "rtc_base/string_utils.h" + +#include "test/gtest.h" + +namespace rtc { + +TEST(string_toHexTest, ToHex) { + EXPECT_EQ(ToHex(0), "0"); + EXPECT_EQ(ToHex(0X1243E), "1243e"); + EXPECT_EQ(ToHex(-20), "ffffffec"); +} + +#if defined(WEBRTC_WIN) + +TEST(string_toutf, Empty) { + char empty_string[] = ""; + EXPECT_TRUE(ToUtf16(empty_string, 0u).empty()); + wchar_t empty_wchar[] = L""; + EXPECT_TRUE(ToUtf8(empty_wchar, 0u).empty()); +} + +#endif // WEBRTC_WIN + +TEST(CompileTimeString, MakeActsLikeAString) { + EXPECT_STREQ(MakeCompileTimeString("abc123"), "abc123"); +} + +TEST(CompileTimeString, ConvertibleToStdString) { + EXPECT_EQ(std::string(MakeCompileTimeString("abab")), "abab"); +} + +namespace detail { +constexpr bool StringEquals(const char* a, const char* b) { + while (*a && *a == *b) + a++, b++; + return *a == *b; +} +} // namespace detail + +static_assert(detail::StringEquals(MakeCompileTimeString("handellm"), + "handellm"), + "String should initialize."); + +static_assert(detail::StringEquals(MakeCompileTimeString("abc123").Concat( + MakeCompileTimeString("def456ghi")), + "abc123def456ghi"), + "Strings should concatenate."); + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/strings/audio_format_to_string.cc b/third_party/libwebrtc/rtc_base/strings/audio_format_to_string.cc new file mode 100644 index 0000000000..7e91c3b49d --- /dev/null +++ b/third_party/libwebrtc/rtc_base/strings/audio_format_to_string.cc @@ -0,0 +1,54 @@ +/* + * 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. + */ + +#include "rtc_base/strings/audio_format_to_string.h" + +#include <utility> + +#include "rtc_base/strings/string_builder.h" + +namespace rtc { +std::string ToString(const webrtc::SdpAudioFormat& saf) { + char sb_buf[1024]; + rtc::SimpleStringBuilder sb(sb_buf); + sb << "{name: " << saf.name; + sb << ", clockrate_hz: " << saf.clockrate_hz; + sb << ", num_channels: " << saf.num_channels; + sb << ", parameters: {"; + const char* sep = ""; + for (const auto& kv : saf.parameters) { + sb << sep << kv.first << ": " << kv.second; + sep = ", "; + } + sb << "}}"; + return sb.str(); +} +std::string ToString(const webrtc::AudioCodecInfo& aci) { + char sb_buf[1024]; + rtc::SimpleStringBuilder sb(sb_buf); + sb << "{sample_rate_hz: " << aci.sample_rate_hz; + sb << ", num_channels: " << aci.num_channels; + sb << ", default_bitrate_bps: " << aci.default_bitrate_bps; + sb << ", min_bitrate_bps: " << aci.min_bitrate_bps; + sb << ", max_bitrate_bps: " << aci.max_bitrate_bps; + sb << ", allow_comfort_noise: " << aci.allow_comfort_noise; + sb << ", supports_network_adaption: " << aci.supports_network_adaption; + sb << "}"; + return sb.str(); +} +std::string ToString(const webrtc::AudioCodecSpec& acs) { + char sb_buf[1024]; + rtc::SimpleStringBuilder sb(sb_buf); + sb << "{format: " << ToString(acs.format); + sb << ", info: " << ToString(acs.info); + sb << "}"; + return sb.str(); +} +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/strings/audio_format_to_string.h b/third_party/libwebrtc/rtc_base/strings/audio_format_to_string.h new file mode 100644 index 0000000000..6a4535c939 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/strings/audio_format_to_string.h @@ -0,0 +1,24 @@ +/* + * 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 RTC_BASE_STRINGS_AUDIO_FORMAT_TO_STRING_H_ +#define RTC_BASE_STRINGS_AUDIO_FORMAT_TO_STRING_H_ + +#include <string> + +#include "api/audio_codecs/audio_format.h" + +namespace rtc { +std::string ToString(const webrtc::SdpAudioFormat& saf); +std::string ToString(const webrtc::AudioCodecInfo& saf); +std::string ToString(const webrtc::AudioCodecSpec& acs); +} // namespace rtc + +#endif // RTC_BASE_STRINGS_AUDIO_FORMAT_TO_STRING_H_ diff --git a/third_party/libwebrtc/rtc_base/strings/json.cc b/third_party/libwebrtc/rtc_base/strings/json.cc new file mode 100644 index 0000000000..5cf153c926 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/strings/json.cc @@ -0,0 +1,296 @@ +/* + * 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 "rtc_base/strings/json.h" + +#include <errno.h> +#include <limits.h> +#include <stdlib.h> + +#include "absl/strings/string_view.h" +#include "rtc_base/string_encode.h" + +namespace rtc { + +bool GetStringFromJson(const Json::Value& in, std::string* out) { + if (!in.isString()) { + if (in.isBool()) { + *out = rtc::ToString(in.asBool()); + } else if (in.isInt()) { + *out = rtc::ToString(in.asInt()); + } else if (in.isUInt()) { + *out = rtc::ToString(in.asUInt()); + } else if (in.isDouble()) { + *out = rtc::ToString(in.asDouble()); + } else { + return false; + } + } else { + *out = in.asString(); + } + return true; +} + +bool GetIntFromJson(const Json::Value& in, int* out) { + bool ret; + if (!in.isString()) { + ret = in.isConvertibleTo(Json::intValue); + if (ret) { + *out = in.asInt(); + } + } else { + long val; // NOLINT + const char* c_str = in.asCString(); + char* end_ptr; + errno = 0; + val = strtol(c_str, &end_ptr, 10); // NOLINT + ret = (end_ptr != c_str && *end_ptr == '\0' && !errno && val >= INT_MIN && + val <= INT_MAX); + *out = val; + } + return ret; +} + +bool GetUIntFromJson(const Json::Value& in, unsigned int* out) { + bool ret; + if (!in.isString()) { + ret = in.isConvertibleTo(Json::uintValue); + if (ret) { + *out = in.asUInt(); + } + } else { + unsigned long val; // NOLINT + const char* c_str = in.asCString(); + char* end_ptr; + errno = 0; + val = strtoul(c_str, &end_ptr, 10); // NOLINT + ret = (end_ptr != c_str && *end_ptr == '\0' && !errno && val <= UINT_MAX); + *out = val; + } + return ret; +} + +bool GetBoolFromJson(const Json::Value& in, bool* out) { + bool ret; + if (!in.isString()) { + ret = in.isConvertibleTo(Json::booleanValue); + if (ret) { + *out = in.asBool(); + } + } else { + if (in.asString() == "true") { + *out = true; + ret = true; + } else if (in.asString() == "false") { + *out = false; + ret = true; + } else { + ret = false; + } + } + return ret; +} + +bool GetDoubleFromJson(const Json::Value& in, double* out) { + bool ret; + if (!in.isString()) { + ret = in.isConvertibleTo(Json::realValue); + if (ret) { + *out = in.asDouble(); + } + } else { + double val; + const char* c_str = in.asCString(); + char* end_ptr; + errno = 0; + val = strtod(c_str, &end_ptr); + ret = (end_ptr != c_str && *end_ptr == '\0' && !errno); + *out = val; + } + return ret; +} + +namespace { +template <typename T> +bool JsonArrayToVector(const Json::Value& value, + bool (*getter)(const Json::Value& in, T* out), + std::vector<T>* vec) { + vec->clear(); + if (!value.isArray()) { + return false; + } + + for (Json::Value::ArrayIndex i = 0; i < value.size(); ++i) { + T val; + if (!getter(value[i], &val)) { + return false; + } + vec->push_back(val); + } + + return true; +} +// Trivial getter helper +bool GetValueFromJson(const Json::Value& in, Json::Value* out) { + *out = in; + return true; +} +} // unnamed namespace + +bool JsonArrayToValueVector(const Json::Value& in, + std::vector<Json::Value>* out) { + return JsonArrayToVector(in, GetValueFromJson, out); +} + +bool JsonArrayToIntVector(const Json::Value& in, std::vector<int>* out) { + return JsonArrayToVector(in, GetIntFromJson, out); +} + +bool JsonArrayToUIntVector(const Json::Value& in, + std::vector<unsigned int>* out) { + return JsonArrayToVector(in, GetUIntFromJson, out); +} + +bool JsonArrayToStringVector(const Json::Value& in, + std::vector<std::string>* out) { + return JsonArrayToVector(in, GetStringFromJson, out); +} + +bool JsonArrayToBoolVector(const Json::Value& in, std::vector<bool>* out) { + return JsonArrayToVector(in, GetBoolFromJson, out); +} + +bool JsonArrayToDoubleVector(const Json::Value& in, std::vector<double>* out) { + return JsonArrayToVector(in, GetDoubleFromJson, out); +} + +namespace { +template <typename T> +Json::Value VectorToJsonArray(const std::vector<T>& vec) { + Json::Value result(Json::arrayValue); + for (size_t i = 0; i < vec.size(); ++i) { + result.append(Json::Value(vec[i])); + } + return result; +} +} // unnamed namespace + +Json::Value ValueVectorToJsonArray(const std::vector<Json::Value>& in) { + return VectorToJsonArray(in); +} + +Json::Value IntVectorToJsonArray(const std::vector<int>& in) { + return VectorToJsonArray(in); +} + +Json::Value UIntVectorToJsonArray(const std::vector<unsigned int>& in) { + return VectorToJsonArray(in); +} + +Json::Value StringVectorToJsonArray(const std::vector<std::string>& in) { + return VectorToJsonArray(in); +} + +Json::Value BoolVectorToJsonArray(const std::vector<bool>& in) { + return VectorToJsonArray(in); +} + +Json::Value DoubleVectorToJsonArray(const std::vector<double>& in) { + return VectorToJsonArray(in); +} + +bool GetValueFromJsonArray(const Json::Value& in, size_t n, Json::Value* out) { + if (!in.isArray() || !in.isValidIndex(static_cast<int>(n))) { + return false; + } + + *out = in[static_cast<Json::Value::ArrayIndex>(n)]; + return true; +} + +bool GetIntFromJsonArray(const Json::Value& in, size_t n, int* out) { + Json::Value x; + return GetValueFromJsonArray(in, n, &x) && GetIntFromJson(x, out); +} + +bool GetUIntFromJsonArray(const Json::Value& in, size_t n, unsigned int* out) { + Json::Value x; + return GetValueFromJsonArray(in, n, &x) && GetUIntFromJson(x, out); +} + +bool GetStringFromJsonArray(const Json::Value& in, size_t n, std::string* out) { + Json::Value x; + return GetValueFromJsonArray(in, n, &x) && GetStringFromJson(x, out); +} + +bool GetBoolFromJsonArray(const Json::Value& in, size_t n, bool* out) { + Json::Value x; + return GetValueFromJsonArray(in, n, &x) && GetBoolFromJson(x, out); +} + +bool GetDoubleFromJsonArray(const Json::Value& in, size_t n, double* out) { + Json::Value x; + return GetValueFromJsonArray(in, n, &x) && GetDoubleFromJson(x, out); +} + +bool GetValueFromJsonObject(const Json::Value& in, + absl::string_view k, + Json::Value* out) { + std::string k_str(k); + if (!in.isObject() || !in.isMember(k_str)) { + return false; + } + + *out = in[k_str]; + return true; +} + +bool GetIntFromJsonObject(const Json::Value& in, + absl::string_view k, + int* out) { + Json::Value x; + return GetValueFromJsonObject(in, k, &x) && GetIntFromJson(x, out); +} + +bool GetUIntFromJsonObject(const Json::Value& in, + absl::string_view k, + unsigned int* out) { + Json::Value x; + return GetValueFromJsonObject(in, k, &x) && GetUIntFromJson(x, out); +} + +bool GetStringFromJsonObject(const Json::Value& in, + absl::string_view k, + std::string* out) { + Json::Value x; + return GetValueFromJsonObject(in, k, &x) && GetStringFromJson(x, out); +} + +bool GetBoolFromJsonObject(const Json::Value& in, + absl::string_view k, + bool* out) { + Json::Value x; + return GetValueFromJsonObject(in, k, &x) && GetBoolFromJson(x, out); +} + +bool GetDoubleFromJsonObject(const Json::Value& in, + absl::string_view k, + double* out) { + Json::Value x; + return GetValueFromJsonObject(in, k, &x) && GetDoubleFromJson(x, out); +} + +std::string JsonValueToString(const Json::Value& json) { + Json::StreamWriterBuilder builder; + std::string output = Json::writeString(builder, json); + return output.substr(0, output.size() - 1); // trim trailing newline +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/strings/json.h b/third_party/libwebrtc/rtc_base/strings/json.h new file mode 100644 index 0000000000..3e4bac6d89 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/strings/json.h @@ -0,0 +1,83 @@ +/* + * 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 RTC_BASE_STRINGS_JSON_H_ +#define RTC_BASE_STRINGS_JSON_H_ + +#include <string> +#include <vector> + +#include "absl/strings/string_view.h" +#include "json/json.h" + +namespace rtc { + +/////////////////////////////////////////////////////////////////////////////// +// JSON Helpers +/////////////////////////////////////////////////////////////////////////////// + +// Robust conversion operators, better than the ones in JsonCpp. +bool GetIntFromJson(const Json::Value& in, int* out); +bool GetUIntFromJson(const Json::Value& in, unsigned int* out); +bool GetStringFromJson(const Json::Value& in, std::string* out); +bool GetBoolFromJson(const Json::Value& in, bool* out); +bool GetDoubleFromJson(const Json::Value& in, double* out); + +// Pull values out of a JSON array. +bool GetValueFromJsonArray(const Json::Value& in, size_t n, Json::Value* out); +bool GetIntFromJsonArray(const Json::Value& in, size_t n, int* out); +bool GetUIntFromJsonArray(const Json::Value& in, size_t n, unsigned int* out); +bool GetStringFromJsonArray(const Json::Value& in, size_t n, std::string* out); +bool GetBoolFromJsonArray(const Json::Value& in, size_t n, bool* out); +bool GetDoubleFromJsonArray(const Json::Value& in, size_t n, double* out); + +// Convert json arrays to std::vector +bool JsonArrayToValueVector(const Json::Value& in, + std::vector<Json::Value>* out); +bool JsonArrayToIntVector(const Json::Value& in, std::vector<int>* out); +bool JsonArrayToUIntVector(const Json::Value& in, + std::vector<unsigned int>* out); +bool JsonArrayToStringVector(const Json::Value& in, + std::vector<std::string>* out); +bool JsonArrayToBoolVector(const Json::Value& in, std::vector<bool>* out); +bool JsonArrayToDoubleVector(const Json::Value& in, std::vector<double>* out); + +// Convert std::vector to json array +Json::Value ValueVectorToJsonArray(const std::vector<Json::Value>& in); +Json::Value IntVectorToJsonArray(const std::vector<int>& in); +Json::Value UIntVectorToJsonArray(const std::vector<unsigned int>& in); +Json::Value StringVectorToJsonArray(const std::vector<std::string>& in); +Json::Value BoolVectorToJsonArray(const std::vector<bool>& in); +Json::Value DoubleVectorToJsonArray(const std::vector<double>& in); + +// Pull values out of a JSON object. +bool GetValueFromJsonObject(const Json::Value& in, + absl::string_view k, + Json::Value* out); +bool GetIntFromJsonObject(const Json::Value& in, absl::string_view k, int* out); +bool GetUIntFromJsonObject(const Json::Value& in, + absl::string_view k, + unsigned int* out); +bool GetStringFromJsonObject(const Json::Value& in, + absl::string_view k, + std::string* out); +bool GetBoolFromJsonObject(const Json::Value& in, + absl::string_view k, + bool* out); +bool GetDoubleFromJsonObject(const Json::Value& in, + absl::string_view k, + double* out); + +// Writes out a Json value as a string. +std::string JsonValueToString(const Json::Value& json); + +} // namespace rtc + +#endif // RTC_BASE_STRINGS_JSON_H_ diff --git a/third_party/libwebrtc/rtc_base/strings/json_unittest.cc b/third_party/libwebrtc/rtc_base/strings/json_unittest.cc new file mode 100644 index 0000000000..82d26f179e --- /dev/null +++ b/third_party/libwebrtc/rtc_base/strings/json_unittest.cc @@ -0,0 +1,283 @@ +/* + * Copyright 2009 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 "rtc_base/strings/json.h" + +#include <vector> + +#include "test/gtest.h" + +namespace rtc { + +static Json::Value in_s("foo"); +static Json::Value in_sn("99"); +static Json::Value in_si("-99"); +static Json::Value in_sb("true"); +static Json::Value in_sd("1.2"); +static Json::Value in_n(12); +static Json::Value in_i(-12); +static Json::Value in_u(34U); +static Json::Value in_b(true); +static Json::Value in_d(1.2); +static Json::Value big_sn("12345678901234567890"); +static Json::Value big_si("-12345678901234567890"); +static Json::Value big_u(0xFFFFFFFF); +static Json::Value bad_a(Json::arrayValue); +static Json::Value bad_o(Json::objectValue); + +TEST(JsonTest, GetString) { + std::string out; + EXPECT_TRUE(GetStringFromJson(in_s, &out)); + EXPECT_EQ("foo", out); + EXPECT_TRUE(GetStringFromJson(in_sn, &out)); + EXPECT_EQ("99", out); + EXPECT_TRUE(GetStringFromJson(in_si, &out)); + EXPECT_EQ("-99", out); + EXPECT_TRUE(GetStringFromJson(in_i, &out)); + EXPECT_EQ("-12", out); + EXPECT_TRUE(GetStringFromJson(in_n, &out)); + EXPECT_EQ("12", out); + EXPECT_TRUE(GetStringFromJson(in_u, &out)); + EXPECT_EQ("34", out); + EXPECT_TRUE(GetStringFromJson(in_b, &out)); + EXPECT_EQ("true", out); + // Not supported here yet. + EXPECT_FALSE(GetStringFromJson(bad_a, &out)); + EXPECT_FALSE(GetStringFromJson(bad_o, &out)); +} + +TEST(JsonTest, GetInt) { + int out; + EXPECT_TRUE(GetIntFromJson(in_sn, &out)); + EXPECT_EQ(99, out); + EXPECT_TRUE(GetIntFromJson(in_si, &out)); + EXPECT_EQ(-99, out); + EXPECT_TRUE(GetIntFromJson(in_n, &out)); + EXPECT_EQ(12, out); + EXPECT_TRUE(GetIntFromJson(in_i, &out)); + EXPECT_EQ(-12, out); + EXPECT_TRUE(GetIntFromJson(in_u, &out)); + EXPECT_EQ(34, out); + EXPECT_TRUE(GetIntFromJson(in_b, &out)); + EXPECT_EQ(1, out); + EXPECT_FALSE(GetIntFromJson(in_s, &out)); + EXPECT_FALSE(GetIntFromJson(big_sn, &out)); + EXPECT_FALSE(GetIntFromJson(big_si, &out)); + EXPECT_FALSE(GetIntFromJson(big_u, &out)); + EXPECT_FALSE(GetIntFromJson(bad_a, &out)); + EXPECT_FALSE(GetIntFromJson(bad_o, &out)); +} + +TEST(JsonTest, GetUInt) { + unsigned int out; + EXPECT_TRUE(GetUIntFromJson(in_sn, &out)); + EXPECT_EQ(99U, out); + EXPECT_TRUE(GetUIntFromJson(in_n, &out)); + EXPECT_EQ(12U, out); + EXPECT_TRUE(GetUIntFromJson(in_u, &out)); + EXPECT_EQ(34U, out); + EXPECT_TRUE(GetUIntFromJson(in_b, &out)); + EXPECT_EQ(1U, out); + EXPECT_TRUE(GetUIntFromJson(big_u, &out)); + EXPECT_EQ(0xFFFFFFFFU, out); + EXPECT_FALSE(GetUIntFromJson(in_s, &out)); + // TODO(bugs.webrtc.org/9804): Fail reading negative strings. + // EXPECT_FALSE(GetUIntFromJson(in_si, &out)); + EXPECT_FALSE(GetUIntFromJson(in_i, &out)); + EXPECT_FALSE(GetUIntFromJson(big_sn, &out)); + EXPECT_FALSE(GetUIntFromJson(big_si, &out)); + EXPECT_FALSE(GetUIntFromJson(bad_a, &out)); + EXPECT_FALSE(GetUIntFromJson(bad_o, &out)); +} + +TEST(JsonTest, GetBool) { + bool out; + EXPECT_TRUE(GetBoolFromJson(in_sb, &out)); + EXPECT_EQ(true, out); + EXPECT_TRUE(GetBoolFromJson(in_n, &out)); + EXPECT_EQ(true, out); + EXPECT_TRUE(GetBoolFromJson(in_i, &out)); + EXPECT_EQ(true, out); + EXPECT_TRUE(GetBoolFromJson(in_u, &out)); + EXPECT_EQ(true, out); + EXPECT_TRUE(GetBoolFromJson(in_b, &out)); + EXPECT_EQ(true, out); + EXPECT_TRUE(GetBoolFromJson(big_u, &out)); + EXPECT_EQ(true, out); + EXPECT_FALSE(GetBoolFromJson(in_s, &out)); + EXPECT_FALSE(GetBoolFromJson(in_sn, &out)); + EXPECT_FALSE(GetBoolFromJson(in_si, &out)); + EXPECT_FALSE(GetBoolFromJson(big_sn, &out)); + EXPECT_FALSE(GetBoolFromJson(big_si, &out)); + EXPECT_FALSE(GetBoolFromJson(bad_a, &out)); + EXPECT_FALSE(GetBoolFromJson(bad_o, &out)); +} + +TEST(JsonTest, GetDouble) { + double out; + EXPECT_TRUE(GetDoubleFromJson(in_sn, &out)); + EXPECT_EQ(99, out); + EXPECT_TRUE(GetDoubleFromJson(in_si, &out)); + EXPECT_EQ(-99, out); + EXPECT_TRUE(GetDoubleFromJson(in_sd, &out)); + EXPECT_EQ(1.2, out); + EXPECT_TRUE(GetDoubleFromJson(in_n, &out)); + EXPECT_EQ(12, out); + EXPECT_TRUE(GetDoubleFromJson(in_i, &out)); + EXPECT_EQ(-12, out); + EXPECT_TRUE(GetDoubleFromJson(in_u, &out)); + EXPECT_EQ(34, out); + EXPECT_TRUE(GetDoubleFromJson(in_b, &out)); + EXPECT_EQ(1, out); + EXPECT_TRUE(GetDoubleFromJson(in_d, &out)); + EXPECT_EQ(1.2, out); + EXPECT_FALSE(GetDoubleFromJson(in_s, &out)); +} + +TEST(JsonTest, GetFromArray) { + Json::Value a, out; + a.append(in_s); + a.append(in_i); + a.append(in_u); + a.append(in_b); + EXPECT_TRUE(GetValueFromJsonArray(a, 0, &out)); + EXPECT_TRUE(GetValueFromJsonArray(a, 3, &out)); + EXPECT_FALSE(GetValueFromJsonArray(a, 99, &out)); + EXPECT_FALSE(GetValueFromJsonArray(a, 0xFFFFFFFF, &out)); +} + +TEST(JsonTest, GetFromObject) { + Json::Value o, out; + o["string"] = in_s; + o["int"] = in_i; + o["uint"] = in_u; + o["bool"] = in_b; + EXPECT_TRUE(GetValueFromJsonObject(o, "int", &out)); + EXPECT_TRUE(GetValueFromJsonObject(o, "bool", &out)); + EXPECT_FALSE(GetValueFromJsonObject(o, "foo", &out)); + EXPECT_FALSE(GetValueFromJsonObject(o, "", &out)); +} + +namespace { +template <typename T> +std::vector<T> VecOf3(const T& a, const T& b, const T& c) { + std::vector<T> in; + in.push_back(a); + in.push_back(b); + in.push_back(c); + return in; +} +template <typename T> +Json::Value JsonVecOf3(const T& a, const T& b, const T& c) { + Json::Value in(Json::arrayValue); + in.append(a); + in.append(b); + in.append(c); + return in; +} +} // unnamed namespace + +TEST(JsonTest, ValueVectorToFromArray) { + std::vector<Json::Value> in = VecOf3<Json::Value>("a", "b", "c"); + Json::Value out = ValueVectorToJsonArray(in); + EXPECT_EQ(in.size(), out.size()); + for (Json::Value::ArrayIndex i = 0; i < in.size(); ++i) { + EXPECT_EQ(in[i].asString(), out[i].asString()); + } + Json::Value inj = JsonVecOf3<Json::Value>("a", "b", "c"); + EXPECT_EQ(inj, out); + std::vector<Json::Value> outj; + EXPECT_TRUE(JsonArrayToValueVector(inj, &outj)); + for (Json::Value::ArrayIndex i = 0; i < in.size(); i++) { + EXPECT_EQ(in[i], outj[i]); + } +} + +TEST(JsonTest, IntVectorToFromArray) { + std::vector<int> in = VecOf3<int>(1, 2, 3); + Json::Value out = IntVectorToJsonArray(in); + EXPECT_EQ(in.size(), out.size()); + for (Json::Value::ArrayIndex i = 0; i < in.size(); ++i) { + EXPECT_EQ(in[i], out[i].asInt()); + } + Json::Value inj = JsonVecOf3<int>(1, 2, 3); + EXPECT_EQ(inj, out); + std::vector<int> outj; + EXPECT_TRUE(JsonArrayToIntVector(inj, &outj)); + for (Json::Value::ArrayIndex i = 0; i < in.size(); i++) { + EXPECT_EQ(in[i], outj[i]); + } +} + +TEST(JsonTest, UIntVectorToFromArray) { + std::vector<unsigned int> in = VecOf3<unsigned int>(1, 2, 3); + Json::Value out = UIntVectorToJsonArray(in); + EXPECT_EQ(in.size(), out.size()); + for (Json::Value::ArrayIndex i = 0; i < in.size(); ++i) { + EXPECT_EQ(in[i], out[i].asUInt()); + } + Json::Value inj = JsonVecOf3<unsigned int>(1, 2, 3); + EXPECT_EQ(inj, out); + std::vector<unsigned int> outj; + EXPECT_TRUE(JsonArrayToUIntVector(inj, &outj)); + for (Json::Value::ArrayIndex i = 0; i < in.size(); i++) { + EXPECT_EQ(in[i], outj[i]); + } +} + +TEST(JsonTest, StringVectorToFromArray) { + std::vector<std::string> in = VecOf3<std::string>("a", "b", "c"); + Json::Value out = StringVectorToJsonArray(in); + EXPECT_EQ(in.size(), out.size()); + for (Json::Value::ArrayIndex i = 0; i < in.size(); ++i) { + EXPECT_EQ(in[i], out[i].asString()); + } + Json::Value inj = JsonVecOf3<std::string>("a", "b", "c"); + EXPECT_EQ(inj, out); + std::vector<std::string> outj; + EXPECT_TRUE(JsonArrayToStringVector(inj, &outj)); + for (Json::Value::ArrayIndex i = 0; i < in.size(); i++) { + EXPECT_EQ(in[i], outj[i]); + } +} + +TEST(JsonTest, BoolVectorToFromArray) { + std::vector<bool> in = VecOf3<bool>(false, true, false); + Json::Value out = BoolVectorToJsonArray(in); + EXPECT_EQ(in.size(), out.size()); + for (Json::Value::ArrayIndex i = 0; i < in.size(); ++i) { + EXPECT_EQ(in[i], out[i].asBool()); + } + Json::Value inj = JsonVecOf3<bool>(false, true, false); + EXPECT_EQ(inj, out); + std::vector<bool> outj; + EXPECT_TRUE(JsonArrayToBoolVector(inj, &outj)); + for (Json::Value::ArrayIndex i = 0; i < in.size(); i++) { + EXPECT_EQ(in[i], outj[i]); + } +} + +TEST(JsonTest, DoubleVectorToFromArray) { + std::vector<double> in = VecOf3<double>(1.0, 2.0, 3.0); + Json::Value out = DoubleVectorToJsonArray(in); + EXPECT_EQ(in.size(), out.size()); + for (Json::Value::ArrayIndex i = 0; i < in.size(); ++i) { + EXPECT_EQ(in[i], out[i].asDouble()); + } + Json::Value inj = JsonVecOf3<double>(1.0, 2.0, 3.0); + EXPECT_EQ(inj, out); + std::vector<double> outj; + EXPECT_TRUE(JsonArrayToDoubleVector(inj, &outj)); + for (Json::Value::ArrayIndex i = 0; i < in.size(); i++) { + EXPECT_EQ(in[i], outj[i]); + } +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/strings/string_builder.cc b/third_party/libwebrtc/rtc_base/strings/string_builder.cc new file mode 100644 index 0000000000..a419b0b3cc --- /dev/null +++ b/third_party/libwebrtc/rtc_base/strings/string_builder.cc @@ -0,0 +1,134 @@ +/* + * 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. + */ + +#include "rtc_base/strings/string_builder.h" + +#include <stdarg.h> + +#include <cstdio> +#include <cstring> + +#include "absl/strings/string_view.h" +#include "rtc_base/checks.h" +#include "rtc_base/numerics/safe_minmax.h" + +namespace rtc { + +SimpleStringBuilder::SimpleStringBuilder(rtc::ArrayView<char> buffer) + : buffer_(buffer) { + buffer_[0] = '\0'; + RTC_DCHECK(IsConsistent()); +} + +SimpleStringBuilder& SimpleStringBuilder::operator<<(char ch) { + return operator<<(absl::string_view(&ch, 1)); +} + +SimpleStringBuilder& SimpleStringBuilder::operator<<(absl::string_view str) { + RTC_DCHECK_LT(size_ + str.length(), buffer_.size()) + << "Buffer size was insufficient"; + const size_t chars_added = + rtc::SafeMin(str.length(), buffer_.size() - size_ - 1); + memcpy(&buffer_[size_], str.data(), chars_added); + size_ += chars_added; + buffer_[size_] = '\0'; + RTC_DCHECK(IsConsistent()); + return *this; +} + +// Numeric conversion routines. +// +// We use std::[v]snprintf instead of std::to_string because: +// * std::to_string relies on the current locale for formatting purposes, +// and therefore concurrent calls to std::to_string from multiple threads +// may result in partial serialization of calls +// * snprintf allows us to print the number directly into our buffer. +// * avoid allocating a std::string (potential heap alloc). +// TODO(tommi): Switch to std::to_chars in C++17. + +SimpleStringBuilder& SimpleStringBuilder::operator<<(int i) { + return AppendFormat("%d", i); +} + +SimpleStringBuilder& SimpleStringBuilder::operator<<(unsigned i) { + return AppendFormat("%u", i); +} + +SimpleStringBuilder& SimpleStringBuilder::operator<<(long i) { // NOLINT + return AppendFormat("%ld", i); +} + +SimpleStringBuilder& SimpleStringBuilder::operator<<(long long i) { // NOLINT + return AppendFormat("%lld", i); +} + +SimpleStringBuilder& SimpleStringBuilder::operator<<( + unsigned long i) { // NOLINT + return AppendFormat("%lu", i); +} + +SimpleStringBuilder& SimpleStringBuilder::operator<<( + unsigned long long i) { // NOLINT + return AppendFormat("%llu", i); +} + +SimpleStringBuilder& SimpleStringBuilder::operator<<(float f) { + return AppendFormat("%g", f); +} + +SimpleStringBuilder& SimpleStringBuilder::operator<<(double f) { + return AppendFormat("%g", f); +} + +SimpleStringBuilder& SimpleStringBuilder::operator<<(long double f) { + return AppendFormat("%Lg", f); +} + +SimpleStringBuilder& SimpleStringBuilder::AppendFormat(const char* fmt, ...) { + va_list args; + va_start(args, fmt); + const int len = + std::vsnprintf(&buffer_[size_], buffer_.size() - size_, fmt, args); + if (len >= 0) { + const size_t chars_added = rtc::SafeMin(len, buffer_.size() - 1 - size_); + size_ += chars_added; + RTC_DCHECK_EQ(len, chars_added) << "Buffer size was insufficient"; + } else { + // This should never happen, but we're paranoid, so re-write the + // terminator in case vsnprintf() overwrote it. + RTC_DCHECK_NOTREACHED(); + buffer_[size_] = '\0'; + } + va_end(args); + RTC_DCHECK(IsConsistent()); + return *this; +} + +StringBuilder& StringBuilder::AppendFormat(const char* fmt, ...) { + va_list args, copy; + va_start(args, fmt); + va_copy(copy, args); + const int predicted_length = std::vsnprintf(nullptr, 0, fmt, copy); + va_end(copy); + + RTC_DCHECK_GE(predicted_length, 0); + if (predicted_length > 0) { + const size_t size = str_.size(); + str_.resize(size + predicted_length); + // Pass "+ 1" to vsnprintf to include space for the '\0'. + const int actual_length = + std::vsnprintf(&str_[size], predicted_length + 1, fmt, args); + RTC_DCHECK_GE(actual_length, 0); + } + va_end(args); + return *this; +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/strings/string_builder.h b/third_party/libwebrtc/rtc_base/strings/string_builder.h new file mode 100644 index 0000000000..00986371d3 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/strings/string_builder.h @@ -0,0 +1,170 @@ +/* + * 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 RTC_BASE_STRINGS_STRING_BUILDER_H_ +#define RTC_BASE_STRINGS_STRING_BUILDER_H_ + +#include <cstdio> +#include <string> +#include <utility> + +#include "absl/strings/string_view.h" +#include "api/array_view.h" +#include "rtc_base/string_encode.h" + +namespace rtc { + +// This is a minimalistic string builder class meant to cover the most cases of +// when you might otherwise be tempted to use a stringstream (discouraged for +// anything except logging). It uses a fixed-size buffer provided by the caller +// and concatenates strings and numbers into it, allowing the results to be +// read via `str()`. +class SimpleStringBuilder { + public: + explicit SimpleStringBuilder(rtc::ArrayView<char> buffer); + SimpleStringBuilder(const SimpleStringBuilder&) = delete; + SimpleStringBuilder& operator=(const SimpleStringBuilder&) = delete; + + SimpleStringBuilder& operator<<(char ch); + SimpleStringBuilder& operator<<(absl::string_view str); + SimpleStringBuilder& operator<<(int i); + SimpleStringBuilder& operator<<(unsigned i); + SimpleStringBuilder& operator<<(long i); // NOLINT + SimpleStringBuilder& operator<<(long long i); // NOLINT + SimpleStringBuilder& operator<<(unsigned long i); // NOLINT + SimpleStringBuilder& operator<<(unsigned long long i); // NOLINT + SimpleStringBuilder& operator<<(float f); + SimpleStringBuilder& operator<<(double f); + SimpleStringBuilder& operator<<(long double f); + + // Returns a pointer to the built string. The name `str()` is borrowed for + // compatibility reasons as we replace usage of stringstream throughout the + // code base. + const char* str() const { return buffer_.data(); } + + // Returns the length of the string. The name `size()` is picked for STL + // compatibility reasons. + size_t size() const { return size_; } + +// Allows appending a printf style formatted string. +#if defined(__GNUC__) + __attribute__((__format__(__printf__, 2, 3))) +#endif + SimpleStringBuilder& + AppendFormat(const char* fmt, ...); + + private: + bool IsConsistent() const { + return size_ <= buffer_.size() - 1 && buffer_[size_] == '\0'; + } + + // An always-zero-terminated fixed-size buffer that we write to. The fixed + // size allows the buffer to be stack allocated, which helps performance. + // Having a fixed size is furthermore useful to avoid unnecessary resizing + // while building it. + const rtc::ArrayView<char> buffer_; + + // Represents the number of characters written to the buffer. + // This does not include the terminating '\0'. + size_t size_ = 0; +}; + +// A string builder that supports dynamic resizing while building a string. +// The class is based around an instance of std::string and allows moving +// ownership out of the class once the string has been built. +// Note that this class uses the heap for allocations, so SimpleStringBuilder +// might be more efficient for some use cases. +class StringBuilder { + public: + StringBuilder() {} + explicit StringBuilder(absl::string_view s) : str_(s) {} + + // TODO(tommi): Support construction from StringBuilder? + StringBuilder(const StringBuilder&) = delete; + StringBuilder& operator=(const StringBuilder&) = delete; + + StringBuilder& operator<<(const absl::string_view str) { + str_.append(str.data(), str.length()); + return *this; + } + + StringBuilder& operator<<(char c) = delete; + + StringBuilder& operator<<(int i) { + str_ += rtc::ToString(i); + return *this; + } + + StringBuilder& operator<<(unsigned i) { + str_ += rtc::ToString(i); + return *this; + } + + StringBuilder& operator<<(long i) { // NOLINT + str_ += rtc::ToString(i); + return *this; + } + + StringBuilder& operator<<(long long i) { // NOLINT + str_ += rtc::ToString(i); + return *this; + } + + StringBuilder& operator<<(unsigned long i) { // NOLINT + str_ += rtc::ToString(i); + return *this; + } + + StringBuilder& operator<<(unsigned long long i) { // NOLINT + str_ += rtc::ToString(i); + return *this; + } + + StringBuilder& operator<<(float f) { + str_ += rtc::ToString(f); + return *this; + } + + StringBuilder& operator<<(double f) { + str_ += rtc::ToString(f); + return *this; + } + + StringBuilder& operator<<(long double f) { + str_ += rtc::ToString(f); + return *this; + } + + const std::string& str() const { return str_; } + + void Clear() { str_.clear(); } + + size_t size() const { return str_.size(); } + + std::string Release() { + std::string ret = std::move(str_); + str_.clear(); + return ret; + } + + // Allows appending a printf style formatted string. + StringBuilder& AppendFormat(const char* fmt, ...) +#if defined(__GNUC__) + __attribute__((__format__(__printf__, 2, 3))) +#endif + ; + + private: + std::string str_; +}; + +} // namespace rtc + +#endif // RTC_BASE_STRINGS_STRING_BUILDER_H_ diff --git a/third_party/libwebrtc/rtc_base/strings/string_builder_unittest.cc b/third_party/libwebrtc/rtc_base/strings/string_builder_unittest.cc new file mode 100644 index 0000000000..99dfd86292 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/strings/string_builder_unittest.cc @@ -0,0 +1,202 @@ +/* + * 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. + */ + +#include "rtc_base/strings/string_builder.h" + +#include <string.h> + +#include "rtc_base/checks.h" +#include "test/gmock.h" +#include "test/gtest.h" + +namespace rtc { + +TEST(SimpleStringBuilder, Limit) { + char sb_buf[10]; + SimpleStringBuilder sb(sb_buf); + EXPECT_EQ(0u, strlen(sb.str())); + + // Test that for a SSB with a buffer size of 10, that we can write 9 chars + // into it. + sb << "012345678"; // 9 characters + '\0'. + EXPECT_EQ(0, strcmp(sb.str(), "012345678")); +} + +TEST(SimpleStringBuilder, NumbersAndChars) { + char sb_buf[100]; + SimpleStringBuilder sb(sb_buf); + sb << 1 << ':' << 2.1 << ":" << 2.2f << ':' << 78187493520ll << ':' + << 78187493520ul; + EXPECT_EQ(0, strcmp(sb.str(), "1:2.1:2.2:78187493520:78187493520")); +} + +TEST(SimpleStringBuilder, Format) { + char sb_buf[100]; + SimpleStringBuilder sb(sb_buf); + sb << "Here we go - "; + sb.AppendFormat("This is a hex formatted value: 0x%08llx", 3735928559ULL); + EXPECT_EQ(0, + strcmp(sb.str(), + "Here we go - This is a hex formatted value: 0xdeadbeef")); +} + +TEST(SimpleStringBuilder, StdString) { + char sb_buf[100]; + SimpleStringBuilder sb(sb_buf); + std::string str = "does this work?"; + sb << str; + EXPECT_EQ(str, sb.str()); +} + +// These tests are safe to run if we have death test support or if DCHECKs are +// off. +#if (GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)) || !RTC_DCHECK_IS_ON + +TEST(SimpleStringBuilderDeathTest, BufferOverrunConstCharP) { + char sb_buf[4]; + SimpleStringBuilder sb(sb_buf); + const char* const msg = "This is just too much"; +#if RTC_DCHECK_IS_ON + EXPECT_DEATH(sb << msg, ""); +#else + sb << msg; + EXPECT_THAT(sb.str(), ::testing::StrEq("Thi")); +#endif +} + +TEST(SimpleStringBuilderDeathTest, BufferOverrunStdString) { + char sb_buf[4]; + SimpleStringBuilder sb(sb_buf); + sb << 12; + const std::string msg = "Aw, come on!"; +#if RTC_DCHECK_IS_ON + EXPECT_DEATH(sb << msg, ""); +#else + sb << msg; + EXPECT_THAT(sb.str(), ::testing::StrEq("12A")); +#endif +} + +TEST(SimpleStringBuilderDeathTest, BufferOverrunInt) { + char sb_buf[4]; + SimpleStringBuilder sb(sb_buf); + constexpr int num = -12345; +#if RTC_DCHECK_IS_ON + EXPECT_DEATH(sb << num, ""); +#else + sb << num; + // If we run into the end of the buffer, resonable results are either that + // the append has no effect or that it's truncated at the point where the + // buffer ends. + EXPECT_THAT(sb.str(), + ::testing::AnyOf(::testing::StrEq(""), ::testing::StrEq("-12"))); +#endif +} + +TEST(SimpleStringBuilderDeathTest, BufferOverrunDouble) { + char sb_buf[5]; + SimpleStringBuilder sb(sb_buf); + constexpr double num = 123.456; +#if RTC_DCHECK_IS_ON + EXPECT_DEATH(sb << num, ""); +#else + sb << num; + EXPECT_THAT(sb.str(), + ::testing::AnyOf(::testing::StrEq(""), ::testing::StrEq("123."))); +#endif +} + +TEST(SimpleStringBuilderDeathTest, BufferOverrunConstCharPAlreadyFull) { + char sb_buf[4]; + SimpleStringBuilder sb(sb_buf); + sb << 123; + const char* const msg = "This is just too much"; +#if RTC_DCHECK_IS_ON + EXPECT_DEATH(sb << msg, ""); +#else + sb << msg; + EXPECT_THAT(sb.str(), ::testing::StrEq("123")); +#endif +} + +TEST(SimpleStringBuilderDeathTest, BufferOverrunIntAlreadyFull) { + char sb_buf[4]; + SimpleStringBuilder sb(sb_buf); + sb << "xyz"; + constexpr int num = -12345; +#if RTC_DCHECK_IS_ON + EXPECT_DEATH(sb << num, ""); +#else + sb << num; + EXPECT_THAT(sb.str(), ::testing::StrEq("xyz")); +#endif +} + +#endif + +//////////////////////////////////////////////////////////////////////////////// +// StringBuilder. + +TEST(StringBuilder, Limit) { + StringBuilder sb; + EXPECT_EQ(0u, sb.str().size()); + + sb << "012345678"; + EXPECT_EQ(sb.str(), "012345678"); +} + +TEST(StringBuilder, NumbersAndChars) { + StringBuilder sb; + sb << 1 << ":" << 2.1 << ":" << 2.2f << ":" << 78187493520ll << ":" + << 78187493520ul; + EXPECT_THAT(sb.str(), + ::testing::MatchesRegex("1:2.10*:2.20*:78187493520:78187493520")); +} + +TEST(StringBuilder, Format) { + StringBuilder sb; + sb << "Here we go - "; + sb.AppendFormat("This is a hex formatted value: 0x%08llx", 3735928559ULL); + EXPECT_EQ(sb.str(), "Here we go - This is a hex formatted value: 0xdeadbeef"); +} + +TEST(StringBuilder, StdString) { + StringBuilder sb; + std::string str = "does this work?"; + sb << str; + EXPECT_EQ(str, sb.str()); +} + +TEST(StringBuilder, Release) { + StringBuilder sb; + std::string str = + "This string has to be of a moderate length, or we might " + "run into problems with small object optimizations."; + EXPECT_LT(sizeof(str), str.size()); + sb << str; + EXPECT_EQ(str, sb.str()); + const char* original_buffer = sb.str().c_str(); + std::string moved = sb.Release(); + EXPECT_TRUE(sb.str().empty()); + EXPECT_EQ(str, moved); + EXPECT_EQ(original_buffer, moved.c_str()); +} + +TEST(StringBuilder, Reset) { + StringBuilder sb("abc"); + sb << "def"; + EXPECT_EQ("abcdef", sb.str()); + sb.Clear(); + EXPECT_TRUE(sb.str().empty()); + sb << 123 << "!"; + EXPECT_EQ("123!", sb.str()); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/strings/string_format.cc b/third_party/libwebrtc/rtc_base/strings/string_format.cc new file mode 100644 index 0000000000..e69fb6193d --- /dev/null +++ b/third_party/libwebrtc/rtc_base/strings/string_format.cc @@ -0,0 +1,41 @@ +/* + * 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. + */ + +#include "rtc_base/strings/string_format.h" + +#include <cstdarg> + +#include "rtc_base/checks.h" + +namespace rtc { + +namespace { + +// This is an arbitrary limitation that can be changed if necessary, or removed +// if someone has the time and inclination to replicate the fancy logic from +// Chromium's base::StringPrinf(). +constexpr int kMaxSize = 512; + +} // namespace + +std::string StringFormat(const char* fmt, ...) { + char buffer[kMaxSize]; + va_list args; + va_start(args, fmt); + int result = vsnprintf(buffer, kMaxSize, fmt, args); + va_end(args); + RTC_DCHECK_GE(result, 0) << "ERROR: vsnprintf() failed with error " << result; + RTC_DCHECK_LT(result, kMaxSize) + << "WARNING: string was truncated from " << result << " to " + << (kMaxSize - 1) << " characters"; + return std::string(buffer); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/strings/string_format.h b/third_party/libwebrtc/rtc_base/strings/string_format.h new file mode 100644 index 0000000000..13124d2925 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/strings/string_format.h @@ -0,0 +1,31 @@ +/* + * 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 RTC_BASE_STRINGS_STRING_FORMAT_H_ +#define RTC_BASE_STRINGS_STRING_FORMAT_H_ + +#include <string> + +namespace rtc { + +#if defined(__GNUC__) +#define RTC_PRINTF_FORMAT(format_param, dots_param) \ + __attribute__((format(printf, format_param, dots_param))) +#else +#define RTC_PRINTF_FORMAT(format_param, dots_param) +#endif + +// Return a C++ string given printf-like input. +// Based on base::StringPrintf() in Chrome but without its fancy dynamic memory +// allocation for any size of the input buffer. +std::string StringFormat(const char* fmt, ...) RTC_PRINTF_FORMAT(1, 2); +} // namespace rtc + +#endif // RTC_BASE_STRINGS_STRING_FORMAT_H_ diff --git a/third_party/libwebrtc/rtc_base/strings/string_format_unittest.cc b/third_party/libwebrtc/rtc_base/strings/string_format_unittest.cc new file mode 100644 index 0000000000..5531001979 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/strings/string_format_unittest.cc @@ -0,0 +1,52 @@ +/* + * 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. + */ + +#include "rtc_base/strings/string_format.h" + +#include <vector> + +#include "absl/strings/string_view.h" +#include "rtc_base/checks.h" +#include "rtc_base/string_encode.h" +#include "test/gtest.h" + +namespace rtc { + +TEST(StringFormatTest, Empty) { + EXPECT_EQ("", StringFormat("%s", "")); +} + +TEST(StringFormatTest, Misc) { + EXPECT_EQ("123hello w", StringFormat("%3d%2s %1c", 123, "hello", 'w')); + EXPECT_EQ("3 = three", StringFormat("%d = %s", 1 + 2, "three")); +} + +TEST(StringFormatTest, MaxSizeShouldWork) { + const int kSrcLen = 512; + char str[kSrcLen]; + std::fill_n(str, kSrcLen, 'A'); + str[kSrcLen - 1] = 0; + EXPECT_EQ(str, StringFormat("%s", str)); +} + +// Test that formating a string using `absl::string_view` works as expected +// whe using `%.*s`. +TEST(StringFormatTest, FormatStringView) { + const std::string main_string("This is a substring test."); + std::vector<absl::string_view> string_views = rtc::split(main_string, ' '); + ASSERT_EQ(string_views.size(), 5u); + + const absl::string_view& sv = string_views[3]; + std::string formatted = + StringFormat("We have a %.*s.", static_cast<int>(sv.size()), sv.data()); + EXPECT_EQ(formatted.compare("We have a substring."), 0); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/stringutils_gn/moz.build b/third_party/libwebrtc/rtc_base/stringutils_gn/moz.build new file mode 100644 index 0000000000..58008d114a --- /dev/null +++ b/third_party/libwebrtc/rtc_base/stringutils_gn/moz.build @@ -0,0 +1,229 @@ +# 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/rtc_base/string_encode.cc", + "/third_party/libwebrtc/rtc_base/string_to_number.cc", + "/third_party/libwebrtc/rtc_base/string_utils.cc", + "/third_party/libwebrtc/rtc_base/strings/string_builder.cc", + "/third_party/libwebrtc/rtc_base/strings/string_format.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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("stringutils_gn") diff --git a/third_party/libwebrtc/rtc_base/strong_alias.h b/third_party/libwebrtc/rtc_base/strong_alias.h new file mode 100644 index 0000000000..3f45113f63 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/strong_alias.h @@ -0,0 +1,76 @@ +/* + * Copyright 2019 The Chromium Authors. All rights reserved. + * Copyright (c) 2021 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 RTC_BASE_STRONG_ALIAS_H_ +#define RTC_BASE_STRONG_ALIAS_H_ + +#include <type_traits> +#include <utility> + +namespace webrtc { + +// This is a copy of +// https://source.chromium.org/chromium/chromium/src/+/main:base/types/strong_alias.h +// as the API (and internals) are using type-safe integral identifiers, but this +// library can't depend on that file. The ostream operator has been removed +// per WebRTC library conventions, and the underlying type is exposed. + +template <typename TagType, typename TheUnderlyingType> +class StrongAlias { + public: + using UnderlyingType = TheUnderlyingType; + constexpr StrongAlias() = default; + constexpr explicit StrongAlias(const UnderlyingType& v) : value_(v) {} + constexpr explicit StrongAlias(UnderlyingType&& v) noexcept + : value_(std::move(v)) {} + + constexpr UnderlyingType* operator->() { return &value_; } + constexpr const UnderlyingType* operator->() const { return &value_; } + + constexpr UnderlyingType& operator*() & { return value_; } + constexpr const UnderlyingType& operator*() const& { return value_; } + constexpr UnderlyingType&& operator*() && { return std::move(value_); } + constexpr const UnderlyingType&& operator*() const&& { + return std::move(value_); + } + + constexpr UnderlyingType& value() & { return value_; } + constexpr const UnderlyingType& value() const& { return value_; } + constexpr UnderlyingType&& value() && { return std::move(value_); } + constexpr const UnderlyingType&& value() const&& { return std::move(value_); } + + constexpr explicit operator const UnderlyingType&() const& { return value_; } + + constexpr bool operator==(const StrongAlias& other) const { + return value_ == other.value_; + } + constexpr bool operator!=(const StrongAlias& other) const { + return value_ != other.value_; + } + constexpr bool operator<(const StrongAlias& other) const { + return value_ < other.value_; + } + constexpr bool operator<=(const StrongAlias& other) const { + return value_ <= other.value_; + } + constexpr bool operator>(const StrongAlias& other) const { + return value_ > other.value_; + } + constexpr bool operator>=(const StrongAlias& other) const { + return value_ >= other.value_; + } + + protected: + UnderlyingType value_; +}; + +} // namespace webrtc + +#endif // RTC_BASE_STRONG_ALIAS_H_ diff --git a/third_party/libwebrtc/rtc_base/strong_alias_unittest.cc b/third_party/libwebrtc/rtc_base/strong_alias_unittest.cc new file mode 100644 index 0000000000..711c805e89 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/strong_alias_unittest.cc @@ -0,0 +1,362 @@ +/* + * Copyright 2019 The Chromium Authors. All rights reserved. + * Copyright (c) 2021 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 "rtc_base/strong_alias.h" + +#include <cstdint> +#include <map> +#include <memory> +#include <string> +#include <type_traits> +#include <utility> + +#include "rtc_base/containers/flat_map.h" +#include "rtc_base/gunit.h" +#include "test/gmock.h" + +// This is a copy of +// https://source.chromium.org/chromium/chromium/src/+/main:base/types/strong_alias_unittest.cc +// but adapted to use WebRTC's includes, remove unit tests that test the ostream +// operator (it's removed in this port) and other adaptations to pass lint. + +namespace webrtc { +namespace { + +// For test correctnenss, it's important that these getters return lexically +// incrementing values as `index` grows. +template <typename T> +T GetExampleValue(int index); + +template <> +int GetExampleValue<int>(int index) { + return 5 + index; +} +template <> +uint64_t GetExampleValue<uint64_t>(int index) { + return 500U + index; +} + +template <> +std::string GetExampleValue<std::string>(int index) { + return std::string('a', index); +} + +} // namespace + +template <typename T> +class StrongAliasTest : public ::testing::Test {}; + +using TestedTypes = ::testing::Types<int, uint64_t, std::string>; +TYPED_TEST_SUITE(StrongAliasTest, TestedTypes); + +TYPED_TEST(StrongAliasTest, ValueAccessesUnderlyingValue) { + using FooAlias = StrongAlias<class FooTag, TypeParam>; + + // Const value getter. + const FooAlias const_alias(GetExampleValue<TypeParam>(1)); + EXPECT_EQ(GetExampleValue<TypeParam>(1), const_alias.value()); + static_assert(std::is_const<typename std::remove_reference< + decltype(const_alias.value())>::type>::value, + "Reference returned by const value getter should be const."); +} + +TYPED_TEST(StrongAliasTest, ExplicitConversionToUnderlyingValue) { + using FooAlias = StrongAlias<class FooTag, TypeParam>; + + const FooAlias const_alias(GetExampleValue<TypeParam>(1)); + EXPECT_EQ(GetExampleValue<TypeParam>(1), static_cast<TypeParam>(const_alias)); +} + +TYPED_TEST(StrongAliasTest, CanBeCopyConstructed) { + using FooAlias = StrongAlias<class FooTag, TypeParam>; + FooAlias alias(GetExampleValue<TypeParam>(0)); + FooAlias copy_constructed = alias; + EXPECT_EQ(copy_constructed, alias); + + FooAlias copy_assigned; + copy_assigned = alias; + EXPECT_EQ(copy_assigned, alias); +} + +TYPED_TEST(StrongAliasTest, CanBeMoveConstructed) { + using FooAlias = StrongAlias<class FooTag, TypeParam>; + FooAlias alias(GetExampleValue<TypeParam>(0)); + FooAlias move_constructed = std::move(alias); + EXPECT_EQ(move_constructed, FooAlias(GetExampleValue<TypeParam>(0))); + + FooAlias alias2(GetExampleValue<TypeParam>(2)); + FooAlias move_assigned; + move_assigned = std::move(alias2); + EXPECT_EQ(move_assigned, FooAlias(GetExampleValue<TypeParam>(2))); + + // Check that FooAlias is nothrow move constructible. This matters for + // performance when used in std::vectors. + static_assert(std::is_nothrow_move_constructible<FooAlias>::value, + "Error: Alias is not nothow move constructible"); +} + +TYPED_TEST(StrongAliasTest, CanBeConstructedFromMoveOnlyType) { + // Note, using a move-only unique_ptr to T: + using FooAlias = StrongAlias<class FooTag, std::unique_ptr<TypeParam>>; + + FooAlias a(std::make_unique<TypeParam>(GetExampleValue<TypeParam>(0))); + EXPECT_EQ(*a.value(), GetExampleValue<TypeParam>(0)); + + auto bare_value = std::make_unique<TypeParam>(GetExampleValue<TypeParam>(1)); + FooAlias b(std::move(bare_value)); + EXPECT_EQ(*b.value(), GetExampleValue<TypeParam>(1)); +} + +TYPED_TEST(StrongAliasTest, MutableOperatorArrow) { + // Note, using a move-only unique_ptr to T: + using Ptr = std::unique_ptr<TypeParam>; + using FooAlias = StrongAlias<class FooTag, Ptr>; + + FooAlias a(std::make_unique<TypeParam>()); + EXPECT_TRUE(a.value()); + + // Check that `a` can be modified through the use of operator->. + a->reset(); + + EXPECT_FALSE(a.value()); +} + +TYPED_TEST(StrongAliasTest, MutableOperatorStar) { + // Note, using a move-only unique_ptr to T: + using Ptr = std::unique_ptr<TypeParam>; + using FooAlias = StrongAlias<class FooTag, Ptr>; + + FooAlias a(std::make_unique<TypeParam>()); + FooAlias b(std::make_unique<TypeParam>()); + EXPECT_TRUE(*a); + EXPECT_TRUE(*b); + + // Check that both the mutable l-value and r-value overloads work and we can + // move out of the aliases. + { Ptr ignore(*std::move(a)); } + { Ptr ignore(std::move(*b)); } + + EXPECT_FALSE(a.value()); + EXPECT_FALSE(b.value()); +} + +TYPED_TEST(StrongAliasTest, MutableValue) { + // Note, using a move-only unique_ptr to T: + using Ptr = std::unique_ptr<TypeParam>; + using FooAlias = StrongAlias<class FooTag, Ptr>; + + FooAlias a(std::make_unique<TypeParam>()); + FooAlias b(std::make_unique<TypeParam>()); + EXPECT_TRUE(a.value()); + EXPECT_TRUE(b.value()); + + // Check that both the mutable l-value and r-value overloads work and we can + // move out of the aliases. + { Ptr ignore(std::move(a).value()); } + { Ptr ignore(std::move(b.value())); } + + EXPECT_FALSE(a.value()); + EXPECT_FALSE(b.value()); +} + +TYPED_TEST(StrongAliasTest, SizeSameAsUnderlyingType) { + using FooAlias = StrongAlias<class FooTag, TypeParam>; + static_assert(sizeof(FooAlias) == sizeof(TypeParam), + "StrongAlias should be as large as the underlying type."); +} + +TYPED_TEST(StrongAliasTest, IsDefaultConstructible) { + using FooAlias = StrongAlias<class FooTag, TypeParam>; + static_assert(std::is_default_constructible<FooAlias>::value, + "Should be possible to default-construct a StrongAlias."); + static_assert( + std::is_trivially_default_constructible<FooAlias>::value == + std::is_trivially_default_constructible<TypeParam>::value, + "Should be possible to trivially default-construct a StrongAlias iff the " + "underlying type is trivially default constructible."); +} + +TEST(StrongAliasTest, TrivialTypeAliasIsStandardLayout) { + using FooAlias = StrongAlias<class FooTag, int>; + static_assert(std::is_standard_layout<FooAlias>::value, + "int-based alias should have standard layout. "); + static_assert(std::is_trivially_copyable<FooAlias>::value, + "int-based alias should be trivially copyable. "); +} + +TYPED_TEST(StrongAliasTest, CannotBeCreatedFromDifferentAlias) { + using FooAlias = StrongAlias<class FooTag, TypeParam>; + using BarAlias = StrongAlias<class BarTag, TypeParam>; + static_assert(!std::is_constructible<FooAlias, BarAlias>::value, + "Should be impossible to construct FooAlias from a BarAlias."); + static_assert(!std::is_convertible<BarAlias, FooAlias>::value, + "Should be impossible to convert a BarAlias into FooAlias."); +} + +TYPED_TEST(StrongAliasTest, CannotBeImplicitlyConverterToUnderlyingValue) { + using FooAlias = StrongAlias<class FooTag, TypeParam>; + static_assert(!std::is_convertible<FooAlias, TypeParam>::value, + "Should be impossible to implicitly convert a StrongAlias into " + "an underlying type."); +} + +TYPED_TEST(StrongAliasTest, ComparesEqualToSameValue) { + using FooAlias = StrongAlias<class FooTag, TypeParam>; + // Comparison to self: + const FooAlias a = FooAlias(GetExampleValue<TypeParam>(0)); + EXPECT_EQ(a, a); + EXPECT_FALSE(a != a); + EXPECT_TRUE(a >= a); + EXPECT_TRUE(a <= a); + EXPECT_FALSE(a > a); + EXPECT_FALSE(a < a); + // Comparison to other equal object: + const FooAlias b = FooAlias(GetExampleValue<TypeParam>(0)); + EXPECT_EQ(a, b); + EXPECT_FALSE(a != b); + EXPECT_TRUE(a >= b); + EXPECT_TRUE(a <= b); + EXPECT_FALSE(a > b); + EXPECT_FALSE(a < b); +} + +TYPED_TEST(StrongAliasTest, ComparesCorrectlyToDifferentValue) { + using FooAlias = StrongAlias<class FooTag, TypeParam>; + const FooAlias a = FooAlias(GetExampleValue<TypeParam>(0)); + const FooAlias b = FooAlias(GetExampleValue<TypeParam>(1)); + EXPECT_NE(a, b); + EXPECT_FALSE(a == b); + EXPECT_TRUE(b >= a); + EXPECT_TRUE(a <= b); + EXPECT_TRUE(b > a); + EXPECT_TRUE(a < b); +} + +TEST(StrongAliasTest, CanBeDerivedFrom) { + // Aliases can be enriched by custom operations or validations if needed. + // Ideally, one could go from a 'using' declaration to a derived class to add + // those methods without the need to change any other code. + class CountryCode : public StrongAlias<CountryCode, std::string> { + public: + explicit CountryCode(const std::string& value) + : StrongAlias<CountryCode, std::string>::StrongAlias(value) { + if (value_.length() != 2) { + // Country code invalid! + value_.clear(); // is_null() will return true. + } + } + + bool is_null() const { return value_.empty(); } + }; + + CountryCode valid("US"); + EXPECT_FALSE(valid.is_null()); + + CountryCode invalid("United States"); + EXPECT_TRUE(invalid.is_null()); +} + +TEST(StrongAliasTest, CanWrapComplexStructures) { + // A pair of strings implements odering and can, in principle, be used as + // a base of StrongAlias. + using PairOfStrings = std::pair<std::string, std::string>; + using ComplexAlias = StrongAlias<class FooTag, PairOfStrings>; + + ComplexAlias a1{std::make_pair("aaa", "bbb")}; + ComplexAlias a2{std::make_pair("ccc", "ddd")}; + EXPECT_TRUE(a1 < a2); + + EXPECT_TRUE(a1.value() == PairOfStrings("aaa", "bbb")); + + // Note a caveat, an std::pair doesn't have an overload of operator<<, and it + // cannot be easily added since ADL rules would require it to be in the std + // namespace. So we can't print ComplexAlias. +} + +TYPED_TEST(StrongAliasTest, CanBeKeysInFlatMap) { + using FooAlias = StrongAlias<class FooTag, TypeParam>; + webrtc::flat_map<FooAlias, std::string> map; + + FooAlias k1(GetExampleValue<TypeParam>(0)); + FooAlias k2(GetExampleValue<TypeParam>(1)); + + map[k1] = "value1"; + map[k2] = "value2"; + + EXPECT_EQ(map[k1], "value1"); + EXPECT_EQ(map[k2], "value2"); +} + +TYPED_TEST(StrongAliasTest, CanBeKeysInStdMap) { + using FooAlias = StrongAlias<class FooTag, TypeParam>; + std::map<FooAlias, std::string> map; + + FooAlias k1(GetExampleValue<TypeParam>(0)); + FooAlias k2(GetExampleValue<TypeParam>(1)); + + map[k1] = "value1"; + map[k2] = "value2"; + + EXPECT_EQ(map[k1], "value1"); + EXPECT_EQ(map[k2], "value2"); +} + +TYPED_TEST(StrongAliasTest, CanDifferentiateOverloads) { + using FooAlias = StrongAlias<class FooTag, TypeParam>; + using BarAlias = StrongAlias<class BarTag, TypeParam>; + class Scope { + public: + static std::string Overload(FooAlias) { return "FooAlias"; } + static std::string Overload(BarAlias) { return "BarAlias"; } + }; + EXPECT_EQ("FooAlias", Scope::Overload(FooAlias())); + EXPECT_EQ("BarAlias", Scope::Overload(BarAlias())); +} + +TEST(StrongAliasTest, EnsureConstexpr) { + using FooAlias = StrongAlias<class FooTag, int>; + + // Check constructors. + static constexpr FooAlias kZero{}; + static constexpr FooAlias kOne(1); + + // Check operator*. + static_assert(*kZero == 0, ""); + static_assert(*kOne == 1, ""); + + // Check value(). + static_assert(kZero.value() == 0, ""); + static_assert(kOne.value() == 1, ""); + + // Check explicit conversions to underlying type. + static_assert(static_cast<int>(kZero) == 0, ""); + static_assert(static_cast<int>(kOne) == 1, ""); + + // Check comparison operations. + static_assert(kZero == kZero, ""); + static_assert(kZero != kOne, ""); + static_assert(kZero < kOne, ""); + static_assert(kZero <= kOne, ""); + static_assert(kOne > kZero, ""); + static_assert(kOne >= kZero, ""); +} + +TEST(StrongAliasTest, BooleansAreEvaluatedAsBooleans) { + using BoolAlias = StrongAlias<class BoolTag, bool>; + + BoolAlias happy(true); + BoolAlias sad(false); + + EXPECT_TRUE(happy); + EXPECT_FALSE(sad); + EXPECT_TRUE(*happy); + EXPECT_FALSE(*sad); +} +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/swap_queue.h b/third_party/libwebrtc/rtc_base/swap_queue.h new file mode 100644 index 0000000000..3c8149c163 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/swap_queue.h @@ -0,0 +1,249 @@ +/* + * Copyright (c) 2015 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 RTC_BASE_SWAP_QUEUE_H_ +#define RTC_BASE_SWAP_QUEUE_H_ + +#include <stddef.h> + +#include <atomic> +#include <utility> +#include <vector> + +#include "absl/base/attributes.h" +#include "rtc_base/checks.h" + +namespace webrtc { + +namespace internal { + +// (Internal; please don't use outside this file.) +template <typename T> +bool NoopSwapQueueItemVerifierFunction(const T&) { + return true; +} + +} // namespace internal + +// Functor to use when supplying a verifier function for the queue. +template <typename T, + bool (*QueueItemVerifierFunction)(const T&) = + internal::NoopSwapQueueItemVerifierFunction> +class SwapQueueItemVerifier { + public: + bool operator()(const T& t) const { return QueueItemVerifierFunction(t); } +}; + +// This class is a fixed-size queue. A single producer calls Insert() to insert +// an element of type T at the back of the queue, and a single consumer calls +// Remove() to remove an element from the front of the queue. It's safe for the +// producer and the consumer to access the queue concurrently, from different +// threads. +// +// To avoid the construction, copying, and destruction of Ts that a naive +// queue implementation would require, for each "full" T passed from +// producer to consumer, SwapQueue<T> passes an "empty" T in the other +// direction (an "empty" T is one that contains nothing of value for the +// consumer). This bidirectional movement is implemented with swap(). +// +// // Create queue: +// Bottle proto(568); // Prepare an empty Bottle. Heap allocates space for +// // 568 ml. +// SwapQueue<Bottle> q(N, proto); // Init queue with N copies of proto. +// // Each copy allocates on the heap. +// // Producer pseudo-code: +// Bottle b(568); // Prepare an empty Bottle. Heap allocates space for 568 ml. +// loop { +// b.Fill(amount); // Where amount <= 568 ml. +// q.Insert(&b); // Swap our full Bottle for an empty one from q. +// } +// +// // Consumer pseudo-code: +// Bottle b(568); // Prepare an empty Bottle. Heap allocates space for 568 ml. +// loop { +// q.Remove(&b); // Swap our empty Bottle for the next-in-line full Bottle. +// Drink(&b); +// } +// +// For a well-behaved Bottle class, there are no allocations in the +// producer, since it just fills an empty Bottle that's already large +// enough; no deallocations in the consumer, since it returns each empty +// Bottle to the queue after having drunk it; and no copies along the +// way, since the queue uses swap() everywhere to move full Bottles in +// one direction and empty ones in the other. +template <typename T, typename QueueItemVerifier = SwapQueueItemVerifier<T>> +class SwapQueue { + public: + // Creates a queue of size size and fills it with default constructed Ts. + explicit SwapQueue(size_t size) : queue_(size) { + RTC_DCHECK(VerifyQueueSlots()); + } + + // Same as above and accepts an item verification functor. + SwapQueue(size_t size, const QueueItemVerifier& queue_item_verifier) + : queue_item_verifier_(queue_item_verifier), queue_(size) { + RTC_DCHECK(VerifyQueueSlots()); + } + + // Creates a queue of size size and fills it with copies of prototype. + SwapQueue(size_t size, const T& prototype) : queue_(size, prototype) { + RTC_DCHECK(VerifyQueueSlots()); + } + + // Same as above and accepts an item verification functor. + SwapQueue(size_t size, + const T& prototype, + const QueueItemVerifier& queue_item_verifier) + : queue_item_verifier_(queue_item_verifier), queue_(size, prototype) { + RTC_DCHECK(VerifyQueueSlots()); + } + + // Resets the queue to have zero content while maintaining the queue size. + // Just like Remove(), this can only be called (safely) from the + // consumer. + void Clear() { + // Drop all non-empty elements by resetting num_elements_ and incrementing + // next_read_index_ by the previous value of num_elements_. Relaxed memory + // ordering is sufficient since the dropped elements are not accessed. + next_read_index_ += std::atomic_exchange_explicit( + &num_elements_, size_t{0}, std::memory_order_relaxed); + if (next_read_index_ >= queue_.size()) { + next_read_index_ -= queue_.size(); + } + + RTC_DCHECK_LT(next_read_index_, queue_.size()); + } + + // Inserts a "full" T at the back of the queue by swapping *input with an + // "empty" T from the queue. + // Returns true if the item was inserted or false if not (the queue was full). + // When specified, the T given in *input must pass the ItemVerifier() test. + // The contents of *input after the call are then also guaranteed to pass the + // ItemVerifier() test. + ABSL_MUST_USE_RESULT bool Insert(T* input) { + RTC_DCHECK(input); + + RTC_DCHECK(queue_item_verifier_(*input)); + + // Load the value of num_elements_. Acquire memory ordering prevents reads + // and writes to queue_[next_write_index_] to be reordered to before the + // load. (That element might be accessed by a concurrent call to Remove() + // until the load finishes.) + if (std::atomic_load_explicit(&num_elements_, std::memory_order_acquire) == + queue_.size()) { + return false; + } + + using std::swap; + swap(*input, queue_[next_write_index_]); + + // Increment the value of num_elements_ to account for the inserted element. + // Release memory ordering prevents the reads and writes to + // queue_[next_write_index_] to be reordered to after the increment. (Once + // the increment has finished, Remove() might start accessing that element.) + const size_t old_num_elements = std::atomic_fetch_add_explicit( + &num_elements_, size_t{1}, std::memory_order_release); + + ++next_write_index_; + if (next_write_index_ == queue_.size()) { + next_write_index_ = 0; + } + + RTC_DCHECK_LT(next_write_index_, queue_.size()); + RTC_DCHECK_LT(old_num_elements, queue_.size()); + + return true; + } + + // Removes the frontmost "full" T from the queue by swapping it with + // the "empty" T in *output. + // Returns true if an item could be removed or false if not (the queue was + // empty). When specified, The T given in *output must pass the ItemVerifier() + // test and the contents of *output after the call are then also guaranteed to + // pass the ItemVerifier() test. + ABSL_MUST_USE_RESULT bool Remove(T* output) { + RTC_DCHECK(output); + + RTC_DCHECK(queue_item_verifier_(*output)); + + // Load the value of num_elements_. Acquire memory ordering prevents reads + // and writes to queue_[next_read_index_] to be reordered to before the + // load. (That element might be accessed by a concurrent call to Insert() + // until the load finishes.) + if (std::atomic_load_explicit(&num_elements_, std::memory_order_acquire) == + 0) { + return false; + } + + using std::swap; + swap(*output, queue_[next_read_index_]); + + // Decrement the value of num_elements_ to account for the removed element. + // Release memory ordering prevents the reads and writes to + // queue_[next_write_index_] to be reordered to after the decrement. (Once + // the decrement has finished, Insert() might start accessing that element.) + std::atomic_fetch_sub_explicit(&num_elements_, size_t{1}, + std::memory_order_release); + + ++next_read_index_; + if (next_read_index_ == queue_.size()) { + next_read_index_ = 0; + } + + RTC_DCHECK_LT(next_read_index_, queue_.size()); + + return true; + } + + // Returns the current number of elements in the queue. Since elements may be + // concurrently added to the queue, the caller must treat this as a lower + // bound, not an exact count. + // May only be called by the consumer. + size_t SizeAtLeast() const { + // Acquire memory ordering ensures that we wait for the producer to finish + // inserting any element in progress. + return std::atomic_load_explicit(&num_elements_, std::memory_order_acquire); + } + + private: + // Verify that the queue slots complies with the ItemVerifier test. This + // function is not thread-safe and can only be used in the constructors. + bool VerifyQueueSlots() { + for (const auto& v : queue_) { + RTC_DCHECK(queue_item_verifier_(v)); + } + return true; + } + + // TODO(peah): Change this to use std::function() once we can use C++11 std + // lib. + QueueItemVerifier queue_item_verifier_; + + // Only accessed by the single producer. + size_t next_write_index_ = 0; + + // Only accessed by the single consumer. + size_t next_read_index_ = 0; + + // Accessed by both the producer and the consumer and used for synchronization + // between them. + std::atomic<size_t> num_elements_{0}; + + // The elements of the queue are acced by both the producer and the consumer, + // mediated by num_elements_. queue_.size() is constant. + std::vector<T> queue_; + + SwapQueue(const SwapQueue&) = delete; + SwapQueue& operator=(const SwapQueue&) = delete; +}; + +} // namespace webrtc + +#endif // RTC_BASE_SWAP_QUEUE_H_ diff --git a/third_party/libwebrtc/rtc_base/swap_queue_gn/moz.build b/third_party/libwebrtc/rtc_base/swap_queue_gn/moz.build new file mode 100644 index 0000000000..3bffe145d6 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/swap_queue_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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("swap_queue_gn") diff --git a/third_party/libwebrtc/rtc_base/swap_queue_unittest.cc b/third_party/libwebrtc/rtc_base/swap_queue_unittest.cc new file mode 100644 index 0000000000..764a25edec --- /dev/null +++ b/third_party/libwebrtc/rtc_base/swap_queue_unittest.cc @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2015 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 "rtc_base/swap_queue.h" + +#include <cstdint> +#include <vector> + +#include "test/gtest.h" + +namespace webrtc { + +namespace { + +// Test parameter for the basic sample based SwapQueue Tests. +const size_t kChunkSize = 3; + +// Queue item verification function for the vector test. +bool LengthVerifierFunction(const std::vector<int>& v) { + return v.size() == kChunkSize; +} + +// Queue item verifier for the vector test. +class LengthVerifierFunctor { + public: + explicit LengthVerifierFunctor(size_t length) : length_(length) {} + + bool operator()(const std::vector<int>& v) const { + return v.size() == length_; + } + + private: + size_t length_; +}; + +} // anonymous namespace + +TEST(SwapQueueTest, BasicOperation) { + std::vector<int> i(kChunkSize, 0); + SwapQueue<std::vector<int>> queue(2, i); + + EXPECT_TRUE(queue.Insert(&i)); + EXPECT_EQ(i.size(), kChunkSize); + EXPECT_TRUE(queue.Insert(&i)); + EXPECT_EQ(i.size(), kChunkSize); + EXPECT_TRUE(queue.Remove(&i)); + EXPECT_EQ(i.size(), kChunkSize); + EXPECT_TRUE(queue.Remove(&i)); + EXPECT_EQ(i.size(), kChunkSize); +} + +TEST(SwapQueueTest, FullQueue) { + SwapQueue<int> queue(2); + + // Fill the queue. + int i = 0; + EXPECT_TRUE(queue.Insert(&i)); + i = 1; + EXPECT_TRUE(queue.Insert(&i)); + + // Ensure that the value is not swapped when doing an Insert + // on a full queue. + i = 2; + EXPECT_FALSE(queue.Insert(&i)); + EXPECT_EQ(i, 2); + + // Ensure that the Insert didn't overwrite anything in the queue. + EXPECT_TRUE(queue.Remove(&i)); + EXPECT_EQ(i, 0); + EXPECT_TRUE(queue.Remove(&i)); + EXPECT_EQ(i, 1); +} + +TEST(SwapQueueTest, EmptyQueue) { + SwapQueue<int> queue(2); + int i = 0; + EXPECT_FALSE(queue.Remove(&i)); + EXPECT_TRUE(queue.Insert(&i)); + EXPECT_TRUE(queue.Remove(&i)); + EXPECT_FALSE(queue.Remove(&i)); +} + +TEST(SwapQueueTest, Clear) { + SwapQueue<int> queue(2); + int i = 0; + + // Fill the queue. + EXPECT_TRUE(queue.Insert(&i)); + EXPECT_TRUE(queue.Insert(&i)); + + // Ensure full queue. + EXPECT_FALSE(queue.Insert(&i)); + + // Empty the queue. + queue.Clear(); + + // Ensure that the queue is empty + EXPECT_FALSE(queue.Remove(&i)); + + // Ensure that the queue is no longer full. + EXPECT_TRUE(queue.Insert(&i)); +} + +TEST(SwapQueueTest, SuccessfulItemVerifyFunction) { + std::vector<int> template_element(kChunkSize); + SwapQueue<std::vector<int>, + SwapQueueItemVerifier<std::vector<int>, LengthVerifierFunction>> + queue(2, template_element); + std::vector<int> valid_chunk(kChunkSize, 0); + + EXPECT_TRUE(queue.Insert(&valid_chunk)); + EXPECT_EQ(valid_chunk.size(), kChunkSize); + EXPECT_TRUE(queue.Remove(&valid_chunk)); + EXPECT_EQ(valid_chunk.size(), kChunkSize); +} + +TEST(SwapQueueTest, SuccessfulItemVerifyFunctor) { + std::vector<int> template_element(kChunkSize); + LengthVerifierFunctor verifier(kChunkSize); + SwapQueue<std::vector<int>, LengthVerifierFunctor> queue(2, template_element, + verifier); + std::vector<int> valid_chunk(kChunkSize, 0); + + EXPECT_TRUE(queue.Insert(&valid_chunk)); + EXPECT_EQ(valid_chunk.size(), kChunkSize); + EXPECT_TRUE(queue.Remove(&valid_chunk)); + EXPECT_EQ(valid_chunk.size(), kChunkSize); +} + +#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID) +TEST(SwapQueueDeathTest, UnsuccessfulItemVerifyFunctor) { + // Queue item verifier for the test. + auto minus_2_verifier = [](const int& i) { return i > -2; }; + SwapQueue<int, decltype(minus_2_verifier)> queue(2, minus_2_verifier); + + int valid_value = 1; + int invalid_value = -4; + EXPECT_TRUE(queue.Insert(&valid_value)); + EXPECT_TRUE(queue.Remove(&valid_value)); + EXPECT_DEATH((void)queue.Insert(&invalid_value), ""); +} + +TEST(SwapQueueDeathTest, UnSuccessfulItemVerifyInsert) { + std::vector<int> template_element(kChunkSize); + SwapQueue<std::vector<int>, + SwapQueueItemVerifier<std::vector<int>, &LengthVerifierFunction>> + queue(2, template_element); + std::vector<int> invalid_chunk(kChunkSize - 1, 0); + EXPECT_DEATH((void)queue.Insert(&invalid_chunk), ""); +} + +TEST(SwapQueueDeathTest, UnSuccessfulItemVerifyRemove) { + std::vector<int> template_element(kChunkSize); + SwapQueue<std::vector<int>, + SwapQueueItemVerifier<std::vector<int>, &LengthVerifierFunction>> + queue(2, template_element); + std::vector<int> invalid_chunk(kChunkSize - 1, 0); + std::vector<int> valid_chunk(kChunkSize, 0); + EXPECT_TRUE(queue.Insert(&valid_chunk)); + EXPECT_EQ(valid_chunk.size(), kChunkSize); + EXPECT_DEATH((void)queue.Remove(&invalid_chunk), ""); +} +#endif + +TEST(SwapQueueTest, VectorContentTest) { + const size_t kQueueSize = 10; + const size_t kFrameLength = 160; + const size_t kDataLength = kQueueSize * kFrameLength; + std::vector<int16_t> buffer_reader(kFrameLength, 0); + std::vector<int16_t> buffer_writer(kFrameLength, 0); + SwapQueue<std::vector<int16_t>> queue(kQueueSize, + std::vector<int16_t>(kFrameLength)); + std::vector<int16_t> samples(kDataLength); + + for (size_t k = 0; k < kDataLength; k++) { + samples[k] = k % 9; + } + + for (size_t k = 0; k < kQueueSize; k++) { + buffer_writer.clear(); + buffer_writer.insert(buffer_writer.end(), &samples[0] + k * kFrameLength, + &samples[0] + (k + 1) * kFrameLength); + + EXPECT_TRUE(queue.Insert(&buffer_writer)); + } + + for (size_t k = 0; k < kQueueSize; k++) { + EXPECT_TRUE(queue.Remove(&buffer_reader)); + + for (size_t j = 0; j < buffer_reader.size(); j++) { + EXPECT_EQ(buffer_reader[j], samples[k * kFrameLength + j]); + } + } +} + +TEST(SwapQueueTest, ZeroSlotQueue) { + SwapQueue<int> queue(0); + int i = 42; + EXPECT_FALSE(queue.Insert(&i)); + EXPECT_FALSE(queue.Remove(&i)); + EXPECT_EQ(i, 42); +} + +TEST(SwapQueueTest, OneSlotQueue) { + SwapQueue<int> queue(1); + int i = 42; + EXPECT_TRUE(queue.Insert(&i)); + i = 43; + EXPECT_FALSE(queue.Insert(&i)); + EXPECT_EQ(i, 43); + EXPECT_TRUE(queue.Remove(&i)); + EXPECT_EQ(i, 42); + EXPECT_FALSE(queue.Remove(&i)); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/synchronization/BUILD.gn b/third_party/libwebrtc/rtc_base/synchronization/BUILD.gn new file mode 100644 index 0000000000..5cab524540 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/synchronization/BUILD.gn @@ -0,0 +1,105 @@ +# 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") +if (is_android) { + import("//build/config/android/config.gni") + import("//build/config/android/rules.gni") +} + +rtc_library("yield") { + sources = [ + "yield.cc", + "yield.h", + ] + deps = [] +} + +rtc_source_set("mutex") { + sources = [ + "mutex.h", + "mutex_critical_section.h", + "mutex_pthread.h", + ] + if (rtc_use_absl_mutex) { + sources += [ "mutex_abseil.h" ] + } + + deps = [ + ":yield", + "..:checks", + "..:macromagic", + "..:platform_thread_types", + "../system:no_unique_address", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/base:core_headers" ] + if (rtc_use_absl_mutex) { + absl_deps += [ "//third_party/abseil-cpp/absl/synchronization" ] + } +} + +rtc_library("sequence_checker_internal") { + visibility = [ "../../api:sequence_checker" ] + sources = [ + "sequence_checker_internal.cc", + "sequence_checker_internal.h", + ] + deps = [ + ":mutex", + "..:checks", + "..:macromagic", + "..:platform_thread_types", + "..:stringutils", + "../../api/task_queue", + "../system:rtc_export", + ] +} + +rtc_library("yield_policy") { + sources = [ + "yield_policy.cc", + "yield_policy.h", + ] + deps = [ "..:checks" ] + absl_deps = [ + "//third_party/abseil-cpp/absl/base:config", + "//third_party/abseil-cpp/absl/base:core_headers", + ] +} + +if (rtc_include_tests && rtc_enable_google_benchmarks) { + rtc_library("synchronization_unittests") { + testonly = true + sources = [ + "mutex_unittest.cc", + "yield_policy_unittest.cc", + ] + deps = [ + ":mutex", + ":yield", + ":yield_policy", + "..:checks", + "..:macromagic", + "..:platform_thread", + "..:rtc_event", + "..:threading", + "../../test:test_support", + "//third_party/google_benchmark", + ] + } + + rtc_library("mutex_benchmark") { + testonly = true + sources = [ "mutex_benchmark.cc" ] + deps = [ + ":mutex", + "../system:unused", + "//third_party/google_benchmark", + ] + } +} diff --git a/third_party/libwebrtc/rtc_base/synchronization/DEPS b/third_party/libwebrtc/rtc_base/synchronization/DEPS new file mode 100644 index 0000000000..4ed1f2444b --- /dev/null +++ b/third_party/libwebrtc/rtc_base/synchronization/DEPS @@ -0,0 +1,11 @@ +specific_include_rules = { + "mutex_abseil\.h": [ + "+absl/synchronization" + ], + ".*_benchmark\.cc": [ + "+benchmark", + ], + ".*_unittest\.cc": [ + "+benchmark", + ] +} diff --git a/third_party/libwebrtc/rtc_base/synchronization/mutex.h b/third_party/libwebrtc/rtc_base/synchronization/mutex.h new file mode 100644 index 0000000000..104f4fd3e1 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/synchronization/mutex.h @@ -0,0 +1,73 @@ +/* + * 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 RTC_BASE_SYNCHRONIZATION_MUTEX_H_ +#define RTC_BASE_SYNCHRONIZATION_MUTEX_H_ + +#include <atomic> + +#include "absl/base/attributes.h" +#include "absl/base/const_init.h" +#include "rtc_base/checks.h" +#include "rtc_base/thread_annotations.h" + +#if defined(WEBRTC_ABSL_MUTEX) +#include "rtc_base/synchronization/mutex_abseil.h" // nogncheck +#elif defined(WEBRTC_WIN) +#include "rtc_base/synchronization/mutex_critical_section.h" +#elif defined(WEBRTC_POSIX) +#include "rtc_base/synchronization/mutex_pthread.h" +#else +#error Unsupported platform. +#endif + +namespace webrtc { + +// The Mutex guarantees exclusive access and aims to follow Abseil semantics +// (i.e. non-reentrant etc). +class RTC_LOCKABLE Mutex final { + public: + Mutex() = default; + Mutex(const Mutex&) = delete; + Mutex& operator=(const Mutex&) = delete; + + void Lock() RTC_EXCLUSIVE_LOCK_FUNCTION() { impl_.Lock(); } + ABSL_MUST_USE_RESULT bool TryLock() RTC_EXCLUSIVE_TRYLOCK_FUNCTION(true) { + return impl_.TryLock(); + } + // Return immediately if this thread holds the mutex, or RTC_DCHECK_IS_ON==0. + // Otherwise, may report an error (typically by crashing with a diagnostic), + // or may return immediately. + void AssertHeld() const RTC_ASSERT_EXCLUSIVE_LOCK() { impl_.AssertHeld(); } + void Unlock() RTC_UNLOCK_FUNCTION() { impl_.Unlock(); } + + private: + MutexImpl impl_; +}; + +// MutexLock, for serializing execution through a scope. +class RTC_SCOPED_LOCKABLE MutexLock final { + public: + MutexLock(const MutexLock&) = delete; + MutexLock& operator=(const MutexLock&) = delete; + + explicit MutexLock(Mutex* mutex) RTC_EXCLUSIVE_LOCK_FUNCTION(mutex) + : mutex_(mutex) { + mutex->Lock(); + } + ~MutexLock() RTC_UNLOCK_FUNCTION() { mutex_->Unlock(); } + + private: + Mutex* mutex_; +}; + +} // namespace webrtc + +#endif // RTC_BASE_SYNCHRONIZATION_MUTEX_H_ diff --git a/third_party/libwebrtc/rtc_base/synchronization/mutex_abseil.h b/third_party/libwebrtc/rtc_base/synchronization/mutex_abseil.h new file mode 100644 index 0000000000..d42f974f10 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/synchronization/mutex_abseil.h @@ -0,0 +1,43 @@ +/* + * 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 RTC_BASE_SYNCHRONIZATION_MUTEX_ABSEIL_H_ +#define RTC_BASE_SYNCHRONIZATION_MUTEX_ABSEIL_H_ + +#include "absl/base/attributes.h" +#include "absl/synchronization/mutex.h" +#include "rtc_base/thread_annotations.h" + +namespace webrtc { + +class RTC_LOCKABLE MutexImpl final { + public: + MutexImpl() = default; + MutexImpl(const MutexImpl&) = delete; + MutexImpl& operator=(const MutexImpl&) = delete; + + void Lock() RTC_EXCLUSIVE_LOCK_FUNCTION() { mutex_.Lock(); } + ABSL_MUST_USE_RESULT bool TryLock() RTC_EXCLUSIVE_TRYLOCK_FUNCTION(true) { + return mutex_.TryLock(); + } + void AssertHeld() const RTC_ASSERT_EXCLUSIVE_LOCK() { +#if RTC_DCHECK_IS_ON + mutex_.AssertHeld(); +#endif + } + void Unlock() RTC_UNLOCK_FUNCTION() { mutex_.Unlock(); } + + private: + absl::Mutex mutex_; +}; + +} // namespace webrtc + +#endif // RTC_BASE_SYNCHRONIZATION_MUTEX_ABSEIL_H_ diff --git a/third_party/libwebrtc/rtc_base/synchronization/mutex_benchmark.cc b/third_party/libwebrtc/rtc_base/synchronization/mutex_benchmark.cc new file mode 100644 index 0000000000..ae0e3c38e7 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/synchronization/mutex_benchmark.cc @@ -0,0 +1,96 @@ +/* + * 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. + */ + +#include "benchmark/benchmark.h" +#include "rtc_base/synchronization/mutex.h" +#include "rtc_base/system/unused.h" + +namespace webrtc { + +class PerfTestData { + public: + PerfTestData() : cache_line_barrier_1_(), cache_line_barrier_2_() { + cache_line_barrier_1_[0]++; // Avoid 'is not used'. + cache_line_barrier_2_[0]++; // Avoid 'is not used'. + } + + int AddToCounter(int add) { + MutexLock mu(&mu_); + my_counter_ += add; + return 0; + } + + private: + uint8_t cache_line_barrier_1_[64]; + Mutex mu_; + uint8_t cache_line_barrier_2_[64]; + int64_t my_counter_ = 0; +}; + +void BM_LockWithMutex(benchmark::State& state) { + static PerfTestData test_data; + for (auto s : state) { + RTC_UNUSED(s); + int add_to_counter = test_data.AddToCounter(2); + benchmark::DoNotOptimize(add_to_counter); + } +} + +BENCHMARK(BM_LockWithMutex)->Threads(1); +BENCHMARK(BM_LockWithMutex)->Threads(2); +BENCHMARK(BM_LockWithMutex)->Threads(4); +BENCHMARK(BM_LockWithMutex)->ThreadPerCpu(); + +} // namespace webrtc + +/* + +Results: + +NB when reproducing: Remember to turn of power management features such as CPU +scaling before running! + +pthreads (Linux): +---------------------------------------------------------------------- +Run on (12 X 4500 MHz CPU s) +CPU Caches: + L1 Data 32 KiB (x6) + L1 Instruction 32 KiB (x6) + L2 Unified 1024 KiB (x6) + L3 Unified 8448 KiB (x1) +Load Average: 0.26, 0.28, 0.44 +---------------------------------------------------------------------- +Benchmark Time CPU Iterations +---------------------------------------------------------------------- +BM_LockWithMutex/threads:1 13.4 ns 13.4 ns 52192906 +BM_LockWithMutex/threads:2 44.2 ns 88.4 ns 8189944 +BM_LockWithMutex/threads:4 52.0 ns 198 ns 3743244 +BM_LockWithMutex/threads:12 84.9 ns 944 ns 733524 + +std::mutex performs like the pthread implementation (Linux). + +Abseil (Linux): +---------------------------------------------------------------------- +Run on (12 X 4500 MHz CPU s) +CPU Caches: + L1 Data 32 KiB (x6) + L1 Instruction 32 KiB (x6) + L2 Unified 1024 KiB (x6) + L3 Unified 8448 KiB (x1) +Load Average: 0.27, 0.24, 0.37 +---------------------------------------------------------------------- +Benchmark Time CPU Iterations +---------------------------------------------------------------------- +BM_LockWithMutex/threads:1 15.0 ns 15.0 ns 46550231 +BM_LockWithMutex/threads:2 91.1 ns 182 ns 4059212 +BM_LockWithMutex/threads:4 40.8 ns 131 ns 5496560 +BM_LockWithMutex/threads:12 37.0 ns 130 ns 5377668 + +*/ diff --git a/third_party/libwebrtc/rtc_base/synchronization/mutex_critical_section.h b/third_party/libwebrtc/rtc_base/synchronization/mutex_critical_section.h new file mode 100644 index 0000000000..b6a3c4a78a --- /dev/null +++ b/third_party/libwebrtc/rtc_base/synchronization/mutex_critical_section.h @@ -0,0 +1,56 @@ +/* + * 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 RTC_BASE_SYNCHRONIZATION_MUTEX_CRITICAL_SECTION_H_ +#define RTC_BASE_SYNCHRONIZATION_MUTEX_CRITICAL_SECTION_H_ + +#if defined(WEBRTC_WIN) +// clang-format off +// clang formating would change include order. + +// Include winsock2.h before including <windows.h> to maintain consistency with +// win32.h. To include win32.h directly, it must be broken out into its own +// build target. +#include <winsock2.h> +#include <windows.h> +#include <sal.h> // must come after windows headers. +// clang-format on + +#include "absl/base/attributes.h" +#include "rtc_base/thread_annotations.h" + +namespace webrtc { + +class RTC_LOCKABLE MutexImpl final { + public: + MutexImpl() { InitializeCriticalSection(&critical_section_); } + MutexImpl(const MutexImpl&) = delete; + MutexImpl& operator=(const MutexImpl&) = delete; + ~MutexImpl() { DeleteCriticalSection(&critical_section_); } + + void Lock() RTC_EXCLUSIVE_LOCK_FUNCTION() { + EnterCriticalSection(&critical_section_); + } + ABSL_MUST_USE_RESULT bool TryLock() RTC_EXCLUSIVE_TRYLOCK_FUNCTION(true) { + return TryEnterCriticalSection(&critical_section_) != FALSE; + } + void AssertHeld() const RTC_ASSERT_EXCLUSIVE_LOCK() {} + void Unlock() RTC_UNLOCK_FUNCTION() { + LeaveCriticalSection(&critical_section_); + } + + private: + CRITICAL_SECTION critical_section_; +}; + +} // namespace webrtc + +#endif // #if defined(WEBRTC_WIN) +#endif // RTC_BASE_SYNCHRONIZATION_MUTEX_CRITICAL_SECTION_H_ diff --git a/third_party/libwebrtc/rtc_base/synchronization/mutex_gn/moz.build b/third_party/libwebrtc/rtc_base/synchronization/mutex_gn/moz.build new file mode 100644 index 0000000000..9799330606 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/synchronization/mutex_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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("mutex_gn") diff --git a/third_party/libwebrtc/rtc_base/synchronization/mutex_pthread.h b/third_party/libwebrtc/rtc_base/synchronization/mutex_pthread.h new file mode 100644 index 0000000000..c749a208aa --- /dev/null +++ b/third_party/libwebrtc/rtc_base/synchronization/mutex_pthread.h @@ -0,0 +1,101 @@ +/* + * 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 RTC_BASE_SYNCHRONIZATION_MUTEX_PTHREAD_H_ +#define RTC_BASE_SYNCHRONIZATION_MUTEX_PTHREAD_H_ + +#if defined(WEBRTC_POSIX) + +#include <pthread.h> +#if defined(WEBRTC_MAC) +#include <pthread_spis.h> +#endif + +#include "absl/base/attributes.h" +#include "rtc_base/system/no_unique_address.h" +#include "rtc_base/thread_annotations.h" + +namespace webrtc { + +class RTC_LOCKABLE MutexImpl final { + public: + MutexImpl() { + pthread_mutexattr_t mutex_attribute; + pthread_mutexattr_init(&mutex_attribute); +#if defined(WEBRTC_MAC) + pthread_mutexattr_setpolicy_np(&mutex_attribute, + _PTHREAD_MUTEX_POLICY_FIRSTFIT); +#endif + pthread_mutex_init(&mutex_, &mutex_attribute); + pthread_mutexattr_destroy(&mutex_attribute); + } + MutexImpl(const MutexImpl&) = delete; + MutexImpl& operator=(const MutexImpl&) = delete; + ~MutexImpl() { pthread_mutex_destroy(&mutex_); } + + void Lock() RTC_EXCLUSIVE_LOCK_FUNCTION() { + pthread_mutex_lock(&mutex_); + owner_.SetOwner(); + } + ABSL_MUST_USE_RESULT bool TryLock() RTC_EXCLUSIVE_TRYLOCK_FUNCTION(true) { + if (pthread_mutex_trylock(&mutex_) != 0) { + return false; + } + owner_.SetOwner(); + return true; + } + void AssertHeld() const RTC_ASSERT_EXCLUSIVE_LOCK() { owner_.AssertOwned(); } + void Unlock() RTC_UNLOCK_FUNCTION() { + owner_.ClearOwner(); + pthread_mutex_unlock(&mutex_); + } + + private: + class OwnerRecord { + public: +#if !RTC_DCHECK_IS_ON + void SetOwner() {} + void ClearOwner() {} + void AssertOwned() const {} +#else + void SetOwner() { + latest_owner_ = pthread_self(); + is_owned_ = true; + } + void ClearOwner() { is_owned_ = false; } + void AssertOwned() const { + RTC_CHECK(is_owned_); + RTC_CHECK(pthread_equal(latest_owner_, pthread_self())); + } + + private: + // Use two separate primitive types, rather than absl::optional, since the + // data race described below might invalidate absl::optional invariants. + bool is_owned_ = false; + pthread_t latest_owner_ = pthread_self(); +#endif + }; + + pthread_mutex_t mutex_; + // This record is modified only with the mutex held, and hence, calls to + // AssertHeld where mutex is held are race-free and will always succeed. + // + // The failure case is more subtle: If AssertHeld is called from some thread + // not holding the mutex, and RTC_DCHECK_IS_ON==1, we have a data race. It is + // highly likely that the calling thread will see `is_owned_` false or + // `latest_owner_` different from itself, and crash. But it may fail to crash, + // and invoke some other undefined behavior (still, this race can happen only + // when RTC_DCHECK_IS_ON==1). + RTC_NO_UNIQUE_ADDRESS OwnerRecord owner_; +}; + +} // namespace webrtc +#endif // #if defined(WEBRTC_POSIX) +#endif // RTC_BASE_SYNCHRONIZATION_MUTEX_PTHREAD_H_ diff --git a/third_party/libwebrtc/rtc_base/synchronization/mutex_unittest.cc b/third_party/libwebrtc/rtc_base/synchronization/mutex_unittest.cc new file mode 100644 index 0000000000..a5ebc5f7d4 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/synchronization/mutex_unittest.cc @@ -0,0 +1,178 @@ +/* + * 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. + */ + +#include "rtc_base/synchronization/mutex.h" + +#include <stddef.h> +#include <stdint.h> + +#include <atomic> +#include <memory> +#include <type_traits> +#include <utility> +#include <vector> + +#include "benchmark/benchmark.h" +#include "rtc_base/checks.h" +#include "rtc_base/event.h" +#include "rtc_base/platform_thread.h" +#include "rtc_base/synchronization/yield.h" +#include "rtc_base/thread.h" +#include "test/gtest.h" + +namespace webrtc { +namespace { + +using ::rtc::Event; +using ::rtc::Thread; + +constexpr int kNumThreads = 16; + +template <class MutexType> +class RTC_LOCKABLE RawMutexLocker { + public: + explicit RawMutexLocker(MutexType& mutex) : mutex_(mutex) {} + void Lock() RTC_EXCLUSIVE_LOCK_FUNCTION() { mutex_.Lock(); } + void Unlock() RTC_UNLOCK_FUNCTION() { mutex_.Unlock(); } + + private: + MutexType& mutex_; +}; + +class RTC_LOCKABLE RawMutexTryLocker { + public: + explicit RawMutexTryLocker(Mutex& mutex) : mutex_(mutex) {} + void Lock() RTC_EXCLUSIVE_LOCK_FUNCTION() { + while (!mutex_.TryLock()) { + YieldCurrentThread(); + } + } + void Unlock() RTC_UNLOCK_FUNCTION() { mutex_.Unlock(); } + + private: + Mutex& mutex_; +}; + +template <class MutexType, class MutexLockType> +class MutexLockLocker { + public: + explicit MutexLockLocker(MutexType& mutex) : mutex_(mutex) {} + void Lock() { lock_ = std::make_unique<MutexLockType>(&mutex_); } + void Unlock() { lock_ = nullptr; } + + private: + MutexType& mutex_; + std::unique_ptr<MutexLockType> lock_; +}; + +template <class MutexType, class MutexLocker> +class LockRunner { + public: + template <typename... Args> + explicit LockRunner(Args... args) + : threads_active_(0), + start_event_(true, false), + done_event_(true, false), + shared_value_(0), + mutex_(args...), + locker_(mutex_) {} + + bool Run() { + // Signal all threads to start. + start_event_.Set(); + + // Wait for all threads to finish. + return done_event_.Wait(kLongTime); + } + + void SetExpectedThreadCount(int count) { threads_active_ = count; } + + int shared_value() { + int shared_value; + locker_.Lock(); + shared_value = shared_value_; + locker_.Unlock(); + return shared_value; + } + + void Loop() { + ASSERT_TRUE(start_event_.Wait(kLongTime)); + locker_.Lock(); + + EXPECT_EQ(0, shared_value_); + int old = shared_value_; + + // Use a loop to increase the chance of race. If the `locker_` + // implementation is faulty, it would be improbable that the error slips + // through. + for (int i = 0; i < kOperationsToRun; ++i) { + benchmark::DoNotOptimize(++shared_value_); + } + EXPECT_EQ(old + kOperationsToRun, shared_value_); + shared_value_ = 0; + + locker_.Unlock(); + if (threads_active_.fetch_sub(1) == 1) { + done_event_.Set(); + } + } + + private: + static constexpr TimeDelta kLongTime = TimeDelta::Seconds(10); + static constexpr int kOperationsToRun = 1000; + + std::atomic<int> threads_active_; + Event start_event_; + Event done_event_; + int shared_value_; + MutexType mutex_; + MutexLocker locker_; +}; + +template <typename Runner> +void StartThreads(std::vector<std::unique_ptr<Thread>>& threads, + Runner* handler) { + for (int i = 0; i < kNumThreads; ++i) { + std::unique_ptr<Thread> thread(Thread::Create()); + thread->Start(); + thread->PostTask([handler] { handler->Loop(); }); + threads.push_back(std::move(thread)); + } +} + +TEST(MutexTest, ProtectsSharedResourceWithMutexAndRawMutexLocker) { + std::vector<std::unique_ptr<Thread>> threads; + LockRunner<Mutex, RawMutexLocker<Mutex>> runner; + StartThreads(threads, &runner); + runner.SetExpectedThreadCount(kNumThreads); + EXPECT_TRUE(runner.Run()); + EXPECT_EQ(0, runner.shared_value()); +} + +TEST(MutexTest, ProtectsSharedResourceWithMutexAndRawMutexTryLocker) { + std::vector<std::unique_ptr<Thread>> threads; + LockRunner<Mutex, RawMutexTryLocker> runner; + StartThreads(threads, &runner); + runner.SetExpectedThreadCount(kNumThreads); + EXPECT_TRUE(runner.Run()); + EXPECT_EQ(0, runner.shared_value()); +} + +TEST(MutexTest, ProtectsSharedResourceWithMutexAndMutexLocker) { + std::vector<std::unique_ptr<Thread>> threads; + LockRunner<Mutex, MutexLockLocker<Mutex, MutexLock>> runner; + StartThreads(threads, &runner); + runner.SetExpectedThreadCount(kNumThreads); + EXPECT_TRUE(runner.Run()); + EXPECT_EQ(0, runner.shared_value()); +} + +} // namespace +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/synchronization/sequence_checker_internal.cc b/third_party/libwebrtc/rtc_base/synchronization/sequence_checker_internal.cc new file mode 100644 index 0000000000..4b9583deb2 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/synchronization/sequence_checker_internal.cc @@ -0,0 +1,86 @@ +/* + * 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 "rtc_base/synchronization/sequence_checker_internal.h" + +#include <string> + +#include "rtc_base/checks.h" +#include "rtc_base/strings/string_builder.h" + +namespace webrtc { +namespace webrtc_sequence_checker_internal { + +SequenceCheckerImpl::SequenceCheckerImpl(bool attach_to_current_thread) + : attached_(attach_to_current_thread), + valid_thread_(rtc::CurrentThreadRef()), + valid_queue_(TaskQueueBase::Current()) {} + +SequenceCheckerImpl::SequenceCheckerImpl(TaskQueueBase* attached_queue) + : attached_(attached_queue != nullptr), + valid_thread_(rtc::PlatformThreadRef()), + valid_queue_(attached_queue) {} + +bool SequenceCheckerImpl::IsCurrent() const { + const TaskQueueBase* const current_queue = TaskQueueBase::Current(); + const rtc::PlatformThreadRef current_thread = rtc::CurrentThreadRef(); + MutexLock scoped_lock(&lock_); + if (!attached_) { // Previously detached. + attached_ = true; + valid_thread_ = current_thread; + valid_queue_ = current_queue; + return true; + } + if (valid_queue_) { + return valid_queue_ == current_queue; + } + return rtc::IsThreadRefEqual(valid_thread_, current_thread); +} + +void SequenceCheckerImpl::Detach() { + MutexLock scoped_lock(&lock_); + attached_ = false; + // We don't need to touch the other members here, they will be + // reset on the next call to IsCurrent(). +} + +#if RTC_DCHECK_IS_ON +std::string SequenceCheckerImpl::ExpectationToString() const { + const TaskQueueBase* const current_queue = TaskQueueBase::Current(); + const rtc::PlatformThreadRef current_thread = rtc::CurrentThreadRef(); + MutexLock scoped_lock(&lock_); + if (!attached_) + return "Checker currently not attached."; + + // The format of the string is meant to compliment the one we have inside of + // FatalLog() (checks.cc). Example: + // + // # Expected: TQ: 0x0 SysQ: 0x7fff69541330 Thread: 0x11dcf6dc0 + // # Actual: TQ: 0x7fa8f0604190 SysQ: 0x7fa8f0604a30 Thread: 0x700006f1a000 + // TaskQueue doesn't match + + rtc::StringBuilder message; + message.AppendFormat( + "# Expected: TQ: %p Thread: %p\n" + "# Actual: TQ: %p Thread: %p\n", + valid_queue_, reinterpret_cast<const void*>(valid_thread_), current_queue, + reinterpret_cast<const void*>(current_thread)); + + if ((valid_queue_ || current_queue) && valid_queue_ != current_queue) { + message << "TaskQueue doesn't match\n"; + } else if (!rtc::IsThreadRefEqual(valid_thread_, current_thread)) { + message << "Threads don't match\n"; + } + + return message.Release(); +} +#endif // RTC_DCHECK_IS_ON + +} // namespace webrtc_sequence_checker_internal +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/synchronization/sequence_checker_internal.h b/third_party/libwebrtc/rtc_base/synchronization/sequence_checker_internal.h new file mode 100644 index 0000000000..a23ac08885 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/synchronization/sequence_checker_internal.h @@ -0,0 +1,90 @@ +/* + * 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 RTC_BASE_SYNCHRONIZATION_SEQUENCE_CHECKER_INTERNAL_H_ +#define RTC_BASE_SYNCHRONIZATION_SEQUENCE_CHECKER_INTERNAL_H_ + +#include <string> +#include <type_traits> + +#include "api/task_queue/task_queue_base.h" +#include "rtc_base/platform_thread_types.h" +#include "rtc_base/synchronization/mutex.h" +#include "rtc_base/system/rtc_export.h" +#include "rtc_base/thread_annotations.h" + +namespace webrtc { +namespace webrtc_sequence_checker_internal { + +// Real implementation of SequenceChecker, for use in debug mode, or +// for temporary use in release mode (e.g. to RTC_CHECK on a threading issue +// seen only in the wild). +// +// Note: You should almost always use the SequenceChecker class to get the +// right version for your build configuration. +class RTC_EXPORT SequenceCheckerImpl { + public: + explicit SequenceCheckerImpl(bool attach_to_current_thread); + explicit SequenceCheckerImpl(TaskQueueBase* attached_queue); + ~SequenceCheckerImpl() = default; + + bool IsCurrent() const; + // Changes the task queue or thread that is checked for in IsCurrent. This can + // be useful when an object may be created on one task queue / thread and then + // used exclusively on another thread. + void Detach(); + + // Returns a string that is formatted to match with the error string printed + // by RTC_CHECK() when a condition is not met. + // This is used in conjunction with the RTC_DCHECK_RUN_ON() macro. + std::string ExpectationToString() const; + + private: + mutable Mutex lock_; + // These are mutable so that IsCurrent can set them. + mutable bool attached_ RTC_GUARDED_BY(lock_); + mutable rtc::PlatformThreadRef valid_thread_ RTC_GUARDED_BY(lock_); + mutable const TaskQueueBase* valid_queue_ RTC_GUARDED_BY(lock_); +}; + +// Do nothing implementation, for use in release mode. +// +// Note: You should almost always use the SequenceChecker class to get the +// right version for your build configuration. +class SequenceCheckerDoNothing { + public: + explicit SequenceCheckerDoNothing(bool attach_to_current_thread) {} + explicit SequenceCheckerDoNothing(TaskQueueBase* attached_queue) {} + bool IsCurrent() const { return true; } + void Detach() {} +}; + +template <typename ThreadLikeObject> +std::enable_if_t<std::is_base_of_v<SequenceCheckerImpl, ThreadLikeObject>, + std::string> +ExpectationToString(const ThreadLikeObject* checker) { +#if RTC_DCHECK_IS_ON + return checker->ExpectationToString(); +#else + return std::string(); +#endif +} + +// Catch-all implementation for types other than explicitly supported above. +template <typename ThreadLikeObject> +std::enable_if_t<!std::is_base_of_v<SequenceCheckerImpl, ThreadLikeObject>, + std::string> +ExpectationToString(const ThreadLikeObject*) { + return std::string(); +} + +} // namespace webrtc_sequence_checker_internal +} // namespace webrtc + +#endif // RTC_BASE_SYNCHRONIZATION_SEQUENCE_CHECKER_INTERNAL_H_ diff --git a/third_party/libwebrtc/rtc_base/synchronization/sequence_checker_internal_gn/moz.build b/third_party/libwebrtc/rtc_base/synchronization/sequence_checker_internal_gn/moz.build new file mode 100644 index 0000000000..a43e97a8c2 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/synchronization/sequence_checker_internal_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/rtc_base/synchronization/sequence_checker_internal.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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("sequence_checker_internal_gn") diff --git a/third_party/libwebrtc/rtc_base/synchronization/yield.cc b/third_party/libwebrtc/rtc_base/synchronization/yield.cc new file mode 100644 index 0000000000..cbb58d12ab --- /dev/null +++ b/third_party/libwebrtc/rtc_base/synchronization/yield.cc @@ -0,0 +1,36 @@ +/* + * 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. + */ + +#include "rtc_base/synchronization/yield.h" + +#if defined(WEBRTC_WIN) +#include <windows.h> +#else +#include <sched.h> +#include <time.h> +#endif + +namespace webrtc { + +void YieldCurrentThread() { + // TODO(bugs.webrtc.org/11634): use dedicated OS functionality instead of + // sleep for yielding. +#if defined(WEBRTC_WIN) + ::Sleep(0); +#elif defined(WEBRTC_MAC) && defined(RTC_USE_NATIVE_MUTEX_ON_MAC) && \ + !RTC_USE_NATIVE_MUTEX_ON_MAC + sched_yield(); +#else + static const struct timespec ts_null = {0}; + nanosleep(&ts_null, nullptr); +#endif +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/synchronization/yield.h b/third_party/libwebrtc/rtc_base/synchronization/yield.h new file mode 100644 index 0000000000..d4f5f99f37 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/synchronization/yield.h @@ -0,0 +1,20 @@ +/* + * 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 RTC_BASE_SYNCHRONIZATION_YIELD_H_ +#define RTC_BASE_SYNCHRONIZATION_YIELD_H_ + +namespace webrtc { + +// Request rescheduling of threads. +void YieldCurrentThread(); + +} // namespace webrtc + +#endif // RTC_BASE_SYNCHRONIZATION_YIELD_H_ diff --git a/third_party/libwebrtc/rtc_base/synchronization/yield_gn/moz.build b/third_party/libwebrtc/rtc_base/synchronization/yield_gn/moz.build new file mode 100644 index 0000000000..ac962ac0a2 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/synchronization/yield_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/rtc_base/synchronization/yield.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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("yield_gn") diff --git a/third_party/libwebrtc/rtc_base/synchronization/yield_policy.cc b/third_party/libwebrtc/rtc_base/synchronization/yield_policy.cc new file mode 100644 index 0000000000..d883d42bf4 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/synchronization/yield_policy.cc @@ -0,0 +1,82 @@ +/* + * 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 "rtc_base/synchronization/yield_policy.h" + +#include "absl/base/attributes.h" +#include "absl/base/config.h" +#include "rtc_base/checks.h" +#if !defined(ABSL_HAVE_THREAD_LOCAL) && defined(WEBRTC_POSIX) +#include <pthread.h> +#endif + +namespace rtc { +namespace { + +#if defined(ABSL_HAVE_THREAD_LOCAL) + +ABSL_CONST_INIT thread_local YieldInterface* current_yield_policy = nullptr; + +YieldInterface* GetCurrentYieldPolicy() { + return current_yield_policy; +} + +void SetCurrentYieldPolicy(YieldInterface* ptr) { + current_yield_policy = ptr; +} + +#elif defined(WEBRTC_POSIX) + +// Emscripten does not support the C++11 thread_local keyword but does support +// the pthread thread-local storage API. +// https://github.com/emscripten-core/emscripten/issues/3502 + +ABSL_CONST_INIT pthread_key_t g_current_yield_policy_tls = 0; + +void InitializeTls() { + RTC_CHECK_EQ(pthread_key_create(&g_current_yield_policy_tls, nullptr), 0); +} + +pthread_key_t GetCurrentYieldPolicyTls() { + static pthread_once_t init_once = PTHREAD_ONCE_INIT; + RTC_CHECK_EQ(pthread_once(&init_once, &InitializeTls), 0); + return g_current_yield_policy_tls; +} + +YieldInterface* GetCurrentYieldPolicy() { + return static_cast<YieldInterface*>( + pthread_getspecific(GetCurrentYieldPolicyTls())); +} + +void SetCurrentYieldPolicy(YieldInterface* ptr) { + pthread_setspecific(GetCurrentYieldPolicyTls(), ptr); +} + +#else +#error Unsupported platform +#endif + +} // namespace + +ScopedYieldPolicy::ScopedYieldPolicy(YieldInterface* policy) + : previous_(GetCurrentYieldPolicy()) { + SetCurrentYieldPolicy(policy); +} + +ScopedYieldPolicy::~ScopedYieldPolicy() { + SetCurrentYieldPolicy(previous_); +} + +void ScopedYieldPolicy::YieldExecution() { + YieldInterface* current = GetCurrentYieldPolicy(); + if (current) + current->YieldExecution(); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/synchronization/yield_policy.h b/third_party/libwebrtc/rtc_base/synchronization/yield_policy.h new file mode 100644 index 0000000000..5def6b7397 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/synchronization/yield_policy.h @@ -0,0 +1,38 @@ +/* + * 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 RTC_BASE_SYNCHRONIZATION_YIELD_POLICY_H_ +#define RTC_BASE_SYNCHRONIZATION_YIELD_POLICY_H_ + +namespace rtc { +class YieldInterface { + public: + virtual ~YieldInterface() = default; + virtual void YieldExecution() = 0; +}; + +// Sets the current thread-local yield policy while it's in scope and reverts +// to the previous policy when it leaves the scope. +class ScopedYieldPolicy final { + public: + explicit ScopedYieldPolicy(YieldInterface* policy); + ScopedYieldPolicy(const ScopedYieldPolicy&) = delete; + ScopedYieldPolicy& operator=(const ScopedYieldPolicy&) = delete; + ~ScopedYieldPolicy(); + // Will yield as specified by the currently active thread-local yield policy + // (which by default is a no-op). + static void YieldExecution(); + + private: + YieldInterface* const previous_; +}; + +} // namespace rtc + +#endif // RTC_BASE_SYNCHRONIZATION_YIELD_POLICY_H_ diff --git a/third_party/libwebrtc/rtc_base/synchronization/yield_policy_gn/moz.build b/third_party/libwebrtc/rtc_base/synchronization/yield_policy_gn/moz.build new file mode 100644 index 0000000000..7adceec9b4 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/synchronization/yield_policy_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/rtc_base/synchronization/yield_policy.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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("yield_policy_gn") diff --git a/third_party/libwebrtc/rtc_base/synchronization/yield_policy_unittest.cc b/third_party/libwebrtc/rtc_base/synchronization/yield_policy_unittest.cc new file mode 100644 index 0000000000..0bf38f4537 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/synchronization/yield_policy_unittest.cc @@ -0,0 +1,68 @@ +/* + * 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 "rtc_base/synchronization/yield_policy.h" + +#include <thread> // Not allowed in production per Chromium style guide. + +#include "rtc_base/event.h" +#include "test/gmock.h" +#include "test/gtest.h" + +namespace rtc { +namespace { +class MockYieldHandler : public YieldInterface { + public: + MOCK_METHOD(void, YieldExecution, (), (override)); +}; +} // namespace +TEST(YieldPolicyTest, HandlerReceivesYieldSignalWhenSet) { + ::testing::StrictMock<MockYieldHandler> handler; + { + Event event; + EXPECT_CALL(handler, YieldExecution()).Times(1); + ScopedYieldPolicy policy(&handler); + event.Set(); + event.Wait(Event::kForever); + } + { + Event event; + EXPECT_CALL(handler, YieldExecution()).Times(0); + event.Set(); + event.Wait(Event::kForever); + } +} + +TEST(YieldPolicyTest, IsThreadLocal) { + Event events[3]; + std::thread other_thread([&]() { + ::testing::StrictMock<MockYieldHandler> local_handler; + // The local handler is never called as we never Wait on this thread. + EXPECT_CALL(local_handler, YieldExecution()).Times(0); + ScopedYieldPolicy policy(&local_handler); + events[0].Set(); + events[1].Set(); + events[2].Set(); + }); + + // Waiting until the other thread has entered the scoped policy. + events[0].Wait(Event::kForever); + // Wait on this thread should not trigger the handler of that policy as it's + // thread local. + events[1].Wait(Event::kForever); + + // We can set a policy that's active on this thread independently. + ::testing::StrictMock<MockYieldHandler> main_handler; + EXPECT_CALL(main_handler, YieldExecution()).Times(1); + ScopedYieldPolicy policy(&main_handler); + events[2].Wait(Event::kForever); + other_thread.join(); +} +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/system/BUILD.gn b/third_party/libwebrtc/rtc_base/system/BUILD.gn new file mode 100644 index 0000000000..486b37590c --- /dev/null +++ b/third_party/libwebrtc/rtc_base/system/BUILD.gn @@ -0,0 +1,111 @@ +# 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") +if (is_android) { + import("//build/config/android/config.gni") + import("//build/config/android/rules.gni") +} + +rtc_source_set("arch") { + sources = [ "arch.h" ] +} + +rtc_source_set("asm_defines") { + sources = [ "asm_defines.h" ] +} + +rtc_library("file_wrapper") { + sources = [ + "file_wrapper.cc", + "file_wrapper.h", + ] + deps = [ + "..:checks", + "..:criticalsection", + "..:safe_conversions", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/strings" ] +} + +if (rtc_include_tests) { + rtc_library("file_wrapper_unittests") { + testonly = true + sources = [ "file_wrapper_unittest.cc" ] + deps = [ + ":file_wrapper", + "//rtc_base:checks", + "//test:fileutils", + "//test:test_support", + ] + } +} + +rtc_source_set("ignore_warnings") { + sources = [ "ignore_warnings.h" ] +} + +rtc_source_set("inline") { + sources = [ "inline.h" ] +} + +rtc_source_set("unused") { + sources = [ "unused.h" ] +} + +rtc_source_set("assume") { + sources = [ "assume.h" ] +} + +rtc_source_set("rtc_export") { + sources = [ + "rtc_export.h", + "rtc_export_template.h", + ] +} + +rtc_source_set("no_unique_address") { + sources = [ "no_unique_address.h" ] +} + +rtc_source_set("no_cfi_icall") { + sources = [ "no_cfi_icall.h" ] + + deps = [ "..:sanitizer" ] +} + +if (is_mac || is_ios) { + rtc_library("cocoa_threading") { + sources = [ + "cocoa_threading.h", + "cocoa_threading.mm", + ] + deps = [ "..:checks" ] + frameworks = [ "Foundation.framework" ] + } + + rtc_library("gcd_helpers") { + sources = [ + "gcd_helpers.h", + "gcd_helpers.m", + ] + include_dirs = [ "../.." ] + } +} + +rtc_source_set("warn_current_thread_is_deadlocked") { + sources = [ "warn_current_thread_is_deadlocked.h" ] + deps = [] + if (is_android && (!build_with_chromium && !build_with_mozilla)) { + sources += [ "warn_current_thread_is_deadlocked.cc" ] + deps += [ + "..:logging", + "../../sdk/android:native_api_stacktrace", + ] + } +} diff --git a/third_party/libwebrtc/rtc_base/system/DEPS b/third_party/libwebrtc/rtc_base/system/DEPS new file mode 100644 index 0000000000..ab9449f70a --- /dev/null +++ b/third_party/libwebrtc/rtc_base/system/DEPS @@ -0,0 +1,5 @@ +specific_include_rules = { + "warn_current_thread_is_deadlocked\.cc": [ + "+sdk/android/native_api/stacktrace/stacktrace.h", + ], +} diff --git a/third_party/libwebrtc/rtc_base/system/arch.h b/third_party/libwebrtc/rtc_base/system/arch.h new file mode 100644 index 0000000000..9d945ef7fc --- /dev/null +++ b/third_party/libwebrtc/rtc_base/system/arch.h @@ -0,0 +1,100 @@ +/* + * 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. + */ + +// This file contains platform-specific typedefs and defines. +// Much of it is derived from Chromium's build/build_config.h. + +#ifndef RTC_BASE_SYSTEM_ARCH_H_ +#define RTC_BASE_SYSTEM_ARCH_H_ + +// Processor architecture detection. For more info on what's defined, see: +// https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros +// https://www.agner.org/optimize/calling_conventions.pdf +// https://sourceforge.net/p/predef/wiki/Architectures/ +// or with gcc, run: "echo | gcc -E -dM -" +#if defined(_M_X64) || defined(__x86_64__) +#define WEBRTC_ARCH_X86_FAMILY +#define WEBRTC_ARCH_X86_64 +#define WEBRTC_ARCH_64_BITS +#define WEBRTC_ARCH_LITTLE_ENDIAN +#elif defined(_M_ARM64) || defined(__aarch64__) +#define WEBRTC_ARCH_ARM_FAMILY +#define WEBRTC_ARCH_64_BITS +#define WEBRTC_ARCH_LITTLE_ENDIAN +#elif defined(_M_IX86) || defined(__i386__) +#define WEBRTC_ARCH_X86_FAMILY +#define WEBRTC_ARCH_X86 +#define WEBRTC_ARCH_32_BITS +#define WEBRTC_ARCH_LITTLE_ENDIAN +#elif defined(_M_ARM) || defined(__ARMEL__) +#define WEBRTC_ARCH_ARM_FAMILY +#define WEBRTC_ARCH_32_BITS +#define WEBRTC_ARCH_LITTLE_ENDIAN +#elif defined(__MIPSEL__) || defined(__MIPSEB__) +#define WEBRTC_ARCH_MIPS_FAMILY +#if defined(__LP64__) +#define WEBRTC_ARCH_64_BITS +#else +#define WEBRTC_ARCH_32_BITS +#endif +#if defined(__MIPSEL__) +#define WEBRTC_ARCH_LITTLE_ENDIAN +#else +#define WEBRTC_ARCH_BIG_ENDIAN +#endif +#elif defined(__PPC__) +#if defined(__PPC64__) +#define WEBRTC_ARCH_64_BITS +#else +#define WEBRTC_ARCH_32_BITS +#endif +#if defined(__LITTLE_ENDIAN__) +#define WEBRTC_ARCH_LITTLE_ENDIAN +#else +#define WEBRTC_ARCH_BIG_ENDIAN +#endif +#elif defined(__sparc) || defined(__sparc__) +#if __SIZEOF_LONG__ == 8 +#define WEBRTC_ARCH_64_BITS +#else +#define WEBRTC_ARCH_32_BITS +#endif +#define WEBRTC_ARCH_BIG_ENDIAN +#elif defined(__riscv) && __riscv_xlen == 64 +#define WEBRTC_ARCH_64_BITS +#define WEBRTC_ARCH_LITTLE_ENDIAN +#elif defined(__riscv) && __riscv_xlen == 32 +#define WEBRTC_ARCH_32_BITS +#define WEBRTC_ARCH_LITTLE_ENDIAN +#elif defined(__loongarch32) +#define WEBRTC_ARCH_LOONG_FAMILY +#define WEBRTC_ARCH_LOONG32 +#define WEBRTC_ARCH_32_BITS +#define WEBRTC_ARCH_LITTLE_ENDIAN +#elif defined(__loongarch64) +#define WEBRTC_ARCH_LOONG_FAMILY +#define WEBRTC_ARCH_LOONG64 +#define WEBRTC_ARCH_64_BITS +#define WEBRTC_ARCH_LITTLE_ENDIAN +#elif defined(__pnacl__) +#define WEBRTC_ARCH_32_BITS +#define WEBRTC_ARCH_LITTLE_ENDIAN +#elif defined(__EMSCRIPTEN__) +#define WEBRTC_ARCH_32_BITS +#define WEBRTC_ARCH_LITTLE_ENDIAN +#else +#error Please add support for your architecture in rtc_base/system/arch.h +#endif + +#if !(defined(WEBRTC_ARCH_LITTLE_ENDIAN) ^ defined(WEBRTC_ARCH_BIG_ENDIAN)) +#error Define either WEBRTC_ARCH_LITTLE_ENDIAN or WEBRTC_ARCH_BIG_ENDIAN +#endif + +#endif // RTC_BASE_SYSTEM_ARCH_H_ diff --git a/third_party/libwebrtc/rtc_base/system/arch_gn/moz.build b/third_party/libwebrtc/rtc_base/system/arch_gn/moz.build new file mode 100644 index 0000000000..136948d0f2 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/system/arch_gn/moz.build @@ -0,0 +1,205 @@ +# 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("arch_gn") diff --git a/third_party/libwebrtc/rtc_base/system/asm_defines.h b/third_party/libwebrtc/rtc_base/system/asm_defines.h new file mode 100644 index 0000000000..a7f6aad272 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/system/asm_defines.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2012 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 RTC_BASE_SYSTEM_ASM_DEFINES_H_ +#define RTC_BASE_SYSTEM_ASM_DEFINES_H_ + +// clang-format off +// clang formatting breaks everything here, e.g. concatenating directives, +// due to absence of context via asm keyword. + +#if defined(__linux__) && defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif + +// Define the macros used in ARM assembly code, so that for Mac or iOS builds +// we add leading underscores for the function names. +#ifdef __APPLE__ +.macro GLOBAL_FUNCTION name +.global _\name +.private_extern _\name +.endm +.macro DEFINE_FUNCTION name +_\name: +.endm +.macro CALL_FUNCTION name +bl _\name +.endm +.macro GLOBAL_LABEL name +.global _\name +.private_extern _\name +.endm +#else +.macro GLOBAL_FUNCTION name +.global \name +.hidden \name +.endm +.macro DEFINE_FUNCTION name +#if defined(__linux__) && defined(__ELF__) +.type \name,%function +#endif +\name: +.endm +.macro CALL_FUNCTION name +bl \name +.endm +.macro GLOBAL_LABEL name +.global \name +.hidden \name +.endm +#endif + +// With Apple's clang compiler, for instructions ldrb, strh, etc., +// the condition code is after the width specifier. Here we define +// only the ones that are actually used in the assembly files. +#if (defined __llvm__) && (defined __APPLE__) +.macro streqh reg1, reg2, num +strheq \reg1, \reg2, \num +.endm +#endif + +.text + +// clang-format on + +#endif // RTC_BASE_SYSTEM_ASM_DEFINES_H_ diff --git a/third_party/libwebrtc/rtc_base/system/asm_defines_gn/moz.build b/third_party/libwebrtc/rtc_base/system/asm_defines_gn/moz.build new file mode 100644 index 0000000000..b99d782d88 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/system/asm_defines_gn/moz.build @@ -0,0 +1,81 @@ +# 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_ARCH_ARM"] = True +DEFINES["WEBRTC_ARCH_ARM_V7"] = True +DEFINES["WEBRTC_ENABLE_LIBEVENT"] = True +DEFINES["WEBRTC_ENABLE_PROTOBUF"] = "0" +DEFINES["WEBRTC_HAS_NEON"] = True +DEFINES["WEBRTC_LIBRARY_IMPL"] = True +DEFINES["WEBRTC_LINUX"] = True +DEFINES["WEBRTC_MOZILLA_BUILD"] = True +DEFINES["WEBRTC_NON_STATIC_TRACE_EVENT_HANDLERS"] = "0" +DEFINES["WEBRTC_POSIX"] = True +DEFINES["WEBRTC_STRICT_FIELD_TRIALS"] = "0" +DEFINES["_GNU_SOURCE"] = True +DEFINES["__STDC_CONSTANT_MACROS"] = True +DEFINES["__STDC_FORMAT_MACROS"] = True + +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" + DEFINES["_DEBUG"] = True + +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 + + OS_LIBS += [ + "android_support", + "unwind" + ] + +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["_FILE_OFFSET_BITS"] = "64" + DEFINES["_LARGEFILE64_SOURCE"] = True + DEFINES["_LARGEFILE_SOURCE"] = True + +if CONFIG["MOZ_X11"] == "1" and CONFIG["OS_TARGET"] == "Linux": + + DEFINES["USE_X11"] = "1" + +Library("asm_defines_gn") diff --git a/third_party/libwebrtc/rtc_base/system/assume.h b/third_party/libwebrtc/rtc_base/system/assume.h new file mode 100644 index 0000000000..231c9e18ad --- /dev/null +++ b/third_party/libwebrtc/rtc_base/system/assume.h @@ -0,0 +1,73 @@ +/* + * 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 RTC_BASE_SYSTEM_ASSUME_H_ +#define RTC_BASE_SYSTEM_ASSUME_H_ + +// Possibly evaluate `p`, promising the compiler that the result is true; the +// compiler is allowed (but not required) to use this information when +// optimizing the code. USE WITH CAUTION! If you promise the compiler things +// that aren't true, it will build a broken binary for you. +// +// As a simple example, the compiler is allowed to transform this +// +// RTC_ASSUME(x == 4); +// return x; +// +// into this +// +// return 4; +// +// It is even allowed to propagate the assumption "backwards in time", if it can +// prove that it must have held at some earlier time. For example, the compiler +// is allowed to transform this +// +// int Add(int x, int y) { +// if (x == 17) +// y += 1; +// RTC_ASSUME(x != 17); +// return x + y; +// } +// +// into this +// +// int Add(int x, int y) { +// return x + y; +// } +// +// since if `x` isn't 17 on the third line of the function body, the test of `x +// == 17` on the first line must fail since nothing can modify the local +// variable `x` in between. +// +// The intended use is to allow the compiler to optimize better. For example, +// here we allow the compiler to omit an instruction that ensures correct +// rounding of negative arguments: +// +// int DivBy2(int x) { +// RTC_ASSUME(x >= 0); +// return x / 2; +// } +// +// and here we allow the compiler to possibly omit a null check: +// +// void Delete(int* p) { +// RTC_ASSUME(p != nullptr); +// delete p; +// } +// +// clang-format off +#if defined(__GNUC__) +#define RTC_ASSUME(p) do { if (!(p)) __builtin_unreachable(); } while (0) +#else +#define RTC_ASSUME(p) do {} while (0) +#endif +// clang-format on + +#endif // RTC_BASE_SYSTEM_ASSUME_H_ diff --git a/third_party/libwebrtc/rtc_base/system/cocoa_threading.h b/third_party/libwebrtc/rtc_base/system/cocoa_threading.h new file mode 100644 index 0000000000..518cb71786 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/system/cocoa_threading.h @@ -0,0 +1,24 @@ +/* + * 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 RTC_BASE_SYSTEM_COCOA_THREADING_H_ +#define RTC_BASE_SYSTEM_COCOA_THREADING_H_ + +// If Cocoa is to be used on more than one thread, it must know that the +// application is multithreaded. Since it's possible to enter Cocoa code +// from threads created by pthread_thread_create, Cocoa won't necessarily +// be aware that the application is multithreaded. Spawning an NSThread is +// enough to get Cocoa to set up for multithreaded operation, so this is done +// if necessary before pthread_thread_create spawns any threads. +// +// http://developer.apple.com/documentation/Cocoa/Conceptual/Multithreading/CreatingThreads/chapter_4_section_4.html +void InitCocoaMultiThreading(); + +#endif // RTC_BASE_SYSTEM_COCOA_THREADING_H_ diff --git a/third_party/libwebrtc/rtc_base/system/cocoa_threading.mm b/third_party/libwebrtc/rtc_base/system/cocoa_threading.mm new file mode 100644 index 0000000000..c09862e7e5 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/system/cocoa_threading.mm @@ -0,0 +1,24 @@ +/* + * 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. + */ +#include "rtc_base/system/cocoa_threading.h" + +#import <Foundation/Foundation.h> + +#include "rtc_base/checks.h" + +void InitCocoaMultiThreading() { + static BOOL is_cocoa_multithreaded = [NSThread isMultiThreaded]; + if (!is_cocoa_multithreaded) { + // +[NSObject class] is idempotent. + [NSThread detachNewThreadSelector:@selector(class) toTarget:[NSObject class] withObject:nil]; + is_cocoa_multithreaded = YES; + RTC_DCHECK([NSThread isMultiThreaded]); + } +} diff --git a/third_party/libwebrtc/rtc_base/system/cocoa_threading_gn/moz.build b/third_party/libwebrtc/rtc_base/system/cocoa_threading_gn/moz.build new file mode 100644 index 0000000000..429299b480 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/system/cocoa_threading_gn/moz.build @@ -0,0 +1,67 @@ +# 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. ### + +CMMFLAGS += [ + "-fobjc-arc" +] + +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_MAC"] = True +DEFINES["WEBRTC_MOZILLA_BUILD"] = True +DEFINES["WEBRTC_NON_STATIC_TRACE_EVENT_HANDLERS"] = "0" +DEFINES["WEBRTC_POSIX"] = True +DEFINES["WEBRTC_STRICT_FIELD_TRIALS"] = "0" +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 + +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/rtc_base/system/cocoa_threading.mm" +] + +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" + DEFINES["_DEBUG"] = True + +if CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +Library("cocoa_threading_gn") diff --git a/third_party/libwebrtc/rtc_base/system/file_wrapper.cc b/third_party/libwebrtc/rtc_base/system/file_wrapper.cc new file mode 100644 index 0000000000..af34d0e411 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/system/file_wrapper.cc @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2012 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 "rtc_base/system/file_wrapper.h" + +#include <stddef.h> + +#include <cerrno> +#include <cstdint> +#include <string> + +#include "absl/strings/string_view.h" +#include "rtc_base/checks.h" +#include "rtc_base/numerics/safe_conversions.h" + +#ifdef _WIN32 +#include <Windows.h> +#else +#endif + +#include <utility> + +namespace webrtc { +namespace { +FILE* FileOpen(absl::string_view file_name_utf8, bool read_only, int* error) { + RTC_CHECK_EQ(file_name_utf8.find_first_of('\0'), absl::string_view::npos) + << "Invalid filename, containing NUL character"; + std::string file_name(file_name_utf8); +#if defined(_WIN32) + int len = MultiByteToWideChar(CP_UTF8, 0, file_name.c_str(), -1, nullptr, 0); + std::wstring wstr(len, 0); + MultiByteToWideChar(CP_UTF8, 0, file_name.c_str(), -1, &wstr[0], len); + FILE* file = _wfopen(wstr.c_str(), read_only ? L"rb" : L"wb"); +#else + FILE* file = fopen(file_name.c_str(), read_only ? "rb" : "wb"); +#endif + if (!file && error) { + *error = errno; + } + return file; +} + +} // namespace + +// static +FileWrapper FileWrapper::OpenReadOnly(absl::string_view file_name_utf8) { + return FileWrapper(FileOpen(file_name_utf8, true, nullptr)); +} + +// static +FileWrapper FileWrapper::OpenWriteOnly(absl::string_view file_name_utf8, + int* error /*=nullptr*/) { + return FileWrapper(FileOpen(file_name_utf8, false, error)); +} + +FileWrapper::FileWrapper(FileWrapper&& other) { + operator=(std::move(other)); +} + +FileWrapper& FileWrapper::operator=(FileWrapper&& other) { + Close(); + file_ = other.file_; + other.file_ = nullptr; + return *this; +} + +bool FileWrapper::SeekRelative(int64_t offset) { + RTC_DCHECK(file_); + return fseek(file_, rtc::checked_cast<long>(offset), SEEK_CUR) == 0; +} + +bool FileWrapper::SeekTo(int64_t position) { + RTC_DCHECK(file_); + return fseek(file_, rtc::checked_cast<long>(position), SEEK_SET) == 0; +} + +long FileWrapper::FileSize() { + if (file_ == nullptr) + return -1; + long original_position = ftell(file_); + if (original_position < 0) + return -1; + int seek_error = fseek(file_, 0, SEEK_END); + if (seek_error) + return -1; + long file_size = ftell(file_); + seek_error = fseek(file_, original_position, SEEK_SET); + if (seek_error) + return -1; + return file_size; +} + +bool FileWrapper::Flush() { + RTC_DCHECK(file_); + return fflush(file_) == 0; +} + +size_t FileWrapper::Read(void* buf, size_t length) { + RTC_DCHECK(file_); + return fread(buf, 1, length, file_); +} + +bool FileWrapper::ReadEof() const { + RTC_DCHECK(file_); + return feof(file_); +} + +bool FileWrapper::Write(const void* buf, size_t length) { + RTC_DCHECK(file_); + return fwrite(buf, 1, length, file_) == length; +} + +bool FileWrapper::Close() { + if (file_ == nullptr) + return true; + + bool success = fclose(file_) == 0; + file_ = nullptr; + return success; +} + +FILE* FileWrapper::Release() { + FILE* file = file_; + file_ = nullptr; + return file; +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/system/file_wrapper.h b/third_party/libwebrtc/rtc_base/system/file_wrapper.h new file mode 100644 index 0000000000..92a552cfd9 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/system/file_wrapper.h @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2011 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 RTC_BASE_SYSTEM_FILE_WRAPPER_H_ +#define RTC_BASE_SYSTEM_FILE_WRAPPER_H_ + +#include <stddef.h> +#include <stdint.h> +#include <stdio.h> + +#include <string> + +#include "absl/strings/string_view.h" + +// Implementation that can read (exclusive) or write from/to a file. + +namespace webrtc { + +// This class is a thin wrapper around FILE*. It's main features are that it +// owns the FILE*, calling fclose on destruction, and that on windows, file +// names passed to the open methods are always treated as utf-8, regardless of +// system code page. + +// Most of the methods return only a success/fail indication. When needed, an +// optional argument |int* error| should be added to all methods, in the same +// way as for the OpenWriteOnly methods. +class FileWrapper final { + public: + // Opens a file, in read or write mode. Use the is_open() method on the + // returned object to check if the open operation was successful. On failure, + // and if `error` is non-null, the system errno value is stored at |*error|. + // The file is closed by the destructor. + static FileWrapper OpenReadOnly(absl::string_view file_name_utf8); + static FileWrapper OpenWriteOnly(absl::string_view file_name_utf8, + int* error = nullptr); + + FileWrapper() = default; + + // Takes over ownership of `file`, closing it on destruction. Calling with + // null `file` is allowed, and results in a FileWrapper with is_open() false. + explicit FileWrapper(FILE* file) : file_(file) {} + ~FileWrapper() { Close(); } + + // Copying is not supported. + FileWrapper(const FileWrapper&) = delete; + FileWrapper& operator=(const FileWrapper&) = delete; + + // Support for move semantics. + FileWrapper(FileWrapper&&); + FileWrapper& operator=(FileWrapper&&); + + // Returns true if a file has been opened. If the file is not open, no methods + // but is_open and Close may be called. + bool is_open() const { return file_ != nullptr; } + + // Closes the file, and implies Flush. Returns true on success, false if + // writing buffered data fails. On failure, the file is nevertheless closed. + // Calling Close on an already closed file does nothing and returns success. + bool Close(); + + // Releases and returns the wrapped file without closing it. This call passes + // the ownership of the file to the caller, and the wrapper is no longer + // responsible for closing it. Similarly the previously wrapped file is no + // longer available for the wrapper to use in any aspect. + FILE* Release(); + + // Write any buffered data to the underlying file. Returns true on success, + // false on write error. Note: Flushing when closing, is not required. + bool Flush(); + + // Seeks to the beginning of file. Returns true on success, false on failure, + // e.g., if the underlying file isn't seekable. + bool Rewind() { return SeekTo(0); } + // TODO(nisse): The seek functions are used only by the WavReader. If that + // code is demoted to test code, seek functions can be deleted from this + // utility. + // Seek relative to current file position. + bool SeekRelative(int64_t offset); + // Seek to given position. + bool SeekTo(int64_t position); + + // Returns the file size or -1 if a size could not be determined. + // (A file size might not exists for non-seekable files or file-like + // objects, for example /dev/tty on unix.) + long FileSize(); + + // Returns number of bytes read. Short count indicates EOF or error. + size_t Read(void* buf, size_t length); + + // If the most recent Read() returned a short count, this methods returns true + // if the short count was due to EOF, and false it it was due to some i/o + // error. + bool ReadEof() const; + + // Returns true if all data was successfully written (or buffered), or false + // if there was an error. Writing buffered data can fail later, and is + // reported with return value from Flush or Close. + bool Write(const void* buf, size_t length); + + private: + FILE* file_ = nullptr; +}; + +} // namespace webrtc + +#endif // RTC_BASE_SYSTEM_FILE_WRAPPER_H_ diff --git a/third_party/libwebrtc/rtc_base/system/file_wrapper_gn/moz.build b/third_party/libwebrtc/rtc_base/system/file_wrapper_gn/moz.build new file mode 100644 index 0000000000..6d0a523103 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/system/file_wrapper_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/rtc_base/system/file_wrapper.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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("file_wrapper_gn") diff --git a/third_party/libwebrtc/rtc_base/system/file_wrapper_unittest.cc b/third_party/libwebrtc/rtc_base/system/file_wrapper_unittest.cc new file mode 100644 index 0000000000..980b565c73 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/system/file_wrapper_unittest.cc @@ -0,0 +1,69 @@ +/* + * Copyright 2021 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 "rtc_base/system/file_wrapper.h" + +#include "rtc_base/checks.h" +#include "test/gtest.h" +#include "test/testsupport/file_utils.h" + +namespace webrtc { + +TEST(FileWrapper, FileSize) { + auto test_info = ::testing::UnitTest::GetInstance()->current_test_info(); + std::string test_name = + std::string(test_info->test_case_name()) + "_" + test_info->name(); + std::replace(test_name.begin(), test_name.end(), '/', '_'); + const std::string temp_filename = test::OutputPath() + test_name; + + // Write + { + FileWrapper file = FileWrapper::OpenWriteOnly(temp_filename); + ASSERT_TRUE(file.is_open()); + EXPECT_EQ(file.FileSize(), 0); + + EXPECT_TRUE(file.Write("foo", 3)); + EXPECT_EQ(file.FileSize(), 3); + + // FileSize() doesn't change the file size. + EXPECT_EQ(file.FileSize(), 3); + + // FileSize() doesn't move the write position. + EXPECT_TRUE(file.Write("bar", 3)); + EXPECT_EQ(file.FileSize(), 6); + } + + // Read + { + FileWrapper file = FileWrapper::OpenReadOnly(temp_filename); + ASSERT_TRUE(file.is_open()); + EXPECT_EQ(file.FileSize(), 6); + + char buf[10]; + size_t bytes_read = file.Read(buf, 3); + EXPECT_EQ(bytes_read, 3u); + EXPECT_EQ(memcmp(buf, "foo", 3), 0); + + // FileSize() doesn't move the read position. + EXPECT_EQ(file.FileSize(), 6); + + // Attempting to read past the end reads what is available + // and sets the EOF flag. + bytes_read = file.Read(buf, 5); + EXPECT_EQ(bytes_read, 3u); + EXPECT_EQ(memcmp(buf, "bar", 3), 0); + EXPECT_TRUE(file.ReadEof()); + } + + // Clean up temporary file. + remove(temp_filename.c_str()); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/system/gcd_helpers.h b/third_party/libwebrtc/rtc_base/system/gcd_helpers.h new file mode 100644 index 0000000000..a8df0a9d83 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/system/gcd_helpers.h @@ -0,0 +1,29 @@ +/* + * 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 RTC_BASE_SYSTEM_GCD_HELPERS_H_ +#define RTC_BASE_SYSTEM_GCD_HELPERS_H_ + +#include <dispatch/dispatch.h> + +#ifdef __cplusplus +extern "C" { +#endif + +DISPATCH_RETURNS_RETAINED DISPATCH_WARN_RESULT DISPATCH_NOTHROW dispatch_queue_t +RTCDispatchQueueCreateWithTarget(const char* label, + dispatch_queue_attr_t attr, + dispatch_queue_t target); + +#ifdef __cplusplus +} +#endif + +#endif // RTC_BASE_SYSTEM_GCD_HELPERS_H_ diff --git a/third_party/libwebrtc/rtc_base/system/gcd_helpers.m b/third_party/libwebrtc/rtc_base/system/gcd_helpers.m new file mode 100644 index 0000000000..fd9a361fa1 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/system/gcd_helpers.m @@ -0,0 +1,22 @@ +/* + * 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. + */ + +#include "rtc_base/system/gcd_helpers.h" + +dispatch_queue_t RTCDispatchQueueCreateWithTarget(const char *label, + dispatch_queue_attr_t attr, + dispatch_queue_t target) { + if (@available(iOS 10, macOS 10.12, tvOS 10, watchOS 3, *)) { + return dispatch_queue_create_with_target(label, attr, target); + } + dispatch_queue_t queue = dispatch_queue_create(label, attr); + dispatch_set_target_queue(queue, target); + return queue; +} diff --git a/third_party/libwebrtc/rtc_base/system/gcd_helpers_gn/moz.build b/third_party/libwebrtc/rtc_base/system/gcd_helpers_gn/moz.build new file mode 100644 index 0000000000..243694e1d5 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/system/gcd_helpers_gn/moz.build @@ -0,0 +1,67 @@ +# 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. ### + +CMFLAGS += [ + "-fobjc-arc" +] + +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_MAC"] = True +DEFINES["WEBRTC_MOZILLA_BUILD"] = True +DEFINES["WEBRTC_NON_STATIC_TRACE_EVENT_HANDLERS"] = "0" +DEFINES["WEBRTC_POSIX"] = True +DEFINES["WEBRTC_STRICT_FIELD_TRIALS"] = "0" +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 + +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/rtc_base/system/gcd_helpers.m" +] + +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" + DEFINES["_DEBUG"] = True + +if CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +Library("gcd_helpers_gn") diff --git a/third_party/libwebrtc/rtc_base/system/ignore_warnings.h b/third_party/libwebrtc/rtc_base/system/ignore_warnings.h new file mode 100644 index 0000000000..e891c508f8 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/system/ignore_warnings.h @@ -0,0 +1,29 @@ +/* + * 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 RTC_BASE_SYSTEM_IGNORE_WARNINGS_H_ +#define RTC_BASE_SYSTEM_IGNORE_WARNINGS_H_ + +#ifdef __clang__ +#define RTC_PUSH_IGNORING_WFRAME_LARGER_THAN() \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Wframe-larger-than=\"") +#define RTC_POP_IGNORING_WFRAME_LARGER_THAN() _Pragma("clang diagnostic pop") +#elif __GNUC__ +#define RTC_PUSH_IGNORING_WFRAME_LARGER_THAN() \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wframe-larger-than=\"") +#define RTC_POP_IGNORING_WFRAME_LARGER_THAN() _Pragma("GCC diagnostic pop") +#else +#define RTC_PUSH_IGNORING_WFRAME_LARGER_THAN() +#define RTC_POP_IGNORING_WFRAME_LARGER_THAN() +#endif + +#endif // RTC_BASE_SYSTEM_IGNORE_WARNINGS_H_ diff --git a/third_party/libwebrtc/rtc_base/system/ignore_warnings_gn/moz.build b/third_party/libwebrtc/rtc_base/system/ignore_warnings_gn/moz.build new file mode 100644 index 0000000000..61bbeefabc --- /dev/null +++ b/third_party/libwebrtc/rtc_base/system/ignore_warnings_gn/moz.build @@ -0,0 +1,205 @@ +# 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("ignore_warnings_gn") diff --git a/third_party/libwebrtc/rtc_base/system/inline.h b/third_party/libwebrtc/rtc_base/system/inline.h new file mode 100644 index 0000000000..f585d34ded --- /dev/null +++ b/third_party/libwebrtc/rtc_base/system/inline.h @@ -0,0 +1,31 @@ +/* + * 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 RTC_BASE_SYSTEM_INLINE_H_ +#define RTC_BASE_SYSTEM_INLINE_H_ + +#if defined(_MSC_VER) + +#define RTC_FORCE_INLINE __forceinline +#define RTC_NO_INLINE __declspec(noinline) + +#elif defined(__GNUC__) + +#define RTC_FORCE_INLINE __attribute__((__always_inline__)) +#define RTC_NO_INLINE __attribute__((__noinline__)) + +#else + +#define RTC_FORCE_INLINE +#define RTC_NO_INLINE + +#endif + +#endif // RTC_BASE_SYSTEM_INLINE_H_ diff --git a/third_party/libwebrtc/rtc_base/system/inline_gn/moz.build b/third_party/libwebrtc/rtc_base/system/inline_gn/moz.build new file mode 100644 index 0000000000..574d7958f1 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/system/inline_gn/moz.build @@ -0,0 +1,205 @@ +# 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("inline_gn") diff --git a/third_party/libwebrtc/rtc_base/system/no_cfi_icall.h b/third_party/libwebrtc/rtc_base/system/no_cfi_icall.h new file mode 100644 index 0000000000..42d6c9c2ca --- /dev/null +++ b/third_party/libwebrtc/rtc_base/system/no_cfi_icall.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2022 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 RTC_BASE_SYSTEM_NO_CFI_ICALL_H_ +#define RTC_BASE_SYSTEM_NO_CFI_ICALL_H_ + +#include "rtc_base/sanitizer.h" + +// DISABLE_CFI_ICALL -- Disable Control Flow Integrity indirect call checks. +// Note that the same macro is defined in "base/compiler_specific.h". +// Only use this when building standalone WebRTC. +#if !defined(WEBRTC_CHROMIUM_BUILD) +#if !defined(DISABLE_CFI_ICALL) +#if defined(WEBRTC_WIN) +// Windows also needs __declspec(guard(nocf)). +#define DISABLE_CFI_ICALL RTC_NO_SANITIZE("cfi-icall") __declspec(guard(nocf)) +#else +#define DISABLE_CFI_ICALL RTC_NO_SANITIZE("cfi-icall") +#endif // defined(WEBRTC_WIN) +#endif // !defined(DISABLE_CFI_ICALL) +#if !defined(DISABLE_CFI_ICALL) +#define DISABLE_CFI_ICALL +#endif +#endif // !defined(WEBRTC_CHROMIUM_BUILD) + +#endif // RTC_BASE_SYSTEM_NO_CFI_ICALL_H_ diff --git a/third_party/libwebrtc/rtc_base/system/no_unique_address.h b/third_party/libwebrtc/rtc_base/system/no_unique_address.h new file mode 100644 index 0000000000..a40db3453b --- /dev/null +++ b/third_party/libwebrtc/rtc_base/system/no_unique_address.h @@ -0,0 +1,37 @@ +/* + * 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 RTC_BASE_SYSTEM_NO_UNIQUE_ADDRESS_H_ +#define RTC_BASE_SYSTEM_NO_UNIQUE_ADDRESS_H_ + +// RTC_NO_UNIQUE_ADDRESS is a portable annotation to tell the compiler that +// a data member need not have an address distinct from all other non-static +// data members of its class. +// It allows empty types to actually occupy zero bytes as class members, +// instead of occupying at least one byte just so that they get their own +// address. There is almost never any reason not to use it on class members +// that could possibly be empty. +// The macro expands to [[no_unique_address]] if the compiler supports the +// attribute, it expands to nothing otherwise. +// Clang should supports this attribute since C++11, while other compilers +// should add support for it starting from C++20. Among clang compilers, +// clang-cl doesn't support it yet and support is unclear also when the target +// platform is iOS. +#ifndef __has_cpp_attribute +#define __has_cpp_attribute(x) 0 +#endif +#if __has_cpp_attribute(no_unique_address) +// NOLINTNEXTLINE(whitespace/braces) +#define RTC_NO_UNIQUE_ADDRESS [[no_unique_address]] +#else +#define RTC_NO_UNIQUE_ADDRESS +#endif + +#endif // RTC_BASE_SYSTEM_NO_UNIQUE_ADDRESS_H_ diff --git a/third_party/libwebrtc/rtc_base/system/no_unique_address_gn/moz.build b/third_party/libwebrtc/rtc_base/system/no_unique_address_gn/moz.build new file mode 100644 index 0000000000..4d51581c1b --- /dev/null +++ b/third_party/libwebrtc/rtc_base/system/no_unique_address_gn/moz.build @@ -0,0 +1,205 @@ +# 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("no_unique_address_gn") diff --git a/third_party/libwebrtc/rtc_base/system/rtc_export.h b/third_party/libwebrtc/rtc_base/system/rtc_export.h new file mode 100644 index 0000000000..d1eb60ad78 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/system/rtc_export.h @@ -0,0 +1,43 @@ +/* + * 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 RTC_BASE_SYSTEM_RTC_EXPORT_H_ +#define RTC_BASE_SYSTEM_RTC_EXPORT_H_ + +// RTC_EXPORT is used to mark symbols as exported or imported when WebRTC is +// built or used as a shared library. +// When WebRTC is built as a static library the RTC_EXPORT macro expands to +// nothing. + +#ifdef WEBRTC_ENABLE_SYMBOL_EXPORT + +#ifdef WEBRTC_WIN + +#ifdef WEBRTC_LIBRARY_IMPL +#define RTC_EXPORT __declspec(dllexport) +#else +#define RTC_EXPORT __declspec(dllimport) +#endif + +#else // WEBRTC_WIN + +#if __has_attribute(visibility) && defined(WEBRTC_LIBRARY_IMPL) +#define RTC_EXPORT __attribute__((visibility("default"))) +#endif + +#endif // WEBRTC_WIN + +#endif // WEBRTC_ENABLE_SYMBOL_EXPORT + +#ifndef RTC_EXPORT +#define RTC_EXPORT +#endif + +#endif // RTC_BASE_SYSTEM_RTC_EXPORT_H_ diff --git a/third_party/libwebrtc/rtc_base/system/rtc_export_gn/moz.build b/third_party/libwebrtc/rtc_base/system/rtc_export_gn/moz.build new file mode 100644 index 0000000000..e4d340d3c6 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/system/rtc_export_gn/moz.build @@ -0,0 +1,205 @@ +# 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("rtc_export_gn") diff --git a/third_party/libwebrtc/rtc_base/system/rtc_export_template.h b/third_party/libwebrtc/rtc_base/system/rtc_export_template.h new file mode 100644 index 0000000000..4ac7043835 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/system/rtc_export_template.h @@ -0,0 +1,197 @@ +/* + * 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 RTC_BASE_SYSTEM_RTC_EXPORT_TEMPLATE_H_ +#define RTC_BASE_SYSTEM_RTC_EXPORT_TEMPLATE_H_ + +// clang-format off +// clang formating would cause cpplint errors in the macros below. + +// Most of this was borrowed (with minor modifications) from Chromium's +// base/export_template.h. + +// Synopsis +// +// This header provides macros for using RTC_EXPORT macros with explicit +// template instantiation declarations and definitions. +// Generally, the RTC_EXPORT macros are used at declarations, +// and GCC requires them to be used at explicit instantiation declarations, +// but MSVC requires __declspec(dllexport) to be used at the explicit +// instantiation definitions instead. + +// Usage +// +// In a header file, write: +// +// extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT) foo<bar>; +// +// In a source file, write: +// +// template class RTC_EXPORT_TEMPLATE_DEFINE(RTC_EXPORT) foo<bar>; + +// Implementation notes +// +// On Windows, when building when RTC_EXPORT expands to __declspec(dllexport)), +// we want the two lines to expand to: +// +// extern template class foo<bar>; +// template class RTC_EXPORT foo<bar>; +// +// In all other cases (non-Windows, and Windows when RTC_EXPORT expands to +// __declspec(dllimport)), we want: +// +// extern template class RTC_EXPORT foo<bar>; +// template class foo<bar>; +// +// The implementation of this header uses some subtle macro semantics to +// detect what the provided RTC_EXPORT value was defined as and then +// to dispatch to appropriate macro definitions. Unfortunately, +// MSVC's C preprocessor is rather non-compliant and requires special +// care to make it work. +// +// Issue 1. +// +// #define F(x) +// F() +// +// MSVC emits warning C4003 ("not enough actual parameters for macro +// 'F'), even though it's a valid macro invocation. This affects the +// macros below that take just an "export" parameter, because export +// may be empty. +// +// As a workaround, we can add a dummy parameter and arguments: +// +// #define F(x,_) +// F(,) +// +// Issue 2. +// +// #define F(x) G##x +// #define Gj() ok +// F(j()) +// +// The correct replacement for "F(j())" is "ok", but MSVC replaces it +// with "Gj()". As a workaround, we can pass the result to an +// identity macro to force MSVC to look for replacements again. (This +// is why RTC_EXPORT_TEMPLATE_STYLE_3 exists.) + +#define RTC_EXPORT_TEMPLATE_DECLARE(export) \ + RTC_EXPORT_TEMPLATE_INVOKE( \ + DECLARE, \ + RTC_EXPORT_TEMPLATE_STYLE(export, ), export) // NOLINT +#define RTC_EXPORT_TEMPLATE_DEFINE(export) \ + RTC_EXPORT_TEMPLATE_INVOKE( \ + DEFINE, \ + RTC_EXPORT_TEMPLATE_STYLE(export, ), export) // NOLINT + +// INVOKE is an internal helper macro to perform parameter replacements +// and token pasting to chain invoke another macro. E.g., +// RTC_EXPORT_TEMPLATE_INVOKE(DECLARE, DEFAULT, RTC_EXPORT) +// will export to call +// RTC_EXPORT_TEMPLATE_DECLARE_DEFAULT(RTC_EXPORT, ) +// (but with RTC_EXPORT expanded too). +#define RTC_EXPORT_TEMPLATE_INVOKE(which, style, export) \ + RTC_EXPORT_TEMPLATE_INVOKE_2(which, style, export) +#define RTC_EXPORT_TEMPLATE_INVOKE_2(which, style, export) \ + RTC_EXPORT_TEMPLATE_##which##_##style(export, ) + +// Default style is to apply the RTC_EXPORT macro at declaration sites. +#define RTC_EXPORT_TEMPLATE_DECLARE_DEFAULT(export, _) export +#define RTC_EXPORT_TEMPLATE_DEFINE_DEFAULT(export, _) + +// The "MSVC hack" style is used when RTC_EXPORT is defined +// as __declspec(dllexport), which MSVC requires to be used at +// definition sites instead. +#define RTC_EXPORT_TEMPLATE_DECLARE_MSVC_HACK(export, _) +#define RTC_EXPORT_TEMPLATE_DEFINE_MSVC_HACK(export, _) export + +// RTC_EXPORT_TEMPLATE_STYLE is an internal helper macro that identifies which +// export style needs to be used for the provided RTC_EXPORT macro definition. +// "", "__attribute__(...)", and "__declspec(dllimport)" are mapped +// to "DEFAULT"; while "__declspec(dllexport)" is mapped to "MSVC_HACK". +// +// It's implemented with token pasting to transform the __attribute__ and +// __declspec annotations into macro invocations. E.g., if RTC_EXPORT is +// defined as "__declspec(dllimport)", it undergoes the following sequence of +// macro substitutions: +// RTC_EXPORT_TEMPLATE_STYLE(RTC_EXPORT,) +// RTC_EXPORT_TEMPLATE_STYLE_2(__declspec(dllimport),) +// RTC_EXPORT_TEMPLATE_STYLE_3( +// RTC_EXPORT_TEMPLATE_STYLE_MATCH__declspec(dllimport)) +// RTC_EXPORT_TEMPLATE_STYLE_MATCH__declspec(dllimport) +// RTC_EXPORT_TEMPLATE_STYLE_MATCH_DECLSPEC_dllimport +// DEFAULT +#define RTC_EXPORT_TEMPLATE_STYLE(export, _) \ + RTC_EXPORT_TEMPLATE_STYLE_2(export, ) +#define RTC_EXPORT_TEMPLATE_STYLE_2(export, _) \ + RTC_EXPORT_TEMPLATE_STYLE_3( \ + RTC_EXPORT_TEMPLATE_STYLE_MATCH_foj3FJo5StF0OvIzl7oMxA##export) +#define RTC_EXPORT_TEMPLATE_STYLE_3(style) style + +// Internal helper macros for RTC_EXPORT_TEMPLATE_STYLE. +// +// XXX: C++ reserves all identifiers containing "__" for the implementation, +// but "__attribute__" and "__declspec" already contain "__" and the token-paste +// operator can only add characters; not remove them. To minimize the risk of +// conflict with implementations, we include "foj3FJo5StF0OvIzl7oMxA" (a random +// 128-bit string, encoded in Base64) in the macro name. +#define RTC_EXPORT_TEMPLATE_STYLE_MATCH_foj3FJo5StF0OvIzl7oMxA DEFAULT +#define RTC_EXPORT_TEMPLATE_STYLE_MATCH_foj3FJo5StF0OvIzl7oMxA__attribute__( \ + ...) \ + DEFAULT +#define RTC_EXPORT_TEMPLATE_STYLE_MATCH_foj3FJo5StF0OvIzl7oMxA__declspec(arg) \ + RTC_EXPORT_TEMPLATE_STYLE_MATCH_DECLSPEC_##arg + +// Internal helper macros for RTC_EXPORT_TEMPLATE_STYLE. +#define RTC_EXPORT_TEMPLATE_STYLE_MATCH_DECLSPEC_dllexport MSVC_HACK +#define RTC_EXPORT_TEMPLATE_STYLE_MATCH_DECLSPEC_dllimport DEFAULT + +// Sanity checks. +// +// RTC_EXPORT_TEMPLATE_TEST uses the same macro invocation pattern as +// RTC_EXPORT_TEMPLATE_DECLARE and RTC_EXPORT_TEMPLATE_DEFINE do to check that +// they're working correctly. When they're working correctly, the sequence of +// macro replacements should go something like: +// +// RTC_EXPORT_TEMPLATE_TEST(DEFAULT, __declspec(dllimport)); +// +// static_assert(RTC_EXPORT_TEMPLATE_INVOKE(TEST_DEFAULT, +// RTC_EXPORT_TEMPLATE_STYLE(__declspec(dllimport), ), +// __declspec(dllimport)), "__declspec(dllimport)"); +// +// static_assert(RTC_EXPORT_TEMPLATE_INVOKE(TEST_DEFAULT, +// DEFAULT, __declspec(dllimport)), "__declspec(dllimport)"); +// +// static_assert(RTC_EXPORT_TEMPLATE_TEST_DEFAULT_DEFAULT( +// __declspec(dllimport)), "__declspec(dllimport)"); +// +// static_assert(true, "__declspec(dllimport)"); +// +// When they're not working correctly, a syntax error should occur instead. +#define RTC_EXPORT_TEMPLATE_TEST(want, export) \ + static_assert( \ + RTC_EXPORT_TEMPLATE_INVOKE( \ + TEST_##want, \ + RTC_EXPORT_TEMPLATE_STYLE(export, ), export), #export) // NOLINT +#define RTC_EXPORT_TEMPLATE_TEST_DEFAULT_DEFAULT(...) true +#define RTC_EXPORT_TEMPLATE_TEST_MSVC_HACK_MSVC_HACK(...) true + +RTC_EXPORT_TEMPLATE_TEST(DEFAULT, ); // NOLINT +RTC_EXPORT_TEMPLATE_TEST(DEFAULT, __attribute__((visibility("default")))); +RTC_EXPORT_TEMPLATE_TEST(MSVC_HACK, __declspec(dllexport)); +RTC_EXPORT_TEMPLATE_TEST(DEFAULT, __declspec(dllimport)); + +#undef RTC_EXPORT_TEMPLATE_TEST +#undef RTC_EXPORT_TEMPLATE_TEST_DEFAULT_DEFAULT +#undef RTC_EXPORT_TEMPLATE_TEST_MSVC_HACK_MSVC_HACK + +// clang-format on + +#endif // RTC_BASE_SYSTEM_RTC_EXPORT_TEMPLATE_H_ diff --git a/third_party/libwebrtc/rtc_base/system/unused.h b/third_party/libwebrtc/rtc_base/system/unused.h new file mode 100644 index 0000000000..03d0c2f0a7 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/system/unused.h @@ -0,0 +1,28 @@ +/* + * 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 RTC_BASE_SYSTEM_UNUSED_H_ +#define RTC_BASE_SYSTEM_UNUSED_H_ + +// Prevent the compiler from warning about an unused variable. For example: +// int result = DoSomething(); +// RTC_DCHECK(result == 17); +// RTC_UNUSED(result); +// Note: In most cases it is better to remove the unused variable rather than +// suppressing the compiler warning. +#ifndef RTC_UNUSED +#ifdef __cplusplus +#define RTC_UNUSED(x) static_cast<void>(x) +#else +#define RTC_UNUSED(x) (void)(x) +#endif +#endif // RTC_UNUSED + +#endif // RTC_BASE_SYSTEM_UNUSED_H_ diff --git a/third_party/libwebrtc/rtc_base/system/unused_gn/moz.build b/third_party/libwebrtc/rtc_base/system/unused_gn/moz.build new file mode 100644 index 0000000000..c6dd8a6bab --- /dev/null +++ b/third_party/libwebrtc/rtc_base/system/unused_gn/moz.build @@ -0,0 +1,205 @@ +# 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("unused_gn") diff --git a/third_party/libwebrtc/rtc_base/system/warn_current_thread_is_deadlocked.cc b/third_party/libwebrtc/rtc_base/system/warn_current_thread_is_deadlocked.cc new file mode 100644 index 0000000000..d39b04039a --- /dev/null +++ b/third_party/libwebrtc/rtc_base/system/warn_current_thread_is_deadlocked.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 "rtc_base/system/warn_current_thread_is_deadlocked.h" + +#include "rtc_base/logging.h" +#include "sdk/android/native_api/stacktrace/stacktrace.h" + +namespace webrtc { + +void WarnThatTheCurrentThreadIsProbablyDeadlocked() { + RTC_LOG(LS_WARNING) << "Probable deadlock:"; + RTC_LOG(LS_WARNING) << StackTraceToString(GetStackTrace()); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/system/warn_current_thread_is_deadlocked.h b/third_party/libwebrtc/rtc_base/system/warn_current_thread_is_deadlocked.h new file mode 100644 index 0000000000..eac12022ed --- /dev/null +++ b/third_party/libwebrtc/rtc_base/system/warn_current_thread_is_deadlocked.h @@ -0,0 +1,24 @@ +/* + * 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 RTC_BASE_SYSTEM_WARN_CURRENT_THREAD_IS_DEADLOCKED_H_ +#define RTC_BASE_SYSTEM_WARN_CURRENT_THREAD_IS_DEADLOCKED_H_ + +namespace webrtc { + +#if defined(WEBRTC_ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD) && !defined(MOZ_WIDGET_ANDROID) +void WarnThatTheCurrentThreadIsProbablyDeadlocked(); +#else +inline void WarnThatTheCurrentThreadIsProbablyDeadlocked() {} +#endif + +} // namespace webrtc + +#endif // RTC_BASE_SYSTEM_WARN_CURRENT_THREAD_IS_DEADLOCKED_H_ diff --git a/third_party/libwebrtc/rtc_base/system/warn_current_thread_is_deadlocked_gn/moz.build b/third_party/libwebrtc/rtc_base/system/warn_current_thread_is_deadlocked_gn/moz.build new file mode 100644 index 0000000000..3aa57ac48e --- /dev/null +++ b/third_party/libwebrtc/rtc_base/system/warn_current_thread_is_deadlocked_gn/moz.build @@ -0,0 +1,205 @@ +# 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("warn_current_thread_is_deadlocked_gn") diff --git a/third_party/libwebrtc/rtc_base/system_time.cc b/third_party/libwebrtc/rtc_base/system_time.cc new file mode 100644 index 0000000000..1a5e447916 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/system_time.cc @@ -0,0 +1,104 @@ +/* + * Copyright 2021 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. + */ + +// If WEBRTC_EXCLUDE_SYSTEM_TIME is set, an implementation of +// rtc::SystemTimeNanos() must be provided externally. +#ifndef WEBRTC_EXCLUDE_SYSTEM_TIME + +#error Mozilla: Must not use the built-in libwebrtc clock + +#include <stdint.h> + +#include <limits> + +#if defined(WEBRTC_POSIX) +#include <sys/time.h> +#if defined(WEBRTC_MAC) +#include <mach/mach_time.h> +#endif +#endif + +#if defined(WEBRTC_WIN) +// clang-format off +// clang formatting would put <windows.h> last, +// which leads to compilation failure. +#include <windows.h> +#include <mmsystem.h> +#include <sys/timeb.h> +// clang-format on +#endif + +#include "rtc_base/checks.h" +#include "rtc_base/numerics/safe_conversions.h" +#include "rtc_base/system_time.h" +#include "rtc_base/time_utils.h" + +namespace rtc { + +int64_t SystemTimeNanos() { + int64_t ticks; +#if defined(WEBRTC_MAC) + static mach_timebase_info_data_t timebase; + if (timebase.denom == 0) { + // Get the timebase if this is the first time we run. + // Recommended by Apple's QA1398. + if (mach_timebase_info(&timebase) != KERN_SUCCESS) { + RTC_DCHECK_NOTREACHED(); + } + } + // Use timebase to convert absolute time tick units into nanoseconds. + const auto mul = [](uint64_t a, uint32_t b) -> int64_t { + RTC_DCHECK_NE(b, 0); + RTC_DCHECK_LE(a, std::numeric_limits<int64_t>::max() / b) + << "The multiplication " << a << " * " << b << " overflows"; + return rtc::dchecked_cast<int64_t>(a * b); + }; + ticks = mul(mach_absolute_time(), timebase.numer) / timebase.denom; +#elif defined(WEBRTC_POSIX) + struct timespec ts; + // TODO(deadbeef): Do we need to handle the case when CLOCK_MONOTONIC is not + // supported? + clock_gettime(CLOCK_MONOTONIC, &ts); + ticks = kNumNanosecsPerSec * static_cast<int64_t>(ts.tv_sec) + + static_cast<int64_t>(ts.tv_nsec); +#elif defined(WINUWP) + ticks = WinUwpSystemTimeNanos(); +#elif defined(WEBRTC_WIN) + // TODO(webrtc:14601): Fix the volatile increment instead of suppressing the + // warning. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-volatile" + static volatile LONG last_timegettime = 0; + static volatile int64_t num_wrap_timegettime = 0; + volatile LONG* last_timegettime_ptr = &last_timegettime; + DWORD now = timeGetTime(); + // Atomically update the last gotten time + DWORD old = InterlockedExchange(last_timegettime_ptr, now); + if (now < old) { + // If now is earlier than old, there may have been a race between threads. + // 0x0fffffff ~3.1 days, the code will not take that long to execute + // so it must have been a wrap around. + if (old > 0xf0000000 && now < 0x0fffffff) { + num_wrap_timegettime++; + } + } + ticks = now + (num_wrap_timegettime << 32); + // TODO(deadbeef): Calculate with nanosecond precision. Otherwise, we're + // just wasting a multiply and divide when doing Time() on Windows. + ticks = ticks * kNumNanosecsPerMillisec; +#pragma clang diagnostic pop +#else +#error Unsupported platform. +#endif + return ticks; +} + +} // namespace rtc +#endif // WEBRTC_EXCLUDE_SYSTEM_TIME diff --git a/third_party/libwebrtc/rtc_base/system_time.h b/third_party/libwebrtc/rtc_base/system_time.h new file mode 100644 index 0000000000..c0ebc2a217 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/system_time.h @@ -0,0 +1,24 @@ +/* + * Copyright 2021 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 RTC_BASE_SYSTEM_TIME_H_ +#define RTC_BASE_SYSTEM_TIME_H_ + +#include <cstdint> + +namespace rtc { + +// Returns the actual system time, even if a clock is set for testing. +// Useful for timeouts while using a test clock, or for logging. +int64_t SystemTimeNanos(); + +} // namespace rtc + +#endif // RTC_BASE_SYSTEM_TIME_H_ diff --git a/third_party/libwebrtc/rtc_base/task_queue.cc b/third_party/libwebrtc/rtc_base/task_queue.cc new file mode 100644 index 0000000000..7c972ed152 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/task_queue.cc @@ -0,0 +1,32 @@ +/* + * 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 "rtc_base/task_queue.h" + +#include "api/task_queue/task_queue_base.h" + +namespace rtc { + +TaskQueue::TaskQueue( + std::unique_ptr<webrtc::TaskQueueBase, webrtc::TaskQueueDeleter> task_queue) + : impl_(task_queue.release()) {} + +TaskQueue::~TaskQueue() { + // There might running task that tries to rescheduler itself to the TaskQueue + // and not yet aware TaskQueue destructor is called. + // Calling back to TaskQueue::PostTask need impl_ pointer still be valid, so + // do not invalidate impl_ pointer until Delete returns. + impl_->Delete(); +} + +bool TaskQueue::IsCurrent() const { + return impl_->IsCurrent(); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/task_queue.h b/third_party/libwebrtc/rtc_base/task_queue.h new file mode 100644 index 0000000000..e52c49cf00 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/task_queue.h @@ -0,0 +1,117 @@ +/* + * Copyright 2016 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 RTC_BASE_TASK_QUEUE_H_ +#define RTC_BASE_TASK_QUEUE_H_ + +#include <stdint.h> + +#include <memory> +#include <utility> + +#include "absl/functional/any_invocable.h" +#include "absl/memory/memory.h" +#include "api/task_queue/task_queue_base.h" +#include "api/task_queue/task_queue_factory.h" +#include "rtc_base/system/rtc_export.h" +#include "rtc_base/thread_annotations.h" + +namespace rtc { +// Implements a task queue that asynchronously executes tasks in a way that +// guarantees that they're executed in FIFO order and that tasks never overlap. +// Tasks may always execute on the same worker thread and they may not. +// To DCHECK that tasks are executing on a known task queue, use IsCurrent(). +// +// Here are some usage examples: +// +// 1) Asynchronously running a lambda: +// +// class MyClass { +// ... +// TaskQueue queue_("MyQueue"); +// }; +// +// void MyClass::StartWork() { +// queue_.PostTask([]() { Work(); }); +// ... +// +// 2) Posting a custom task on a timer. The task posts itself again after +// every running: +// +// class TimerTask : public QueuedTask { +// public: +// TimerTask() {} +// private: +// bool Run() override { +// ++count_; +// TaskQueueBase::Current()->PostDelayedTask( +// absl::WrapUnique(this), 1000); +// // Ownership has been transferred to the next occurance, +// // so return false to prevent from being deleted now. +// return false; +// } +// int count_ = 0; +// }; +// ... +// queue_.PostDelayedTask(std::make_unique<TimerTask>(), 1000); +// +// For more examples, see task_queue_unittests.cc. +// +// A note on destruction: +// +// When a TaskQueue is deleted, pending tasks will not be executed but they will +// be deleted. The deletion of tasks may happen asynchronously after the +// TaskQueue itself has been deleted or it may happen synchronously while the +// TaskQueue instance is being deleted. This may vary from one OS to the next +// so assumptions about lifetimes of pending tasks should not be made. +class RTC_LOCKABLE RTC_EXPORT TaskQueue { + public: + // TaskQueue priority levels. On some platforms these will map to thread + // priorities, on others such as Mac and iOS, GCD queue priorities. + using Priority = ::webrtc::TaskQueueFactory::Priority; + + explicit TaskQueue(std::unique_ptr<webrtc::TaskQueueBase, + webrtc::TaskQueueDeleter> task_queue); + ~TaskQueue(); + + TaskQueue(const TaskQueue&) = delete; + TaskQueue& operator=(const TaskQueue&) = delete; + + // Used for DCHECKing the current queue. + bool IsCurrent() const; + + // Returns non-owning pointer to the task queue implementation. + webrtc::TaskQueueBase* Get() { return impl_; } + + void PostTask( + absl::AnyInvocable<void() &&> task, + const webrtc::Location& location = webrtc::Location::Current()) { + impl_->PostTask(std::move(task), location); + } + void PostDelayedTask( + absl::AnyInvocable<void() &&> task, + webrtc::TimeDelta delay, + const webrtc::Location& location = webrtc::Location::Current()) { + impl_->PostDelayedTask(std::move(task), delay, location); + } + void PostDelayedHighPrecisionTask( + absl::AnyInvocable<void() &&> task, + webrtc::TimeDelta delay, + const webrtc::Location& location = webrtc::Location::Current()) { + impl_->PostDelayedHighPrecisionTask(std::move(task), delay, location); + } + + private: + webrtc::TaskQueueBase* const impl_; +}; + +} // namespace rtc + +#endif // RTC_BASE_TASK_QUEUE_H_ diff --git a/third_party/libwebrtc/rtc_base/task_queue_for_test.cc b/third_party/libwebrtc/rtc_base/task_queue_for_test.cc new file mode 100644 index 0000000000..cb6b23ceae --- /dev/null +++ b/third_party/libwebrtc/rtc_base/task_queue_for_test.cc @@ -0,0 +1,21 @@ +/* + * 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. + */ + +#include "rtc_base/task_queue_for_test.h" + +#include "api/task_queue/default_task_queue_factory.h" + +namespace webrtc { + +TaskQueueForTest::TaskQueueForTest(absl::string_view name, Priority priority) + : TaskQueue( + CreateDefaultTaskQueueFactory()->CreateTaskQueue(name, priority)) {} + +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/task_queue_for_test.h b/third_party/libwebrtc/rtc_base/task_queue_for_test.h new file mode 100644 index 0000000000..4c7f842abe --- /dev/null +++ b/third_party/libwebrtc/rtc_base/task_queue_for_test.h @@ -0,0 +1,68 @@ +/* + * 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 RTC_BASE_TASK_QUEUE_FOR_TEST_H_ +#define RTC_BASE_TASK_QUEUE_FOR_TEST_H_ + +#include <utility> + +#include "absl/cleanup/cleanup.h" +#include "absl/strings/string_view.h" +#include "api/function_view.h" +#include "api/task_queue/task_queue_base.h" +#include "rtc_base/checks.h" +#include "rtc_base/event.h" +#include "rtc_base/task_queue.h" +#include "rtc_base/thread_annotations.h" + +namespace webrtc { + +inline void SendTask(TaskQueueBase* task_queue, + rtc::FunctionView<void()> task) { + if (task_queue->IsCurrent()) { + task(); + return; + } + + rtc::Event event; + absl::Cleanup cleanup = [&event] { event.Set(); }; + task_queue->PostTask([task, cleanup = std::move(cleanup)] { task(); }); + RTC_CHECK(event.Wait(/*give_up_after=*/rtc::Event::kForever, + /*warn_after=*/TimeDelta::Seconds(10))); +} + +class RTC_LOCKABLE TaskQueueForTest : public rtc::TaskQueue { + public: + using rtc::TaskQueue::TaskQueue; + explicit TaskQueueForTest(absl::string_view name = "TestQueue", + Priority priority = Priority::NORMAL); + TaskQueueForTest(const TaskQueueForTest&) = delete; + TaskQueueForTest& operator=(const TaskQueueForTest&) = delete; + ~TaskQueueForTest() = default; + + // A convenience, test-only method that blocks the current thread while + // a task executes on the task queue. + void SendTask(rtc::FunctionView<void()> task) { + ::webrtc::SendTask(Get(), task); + } + + // Wait for the completion of all tasks posted prior to the + // WaitForPreviouslyPostedTasks() call. + void WaitForPreviouslyPostedTasks() { + RTC_DCHECK(!Get()->IsCurrent()); + // Post an empty task on the queue and wait for it to finish, to ensure + // that all already posted tasks on the queue get executed. + SendTask([]() {}); + } +}; + +} // namespace webrtc + +#endif // RTC_BASE_TASK_QUEUE_FOR_TEST_H_ diff --git a/third_party/libwebrtc/rtc_base/task_queue_gcd.cc b/third_party/libwebrtc/rtc_base/task_queue_gcd.cc new file mode 100644 index 0000000000..fb870e7637 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/task_queue_gcd.cc @@ -0,0 +1,162 @@ +/* + * Copyright 2016 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 file contains the implementation of TaskQueue for Mac and iOS. +// The implementation uses Grand Central Dispatch queues (GCD) to +// do the actual task queuing. + +#include "rtc_base/task_queue_gcd.h" + +#include <dispatch/dispatch.h> +#include <string.h> + +#include <memory> + +#include "absl/functional/any_invocable.h" +#include "absl/strings/string_view.h" +#include "api/location.h" +#include "api/task_queue/task_queue_base.h" +#include "api/units/time_delta.h" +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" +#include "rtc_base/system/gcd_helpers.h" + +namespace webrtc { +namespace { + +int TaskQueuePriorityToGCD(TaskQueueFactory::Priority priority) { + switch (priority) { + case TaskQueueFactory::Priority::NORMAL: + return DISPATCH_QUEUE_PRIORITY_DEFAULT; + case TaskQueueFactory::Priority::HIGH: + return DISPATCH_QUEUE_PRIORITY_HIGH; + case TaskQueueFactory::Priority::LOW: + return DISPATCH_QUEUE_PRIORITY_LOW; + } +} + +class TaskQueueGcd final : public TaskQueueBase { + public: + TaskQueueGcd(absl::string_view queue_name, int gcd_priority); + + void Delete() override; + + protected: + void PostTaskImpl(absl::AnyInvocable<void() &&> task, + const PostTaskTraits& traits, + const Location& location) override; + void PostDelayedTaskImpl(absl::AnyInvocable<void() &&> task, + TimeDelta delay, + const PostDelayedTaskTraits& traits, + const Location& location) override; + + private: + struct TaskContext { + TaskContext(TaskQueueGcd* queue, absl::AnyInvocable<void() &&> task) + : queue(queue), task(std::move(task)) {} + + TaskQueueGcd* const queue; + absl::AnyInvocable<void() &&> task; + }; + + ~TaskQueueGcd() override; + static void RunTask(void* task_context); + static void SetNotActive(void* task_queue); + static void DeleteQueue(void* task_queue); + + dispatch_queue_t queue_; + bool is_active_; +}; + +TaskQueueGcd::TaskQueueGcd(absl::string_view queue_name, int gcd_priority) + : queue_(RTCDispatchQueueCreateWithTarget( + std::string(queue_name).c_str(), + DISPATCH_QUEUE_SERIAL, + dispatch_get_global_queue(gcd_priority, 0))), + is_active_(true) { + RTC_CHECK(queue_); + dispatch_set_context(queue_, this); + // Assign a finalizer that will delete the queue when the last reference + // is released. This may run after the TaskQueue::Delete. + dispatch_set_finalizer_f(queue_, &DeleteQueue); +} + +TaskQueueGcd::~TaskQueueGcd() = default; + +void TaskQueueGcd::Delete() { + RTC_DCHECK(!IsCurrent()); + // Implementation/behavioral note: + // Dispatch queues are reference counted via calls to dispatch_retain and + // dispatch_release. Pending blocks submitted to a queue also hold a + // reference to the queue until they have finished. Once all references to a + // queue have been released, the queue will be deallocated by the system. + // This is why we check the is_active_ before running tasks. + + // Use dispatch_sync to set the is_active_ to guarantee that there's not a + // race with checking it from a task. + dispatch_sync_f(queue_, this, &SetNotActive); + dispatch_release(queue_); +} + +void TaskQueueGcd::PostTaskImpl(absl::AnyInvocable<void() &&> task, + const PostTaskTraits& traits, + const Location& location) { + auto* context = new TaskContext(this, std::move(task)); + dispatch_async_f(queue_, context, &RunTask); +} + +void TaskQueueGcd::PostDelayedTaskImpl(absl::AnyInvocable<void() &&> task, + TimeDelta delay, + const PostDelayedTaskTraits& traits, + const Location& location) { + auto* context = new TaskContext(this, std::move(task)); + dispatch_after_f(dispatch_time(DISPATCH_TIME_NOW, delay.us() * NSEC_PER_USEC), + queue_, context, &RunTask); +} + +// static +void TaskQueueGcd::RunTask(void* task_context) { + std::unique_ptr<TaskContext> tc(static_cast<TaskContext*>(task_context)); + CurrentTaskQueueSetter set_current(tc->queue); + if (tc->queue->is_active_) { + std::move(tc->task)(); + } + // Delete the task before CurrentTaskQueueSetter clears state that this code + // is running on the task queue. + tc = nullptr; +} + +// static +void TaskQueueGcd::SetNotActive(void* task_queue) { + static_cast<TaskQueueGcd*>(task_queue)->is_active_ = false; +} + +// static +void TaskQueueGcd::DeleteQueue(void* task_queue) { + delete static_cast<TaskQueueGcd*>(task_queue); +} + +class TaskQueueGcdFactory final : public TaskQueueFactory { + public: + std::unique_ptr<TaskQueueBase, TaskQueueDeleter> CreateTaskQueue( + absl::string_view name, + Priority priority) const override { + return std::unique_ptr<TaskQueueBase, TaskQueueDeleter>( + new TaskQueueGcd(name, TaskQueuePriorityToGCD(priority))); + } +}; + +} // namespace + +std::unique_ptr<TaskQueueFactory> CreateTaskQueueGcdFactory() { + return std::make_unique<TaskQueueGcdFactory>(); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/task_queue_gcd.h b/third_party/libwebrtc/rtc_base/task_queue_gcd.h new file mode 100644 index 0000000000..dc6039e99a --- /dev/null +++ b/third_party/libwebrtc/rtc_base/task_queue_gcd.h @@ -0,0 +1,24 @@ +/* + * 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 RTC_BASE_TASK_QUEUE_GCD_H_ +#define RTC_BASE_TASK_QUEUE_GCD_H_ + +#include <memory> + +#include "api/task_queue/task_queue_factory.h" + +namespace webrtc { + +std::unique_ptr<TaskQueueFactory> CreateTaskQueueGcdFactory(); + +} // namespace webrtc + +#endif // RTC_BASE_TASK_QUEUE_GCD_H_ diff --git a/third_party/libwebrtc/rtc_base/task_queue_libevent.cc b/third_party/libwebrtc/rtc_base/task_queue_libevent.cc new file mode 100644 index 0000000000..e27c6eff9f --- /dev/null +++ b/third_party/libwebrtc/rtc_base/task_queue_libevent.cc @@ -0,0 +1,336 @@ +/* + * Copyright 2016 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 "rtc_base/task_queue_libevent.h" + +#include <errno.h> +#include <fcntl.h> +#include <pthread.h> +#include <signal.h> +#include <stdint.h> +#include <time.h> +#include <unistd.h> + +#include <list> +#include <memory> +#include <type_traits> +#include <utility> + +#include "absl/container/inlined_vector.h" +#include "absl/functional/any_invocable.h" +#include "absl/strings/string_view.h" +#include "api/task_queue/task_queue_base.h" +#include "api/units/time_delta.h" +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" +#include "rtc_base/numerics/safe_conversions.h" +#include "rtc_base/platform_thread.h" +#include "rtc_base/platform_thread_types.h" +#include "rtc_base/synchronization/mutex.h" +#include "rtc_base/thread_annotations.h" +#include "rtc_base/time_utils.h" +#include "third_party/libevent/event.h" + +namespace webrtc { +namespace { +constexpr char kQuit = 1; +constexpr char kRunTasks = 2; + +using Priority = TaskQueueFactory::Priority; + +// This ignores the SIGPIPE signal on the calling thread. +// This signal can be fired when trying to write() to a pipe that's being +// closed or while closing a pipe that's being written to. +// We can run into that situation so we ignore this signal and continue as +// normal. +// As a side note for this implementation, it would be great if we could safely +// restore the sigmask, but unfortunately the operation of restoring it, can +// itself actually cause SIGPIPE to be signaled :-| (e.g. on MacOS) +// The SIGPIPE signal by default causes the process to be terminated, so we +// don't want to risk that. +// An alternative to this approach is to ignore the signal for the whole +// process: +// signal(SIGPIPE, SIG_IGN); +void IgnoreSigPipeSignalOnCurrentThread() { + sigset_t sigpipe_mask; + sigemptyset(&sigpipe_mask); + sigaddset(&sigpipe_mask, SIGPIPE); + pthread_sigmask(SIG_BLOCK, &sigpipe_mask, nullptr); +} + +bool SetNonBlocking(int fd) { + const int flags = fcntl(fd, F_GETFL); + RTC_CHECK(flags != -1); + return (flags & O_NONBLOCK) || fcntl(fd, F_SETFL, flags | O_NONBLOCK) != -1; +} + +// TODO(tommi): This is a hack to support two versions of libevent that we're +// compatible with. The method we really want to call is event_assign(), +// since event_set() has been marked as deprecated (and doesn't accept +// passing event_base__ as a parameter). However, the version of libevent +// that we have in Chromium, doesn't have event_assign(), so we need to call +// event_set() there. +void EventAssign(struct event* ev, + struct event_base* base, + int fd, + short events, + void (*callback)(int, short, void*), + void* arg) { +#if defined(_EVENT2_EVENT_H_) + RTC_CHECK_EQ(0, event_assign(ev, base, fd, events, callback, arg)); +#else + event_set(ev, fd, events, callback, arg); + RTC_CHECK_EQ(0, event_base_set(base, ev)); +#endif +} + +rtc::ThreadPriority TaskQueuePriorityToThreadPriority(Priority priority) { + switch (priority) { + case Priority::HIGH: + return rtc::ThreadPriority::kRealtime; + case Priority::LOW: + return rtc::ThreadPriority::kLow; + case Priority::NORMAL: + return rtc::ThreadPriority::kNormal; + } +} + +class TaskQueueLibevent final : public TaskQueueBase { + public: + TaskQueueLibevent(absl::string_view queue_name, rtc::ThreadPriority priority); + + void Delete() override; + + protected: + void PostTaskImpl(absl::AnyInvocable<void() &&> task, + const PostTaskTraits& traits, + const Location& location) override; + void PostDelayedTaskImpl(absl::AnyInvocable<void() &&> task, + TimeDelta delay, + const PostDelayedTaskTraits& traits, + const Location& location) override; + + private: + struct TimerEvent; + + void PostDelayedTaskOnTaskQueue(absl::AnyInvocable<void() &&> task, + TimeDelta delay); + + ~TaskQueueLibevent() override = default; + + static void OnWakeup(int socket, short flags, void* context); // NOLINT + static void RunTimer(int fd, short flags, void* context); // NOLINT + + bool is_active_ = true; + int wakeup_pipe_in_ = -1; + int wakeup_pipe_out_ = -1; + event_base* event_base_; + event wakeup_event_; + rtc::PlatformThread thread_; + Mutex pending_lock_; + absl::InlinedVector<absl::AnyInvocable<void() &&>, 4> pending_ + RTC_GUARDED_BY(pending_lock_); + // Holds a list of events pending timers for cleanup when the loop exits. + std::list<TimerEvent*> pending_timers_; +}; + +struct TaskQueueLibevent::TimerEvent { + TimerEvent(TaskQueueLibevent* task_queue, absl::AnyInvocable<void() &&> task) + : task_queue(task_queue), task(std::move(task)) {} + ~TimerEvent() { event_del(&ev); } + + event ev; + TaskQueueLibevent* task_queue; + absl::AnyInvocable<void() &&> task; +}; + +TaskQueueLibevent::TaskQueueLibevent(absl::string_view queue_name, + rtc::ThreadPriority priority) + : event_base_(event_base_new()) { + int fds[2]; + RTC_CHECK(pipe(fds) == 0); + SetNonBlocking(fds[0]); + SetNonBlocking(fds[1]); + wakeup_pipe_out_ = fds[0]; + wakeup_pipe_in_ = fds[1]; + + EventAssign(&wakeup_event_, event_base_, wakeup_pipe_out_, + EV_READ | EV_PERSIST, OnWakeup, this); + event_add(&wakeup_event_, 0); + thread_ = rtc::PlatformThread::SpawnJoinable( + [this] { + { + CurrentTaskQueueSetter set_current(this); + while (is_active_) + event_base_loop(event_base_, 0); + + // Ensure remaining deleted tasks are destroyed with Current() set up + // to this task queue. + absl::InlinedVector<absl::AnyInvocable<void() &&>, 4> pending; + MutexLock lock(&pending_lock_); + pending_.swap(pending); + } + for (TimerEvent* timer : pending_timers_) + delete timer; + +#if RTC_DCHECK_IS_ON + MutexLock lock(&pending_lock_); + RTC_DCHECK(pending_.empty()); +#endif + }, + queue_name, rtc::ThreadAttributes().SetPriority(priority)); +} + +void TaskQueueLibevent::Delete() { + RTC_DCHECK(!IsCurrent()); + struct timespec ts; + char message = kQuit; + while (write(wakeup_pipe_in_, &message, sizeof(message)) != sizeof(message)) { + // The queue is full, so we have no choice but to wait and retry. + RTC_CHECK_EQ(EAGAIN, errno); + ts.tv_sec = 0; + ts.tv_nsec = 1000000; + nanosleep(&ts, nullptr); + } + + thread_.Finalize(); + + event_del(&wakeup_event_); + + IgnoreSigPipeSignalOnCurrentThread(); + + close(wakeup_pipe_in_); + close(wakeup_pipe_out_); + wakeup_pipe_in_ = -1; + wakeup_pipe_out_ = -1; + + event_base_free(event_base_); + delete this; +} + +void TaskQueueLibevent::PostTaskImpl(absl::AnyInvocable<void() &&> task, + const PostTaskTraits& traits, + const Location& location) { + { + MutexLock lock(&pending_lock_); + bool had_pending_tasks = !pending_.empty(); + pending_.push_back(std::move(task)); + + // Only write to the pipe if there were no pending tasks before this one + // since the thread could be sleeping. If there were already pending tasks + // then we know there's either a pending write in the pipe or the thread has + // not yet processed the pending tasks. In either case, the thread will + // eventually wake up and process all pending tasks including this one. + if (had_pending_tasks) { + return; + } + } + + // Note: This behvior outlined above ensures we never fill up the pipe write + // buffer since there will only ever be 1 byte pending. + char message = kRunTasks; + RTC_CHECK_EQ(write(wakeup_pipe_in_, &message, sizeof(message)), + sizeof(message)); +} + +void TaskQueueLibevent::PostDelayedTaskOnTaskQueue( + absl::AnyInvocable<void() &&> task, + TimeDelta delay) { + // libevent api is not thread safe by default, thus event_add need to be + // called on the `thread_`. + RTC_DCHECK(IsCurrent()); + + TimerEvent* timer = new TimerEvent(this, std::move(task)); + EventAssign(&timer->ev, event_base_, -1, 0, &TaskQueueLibevent::RunTimer, + timer); + pending_timers_.push_back(timer); + timeval tv = {.tv_sec = rtc::dchecked_cast<int>(delay.us() / 1'000'000), + .tv_usec = rtc::dchecked_cast<int>(delay.us() % 1'000'000)}; + event_add(&timer->ev, &tv); +} + +void TaskQueueLibevent::PostDelayedTaskImpl(absl::AnyInvocable<void() &&> task, + TimeDelta delay, + const PostDelayedTaskTraits& traits, + const Location& location) { + if (IsCurrent()) { + PostDelayedTaskOnTaskQueue(std::move(task), delay); + } else { + int64_t posted_us = rtc::TimeMicros(); + PostTask([posted_us, delay, task = std::move(task), this]() mutable { + // Compensate for the time that has passed since the posting. + TimeDelta post_time = TimeDelta::Micros(rtc::TimeMicros() - posted_us); + PostDelayedTaskOnTaskQueue( + std::move(task), std::max(delay - post_time, TimeDelta::Zero())); + }); + } +} + +// static +void TaskQueueLibevent::OnWakeup(int socket, + short flags, // NOLINT + void* context) { + TaskQueueLibevent* me = static_cast<TaskQueueLibevent*>(context); + RTC_DCHECK(me->wakeup_pipe_out_ == socket); + char buf; + RTC_CHECK(sizeof(buf) == read(socket, &buf, sizeof(buf))); + switch (buf) { + case kQuit: + me->is_active_ = false; + event_base_loopbreak(me->event_base_); + break; + case kRunTasks: { + absl::InlinedVector<absl::AnyInvocable<void() &&>, 4> tasks; + { + MutexLock lock(&me->pending_lock_); + tasks.swap(me->pending_); + } + RTC_DCHECK(!tasks.empty()); + for (auto& task : tasks) { + std::move(task)(); + // Prefer to delete the `task` before running the next one. + task = nullptr; + } + break; + } + default: + RTC_DCHECK_NOTREACHED(); + break; + } +} + +// static +void TaskQueueLibevent::RunTimer(int fd, + short flags, // NOLINT + void* context) { + TimerEvent* timer = static_cast<TimerEvent*>(context); + std::move(timer->task)(); + timer->task_queue->pending_timers_.remove(timer); + delete timer; +} + +class TaskQueueLibeventFactory final : public TaskQueueFactory { + public: + std::unique_ptr<TaskQueueBase, TaskQueueDeleter> CreateTaskQueue( + absl::string_view name, + Priority priority) const override { + return std::unique_ptr<TaskQueueBase, TaskQueueDeleter>( + new TaskQueueLibevent(name, + TaskQueuePriorityToThreadPriority(priority))); + } +}; + +} // namespace + +std::unique_ptr<TaskQueueFactory> CreateTaskQueueLibeventFactory() { + return std::make_unique<TaskQueueLibeventFactory>(); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/task_queue_libevent.h b/third_party/libwebrtc/rtc_base/task_queue_libevent.h new file mode 100644 index 0000000000..aaa72d4a1b --- /dev/null +++ b/third_party/libwebrtc/rtc_base/task_queue_libevent.h @@ -0,0 +1,24 @@ +/* + * 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 RTC_BASE_TASK_QUEUE_LIBEVENT_H_ +#define RTC_BASE_TASK_QUEUE_LIBEVENT_H_ + +#include <memory> + +#include "api/task_queue/task_queue_factory.h" + +namespace webrtc { + +std::unique_ptr<TaskQueueFactory> CreateTaskQueueLibeventFactory(); + +} // namespace webrtc + +#endif // RTC_BASE_TASK_QUEUE_LIBEVENT_H_ diff --git a/third_party/libwebrtc/rtc_base/task_queue_stdlib.cc b/third_party/libwebrtc/rtc_base/task_queue_stdlib.cc new file mode 100644 index 0000000000..1ac01e1830 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/task_queue_stdlib.cc @@ -0,0 +1,313 @@ +/* + * 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. + */ + +#include "rtc_base/task_queue_stdlib.h" + +#include <string.h> + +#include <algorithm> +#include <map> +#include <memory> +#include <queue> +#include <utility> + +#include "absl/functional/any_invocable.h" +#include "absl/strings/string_view.h" +#include "api/task_queue/task_queue_base.h" +#include "api/units/time_delta.h" +#include "rtc_base/checks.h" +#include "rtc_base/event.h" +#include "rtc_base/logging.h" +#include "rtc_base/numerics/divide_round.h" +#include "rtc_base/platform_thread.h" +#include "rtc_base/synchronization/mutex.h" +#include "rtc_base/thread_annotations.h" +#include "rtc_base/time_utils.h" + +namespace webrtc { +namespace { + +rtc::ThreadPriority TaskQueuePriorityToThreadPriority( + TaskQueueFactory::Priority priority) { + switch (priority) { + case TaskQueueFactory::Priority::HIGH: + return rtc::ThreadPriority::kRealtime; + case TaskQueueFactory::Priority::LOW: + return rtc::ThreadPriority::kLow; + case TaskQueueFactory::Priority::NORMAL: + return rtc::ThreadPriority::kNormal; + } +} + +class TaskQueueStdlib final : public TaskQueueBase { + public: + TaskQueueStdlib(absl::string_view queue_name, rtc::ThreadPriority priority); + ~TaskQueueStdlib() override = default; + + void Delete() override; + + protected: + void PostTaskImpl(absl::AnyInvocable<void() &&> task, + const PostTaskTraits& traits, + const Location& location) override; + void PostDelayedTaskImpl(absl::AnyInvocable<void() &&> task, + TimeDelta delay, + const PostDelayedTaskTraits& traits, + const Location& location) override; + + private: + using OrderId = uint64_t; + + struct DelayedEntryTimeout { + // TODO(bugs.webrtc.org/13756): Migrate to Timestamp. + int64_t next_fire_at_us{}; + OrderId order{}; + + bool operator<(const DelayedEntryTimeout& o) const { + return std::tie(next_fire_at_us, order) < + std::tie(o.next_fire_at_us, o.order); + } + }; + + struct NextTask { + bool final_task = false; + absl::AnyInvocable<void() &&> run_task; + TimeDelta sleep_time = rtc::Event::kForever; + }; + + static rtc::PlatformThread InitializeThread(TaskQueueStdlib* me, + absl::string_view queue_name, + rtc::ThreadPriority priority); + + NextTask GetNextTask(); + + void ProcessTasks(); + + void NotifyWake(); + + // Signaled whenever a new task is pending. + rtc::Event flag_notify_; + + Mutex pending_lock_; + + // Indicates if the worker thread needs to shutdown now. + bool thread_should_quit_ RTC_GUARDED_BY(pending_lock_) = false; + + // Holds the next order to use for the next task to be + // put into one of the pending queues. + OrderId thread_posting_order_ RTC_GUARDED_BY(pending_lock_) = 0; + + // The list of all pending tasks that need to be processed in the + // FIFO queue ordering on the worker thread. + std::queue<std::pair<OrderId, absl::AnyInvocable<void() &&>>> pending_queue_ + RTC_GUARDED_BY(pending_lock_); + + // The list of all pending tasks that need to be processed at a future + // time based upon a delay. On the off change the delayed task should + // happen at exactly the same time interval as another task then the + // task is processed based on FIFO ordering. std::priority_queue was + // considered but rejected due to its inability to extract the + // move-only value out of the queue without the presence of a hack. + std::map<DelayedEntryTimeout, absl::AnyInvocable<void() &&>> delayed_queue_ + RTC_GUARDED_BY(pending_lock_); + + // Contains the active worker thread assigned to processing + // tasks (including delayed tasks). + // Placing this last ensures the thread doesn't touch uninitialized attributes + // throughout it's lifetime. + rtc::PlatformThread thread_; +}; + +TaskQueueStdlib::TaskQueueStdlib(absl::string_view queue_name, + rtc::ThreadPriority priority) + : flag_notify_(/*manual_reset=*/false, /*initially_signaled=*/false), + thread_(InitializeThread(this, queue_name, priority)) {} + +// static +rtc::PlatformThread TaskQueueStdlib::InitializeThread( + TaskQueueStdlib* me, + absl::string_view queue_name, + rtc::ThreadPriority priority) { + rtc::Event started; + auto thread = rtc::PlatformThread::SpawnJoinable( + [&started, me] { + CurrentTaskQueueSetter set_current(me); + started.Set(); + me->ProcessTasks(); + }, + queue_name, rtc::ThreadAttributes().SetPriority(priority)); + started.Wait(rtc::Event::kForever); + return thread; +} + +void TaskQueueStdlib::Delete() { + RTC_DCHECK(!IsCurrent()); + + { + MutexLock lock(&pending_lock_); + thread_should_quit_ = true; + } + + NotifyWake(); + + delete this; +} + +void TaskQueueStdlib::PostTaskImpl(absl::AnyInvocable<void() &&> task, + const PostTaskTraits& traits, + const Location& location) { + { + MutexLock lock(&pending_lock_); + pending_queue_.push( + std::make_pair(++thread_posting_order_, std::move(task))); + } + + NotifyWake(); +} + +void TaskQueueStdlib::PostDelayedTaskImpl(absl::AnyInvocable<void() &&> task, + TimeDelta delay, + const PostDelayedTaskTraits& traits, + const Location& location) { + DelayedEntryTimeout delayed_entry; + delayed_entry.next_fire_at_us = rtc::TimeMicros() + delay.us(); + + { + MutexLock lock(&pending_lock_); + delayed_entry.order = ++thread_posting_order_; + delayed_queue_[delayed_entry] = std::move(task); + } + + NotifyWake(); +} + +TaskQueueStdlib::NextTask TaskQueueStdlib::GetNextTask() { + NextTask result; + + const int64_t tick_us = rtc::TimeMicros(); + + MutexLock lock(&pending_lock_); + + if (thread_should_quit_) { + result.final_task = true; + return result; + } + + if (delayed_queue_.size() > 0) { + auto delayed_entry = delayed_queue_.begin(); + const auto& delay_info = delayed_entry->first; + auto& delay_run = delayed_entry->second; + if (tick_us >= delay_info.next_fire_at_us) { + if (pending_queue_.size() > 0) { + auto& entry = pending_queue_.front(); + auto& entry_order = entry.first; + auto& entry_run = entry.second; + if (entry_order < delay_info.order) { + result.run_task = std::move(entry_run); + pending_queue_.pop(); + return result; + } + } + + result.run_task = std::move(delay_run); + delayed_queue_.erase(delayed_entry); + return result; + } + + result.sleep_time = TimeDelta::Millis( + DivideRoundUp(delay_info.next_fire_at_us - tick_us, 1'000)); + } + + if (pending_queue_.size() > 0) { + auto& entry = pending_queue_.front(); + result.run_task = std::move(entry.second); + pending_queue_.pop(); + } + + return result; +} + +void TaskQueueStdlib::ProcessTasks() { + while (true) { + auto task = GetNextTask(); + + if (task.final_task) + break; + + if (task.run_task) { + // process entry immediately then try again + std::move(task.run_task)(); + + // Attempt to run more tasks before going to sleep. + continue; + } + + flag_notify_.Wait(task.sleep_time); + } + + // Ensure remaining deleted tasks are destroyed with Current() set up to this + // task queue. + std::queue<std::pair<OrderId, absl::AnyInvocable<void() &&>>> pending_queue; + { + MutexLock lock(&pending_lock_); + pending_queue_.swap(pending_queue); + } + pending_queue = {}; +#if RTC_DCHECK_IS_ON + MutexLock lock(&pending_lock_); + RTC_DCHECK(pending_queue_.empty()); +#endif +} + +void TaskQueueStdlib::NotifyWake() { + // The queue holds pending tasks to complete. Either tasks are to be + // executed immediately or tasks are to be run at some future delayed time. + // For immediate tasks the task queue's thread is busy running the task and + // the thread will not be waiting on the flag_notify_ event. If no immediate + // tasks are available but a delayed task is pending then the thread will be + // waiting on flag_notify_ with a delayed time-out of the nearest timed task + // to run. If no immediate or pending tasks are available, the thread will + // wait on flag_notify_ until signaled that a task has been added (or the + // thread to be told to shutdown). + + // In all cases, when a new immediate task, delayed task, or request to + // shutdown the thread is added the flag_notify_ is signaled after. If the + // thread was waiting then the thread will wake up immediately and re-assess + // what task needs to be run next (i.e. run a task now, wait for the nearest + // timed delayed task, or shutdown the thread). If the thread was not waiting + // then the thread will remained signaled to wake up the next time any + // attempt to wait on the flag_notify_ event occurs. + + // Any immediate or delayed pending task (or request to shutdown the thread) + // must always be added to the queue prior to signaling flag_notify_ to wake + // up the possibly sleeping thread. This prevents a race condition where the + // thread is notified to wake up but the task queue's thread finds nothing to + // do so it waits once again to be signaled where such a signal may never + // happen. + flag_notify_.Set(); +} + +class TaskQueueStdlibFactory final : public TaskQueueFactory { + public: + std::unique_ptr<TaskQueueBase, TaskQueueDeleter> CreateTaskQueue( + absl::string_view name, + Priority priority) const override { + return std::unique_ptr<TaskQueueBase, TaskQueueDeleter>( + new TaskQueueStdlib(name, TaskQueuePriorityToThreadPriority(priority))); + } +}; + +} // namespace + +std::unique_ptr<TaskQueueFactory> CreateTaskQueueStdlibFactory() { + return std::make_unique<TaskQueueStdlibFactory>(); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/task_queue_stdlib.h b/third_party/libwebrtc/rtc_base/task_queue_stdlib.h new file mode 100644 index 0000000000..fb03dff3d8 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/task_queue_stdlib.h @@ -0,0 +1,24 @@ +/* + * 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 RTC_BASE_TASK_QUEUE_STDLIB_H_ +#define RTC_BASE_TASK_QUEUE_STDLIB_H_ + +#include <memory> + +#include "api/task_queue/task_queue_factory.h" + +namespace webrtc { + +std::unique_ptr<TaskQueueFactory> CreateTaskQueueStdlibFactory(); + +} // namespace webrtc + +#endif // RTC_BASE_TASK_QUEUE_STDLIB_H_ diff --git a/third_party/libwebrtc/rtc_base/task_queue_stdlib_unittest.cc b/third_party/libwebrtc/rtc_base/task_queue_stdlib_unittest.cc new file mode 100644 index 0000000000..0654e9719c --- /dev/null +++ b/third_party/libwebrtc/rtc_base/task_queue_stdlib_unittest.cc @@ -0,0 +1,29 @@ +/* + * Copyright 2022 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 "rtc_base/task_queue_stdlib.h" + +#include "api/task_queue/task_queue_test.h" +#include "test/gtest.h" + +namespace webrtc { +namespace { + +std::unique_ptr<TaskQueueFactory> CreateTaskQueueFactory( + const webrtc::FieldTrialsView*) { + return CreateTaskQueueStdlibFactory(); +} + +INSTANTIATE_TEST_SUITE_P(TaskQueueStdlib, + TaskQueueTest, + ::testing::Values(CreateTaskQueueFactory)); + +} // namespace +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/task_queue_unittest.cc b/third_party/libwebrtc/rtc_base/task_queue_unittest.cc new file mode 100644 index 0000000000..579dc3cced --- /dev/null +++ b/third_party/libwebrtc/rtc_base/task_queue_unittest.cc @@ -0,0 +1,83 @@ +/* + * Copyright 2016 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. + */ + +#if defined(WEBRTC_WIN) +// clang-format off +#include <windows.h> // Must come first. +#include <mmsystem.h> +// clang-format on +#endif + +#include <stdint.h> + +#include <memory> +#include <utility> +#include <vector> + +#include "absl/memory/memory.h" +#include "api/units/time_delta.h" +#include "rtc_base/event.h" +#include "rtc_base/task_queue_for_test.h" +#include "rtc_base/time_utils.h" +#include "test/gtest.h" + +namespace rtc { + +namespace { +using ::webrtc::TimeDelta; +// Noop on all platforms except Windows, where it turns on high precision +// multimedia timers which increases the precision of TimeMillis() while in +// scope. +class EnableHighResTimers { + public: +#if !defined(WEBRTC_WIN) + EnableHighResTimers() {} +#else + EnableHighResTimers() : enabled_(timeBeginPeriod(1) == TIMERR_NOERROR) {} + ~EnableHighResTimers() { + if (enabled_) + timeEndPeriod(1); + } + + private: + const bool enabled_; +#endif +}; + +void CheckCurrent(Event* signal, TaskQueue* queue) { + EXPECT_TRUE(queue->IsCurrent()); + if (signal) + signal->Set(); +} + +} // namespace + +// This task needs to be run manually due to the slowness of some of our bots. +// TODO(tommi): Can we run this on the perf bots? +TEST(TaskQueueTest, DISABLED_PostDelayedHighRes) { + EnableHighResTimers high_res_scope; + + static const char kQueueName[] = "PostDelayedHighRes"; + Event event; + webrtc::TaskQueueForTest queue(kQueueName, TaskQueue::Priority::HIGH); + + uint32_t start = Time(); + queue.PostDelayedTask([&event, &queue] { CheckCurrent(&event, &queue); }, + TimeDelta::Millis(3)); + EXPECT_TRUE(event.Wait(webrtc::TimeDelta::Seconds(1))); + uint32_t end = TimeMillis(); + // These tests are a little relaxed due to how "powerful" our test bots can + // be. Most recently we've seen windows bots fire the callback after 94-99ms, + // which is why we have a little bit of leeway backwards as well. + EXPECT_GE(end - start, 3u); + EXPECT_NEAR(end - start, 3, 3u); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/task_queue_win.cc b/third_party/libwebrtc/rtc_base/task_queue_win.cc new file mode 100644 index 0000000000..bf55a25c69 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/task_queue_win.cc @@ -0,0 +1,414 @@ +/* + * Copyright 2016 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. + */ + +// Mozilla - this file should not be included in Mozilla builds until +// win32k API usage is removed. This was once done in Bug 1395259, but +// the upstreaming attempt stalled. Until win32k usage is officially +// removed upstream, we have reverted to upstream's version of the file +// (to reduce or elminate merge conflicts), and a static assert is +// placed here to ensure this file isn't accidentally included in the +// Mozilla build. +static_assert(false, "This file should not be built, see Bug 1797161."); + +#include "rtc_base/task_queue_win.h" + +// clang-format off +// clang formating would change include order. + +// Include winsock2.h before including <windows.h> to maintain consistency with +// win32.h. To include win32.h directly, it must be broken out into its own +// build target. +#include <winsock2.h> +#include <windows.h> +#include <sal.h> // Must come after windows headers. +#include <mmsystem.h> // Must come after windows headers. +// clang-format on +#include <string.h> + +#include <algorithm> +#include <functional> +#include <memory> +#include <queue> +#include <utility> + +#include "absl/functional/any_invocable.h" +#include "absl/strings/string_view.h" +#include "absl/types/optional.h" +#include "api/task_queue/task_queue_base.h" +#include "api/units/time_delta.h" +#include "api/units/timestamp.h" +#include "rtc_base/arraysize.h" +#include "rtc_base/checks.h" +#include "rtc_base/event.h" +#include "rtc_base/logging.h" +#include "rtc_base/numerics/safe_conversions.h" +#include "rtc_base/platform_thread.h" +#include "rtc_base/synchronization/mutex.h" +#include "rtc_base/time_utils.h" + +namespace webrtc { +namespace { +#define WM_QUEUE_DELAYED_TASK WM_USER + 2 + +void CALLBACK InitializeQueueThread(ULONG_PTR param) { + MSG msg; + ::PeekMessage(&msg, nullptr, WM_USER, WM_USER, PM_NOREMOVE); + rtc::Event* data = reinterpret_cast<rtc::Event*>(param); + data->Set(); +} + +rtc::ThreadPriority TaskQueuePriorityToThreadPriority( + TaskQueueFactory::Priority priority) { + switch (priority) { + case TaskQueueFactory::Priority::HIGH: + return rtc::ThreadPriority::kRealtime; + case TaskQueueFactory::Priority::LOW: + return rtc::ThreadPriority::kLow; + case TaskQueueFactory::Priority::NORMAL: + return rtc::ThreadPriority::kNormal; + } +} + +Timestamp CurrentTime() { + static const UINT kPeriod = 1; + bool high_res = (timeBeginPeriod(kPeriod) == TIMERR_NOERROR); + Timestamp ret = Timestamp::Micros(rtc::TimeMicros()); + if (high_res) + timeEndPeriod(kPeriod); + return ret; +} + +class DelayedTaskInfo { + public: + // Default ctor needed to support priority_queue::pop(). + DelayedTaskInfo() {} + DelayedTaskInfo(TimeDelta delay, absl::AnyInvocable<void() &&> task) + : due_time_(CurrentTime() + delay), task_(std::move(task)) {} + DelayedTaskInfo(DelayedTaskInfo&&) = default; + + // Implement for priority_queue. + bool operator>(const DelayedTaskInfo& other) const { + return due_time_ > other.due_time_; + } + + // Required by priority_queue::pop(). + DelayedTaskInfo& operator=(DelayedTaskInfo&& other) = default; + + // See below for why this method is const. + void Run() const { + RTC_DCHECK(task_); + std::move(task_)(); + } + + Timestamp due_time() const { return due_time_; } + + private: + Timestamp due_time_ = Timestamp::Zero(); + + // `task` needs to be mutable because std::priority_queue::top() returns + // a const reference and a key in an ordered queue must not be changed. + // There are two basic workarounds, one using const_cast, which would also + // make the key (`due_time`), non-const and the other is to make the non-key + // (`task`), mutable. + // Because of this, the `task` variable is made private and can only be + // mutated by calling the `Run()` method. + mutable absl::AnyInvocable<void() &&> task_; +}; + +class MultimediaTimer { + public: + // Note: We create an event that requires manual reset. + MultimediaTimer() : event_(::CreateEvent(nullptr, true, false, nullptr)) {} + + ~MultimediaTimer() { + Cancel(); + ::CloseHandle(event_); + } + + MultimediaTimer(const MultimediaTimer&) = delete; + MultimediaTimer& operator=(const MultimediaTimer&) = delete; + + bool StartOneShotTimer(UINT delay_ms) { + RTC_DCHECK_EQ(0, timer_id_); + RTC_DCHECK(event_ != nullptr); + timer_id_ = + ::timeSetEvent(delay_ms, 0, reinterpret_cast<LPTIMECALLBACK>(event_), 0, + TIME_ONESHOT | TIME_CALLBACK_EVENT_SET); + return timer_id_ != 0; + } + + void Cancel() { + if (timer_id_) { + ::timeKillEvent(timer_id_); + timer_id_ = 0; + } + // Now that timer is killed and not able to set the event, reset the event. + // Doing it in opposite order is racy because event may be set between + // event was reset and timer is killed leaving MultimediaTimer in surprising + // state where both event is set and timer is canceled. + ::ResetEvent(event_); + } + + HANDLE* event_for_wait() { return &event_; } + + private: + HANDLE event_ = nullptr; + MMRESULT timer_id_ = 0; +}; + +class TaskQueueWin : public TaskQueueBase { + public: + TaskQueueWin(absl::string_view queue_name, rtc::ThreadPriority priority); + ~TaskQueueWin() override = default; + + void Delete() override; + + protected: + void PostTaskImpl(absl::AnyInvocable<void() &&> task, + const PostTaskTraits& traits, + const Location& location) override; + void PostDelayedTaskImpl(absl::AnyInvocable<void() &&> task, + TimeDelta delay, + const PostDelayedTaskTraits& traits, + const Location& location) override; + void RunPendingTasks(); + + private: + void RunThreadMain(); + bool ProcessQueuedMessages(); + void RunDueTasks(); + void ScheduleNextTimer(); + void CancelTimers(); + + MultimediaTimer timer_; + // Since priority_queue<> by defult orders items in terms of + // largest->smallest, using std::less<>, and we want smallest->largest, + // we would like to use std::greater<> here. + std::priority_queue<DelayedTaskInfo, + std::vector<DelayedTaskInfo>, + std::greater<DelayedTaskInfo>> + timer_tasks_; + UINT_PTR timer_id_ = 0; + rtc::PlatformThread thread_; + Mutex pending_lock_; + std::queue<absl::AnyInvocable<void() &&>> pending_ + RTC_GUARDED_BY(pending_lock_); + HANDLE in_queue_; +}; + +TaskQueueWin::TaskQueueWin(absl::string_view queue_name, + rtc::ThreadPriority priority) + : in_queue_(::CreateEvent(nullptr, true, false, nullptr)) { + RTC_DCHECK(in_queue_); + thread_ = rtc::PlatformThread::SpawnJoinable( + [this] { RunThreadMain(); }, queue_name, + rtc::ThreadAttributes().SetPriority(priority)); + + rtc::Event event(false, false); + RTC_CHECK(thread_.QueueAPC(&InitializeQueueThread, + reinterpret_cast<ULONG_PTR>(&event))); + event.Wait(rtc::Event::kForever); +} + +void TaskQueueWin::Delete() { + RTC_DCHECK(!IsCurrent()); + RTC_CHECK(thread_.GetHandle() != absl::nullopt); + while ( + !::PostThreadMessage(GetThreadId(*thread_.GetHandle()), WM_QUIT, 0, 0)) { + RTC_CHECK_EQ(ERROR_NOT_ENOUGH_QUOTA, ::GetLastError()); + Sleep(1); + } + thread_.Finalize(); + ::CloseHandle(in_queue_); + delete this; +} + +void TaskQueueWin::PostTaskImpl(absl::AnyInvocable<void() &&> task, + const PostTaskTraits& traits, + const Location& location) { + MutexLock lock(&pending_lock_); + pending_.push(std::move(task)); + ::SetEvent(in_queue_); +} + +void TaskQueueWin::PostDelayedTaskImpl(absl::AnyInvocable<void() &&> task, + TimeDelta delay, + const PostDelayedTaskTraits& traits, + const Location& location) { + if (delay <= TimeDelta::Zero()) { + PostTask(std::move(task)); + return; + } + + auto* task_info = new DelayedTaskInfo(delay, std::move(task)); + RTC_CHECK(thread_.GetHandle() != absl::nullopt); + if (!::PostThreadMessage(GetThreadId(*thread_.GetHandle()), + WM_QUEUE_DELAYED_TASK, 0, + reinterpret_cast<LPARAM>(task_info))) { + delete task_info; + } +} + +void TaskQueueWin::RunPendingTasks() { + while (true) { + absl::AnyInvocable<void() &&> task; + { + MutexLock lock(&pending_lock_); + if (pending_.empty()) + break; + task = std::move(pending_.front()); + pending_.pop(); + } + + std::move(task)(); + } +} + +void TaskQueueWin::RunThreadMain() { + CurrentTaskQueueSetter set_current(this); + HANDLE handles[2] = {*timer_.event_for_wait(), in_queue_}; + while (true) { + // Make sure we do an alertable wait as that's required to allow APCs to run + // (e.g. required for InitializeQueueThread and stopping the thread in + // PlatformThread). + DWORD result = ::MsgWaitForMultipleObjectsEx( + arraysize(handles), handles, INFINITE, QS_ALLEVENTS, MWMO_ALERTABLE); + RTC_CHECK_NE(WAIT_FAILED, result); + if (result == (WAIT_OBJECT_0 + 2)) { + // There are messages in the message queue that need to be handled. + if (!ProcessQueuedMessages()) + break; + } + + if (result == WAIT_OBJECT_0 || + (!timer_tasks_.empty() && + ::WaitForSingleObject(*timer_.event_for_wait(), 0) == WAIT_OBJECT_0)) { + // The multimedia timer was signaled. + timer_.Cancel(); + RunDueTasks(); + ScheduleNextTimer(); + } + + if (result == (WAIT_OBJECT_0 + 1)) { + ::ResetEvent(in_queue_); + RunPendingTasks(); + } + } + // Ensure remaining deleted tasks are destroyed with Current() set up to this + // task queue. + std::queue<absl::AnyInvocable<void() &&>> pending; + { + MutexLock lock(&pending_lock_); + pending_.swap(pending); + } + pending = {}; +#if RTC_DCHECK_IS_ON + MutexLock lock(&pending_lock_); + RTC_DCHECK(pending_.empty()); +#endif +} + +bool TaskQueueWin::ProcessQueuedMessages() { + MSG msg = {}; + // To protect against overly busy message queues, we limit the time + // we process tasks to a few milliseconds. If we don't do that, there's + // a chance that timer tasks won't ever run. + static constexpr TimeDelta kMaxTaskProcessingTime = TimeDelta::Millis(500); + Timestamp start = CurrentTime(); + while (::PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE) && + msg.message != WM_QUIT) { + if (!msg.hwnd) { + switch (msg.message) { + case WM_QUEUE_DELAYED_TASK: { + std::unique_ptr<DelayedTaskInfo> info( + reinterpret_cast<DelayedTaskInfo*>(msg.lParam)); + bool need_to_schedule_timers = + timer_tasks_.empty() || + timer_tasks_.top().due_time() > info->due_time(); + timer_tasks_.push(std::move(*info)); + if (need_to_schedule_timers) { + CancelTimers(); + ScheduleNextTimer(); + } + break; + } + case WM_TIMER: { + RTC_DCHECK_EQ(timer_id_, msg.wParam); + ::KillTimer(nullptr, msg.wParam); + timer_id_ = 0; + RunDueTasks(); + ScheduleNextTimer(); + break; + } + default: + RTC_DCHECK_NOTREACHED(); + break; + } + } else { + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); + } + + if (CurrentTime() > start + kMaxTaskProcessingTime) + break; + } + return msg.message != WM_QUIT; +} + +void TaskQueueWin::RunDueTasks() { + RTC_DCHECK(!timer_tasks_.empty()); + Timestamp now = CurrentTime(); + do { + const auto& top = timer_tasks_.top(); + if (top.due_time() > now) + break; + top.Run(); + timer_tasks_.pop(); + } while (!timer_tasks_.empty()); +} + +void TaskQueueWin::ScheduleNextTimer() { + RTC_DCHECK_EQ(timer_id_, 0); + if (timer_tasks_.empty()) + return; + + const auto& next_task = timer_tasks_.top(); + TimeDelta delay = + std::max(TimeDelta::Zero(), next_task.due_time() - CurrentTime()); + uint32_t milliseconds = delay.RoundUpTo(TimeDelta::Millis(1)).ms<uint32_t>(); + if (!timer_.StartOneShotTimer(milliseconds)) + timer_id_ = ::SetTimer(nullptr, 0, milliseconds, nullptr); +} + +void TaskQueueWin::CancelTimers() { + timer_.Cancel(); + if (timer_id_) { + ::KillTimer(nullptr, timer_id_); + timer_id_ = 0; + } +} + +class TaskQueueWinFactory : public TaskQueueFactory { + public: + std::unique_ptr<TaskQueueBase, TaskQueueDeleter> CreateTaskQueue( + absl::string_view name, + Priority priority) const override { + return std::unique_ptr<TaskQueueBase, TaskQueueDeleter>( + new TaskQueueWin(name, TaskQueuePriorityToThreadPriority(priority))); + } +}; + +} // namespace + +std::unique_ptr<TaskQueueFactory> CreateTaskQueueWinFactory() { + return std::make_unique<TaskQueueWinFactory>(); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/task_queue_win.h b/third_party/libwebrtc/rtc_base/task_queue_win.h new file mode 100644 index 0000000000..972611abc2 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/task_queue_win.h @@ -0,0 +1,24 @@ +/* + * 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 RTC_BASE_TASK_QUEUE_WIN_H_ +#define RTC_BASE_TASK_QUEUE_WIN_H_ + +#include <memory> + +#include "api/task_queue/task_queue_factory.h" + +namespace webrtc { + +std::unique_ptr<TaskQueueFactory> CreateTaskQueueWinFactory(); + +} + +#endif // RTC_BASE_TASK_QUEUE_WIN_H_ diff --git a/third_party/libwebrtc/rtc_base/task_utils/BUILD.gn b/third_party/libwebrtc/rtc_base/task_utils/BUILD.gn new file mode 100644 index 0000000000..5fcf25ef0b --- /dev/null +++ b/third_party/libwebrtc/rtc_base/task_utils/BUILD.gn @@ -0,0 +1,47 @@ +# 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_library("repeating_task") { + sources = [ + "repeating_task.cc", + "repeating_task.h", + ] + deps = [ + "..:logging", + "..:timeutils", + "../../api:sequence_checker", + "../../api/task_queue", + "../../api/task_queue:pending_task_safety_flag", + "../../api/units:time_delta", + "../../api/units:timestamp", + "../../system_wrappers:system_wrappers", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/functional:any_invocable" ] +} + +if (rtc_include_tests) { + rtc_library("repeating_task_unittests") { + testonly = true + sources = [ "repeating_task_unittest.cc" ] + deps = [ + ":repeating_task", + "..:rtc_event", + "..:rtc_task_queue", + "..:task_queue_for_test", + "../../api/task_queue", + "../../api/task_queue/test:mock_task_queue_base", + "../../api/units:time_delta", + "../../api/units:timestamp", + "../../system_wrappers:system_wrappers", + "../../test:test_support", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/functional:any_invocable" ] + } +} diff --git a/third_party/libwebrtc/rtc_base/task_utils/repeating_task.cc b/third_party/libwebrtc/rtc_base/task_utils/repeating_task.cc new file mode 100644 index 0000000000..6b76d7673a --- /dev/null +++ b/third_party/libwebrtc/rtc_base/task_utils/repeating_task.cc @@ -0,0 +1,140 @@ +/* + * 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 "rtc_base/task_utils/repeating_task.h" + +#include "absl/functional/any_invocable.h" +#include "api/task_queue/pending_task_safety_flag.h" +#include "rtc_base/logging.h" + +namespace webrtc { +namespace { + +class RepeatingTask { + public: + RepeatingTask(TaskQueueBase* task_queue, + TaskQueueBase::DelayPrecision precision, + TimeDelta first_delay, + absl::AnyInvocable<TimeDelta()> task, + Clock* clock, + rtc::scoped_refptr<PendingTaskSafetyFlag> alive_flag, + const Location& location); + RepeatingTask(RepeatingTask&&) = default; + RepeatingTask& operator=(RepeatingTask&&) = delete; + ~RepeatingTask() = default; + + void operator()() &&; + + private: + TaskQueueBase* const task_queue_; + const TaskQueueBase::DelayPrecision precision_; + Clock* const clock_; + const Location location_; + absl::AnyInvocable<TimeDelta()> task_; + // This is always finite. + Timestamp next_run_time_ RTC_GUARDED_BY(task_queue_); + rtc::scoped_refptr<PendingTaskSafetyFlag> alive_flag_ + RTC_GUARDED_BY(task_queue_); +}; + +RepeatingTask::RepeatingTask( + TaskQueueBase* task_queue, + TaskQueueBase::DelayPrecision precision, + TimeDelta first_delay, + absl::AnyInvocable<TimeDelta()> task, + Clock* clock, + rtc::scoped_refptr<PendingTaskSafetyFlag> alive_flag, + const Location& location) + : task_queue_(task_queue), + precision_(precision), + clock_(clock), + location_(location), + task_(std::move(task)), + next_run_time_(clock_->CurrentTime() + first_delay), + alive_flag_(std::move(alive_flag)) {} + +void RepeatingTask::operator()() && { + RTC_DCHECK_RUN_ON(task_queue_); + if (!alive_flag_->alive()) + return; + + webrtc_repeating_task_impl::RepeatingTaskImplDTraceProbeRun(); + TimeDelta delay = task_(); + RTC_DCHECK_GE(delay, TimeDelta::Zero()); + + // A delay of +infinity means that the task should not be run again. + // Alternatively, the closure might have stopped this task. + if (delay.IsPlusInfinity() || !alive_flag_->alive()) + return; + + TimeDelta lost_time = clock_->CurrentTime() - next_run_time_; + next_run_time_ += delay; + delay -= lost_time; + delay = std::max(delay, TimeDelta::Zero()); + + task_queue_->PostDelayedTaskWithPrecision(precision_, std::move(*this), delay, + location_); +} + +} // namespace + +RepeatingTaskHandle RepeatingTaskHandle::Start( + TaskQueueBase* task_queue, + absl::AnyInvocable<TimeDelta()> closure, + TaskQueueBase::DelayPrecision precision, + Clock* clock, + const Location& location) { + auto alive_flag = PendingTaskSafetyFlag::CreateDetached(); + webrtc_repeating_task_impl::RepeatingTaskHandleDTraceProbeStart(); + task_queue->PostTask( + RepeatingTask(task_queue, precision, TimeDelta::Zero(), + std::move(closure), clock, alive_flag, location), + location); + return RepeatingTaskHandle(std::move(alive_flag)); +} + +// DelayedStart is equivalent to Start except that the first invocation of the +// closure will be delayed by the given amount. +RepeatingTaskHandle RepeatingTaskHandle::DelayedStart( + TaskQueueBase* task_queue, + TimeDelta first_delay, + absl::AnyInvocable<TimeDelta()> closure, + TaskQueueBase::DelayPrecision precision, + Clock* clock, + const Location& location) { + auto alive_flag = PendingTaskSafetyFlag::CreateDetached(); + webrtc_repeating_task_impl::RepeatingTaskHandleDTraceProbeDelayedStart(); + task_queue->PostDelayedTaskWithPrecision( + precision, + RepeatingTask(task_queue, precision, first_delay, std::move(closure), + clock, alive_flag, location), + first_delay, location); + return RepeatingTaskHandle(std::move(alive_flag)); +} + +void RepeatingTaskHandle::Stop() { + if (repeating_task_) { + repeating_task_->SetNotAlive(); + repeating_task_ = nullptr; + } +} + +bool RepeatingTaskHandle::Running() const { + return repeating_task_ != nullptr; +} + +namespace webrtc_repeating_task_impl { +// These methods are empty, but can be externally equipped with actions using +// dtrace. +void RepeatingTaskHandleDTraceProbeStart() {} +void RepeatingTaskHandleDTraceProbeDelayedStart() {} +void RepeatingTaskImplDTraceProbeRun() {} +} // namespace webrtc_repeating_task_impl +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/task_utils/repeating_task.h b/third_party/libwebrtc/rtc_base/task_utils/repeating_task.h new file mode 100644 index 0000000000..28c691c3de --- /dev/null +++ b/third_party/libwebrtc/rtc_base/task_utils/repeating_task.h @@ -0,0 +1,92 @@ +/* + * 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 RTC_BASE_TASK_UTILS_REPEATING_TASK_H_ +#define RTC_BASE_TASK_UTILS_REPEATING_TASK_H_ + +#include <memory> +#include <type_traits> +#include <utility> + +#include "absl/functional/any_invocable.h" +#include "api/task_queue/pending_task_safety_flag.h" +#include "api/task_queue/task_queue_base.h" +#include "api/units/time_delta.h" +#include "system_wrappers/include/clock.h" + +namespace webrtc { + +namespace webrtc_repeating_task_impl { + +// Methods simplifying external tracing of RepeatingTaskHandle operations. +void RepeatingTaskHandleDTraceProbeStart(); +void RepeatingTaskHandleDTraceProbeDelayedStart(); +void RepeatingTaskImplDTraceProbeRun(); + +} // namespace webrtc_repeating_task_impl + +// Allows starting tasks that repeat themselves on a TaskQueue indefinately +// until they are stopped or the TaskQueue is destroyed. It allows starting and +// stopping multiple times, but you must stop one task before starting another +// and it can only be stopped when in the running state. The public interface is +// not thread safe. +class RepeatingTaskHandle { + public: + RepeatingTaskHandle() = default; + ~RepeatingTaskHandle() = default; + RepeatingTaskHandle(RepeatingTaskHandle&& other) = default; + RepeatingTaskHandle& operator=(RepeatingTaskHandle&& other) = default; + RepeatingTaskHandle(const RepeatingTaskHandle&) = delete; + RepeatingTaskHandle& operator=(const RepeatingTaskHandle&) = delete; + + // Start can be used to start a task that will be reposted with a delay + // determined by the return value of the provided closure. The actual task is + // owned by the TaskQueue and will live until it has been stopped or the + // TaskQueue deletes it. It's perfectly fine to destroy the handle while the + // task is running, since the repeated task is owned by the TaskQueue. + // The tasks are scheduled onto the task queue using the specified precision. + static RepeatingTaskHandle Start( + TaskQueueBase* task_queue, + absl::AnyInvocable<TimeDelta()> closure, + TaskQueueBase::DelayPrecision precision = + TaskQueueBase::DelayPrecision::kLow, + Clock* clock = Clock::GetRealTimeClockRaw(), + const Location& location = Location::Current()); + + // DelayedStart is equivalent to Start except that the first invocation of the + // closure will be delayed by the given amount. + static RepeatingTaskHandle DelayedStart( + TaskQueueBase* task_queue, + TimeDelta first_delay, + absl::AnyInvocable<TimeDelta()> closure, + TaskQueueBase::DelayPrecision precision = + TaskQueueBase::DelayPrecision::kLow, + Clock* clock = Clock::GetRealTimeClockRaw(), + const Location& location = Location::Current()); + + // Stops future invocations of the repeating task closure. Can only be called + // from the TaskQueue where the task is running. The closure is guaranteed to + // not be running after Stop() returns unless Stop() is called from the + // closure itself. + void Stop(); + + // Returns true until Stop() was called. + // Can only be called from the TaskQueue where the task is running. + bool Running() const; + + private: + explicit RepeatingTaskHandle( + rtc::scoped_refptr<PendingTaskSafetyFlag> alive_flag) + : repeating_task_(std::move(alive_flag)) {} + rtc::scoped_refptr<PendingTaskSafetyFlag> repeating_task_; +}; + +} // namespace webrtc +#endif // RTC_BASE_TASK_UTILS_REPEATING_TASK_H_ diff --git a/third_party/libwebrtc/rtc_base/task_utils/repeating_task_gn/moz.build b/third_party/libwebrtc/rtc_base/task_utils/repeating_task_gn/moz.build new file mode 100644 index 0000000000..224f776828 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/task_utils/repeating_task_gn/moz.build @@ -0,0 +1,236 @@ +# 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/rtc_base/task_utils/repeating_task.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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("repeating_task_gn") diff --git a/third_party/libwebrtc/rtc_base/task_utils/repeating_task_unittest.cc b/third_party/libwebrtc/rtc_base/task_utils/repeating_task_unittest.cc new file mode 100644 index 0000000000..2c269b43bc --- /dev/null +++ b/third_party/libwebrtc/rtc_base/task_utils/repeating_task_unittest.cc @@ -0,0 +1,439 @@ +/* + * 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 "rtc_base/task_utils/repeating_task.h" + +#include <atomic> +#include <memory> + +#include "absl/functional/any_invocable.h" +#include "api/task_queue/task_queue_base.h" +#include "api/task_queue/test/mock_task_queue_base.h" +#include "api/units/time_delta.h" +#include "api/units/timestamp.h" +#include "rtc_base/event.h" +#include "rtc_base/task_queue_for_test.h" +#include "system_wrappers/include/clock.h" +#include "test/gmock.h" +#include "test/gtest.h" + +// NOTE: Since these tests rely on real time behavior, they will be flaky +// if run on heavily loaded systems. +namespace webrtc { +namespace { +using ::testing::AtLeast; +using ::testing::Invoke; +using ::testing::MockFunction; +using ::testing::NiceMock; +using ::testing::Return; +using ::testing::WithArg; + +constexpr TimeDelta kTimeout = TimeDelta::Millis(1000); + +class MockClosure { + public: + MOCK_METHOD(TimeDelta, Call, ()); + MOCK_METHOD(void, Delete, ()); +}; + +class MockTaskQueue : public MockTaskQueueBase { + public: + MockTaskQueue() : task_queue_setter_(this) {} + + private: + CurrentTaskQueueSetter task_queue_setter_; +}; + +class FakeTaskQueue : public TaskQueueBase { + public: + explicit FakeTaskQueue(SimulatedClock* clock) + : task_queue_setter_(this), clock_(clock) {} + + void Delete() override {} + + void PostTaskImpl(absl::AnyInvocable<void() &&> task, + const PostTaskTraits& /*traits*/, + const Location& /*location*/) override { + last_task_ = std::move(task); + last_precision_ = absl::nullopt; + last_delay_ = TimeDelta::Zero(); + } + + void PostDelayedTaskImpl(absl::AnyInvocable<void() &&> task, + TimeDelta delay, + const PostDelayedTaskTraits& traits, + const Location& /*location*/) override { + last_task_ = std::move(task); + last_precision_ = traits.high_precision + ? TaskQueueBase::DelayPrecision::kHigh + : TaskQueueBase::DelayPrecision::kLow; + last_delay_ = delay; + } + + bool AdvanceTimeAndRunLastTask() { + EXPECT_TRUE(last_task_); + EXPECT_TRUE(last_delay_.IsFinite()); + clock_->AdvanceTime(last_delay_); + last_delay_ = TimeDelta::MinusInfinity(); + auto task = std::move(last_task_); + std::move(task)(); + return last_task_ == nullptr; + } + + bool IsTaskQueued() { return !!last_task_; } + + TimeDelta last_delay() const { + EXPECT_TRUE(last_delay_.IsFinite()); + return last_delay_; + } + + absl::optional<TaskQueueBase::DelayPrecision> last_precision() const { + return last_precision_; + } + + private: + CurrentTaskQueueSetter task_queue_setter_; + SimulatedClock* clock_; + absl::AnyInvocable<void() &&> last_task_; + TimeDelta last_delay_ = TimeDelta::MinusInfinity(); + absl::optional<TaskQueueBase::DelayPrecision> last_precision_; +}; + +// NOTE: Since this utility class holds a raw pointer to a variable that likely +// lives on the stack, it's important that any repeating tasks that use this +// class be explicitly stopped when the test criteria have been met. If the +// task is not stopped, an instance of this class can be deleted when the +// pointed-to MockClosure has been deleted and we end up trying to call a +// virtual method on a deleted object in the dtor. +class MoveOnlyClosure { + public: + explicit MoveOnlyClosure(MockClosure* mock) : mock_(mock) {} + MoveOnlyClosure(const MoveOnlyClosure&) = delete; + MoveOnlyClosure(MoveOnlyClosure&& other) : mock_(other.mock_) { + other.mock_ = nullptr; + } + ~MoveOnlyClosure() { + if (mock_) + mock_->Delete(); + } + TimeDelta operator()() { return mock_->Call(); } + + private: + MockClosure* mock_; +}; +} // namespace + +TEST(RepeatingTaskTest, TaskIsStoppedOnStop) { + const TimeDelta kShortInterval = TimeDelta::Millis(50); + + SimulatedClock clock(Timestamp::Zero()); + FakeTaskQueue task_queue(&clock); + std::atomic_int counter(0); + auto handle = RepeatingTaskHandle::Start( + &task_queue, + [&] { + counter++; + return kShortInterval; + }, + TaskQueueBase::DelayPrecision::kLow, &clock); + EXPECT_EQ(task_queue.last_delay(), TimeDelta::Zero()); + EXPECT_FALSE(task_queue.AdvanceTimeAndRunLastTask()); + EXPECT_EQ(counter.load(), 1); + + // The handle reposted at the short interval. + EXPECT_EQ(task_queue.last_delay(), kShortInterval); + + // Stop the handle. This prevernts the counter from incrementing. + handle.Stop(); + EXPECT_TRUE(task_queue.AdvanceTimeAndRunLastTask()); + EXPECT_EQ(counter.load(), 1); +} + +TEST(RepeatingTaskTest, CompensatesForLongRunTime) { + const TimeDelta kRepeatInterval = TimeDelta::Millis(2); + // Sleeping inside the task for longer than the repeat interval once, should + // be compensated for by repeating the task faster to catch up. + const TimeDelta kSleepDuration = TimeDelta::Millis(20); + + std::atomic_int counter(0); + SimulatedClock clock(Timestamp::Zero()); + FakeTaskQueue task_queue(&clock); + RepeatingTaskHandle::Start( + &task_queue, + [&] { + ++counter; + // Task takes longer than the repeat duration. + clock.AdvanceTime(kSleepDuration); + return kRepeatInterval; + }, + TaskQueueBase::DelayPrecision::kLow, &clock); + + EXPECT_EQ(task_queue.last_delay(), TimeDelta::Zero()); + EXPECT_FALSE(task_queue.AdvanceTimeAndRunLastTask()); + + // Task is posted right away since it took longer to run then the repeat + // interval. + EXPECT_EQ(task_queue.last_delay(), TimeDelta::Zero()); + EXPECT_EQ(counter.load(), 1); +} + +TEST(RepeatingTaskTest, CompensatesForShortRunTime) { + SimulatedClock clock(Timestamp::Zero()); + FakeTaskQueue task_queue(&clock); + std::atomic_int counter(0); + RepeatingTaskHandle::Start( + &task_queue, + [&] { + // Simulate the task taking 100ms, which should be compensated for. + counter++; + clock.AdvanceTime(TimeDelta::Millis(100)); + return TimeDelta::Millis(300); + }, + TaskQueueBase::DelayPrecision::kLow, &clock); + + // Expect instant post task. + EXPECT_EQ(task_queue.last_delay(), TimeDelta::Zero()); + // Task should be retained by the handler since it is not cancelled. + EXPECT_FALSE(task_queue.AdvanceTimeAndRunLastTask()); + // New delay should be 200ms since repeat delay was 300ms but task took 100ms. + EXPECT_EQ(task_queue.last_delay(), TimeDelta::Millis(200)); +} + +TEST(RepeatingTaskTest, CancelDelayedTaskBeforeItRuns) { + rtc::Event done; + MockClosure mock; + EXPECT_CALL(mock, Call).Times(0); + EXPECT_CALL(mock, Delete).WillOnce(Invoke([&done] { done.Set(); })); + TaskQueueForTest task_queue("queue"); + auto handle = RepeatingTaskHandle::DelayedStart( + task_queue.Get(), TimeDelta::Millis(100), MoveOnlyClosure(&mock)); + task_queue.PostTask( + [handle = std::move(handle)]() mutable { handle.Stop(); }); + EXPECT_TRUE(done.Wait(kTimeout)); +} + +TEST(RepeatingTaskTest, CancelTaskAfterItRuns) { + rtc::Event done; + MockClosure mock; + EXPECT_CALL(mock, Call).WillOnce(Return(TimeDelta::Millis(100))); + EXPECT_CALL(mock, Delete).WillOnce(Invoke([&done] { done.Set(); })); + TaskQueueForTest task_queue("queue"); + auto handle = + RepeatingTaskHandle::Start(task_queue.Get(), MoveOnlyClosure(&mock)); + task_queue.PostTask( + [handle = std::move(handle)]() mutable { handle.Stop(); }); + EXPECT_TRUE(done.Wait(kTimeout)); +} + +TEST(RepeatingTaskTest, TaskCanStopItself) { + std::atomic_int counter(0); + SimulatedClock clock(Timestamp::Zero()); + FakeTaskQueue task_queue(&clock); + RepeatingTaskHandle handle = RepeatingTaskHandle::Start(&task_queue, [&] { + ++counter; + handle.Stop(); + return TimeDelta::Millis(2); + }); + EXPECT_EQ(task_queue.last_delay(), TimeDelta::Zero()); + // Task cancelled itself so wants to be released. + EXPECT_TRUE(task_queue.AdvanceTimeAndRunLastTask()); + EXPECT_EQ(counter.load(), 1); +} + +TEST(RepeatingTaskTest, TaskCanStopItselfByReturningInfinity) { + std::atomic_int counter(0); + SimulatedClock clock(Timestamp::Zero()); + FakeTaskQueue task_queue(&clock); + RepeatingTaskHandle handle = RepeatingTaskHandle::Start(&task_queue, [&] { + ++counter; + return TimeDelta::PlusInfinity(); + }); + EXPECT_EQ(task_queue.last_delay(), TimeDelta::Zero()); + // Task cancelled itself so wants to be released. + EXPECT_TRUE(task_queue.AdvanceTimeAndRunLastTask()); + EXPECT_EQ(counter.load(), 1); +} + +TEST(RepeatingTaskTest, ZeroReturnValueRepostsTheTask) { + NiceMock<MockClosure> closure; + rtc::Event done; + EXPECT_CALL(closure, Call()) + .WillOnce(Return(TimeDelta::Zero())) + .WillOnce(Invoke([&] { + done.Set(); + return TimeDelta::PlusInfinity(); + })); + TaskQueueForTest task_queue("queue"); + RepeatingTaskHandle::Start(task_queue.Get(), MoveOnlyClosure(&closure)); + EXPECT_TRUE(done.Wait(kTimeout)); +} + +TEST(RepeatingTaskTest, StartPeriodicTask) { + MockFunction<TimeDelta()> closure; + rtc::Event done; + EXPECT_CALL(closure, Call()) + .WillOnce(Return(TimeDelta::Millis(20))) + .WillOnce(Return(TimeDelta::Millis(20))) + .WillOnce(Invoke([&] { + done.Set(); + return TimeDelta::PlusInfinity(); + })); + TaskQueueForTest task_queue("queue"); + RepeatingTaskHandle::Start(task_queue.Get(), closure.AsStdFunction()); + EXPECT_TRUE(done.Wait(kTimeout)); +} + +TEST(RepeatingTaskTest, Example) { + class ObjectOnTaskQueue { + public: + void DoPeriodicTask() {} + TimeDelta TimeUntilNextRun() { return TimeDelta::Millis(100); } + void StartPeriodicTask(RepeatingTaskHandle* handle, + TaskQueueBase* task_queue) { + *handle = RepeatingTaskHandle::Start(task_queue, [this] { + DoPeriodicTask(); + return TimeUntilNextRun(); + }); + } + }; + TaskQueueForTest task_queue("queue"); + auto object = std::make_unique<ObjectOnTaskQueue>(); + // Create and start the periodic task. + RepeatingTaskHandle handle; + object->StartPeriodicTask(&handle, task_queue.Get()); + // Restart the task + task_queue.PostTask( + [handle = std::move(handle)]() mutable { handle.Stop(); }); + object->StartPeriodicTask(&handle, task_queue.Get()); + task_queue.PostTask( + [handle = std::move(handle)]() mutable { handle.Stop(); }); + struct Destructor { + void operator()() { object.reset(); } + std::unique_ptr<ObjectOnTaskQueue> object; + }; + task_queue.PostTask(Destructor{std::move(object)}); + // Do not wait for the destructor closure in order to create a race between + // task queue destruction and running the desctructor closure. +} + +TEST(RepeatingTaskTest, ClockIntegration) { + absl::AnyInvocable<void() &&> delayed_task; + TimeDelta expected_delay = TimeDelta::Zero(); + SimulatedClock clock(Timestamp::Zero()); + + NiceMock<MockTaskQueue> task_queue; + ON_CALL(task_queue, PostDelayedTaskImpl) + .WillByDefault([&](absl::AnyInvocable<void() &&> task, TimeDelta delay, + const MockTaskQueue::PostDelayedTaskTraits&, + const Location&) { + EXPECT_EQ(delay, expected_delay); + delayed_task = std::move(task); + }); + + expected_delay = TimeDelta::Millis(100); + RepeatingTaskHandle handle = RepeatingTaskHandle::DelayedStart( + &task_queue, TimeDelta::Millis(100), + [&clock]() { + EXPECT_EQ(Timestamp::Millis(100), clock.CurrentTime()); + // Simulate work happening for 10ms. + clock.AdvanceTimeMilliseconds(10); + return TimeDelta::Millis(100); + }, + TaskQueueBase::DelayPrecision::kLow, &clock); + + clock.AdvanceTimeMilliseconds(100); + absl::AnyInvocable<void()&&> task_to_run = std::move(delayed_task); + expected_delay = TimeDelta::Millis(90); + std::move(task_to_run)(); + EXPECT_NE(delayed_task, nullptr); + handle.Stop(); +} + +TEST(RepeatingTaskTest, CanBeStoppedAfterTaskQueueDeletedTheRepeatingTask) { + absl::AnyInvocable<void() &&> repeating_task; + + MockTaskQueue task_queue; + EXPECT_CALL(task_queue, PostDelayedTaskImpl) + .WillOnce(WithArg<0>([&](absl::AnyInvocable<void() &&> task) { + repeating_task = std::move(task); + })); + + RepeatingTaskHandle handle = + RepeatingTaskHandle::DelayedStart(&task_queue, TimeDelta::Millis(100), + [] { return TimeDelta::Millis(100); }); + + // shutdown task queue: delete all pending tasks and run 'regular' task. + repeating_task = nullptr; + handle.Stop(); +} + +TEST(RepeatingTaskTest, DefaultPrecisionIsLow) { + SimulatedClock clock(Timestamp::Zero()); + FakeTaskQueue task_queue(&clock); + // Closure that repeats twice. + MockFunction<TimeDelta()> closure; + EXPECT_CALL(closure, Call()) + .WillOnce(Return(TimeDelta::Millis(1))) + .WillOnce(Return(TimeDelta::PlusInfinity())); + RepeatingTaskHandle::Start(&task_queue, closure.AsStdFunction()); + // Initial task is a PostTask(). + EXPECT_FALSE(task_queue.last_precision().has_value()); + EXPECT_FALSE(task_queue.AdvanceTimeAndRunLastTask()); + // Repeated task is a delayed task with the default precision: low. + EXPECT_TRUE(task_queue.last_precision().has_value()); + EXPECT_EQ(task_queue.last_precision().value(), + TaskQueueBase::DelayPrecision::kLow); + // No more tasks. + EXPECT_TRUE(task_queue.AdvanceTimeAndRunLastTask()); +} + +TEST(RepeatingTaskTest, CanSpecifyToPostTasksWithLowPrecision) { + SimulatedClock clock(Timestamp::Zero()); + FakeTaskQueue task_queue(&clock); + // Closure that repeats twice. + MockFunction<TimeDelta()> closure; + EXPECT_CALL(closure, Call()) + .WillOnce(Return(TimeDelta::Millis(1))) + .WillOnce(Return(TimeDelta::PlusInfinity())); + RepeatingTaskHandle::Start(&task_queue, closure.AsStdFunction(), + TaskQueueBase::DelayPrecision::kLow); + // Initial task is a PostTask(). + EXPECT_FALSE(task_queue.last_precision().has_value()); + EXPECT_FALSE(task_queue.AdvanceTimeAndRunLastTask()); + // Repeated task is a delayed task with the specified precision. + EXPECT_TRUE(task_queue.last_precision().has_value()); + EXPECT_EQ(task_queue.last_precision().value(), + TaskQueueBase::DelayPrecision::kLow); + // No more tasks. + EXPECT_TRUE(task_queue.AdvanceTimeAndRunLastTask()); +} + +TEST(RepeatingTaskTest, CanSpecifyToPostTasksWithHighPrecision) { + SimulatedClock clock(Timestamp::Zero()); + FakeTaskQueue task_queue(&clock); + // Closure that repeats twice. + MockFunction<TimeDelta()> closure; + EXPECT_CALL(closure, Call()) + .WillOnce(Return(TimeDelta::Millis(1))) + .WillOnce(Return(TimeDelta::PlusInfinity())); + RepeatingTaskHandle::Start(&task_queue, closure.AsStdFunction(), + TaskQueueBase::DelayPrecision::kHigh); + // Initial task is a PostTask(). + EXPECT_FALSE(task_queue.last_precision().has_value()); + EXPECT_FALSE(task_queue.AdvanceTimeAndRunLastTask()); + // Repeated task is a delayed task with the specified precision. + EXPECT_TRUE(task_queue.last_precision().has_value()); + EXPECT_EQ(task_queue.last_precision().value(), + TaskQueueBase::DelayPrecision::kHigh); + // No more tasks. + EXPECT_TRUE(task_queue.AdvanceTimeAndRunLastTask()); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/test_base64.h b/third_party/libwebrtc/rtc_base/test_base64.h new file mode 100644 index 0000000000..51d8c58113 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/test_base64.h @@ -0,0 +1,2111 @@ +/* + * 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 RTC_BASE_TEST_BASE64_H_ +#define RTC_BASE_TEST_BASE64_H_ + +/* This file was generated by googleclient/talk/binary2header.sh */ + +static unsigned char testbase64[] = { + 0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49, 0x46, 0x00, 0x01, + 0x02, 0x01, 0x00, 0x48, 0x00, 0x48, 0x00, 0x00, 0xff, 0xe1, 0x0d, 0x07, + 0x45, 0x78, 0x69, 0x66, 0x00, 0x00, 0x4d, 0x4d, 0x00, 0x2a, 0x00, 0x00, + 0x00, 0x08, 0x00, 0x0c, 0x01, 0x0e, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x9e, 0x01, 0x0f, 0x00, 0x02, 0x00, 0x00, 0x00, 0x05, + 0x00, 0x00, 0x00, 0xbe, 0x01, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x09, + 0x00, 0x00, 0x00, 0xc3, 0x01, 0x12, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x01, 0x1a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0xcc, 0x01, 0x1b, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0xd4, 0x01, 0x28, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x02, 0x00, 0x00, 0x01, 0x31, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, + 0x00, 0x00, 0x00, 0xdc, 0x01, 0x32, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, + 0x00, 0x00, 0x00, 0xf0, 0x01, 0x3c, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x01, 0x04, 0x02, 0x13, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x02, 0x00, 0x00, 0x87, 0x69, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x02, 0xc4, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x00, 0x53, 0x4f, 0x4e, 0x59, 0x00, 0x44, 0x53, 0x43, + 0x2d, 0x50, 0x32, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x41, 0x64, + 0x6f, 0x62, 0x65, 0x20, 0x50, 0x68, 0x6f, 0x74, 0x6f, 0x73, 0x68, 0x6f, + 0x70, 0x20, 0x37, 0x2e, 0x30, 0x00, 0x32, 0x30, 0x30, 0x37, 0x3a, 0x30, + 0x31, 0x3a, 0x33, 0x30, 0x20, 0x32, 0x33, 0x3a, 0x31, 0x30, 0x3a, 0x30, + 0x34, 0x00, 0x4d, 0x61, 0x63, 0x20, 0x4f, 0x53, 0x20, 0x58, 0x20, 0x31, + 0x30, 0x2e, 0x34, 0x2e, 0x38, 0x00, 0x00, 0x1c, 0x82, 0x9a, 0x00, 0x05, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x6a, 0x82, 0x9d, 0x00, 0x05, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x72, 0x88, 0x22, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x88, 0x27, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x64, 0x00, 0x00, 0x90, 0x00, 0x00, 0x07, + 0x00, 0x00, 0x00, 0x04, 0x30, 0x32, 0x32, 0x30, 0x90, 0x03, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x02, 0x7a, 0x90, 0x04, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x02, 0x8e, 0x91, 0x01, 0x00, 0x07, + 0x00, 0x00, 0x00, 0x04, 0x01, 0x02, 0x03, 0x00, 0x91, 0x02, 0x00, 0x05, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0xa2, 0x92, 0x04, 0x00, 0x0a, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0xaa, 0x92, 0x05, 0x00, 0x05, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0xb2, 0x92, 0x07, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, 0x92, 0x08, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x92, 0x09, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x0f, 0x00, 0x00, 0x92, 0x0a, 0x00, 0x05, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0xba, 0xa0, 0x00, 0x00, 0x07, + 0x00, 0x00, 0x00, 0x04, 0x30, 0x31, 0x30, 0x30, 0xa0, 0x01, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0x00, 0x00, 0xa0, 0x02, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x64, 0xa0, 0x03, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x64, 0xa3, 0x00, 0x00, 0x07, + 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0xa3, 0x01, 0x00, 0x07, + 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0xa4, 0x01, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x02, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x03, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x06, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x08, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x09, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x0a, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x01, 0x90, 0x00, 0x00, 0x00, 0x1c, + 0x00, 0x00, 0x00, 0x0a, 0x32, 0x30, 0x30, 0x37, 0x3a, 0x30, 0x31, 0x3a, + 0x32, 0x30, 0x20, 0x32, 0x33, 0x3a, 0x30, 0x35, 0x3a, 0x35, 0x32, 0x00, + 0x32, 0x30, 0x30, 0x37, 0x3a, 0x30, 0x31, 0x3a, 0x32, 0x30, 0x20, 0x32, + 0x33, 0x3a, 0x30, 0x35, 0x3a, 0x35, 0x32, 0x00, 0x00, 0x00, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, + 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x4f, + 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x06, 0x00, 0x00, 0x01, 0x1a, 0x00, 0x05, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x12, 0x01, 0x1b, 0x00, 0x05, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x1a, 0x01, 0x28, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x02, 0x01, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x22, 0x02, 0x02, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x09, 0xdd, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48, + 0x00, 0x00, 0x00, 0x01, 0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, + 0x49, 0x46, 0x00, 0x01, 0x02, 0x01, 0x00, 0x48, 0x00, 0x48, 0x00, 0x00, + 0xff, 0xed, 0x00, 0x0c, 0x41, 0x64, 0x6f, 0x62, 0x65, 0x5f, 0x43, 0x4d, + 0x00, 0x02, 0xff, 0xee, 0x00, 0x0e, 0x41, 0x64, 0x6f, 0x62, 0x65, 0x00, + 0x64, 0x80, 0x00, 0x00, 0x00, 0x01, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x0c, + 0x08, 0x08, 0x08, 0x09, 0x08, 0x0c, 0x09, 0x09, 0x0c, 0x11, 0x0b, 0x0a, + 0x0b, 0x11, 0x15, 0x0f, 0x0c, 0x0c, 0x0f, 0x15, 0x18, 0x13, 0x13, 0x15, + 0x13, 0x13, 0x18, 0x11, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x11, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x01, 0x0d, 0x0b, 0x0b, 0x0d, 0x0e, 0x0d, 0x10, 0x0e, + 0x0e, 0x10, 0x14, 0x0e, 0x0e, 0x0e, 0x14, 0x14, 0x0e, 0x0e, 0x0e, 0x0e, + 0x14, 0x11, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x11, 0x11, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x11, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xff, 0xc0, 0x00, 0x11, + 0x08, 0x00, 0x64, 0x00, 0x64, 0x03, 0x01, 0x22, 0x00, 0x02, 0x11, 0x01, + 0x03, 0x11, 0x01, 0xff, 0xdd, 0x00, 0x04, 0x00, 0x07, 0xff, 0xc4, 0x01, + 0x3f, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x02, 0x04, 0x05, + 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x01, 0x00, 0x01, 0x05, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x10, + 0x00, 0x01, 0x04, 0x01, 0x03, 0x02, 0x04, 0x02, 0x05, 0x07, 0x06, 0x08, + 0x05, 0x03, 0x0c, 0x33, 0x01, 0x00, 0x02, 0x11, 0x03, 0x04, 0x21, 0x12, + 0x31, 0x05, 0x41, 0x51, 0x61, 0x13, 0x22, 0x71, 0x81, 0x32, 0x06, 0x14, + 0x91, 0xa1, 0xb1, 0x42, 0x23, 0x24, 0x15, 0x52, 0xc1, 0x62, 0x33, 0x34, + 0x72, 0x82, 0xd1, 0x43, 0x07, 0x25, 0x92, 0x53, 0xf0, 0xe1, 0xf1, 0x63, + 0x73, 0x35, 0x16, 0xa2, 0xb2, 0x83, 0x26, 0x44, 0x93, 0x54, 0x64, 0x45, + 0xc2, 0xa3, 0x74, 0x36, 0x17, 0xd2, 0x55, 0xe2, 0x65, 0xf2, 0xb3, 0x84, + 0xc3, 0xd3, 0x75, 0xe3, 0xf3, 0x46, 0x27, 0x94, 0xa4, 0x85, 0xb4, 0x95, + 0xc4, 0xd4, 0xe4, 0xf4, 0xa5, 0xb5, 0xc5, 0xd5, 0xe5, 0xf5, 0x56, 0x66, + 0x76, 0x86, 0x96, 0xa6, 0xb6, 0xc6, 0xd6, 0xe6, 0xf6, 0x37, 0x47, 0x57, + 0x67, 0x77, 0x87, 0x97, 0xa7, 0xb7, 0xc7, 0xd7, 0xe7, 0xf7, 0x11, 0x00, + 0x02, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x05, 0x06, 0x07, 0x07, + 0x06, 0x05, 0x35, 0x01, 0x00, 0x02, 0x11, 0x03, 0x21, 0x31, 0x12, 0x04, + 0x41, 0x51, 0x61, 0x71, 0x22, 0x13, 0x05, 0x32, 0x81, 0x91, 0x14, 0xa1, + 0xb1, 0x42, 0x23, 0xc1, 0x52, 0xd1, 0xf0, 0x33, 0x24, 0x62, 0xe1, 0x72, + 0x82, 0x92, 0x43, 0x53, 0x15, 0x63, 0x73, 0x34, 0xf1, 0x25, 0x06, 0x16, + 0xa2, 0xb2, 0x83, 0x07, 0x26, 0x35, 0xc2, 0xd2, 0x44, 0x93, 0x54, 0xa3, + 0x17, 0x64, 0x45, 0x55, 0x36, 0x74, 0x65, 0xe2, 0xf2, 0xb3, 0x84, 0xc3, + 0xd3, 0x75, 0xe3, 0xf3, 0x46, 0x94, 0xa4, 0x85, 0xb4, 0x95, 0xc4, 0xd4, + 0xe4, 0xf4, 0xa5, 0xb5, 0xc5, 0xd5, 0xe5, 0xf5, 0x56, 0x66, 0x76, 0x86, + 0x96, 0xa6, 0xb6, 0xc6, 0xd6, 0xe6, 0xf6, 0x27, 0x37, 0x47, 0x57, 0x67, + 0x77, 0x87, 0x97, 0xa7, 0xb7, 0xc7, 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01, + 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00, 0xf2, 0xed, 0xb2, 0x8d, + 0x4d, 0x45, 0xcd, 0x2f, 0x3f, 0x44, 0x68, 0x93, 0xc3, 0x58, 0xc8, 0xf1, + 0x1f, 0x8a, 0x33, 0x86, 0xda, 0x58, 0xc1, 0xa0, 0x02, 0x4f, 0xc4, 0xa1, + 0x69, 0xa5, 0x9b, 0x5b, 0x4b, 0x84, 0x73, 0xdf, 0xc9, 0x15, 0xf8, 0xe3, + 0xd1, 0x0e, 0x07, 0x93, 0xf3, 0xd1, 0x0f, 0x1c, 0x17, 0xef, 0x2e, 0x3b, + 0x5b, 0xdc, 0xff, 0x00, 0xdf, 0x42, 0xbf, 0x8f, 0x8e, 0xdc, 0x82, 0xca, + 0xd8, 0x37, 0x11, 0xa9, 0x3d, 0x82, 0x69, 0x2b, 0xc4, 0x6d, 0xc9, 0x75, + 0x25, 0xbc, 0xf7, 0xec, 0xa1, 0xb5, 0x74, 0x19, 0x5d, 0x2e, 0x8a, 0x9a, + 0x4b, 0x89, 0x7d, 0xc4, 0x68, 0xc6, 0xf6, 0xfe, 0xb2, 0xa0, 0x30, 0x1d, + 0x60, 0x86, 0x88, 0x8d, 0x49, 0x3e, 0x01, 0x11, 0x20, 0xa3, 0x8c, 0xb9, + 0xb1, 0xaa, 0x62, 0xad, 0xbf, 0x18, 0x97, 0x43, 0x47, 0x1d, 0xd2, 0xaf, + 0x04, 0xd9, 0xb8, 0xc8, 0x0d, 0x68, 0xe4, 0xf7, 0x3e, 0x48, 0xf1, 0x05, + 0xbc, 0x25, 0xaa, 0x07, 0x71, 0xd9, 0x14, 0x78, 0xf6, 0x49, 0xb5, 0x90, + 0xfd, 0xa7, 0xc6, 0x14, 0xfd, 0x1b, 0x1c, 0xff, 0x00, 0x4d, 0x8d, 0x2e, + 0x73, 0x8c, 0x35, 0xa3, 0x52, 0x4f, 0x92, 0x48, 0xa6, 0x1a, 0x24, 0xb6, + 0x2a, 0xfa, 0xa5, 0x9e, 0x60, 0x64, 0x39, 0x94, 0x13, 0xcb, 0x27, 0x73, + 0x80, 0xf3, 0x0c, 0xf6, 0xff, 0x00, 0xd2, 0x5a, 0x78, 0xbf, 0x53, 0x71, + 0xf6, 0x01, 0x75, 0xb6, 0x97, 0x6a, 0x25, 0xa1, 0xad, 0x1f, 0xf4, 0xb7, + 0x23, 0x48, 0xb7, 0x94, 0x84, 0x97, 0x5b, 0xff, 0x00, 0x32, 0xa9, 0xdd, + 0xfc, 0xed, 0x9b, 0x7e, 0x0d, 0x9e, 0x52, 0x4a, 0x95, 0x61, 0xff, 0xd0, + 0xf3, 0x3b, 0xa7, 0x70, 0xee, 0x01, 0x8f, 0xb9, 0x59, 0xfa, 0x7e, 0xdf, + 0xe4, 0xc8, 0xf9, 0x2a, 0xc2, 0x5c, 0x63, 0xc3, 0x54, 0x67, 0x87, 0x6e, + 0x10, 0x35, 0x68, 0xd4, 0x79, 0x1e, 0x53, 0x4a, 0xe0, 0xdc, 0xe9, 0xb8, + 0x1f, 0x6a, 0xda, 0x6c, 0x25, 0x94, 0x37, 0xb0, 0xd0, 0xb8, 0xad, 0x67, + 0xe4, 0x55, 0x8a, 0x5b, 0x8b, 0x82, 0xc0, 0x6f, 0x76, 0x80, 0x34, 0x49, + 0x05, 0x2e, 0x9e, 0xc6, 0x1c, 0x66, 0x31, 0xba, 0x10, 0x23, 0xe0, 0xaf, + 0xe1, 0x61, 0x53, 0x43, 0x8d, 0x81, 0xb3, 0x67, 0xef, 0x9e, 0x49, 0x2a, + 0x12, 0x6c, 0xb6, 0x63, 0x1a, 0x0c, 0x31, 0xba, 0x55, 0xcd, 0xac, 0xfa, + 0x8e, 0xdf, 0x91, 0x6e, 0x91, 0xd9, 0xb3, 0xc9, 0x73, 0x90, 0x7a, 0xab, + 0x6a, 0xc2, 0xa4, 0x60, 0xe2, 0x8f, 0xd2, 0x38, 0x03, 0x7d, 0x9e, 0x0d, + 0xff, 0x00, 0xcc, 0xd6, 0xd3, 0x6b, 0x71, 0x67, 0xd2, 0x3e, 0x64, 0x72, + 0xab, 0xdb, 0x8d, 0x54, 0x39, 0xc5, 0x83, 0x6b, 0x3d, 0xee, 0x2e, 0xd4, + 0x92, 0x3c, 0x4a, 0x56, 0xba, 0xb4, 0x79, 0x5c, 0xf7, 0xb2, 0x96, 0x6c, + 0x8d, 0xaf, 0x80, 0x48, 0x3c, 0xf0, 0xb2, 0x1f, 0x63, 0x9c, 0xe9, 0x3f, + 0x24, 0x5c, 0xdb, 0xdd, 0x76, 0x43, 0xde, 0xfd, 0x5c, 0xe3, 0x24, 0xfc, + 0x50, 0x00, 0x93, 0x0a, 0x78, 0x8a, 0x0d, 0x49, 0xca, 0xcf, 0x93, 0x63, + 0x1b, 0x7d, 0xd7, 0x57, 0x50, 0xd5, 0xef, 0x70, 0x6b, 0x4f, 0xc7, 0x45, + 0xdb, 0x74, 0x9e, 0x8d, 0x5e, 0x33, 0x83, 0xd8, 0x37, 0xdd, 0xc3, 0xac, + 0x3d, 0xbf, 0x92, 0xc5, 0x5b, 0xea, 0xbf, 0xd5, 0x62, 0xc0, 0xdc, 0xbc, + 0xbd, 0x2d, 0x22, 0x5a, 0xcf, 0xdd, 0x69, 0xff, 0x00, 0xd1, 0x8e, 0x5d, + 0xa5, 0x38, 0xb5, 0xb0, 0x00, 0xc6, 0xc4, 0x24, 0x4a, 0xd6, 0x8d, 0x18, + 0x04, 0x49, 0x88, 0x9e, 0x55, 0xd6, 0x61, 0xb0, 0xc1, 0x70, 0x32, 0xdd, + 0x3c, 0x95, 0xda, 0xf1, 0xfe, 0xf5, 0x62, 0xbc, 0x76, 0x8e, 0x75, 0x28, + 0x02, 0xa2, 0xe7, 0x7d, 0x92, 0xb9, 0x84, 0x96, 0x96, 0xda, 0xf7, 0x70, + 0x12, 0x4e, 0x5a, 0xff, 0x00, 0xff, 0xd1, 0xf3, 0x7a, 0x21, 0xaf, 0xde, + 0xef, 0xa2, 0x22, 0x55, 0xfc, 0x5a, 0xbd, 0x42, 0xfb, 0x08, 0xfa, 0x67, + 0x4f, 0x82, 0xcd, 0x6d, 0x85, 0xc0, 0x56, 0x3b, 0x90, 0xb7, 0xf0, 0x2a, + 0x0e, 0x63, 0x58, 0x3b, 0xf2, 0xa3, 0x9e, 0x8c, 0xb8, 0x86, 0xbe, 0x49, + 0xf1, 0x2c, 0x0c, 0x86, 0xb4, 0x4c, 0x69, 0xe4, 0xaf, 0x6e, 0xcc, 0x6b, + 0x7d, 0x46, 0xb3, 0x70, 0xec, 0x38, 0x51, 0x7d, 0x02, 0x8a, 0xc7, 0xa6, + 0xd9, 0x20, 0x68, 0x0f, 0x8f, 0x8a, 0xcf, 0xc9, 0xc2, 0xea, 0x59, 0x5b, + 0x48, 0xb0, 0x91, 0xae, 0xe6, 0xc9, 0x03, 0xc9, 0x30, 0x51, 0x66, 0xd4, + 0x0d, 0xad, 0xbd, 0x5f, 0x53, 0xcc, 0x6b, 0xb6, 0x90, 0x5a, 0x3b, 0x83, + 0x0b, 0x43, 0x17, 0x31, 0xd6, 0xc3, 0x6e, 0x12, 0x3b, 0x79, 0xac, 0xc1, + 0x89, 0x47, 0xd9, 0xe8, 0x63, 0x98, 0x45, 0xed, 0x6c, 0x5a, 0xf1, 0xa0, + 0x27, 0xc5, 0x5b, 0xc3, 0x6f, 0xa6, 0xe0, 0x1c, 0x7d, 0xb3, 0xa2, 0x69, + 0x34, 0x7b, 0xae, 0x1a, 0x8d, 0x45, 0x17, 0x9d, 0xeb, 0xfd, 0x21, 0xd8, + 0xb9, 0xae, 0xb5, 0x80, 0xbb, 0x1e, 0xd2, 0x5c, 0xd7, 0x78, 0x13, 0xf9, + 0xae, 0x4b, 0xea, 0xc7, 0x4a, 0x39, 0xbd, 0x55, 0xb3, 0xed, 0x66, 0x38, + 0xf5, 0x09, 0x22, 0x41, 0x23, 0xe8, 0x37, 0xfb, 0x4b, 0xa1, 0xeb, 0xd6, + 0xfe, 0x88, 0x31, 0xbf, 0x41, 0xc0, 0xee, 0xd2, 0x74, 0x02, 0x78, 0x53, + 0xfa, 0x97, 0x43, 0x19, 0x85, 0x65, 0xff, 0x00, 0x9d, 0x71, 0x33, 0xe4, + 0x1a, 0x7d, 0x8d, 0x53, 0x42, 0x56, 0x35, 0x6b, 0xe5, 0x80, 0x06, 0xc7, + 0x57, 0xa7, 0xc4, 0xa9, 0xdb, 0xb6, 0x81, 0x1f, 0xeb, 0xd9, 0x69, 0x56, + 0xc2, 0xd0, 0x00, 0xe5, 0x55, 0xc0, 0x12, 0xc2, 0xd7, 0x4e, 0xa2, 0x5a, + 0x7c, 0x0a, 0xd0, 0x63, 0x9a, 0xd1, 0xaf, 0xd2, 0xe2, 0x3c, 0x12, 0x62, + 0x66, 0xc6, 0x42, 0x23, 0x5a, 0x49, 0x8f, 0x10, 0xa2, 0xd2, 0x3e, 0x28, + 0x9d, 0xc4, 0x88, 0x09, 0x29, 0x16, 0xc3, 0x3c, 0x24, 0x8d, 0xe6, 0x92, + 0x72, 0x1f, 0xff, 0xd2, 0xf3, 0xbb, 0xb0, 0xfe, 0xcb, 0x99, 0xe9, 0xce, + 0xf6, 0x88, 0x2d, 0x77, 0x91, 0x5b, 0x3d, 0x3d, 0xd0, 0xe6, 0x90, 0xa9, + 0x65, 0x57, 0x38, 0x95, 0xdd, 0xcb, 0x9a, 0x7d, 0xce, 0xf2, 0x3f, 0x44, + 0x23, 0x60, 0x58, 0x76, 0xe9, 0xca, 0x8c, 0xea, 0x1b, 0x31, 0x02, 0x32, + 0x23, 0xea, 0xee, 0xb1, 0xcd, 0xb0, 0xc7, 0x87, 0x74, 0x7a, 0xeb, 0x70, + 0x1a, 0x71, 0xe1, 0xfe, 0xe4, 0x1c, 0x1d, 0xae, 0xe5, 0x69, 0xd8, 0xfa, + 0x99, 0x50, 0x0d, 0x1a, 0xf7, 0x2a, 0x3a, 0x0c, 0xf4, 0x1a, 0x8e, 0xc7, + 0x27, 0x5d, 0xbf, 0x18, 0x41, 0xdc, 0xc2, 0xf0, 0x7f, 0x74, 0xf6, 0x3a, + 0x22, 0x66, 0xdb, 0x68, 0xc6, 0x80, 0x48, 0x6b, 0x88, 0x06, 0x39, 0x0d, + 0xee, 0xaa, 0x1f, 0xb3, 0xd5, 0x1b, 0x83, 0xd8, 0x3b, 0x38, 0x8f, 0x69, + 0xfe, 0xdf, 0xd1, 0x4d, 0x29, 0xa1, 0x4c, 0x7a, 0xf4, 0xbf, 0xa7, 0x92, + 0xcf, 0xa5, 0x20, 0x08, 0xf3, 0xf6, 0xff, 0x00, 0x15, 0xbb, 0xd1, 0x31, + 0xd9, 0x5e, 0x3d, 0x75, 0x56, 0x36, 0x88, 0x00, 0x81, 0xe0, 0x16, 0x5e, + 0x55, 0x74, 0x3f, 0x00, 0x9d, 0xe0, 0xcc, 0x69, 0xe7, 0x3a, 0x2d, 0xbe, + 0x90, 0x00, 0xa9, 0xae, 0xef, 0x1f, 0x95, 0x4b, 0x0d, 0x9a, 0xdc, 0xc7, + 0x45, 0xfe, 0xb1, 0x7d, 0x60, 0xa7, 0xa1, 0xe0, 0x1f, 0x4e, 0x1d, 0x99, + 0x69, 0x02, 0x9a, 0xcf, 0x1f, 0xca, 0x7b, 0xbf, 0x90, 0xc5, 0xc2, 0xb3, + 0xeb, 0x57, 0xd6, 0x03, 0x6b, 0xae, 0x39, 0xb6, 0x82, 0xe3, 0x31, 0xa1, + 0x68, 0xf2, 0x6b, 0x5c, 0x12, 0xfa, 0xe1, 0x91, 0x66, 0x47, 0x5d, 0xb8, + 0x3b, 0x4f, 0x44, 0x36, 0xb6, 0x8f, 0x28, 0xdd, 0xff, 0x00, 0x7e, 0x46, + 0xab, 0x12, 0x2b, 0x65, 0x55, 0x32, 0xa7, 0x62, 0xb6, 0xbd, 0xf7, 0x64, + 0x10, 0xdb, 0x03, 0x9f, 0x1b, 0x9e, 0xc7, 0xd9, 0xb8, 0x3b, 0x1f, 0x67, + 0xf3, 0x6c, 0x52, 0x80, 0xd7, 0x7d, 0x0f, 0xea, 0x7f, 0x5d, 0x1d, 0x67, + 0xa6, 0x0b, 0x1e, 0x47, 0xda, 0x69, 0x3b, 0x2e, 0x03, 0xc7, 0xf3, 0x5f, + 0x1f, 0xf0, 0x8b, 0xa1, 0x02, 0x46, 0xba, 0x79, 0xaf, 0x32, 0xff, 0x00, + 0x16, 0xad, 0xca, 0x1d, 0x57, 0x2a, 0xdc, 0x79, 0x18, 0x41, 0xb0, 0xf6, + 0x9e, 0xe4, 0x9f, 0xd0, 0x8f, 0xeb, 0x31, 0xab, 0xd2, 0x83, 0xa4, 0xcb, + 0x8c, 0xb8, 0xa0, 0x42, 0x12, 0x7b, 0x67, 0x9f, 0x2f, 0xf5, 0x09, 0x26, + 0x96, 0xc4, 0xce, 0xa9, 0x20, 0xa7, 0xff, 0xd3, 0xf3, 0x2f, 0xb4, 0x5d, + 0xe9, 0x0a, 0xb7, 0x9f, 0x4c, 0x19, 0xdb, 0x3a, 0x2d, 0x5e, 0x94, 0xfd, + 0xc4, 0xb7, 0xc5, 0x62, 0xf9, 0x2b, 0xfd, 0x2e, 0xe3, 0x5d, 0xe0, 0x7c, + 0x13, 0x48, 0xd1, 0x92, 0x12, 0xa9, 0x0b, 0x7a, 0xbc, 0x2d, 0xc2, 0x7f, + 0x92, 0x60, 0xab, 0x4e, 0x79, 0x2e, 0x00, 0xf0, 0xaa, 0xe1, 0xda, 0x3d, + 0x43, 0xfc, 0xad, 0x55, 0xbb, 0x80, 0x79, 0x81, 0xa0, 0xe6, 0x54, 0x32, + 0x6d, 0x02, 0xbe, 0xf3, 0x61, 0x81, 0xa8, 0x44, 0x14, 0x03, 0x59, 0x0e, + 0x1c, 0xf6, 0x1f, 0xdc, 0xb2, 0xec, 0xa3, 0x23, 0x77, 0xe8, 0x6e, 0x70, + 0xf2, 0x25, 0x1f, 0x1f, 0x17, 0xa9, 0x6d, 0x71, 0x36, 0x97, 0x47, 0x00, + 0xa4, 0x02, 0xe0, 0x2c, 0x7c, 0xc1, 0xab, 0xd5, 0x31, 0x85, 0x35, 0xd4, + 0xe6, 0x13, 0x02, 0xd6, 0x4b, 0x67, 0x48, 0x2b, 0xa9, 0xe9, 0x2e, 0x02, + 0xb6, 0x4f, 0x82, 0xe5, 0x7a, 0x95, 0x19, 0xc6, 0x87, 0x3d, 0xfb, 0xa2, + 0xb8, 0x79, 0x1e, 0x4d, 0x3b, 0x96, 0xcf, 0x4f, 0xbd, 0xcd, 0xa2, 0xa2, + 0x1f, 0xa0, 0x82, 0xd3, 0xfc, 0x97, 0x05, 0x24, 0x36, 0x6b, 0xf3, 0x31, + 0xa2, 0x35, 0x79, 0xef, 0xad, 0xf8, 0xae, 0xaf, 0xaf, 0xd8, 0xf2, 0xd8, + 0x6d, 0xed, 0x6b, 0xda, 0x7b, 0x18, 0x1b, 0x5d, 0xff, 0x00, 0x52, 0xb1, + 0x6d, 0xf0, 0x81, 0x31, 0xca, 0xf4, 0x6e, 0xb1, 0x80, 0xce, 0xb1, 0x84, + 0xc0, 0x21, 0xb7, 0xd6, 0x77, 0x31, 0xd1, 0x27, 0xc1, 0xcd, 0xfe, 0xd2, + 0xe3, 0xec, 0xe8, 0x1d, 0x45, 0x96, 0xb0, 0x9a, 0xb7, 0x87, 0x3f, 0x68, + 0x2d, 0xf7, 0x01, 0x1f, 0xbe, 0xd1, 0xf4, 0x7f, 0xb4, 0xa4, 0x0d, 0x77, + 0xbb, 0xfa, 0x8f, 0x80, 0x3a, 0x7f, 0x43, 0xaa, 0xe2, 0xdf, 0xd2, 0x65, + 0x7e, 0x95, 0xe4, 0x0f, 0x1f, 0xa1, 0xfe, 0x6b, 0x16, 0x9f, 0x52, 0xfa, + 0xc1, 0xd3, 0xba, 0x6d, 0x26, 0xdc, 0xac, 0x86, 0xd4, 0xd9, 0x0d, 0x31, + 0x2e, 0x74, 0x9e, 0xdb, 0x59, 0x2e, 0x55, 0xe8, 0xc9, 0xb2, 0x96, 0xd5, + 0x4b, 0x9f, 0xb8, 0x6d, 0xda, 0x1c, 0x04, 0x09, 0x03, 0xfe, 0x8a, 0xc6, + 0xfa, 0xd3, 0xf5, 0x6a, 0xbe, 0xbb, 0x5b, 0x2e, 0xc6, 0xb5, 0x94, 0xe6, + 0xd5, 0x20, 0x97, 0x7d, 0x1b, 0x1b, 0xf9, 0xad, 0x7c, 0x7d, 0x17, 0xb7, + 0xf3, 0x1e, 0x92, 0x1b, 0x7f, 0xf8, 0xe0, 0x7d, 0x59, 0xdd, 0xfd, 0x32, + 0xd8, 0x8f, 0xa5, 0xe8, 0x3a, 0x12, 0x5c, 0x3f, 0xfc, 0xc4, 0xfa, 0xc3, + 0xb3, 0x77, 0xa7, 0x56, 0xed, 0xdb, 0x76, 0x7a, 0x8d, 0xdd, 0x1f, 0xbf, + 0xfd, 0x44, 0x92, 0x56, 0x8f, 0xff, 0xd4, 0xf2, 0xe8, 0x86, 0x17, 0x1e, + 0xfa, 0x04, 0x56, 0x4b, 0x43, 0x6c, 0x6f, 0x2d, 0xe5, 0x46, 0x01, 0x64, + 0x2b, 0x14, 0x32, 0x5b, 0xb4, 0xa0, 0x52, 0x1d, 0xde, 0x9b, 0x94, 0xdb, + 0xab, 0x6b, 0x81, 0xf7, 0x05, 0xb0, 0xd7, 0x07, 0xb2, 0x27, 0x55, 0xc6, + 0x57, 0x65, 0xd8, 0x76, 0x6e, 0x64, 0xed, 0xee, 0x16, 0xce, 0x27, 0x57, + 0x63, 0xda, 0x0c, 0xc2, 0x8e, 0x51, 0x67, 0x84, 0xfa, 0x1d, 0xdd, 0x62, + 0xc7, 0x07, 0xe9, 0xf7, 0xa3, 0xd6, 0x6c, 0x02, 0x41, 0x55, 0x31, 0xf3, + 0x2b, 0xb3, 0xba, 0x2b, 0x2e, 0x68, 0x24, 0x1d, 0x47, 0x64, 0xca, 0xa6, + 0x50, 0x41, 0x65, 0x90, 0x6c, 0xb1, 0xa5, 0xae, 0x33, 0x23, 0x51, 0xe4, + 0xab, 0x7d, 0x5d, 0xcb, 0xb6, 0xcc, 0x37, 0xd0, 0x40, 0x73, 0x71, 0xde, + 0x58, 0x09, 0xe7, 0x6f, 0x2c, 0x44, 0xc9, 0xc9, 0xae, 0xba, 0x9d, 0x63, + 0x88, 0x01, 0xa0, 0x95, 0x9d, 0xf5, 0x3f, 0x2a, 0xe6, 0x67, 0xdb, 0x50, + 0x83, 0x55, 0xad, 0x36, 0x3e, 0x78, 0x10, 0x74, 0x77, 0xfd, 0x2d, 0xaa, + 0x4c, 0x7d, 0x58, 0x73, 0x91, 0xa0, 0x0f, 0x51, 0x45, 0xb7, 0x33, 0xdd, + 0x58, 0x69, 0x1d, 0xd8, 0x0c, 0x9f, 0x96, 0x88, 0x19, 0x99, 0x19, 0xac, + 0xcf, 0xa3, 0xd2, 0xad, 0xb5, 0xdb, 0x76, 0x8f, 0xad, 0xc4, 0xea, 0xcf, + 0xdf, 0x7e, 0xdf, 0xdd, 0xfc, 0xd5, 0xa3, 0x5e, 0x43, 0x2b, 0x6b, 0xb2, + 0xad, 0x3b, 0x6a, 0xa4, 0x13, 0xa7, 0x04, 0xac, 0x7a, 0x6f, 0xb3, 0x23, + 0x26, 0xcc, 0xfb, 0xb4, 0x75, 0x8e, 0x01, 0x83, 0xf7, 0x58, 0x3e, 0x8b, + 0x53, 0xa7, 0x2a, 0x1a, 0x31, 0x42, 0x36, 0x5d, 0x4c, 0x9a, 0xf2, 0xdc, + 0xc6, 0xfe, 0x98, 0xb4, 0x34, 0xcb, 0x48, 0x0a, 0x8f, 0xdb, 0xb2, 0xeb, + 0x76, 0xd6, 0x07, 0x5c, 0x59, 0xc9, 0x64, 0x8f, 0x93, 0xa7, 0x73, 0x16, + 0x83, 0xaf, 0x0e, 0xa4, 0x33, 0xef, 0x50, 0xc5, 0x0c, 0xda, 0x59, 0x10, + 0x06, 0x8a, 0x2e, 0x29, 0x0e, 0xac, 0xc2, 0x31, 0x3d, 0x36, 0x69, 0x7e, + 0xd6, 0xcc, 0xf5, 0x3d, 0x6f, 0xb3, 0xeb, 0x1b, 0x76, 0xef, 0x3b, 0xa3, + 0xfa, 0xc9, 0x2b, 0x5f, 0x66, 0x6f, 0xa9, 0x1e, 0x73, 0xf2, 0x49, 0x2e, + 0x39, 0xf7, 0x4f, 0xb7, 0x8d, 0xff, 0xd5, 0xf3, 0x26, 0xfe, 0x0a, 0xc5, + 0x1b, 0xa7, 0xcb, 0xb2, 0xcf, 0x49, 0x03, 0xb2, 0x46, 0xee, 0xd9, 0xd9, + 0xb3, 0xf4, 0x9f, 0x25, 0x4a, 0xdf, 0x4b, 0x77, 0xe8, 0x27, 0xd4, 0xef, + 0x1c, 0x2a, 0x29, 0x26, 0xc5, 0x7c, 0x9d, 0x6c, 0x7f, 0xb7, 0x6e, 0x1b, + 0x26, 0x7f, 0x05, 0xa3, 0xfe, 0x53, 0x8d, 0x62, 0x57, 0x30, 0x92, 0x12, + 0xfa, 0x2f, 0x86, 0xdf, 0xa4, 0xec, 0x67, 0xfe, 0xd0, 0xf4, 0xff, 0x00, + 0x4d, 0xfc, 0xdf, 0x78, 0xe1, 0x68, 0x7d, 0x54, 0x99, 0xbf, 0x6f, 0xf3, + 0xbe, 0xdf, 0x8e, 0xdd, 0x7f, 0xef, 0xeb, 0x97, 0x49, 0x3e, 0x3b, 0x7f, + 0x06, 0x2c, 0x9f, 0x37, 0x5f, 0xf0, 0x9f, 0x4c, 0xeb, 0x7b, 0xbf, 0x67, + 0x55, 0xe8, 0xff, 0x00, 0x31, 0xbc, 0x7a, 0x9e, 0x31, 0xdb, 0xfe, 0x92, + 0xae, 0x37, 0x7a, 0x4d, 0xdb, 0xe2, 0x17, 0x9d, 0xa4, 0xa3, 0xc9, 0xba, + 0xfc, 0x7b, 0x7d, 0x5f, 0x52, 0xa7, 0x7e, 0xd1, 0x28, 0xf8, 0xf3, 0xb0, + 0xc7, 0x32, 0xbc, 0x99, 0x24, 0xc5, 0xe3, 0xab, 0xeb, 0x1f, 0xa4, 0xf5, + 0xfc, 0xe1, 0x25, 0xe4, 0xe9, 0x24, 0x97, 0xff, 0xd9, 0xff, 0xed, 0x2e, + 0x1c, 0x50, 0x68, 0x6f, 0x74, 0x6f, 0x73, 0x68, 0x6f, 0x70, 0x20, 0x33, + 0x2e, 0x30, 0x00, 0x38, 0x42, 0x49, 0x4d, 0x04, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x2b, 0x1c, 0x02, 0x00, 0x00, 0x02, 0x00, 0x02, 0x1c, 0x02, + 0x78, 0x00, 0x1f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x38, + 0x42, 0x49, 0x4d, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xfb, + 0x09, 0xa6, 0xbd, 0x07, 0x4c, 0x2a, 0x36, 0x9d, 0x8f, 0xe2, 0xcc, 0x57, + 0xa9, 0xac, 0x85, 0x38, 0x42, 0x49, 0x4d, 0x03, 0xea, 0x00, 0x00, 0x00, + 0x00, 0x1d, 0xb0, 0x3c, 0x3f, 0x78, 0x6d, 0x6c, 0x20, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x3d, 0x22, 0x31, 0x2e, 0x30, 0x22, 0x20, 0x65, + 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x3d, 0x22, 0x55, 0x54, 0x46, + 0x2d, 0x38, 0x22, 0x3f, 0x3e, 0x0a, 0x3c, 0x21, 0x44, 0x4f, 0x43, 0x54, + 0x59, 0x50, 0x45, 0x20, 0x70, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x50, 0x55, + 0x42, 0x4c, 0x49, 0x43, 0x20, 0x22, 0x2d, 0x2f, 0x2f, 0x41, 0x70, 0x70, + 0x6c, 0x65, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x2f, + 0x2f, 0x44, 0x54, 0x44, 0x20, 0x50, 0x4c, 0x49, 0x53, 0x54, 0x20, 0x31, + 0x2e, 0x30, 0x2f, 0x2f, 0x45, 0x4e, 0x22, 0x20, 0x22, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x61, 0x70, 0x70, 0x6c, + 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x44, 0x54, 0x44, 0x73, 0x2f, 0x50, + 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x4c, 0x69, 0x73, 0x74, 0x2d, + 0x31, 0x2e, 0x30, 0x2e, 0x64, 0x74, 0x64, 0x22, 0x3e, 0x0a, 0x3c, 0x70, + 0x6c, 0x69, 0x73, 0x74, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x3d, 0x22, 0x31, 0x2e, 0x30, 0x22, 0x3e, 0x0a, 0x3c, 0x64, 0x69, 0x63, + 0x74, 0x3e, 0x0a, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, + 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, + 0x2e, 0x50, 0x61, 0x67, 0x65, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x2e, + 0x50, 0x4d, 0x48, 0x6f, 0x72, 0x69, 0x7a, 0x6f, 0x6e, 0x74, 0x61, 0x6c, + 0x52, 0x65, 0x73, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x3c, + 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, + 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, + 0x63, 0x72, 0x65, 0x61, 0x74, 0x6f, 0x72, 0x3c, 0x2f, 0x6b, 0x65, 0x79, + 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, + 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x69, 0x6e, 0x74, 0x69, 0x6e, 0x67, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, + 0x72, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, + 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, + 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, + 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x41, 0x72, 0x72, + 0x61, 0x79, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, + 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x64, + 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, + 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x67, 0x65, 0x46, 0x6f, + 0x72, 0x6d, 0x61, 0x74, 0x2e, 0x50, 0x4d, 0x48, 0x6f, 0x72, 0x69, 0x7a, + 0x6f, 0x6e, 0x74, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x3c, 0x2f, 0x6b, 0x65, + 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, + 0x3e, 0x37, 0x32, 0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, + 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, + 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, + 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, + 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, + 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, + 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x69, + 0x6e, 0x67, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x3c, 0x2f, 0x73, + 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, + 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, + 0x65, 0x74, 0x2e, 0x6d, 0x6f, 0x64, 0x44, 0x61, 0x74, 0x65, 0x3c, 0x2f, + 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x61, + 0x74, 0x65, 0x3e, 0x32, 0x30, 0x30, 0x37, 0x2d, 0x30, 0x31, 0x2d, 0x33, + 0x30, 0x54, 0x32, 0x32, 0x3a, 0x30, 0x38, 0x3a, 0x34, 0x31, 0x5a, 0x3c, + 0x2f, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, + 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, + 0x65, 0x74, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x46, 0x6c, 0x61, 0x67, + 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, + 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x30, 0x3c, 0x2f, 0x69, + 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, + 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x2f, 0x61, + 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, + 0x74, 0x3e, 0x0a, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, + 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, + 0x2e, 0x50, 0x61, 0x67, 0x65, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x2e, + 0x50, 0x4d, 0x4f, 0x72, 0x69, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x3c, 0x64, 0x69, + 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, + 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, + 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x72, + 0x65, 0x61, 0x74, 0x6f, 0x72, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, + 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, + 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, + 0x74, 0x69, 0x6e, 0x67, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x3c, + 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x3c, + 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, + 0x65, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x41, 0x72, 0x72, 0x61, 0x79, + 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x61, 0x72, + 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x69, 0x63, + 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, + 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x67, 0x65, 0x46, 0x6f, 0x72, 0x6d, + 0x61, 0x74, 0x2e, 0x50, 0x4d, 0x4f, 0x72, 0x69, 0x65, 0x6e, 0x74, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, + 0x09, 0x09, 0x09, 0x3c, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, + 0x31, 0x3c, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x0a, + 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, + 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, + 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x6c, 0x69, 0x65, + 0x6e, 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, + 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, + 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, + 0x69, 0x6e, 0x67, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x3c, 0x2f, + 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, + 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, + 0x6b, 0x65, 0x74, 0x2e, 0x6d, 0x6f, 0x64, 0x44, 0x61, 0x74, 0x65, 0x3c, + 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x64, + 0x61, 0x74, 0x65, 0x3e, 0x32, 0x30, 0x30, 0x37, 0x2d, 0x30, 0x31, 0x2d, + 0x33, 0x30, 0x54, 0x32, 0x32, 0x3a, 0x30, 0x38, 0x3a, 0x34, 0x31, 0x5a, + 0x3c, 0x2f, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, + 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, + 0x6b, 0x65, 0x74, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x46, 0x6c, 0x61, + 0x67, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, + 0x3c, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x30, 0x3c, 0x2f, + 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x0a, 0x09, 0x09, 0x09, + 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x2f, + 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x3c, 0x2f, 0x64, 0x69, + 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, + 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, + 0x74, 0x2e, 0x50, 0x61, 0x67, 0x65, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, + 0x2e, 0x50, 0x4d, 0x53, 0x63, 0x61, 0x6c, 0x69, 0x6e, 0x67, 0x3c, 0x2f, + 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, + 0x0a, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, + 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, + 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74, + 0x6f, 0x72, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, + 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, + 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x69, 0x6e, + 0x67, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x3c, 0x2f, 0x73, 0x74, + 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, + 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, + 0x69, 0x74, 0x65, 0x6d, 0x41, 0x72, 0x72, 0x61, 0x79, 0x3c, 0x2f, 0x6b, + 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x61, 0x72, 0x72, 0x61, 0x79, + 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, + 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, + 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, + 0x2e, 0x50, 0x61, 0x67, 0x65, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x2e, + 0x50, 0x4d, 0x53, 0x63, 0x61, 0x6c, 0x69, 0x6e, 0x67, 0x3c, 0x2f, 0x6b, + 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, + 0x6c, 0x3e, 0x31, 0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, + 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, + 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, + 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, + 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, + 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, + 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x69, + 0x6e, 0x67, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x3c, 0x2f, 0x73, + 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, + 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, + 0x65, 0x74, 0x2e, 0x6d, 0x6f, 0x64, 0x44, 0x61, 0x74, 0x65, 0x3c, 0x2f, + 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x61, + 0x74, 0x65, 0x3e, 0x32, 0x30, 0x30, 0x37, 0x2d, 0x30, 0x31, 0x2d, 0x33, + 0x30, 0x54, 0x32, 0x32, 0x3a, 0x30, 0x38, 0x3a, 0x34, 0x31, 0x5a, 0x3c, + 0x2f, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, + 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, + 0x65, 0x74, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x46, 0x6c, 0x61, 0x67, + 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, + 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x30, 0x3c, 0x2f, 0x69, + 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, + 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x2f, 0x61, + 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, + 0x74, 0x3e, 0x0a, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, + 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, + 0x2e, 0x50, 0x61, 0x67, 0x65, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x2e, + 0x50, 0x4d, 0x56, 0x65, 0x72, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x52, 0x65, + 0x73, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x3c, 0x64, 0x69, + 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, + 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, + 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x72, + 0x65, 0x61, 0x74, 0x6f, 0x72, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, + 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, + 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, + 0x74, 0x69, 0x6e, 0x67, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x3c, + 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x3c, + 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, + 0x65, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x41, 0x72, 0x72, 0x61, 0x79, + 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x61, 0x72, + 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x69, 0x63, + 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, + 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x67, 0x65, 0x46, 0x6f, 0x72, 0x6d, + 0x61, 0x74, 0x2e, 0x50, 0x4d, 0x56, 0x65, 0x72, 0x74, 0x69, 0x63, 0x61, + 0x6c, 0x52, 0x65, 0x73, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, + 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x37, 0x32, 0x3c, + 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, + 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, + 0x65, 0x74, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x3c, 0x2f, 0x6b, + 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, + 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x69, 0x6e, 0x67, 0x6d, 0x61, + 0x6e, 0x61, 0x67, 0x65, 0x72, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, + 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, + 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x6d, + 0x6f, 0x64, 0x44, 0x61, 0x74, 0x65, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, + 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x32, + 0x30, 0x30, 0x37, 0x2d, 0x30, 0x31, 0x2d, 0x33, 0x30, 0x54, 0x32, 0x32, + 0x3a, 0x30, 0x38, 0x3a, 0x34, 0x31, 0x5a, 0x3c, 0x2f, 0x64, 0x61, 0x74, + 0x65, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, + 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x73, + 0x74, 0x61, 0x74, 0x65, 0x46, 0x6c, 0x61, 0x67, 0x3c, 0x2f, 0x6b, 0x65, + 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x69, 0x6e, 0x74, 0x65, + 0x67, 0x65, 0x72, 0x3e, 0x30, 0x3c, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x67, + 0x65, 0x72, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, + 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x2f, 0x61, 0x72, 0x72, 0x61, 0x79, + 0x3e, 0x0a, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, + 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x67, + 0x65, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x2e, 0x50, 0x4d, 0x56, 0x65, + 0x72, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x53, 0x63, 0x61, 0x6c, 0x69, 0x6e, + 0x67, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x3c, 0x64, 0x69, + 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, + 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, + 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x72, + 0x65, 0x61, 0x74, 0x6f, 0x72, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, + 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, + 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, + 0x74, 0x69, 0x6e, 0x67, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x3c, + 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x3c, + 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, + 0x65, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x41, 0x72, 0x72, 0x61, 0x79, + 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x61, 0x72, + 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x69, 0x63, + 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, + 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x67, 0x65, 0x46, 0x6f, 0x72, 0x6d, + 0x61, 0x74, 0x2e, 0x50, 0x4d, 0x56, 0x65, 0x72, 0x74, 0x69, 0x63, 0x61, + 0x6c, 0x53, 0x63, 0x61, 0x6c, 0x69, 0x6e, 0x67, 0x3c, 0x2f, 0x6b, 0x65, + 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, + 0x3e, 0x31, 0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, + 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, + 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, + 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, + 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, + 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, + 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x69, 0x6e, + 0x67, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x3c, 0x2f, 0x73, 0x74, + 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, + 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, + 0x74, 0x2e, 0x6d, 0x6f, 0x64, 0x44, 0x61, 0x74, 0x65, 0x3c, 0x2f, 0x6b, + 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x61, 0x74, + 0x65, 0x3e, 0x32, 0x30, 0x30, 0x37, 0x2d, 0x30, 0x31, 0x2d, 0x33, 0x30, + 0x54, 0x32, 0x32, 0x3a, 0x30, 0x38, 0x3a, 0x34, 0x31, 0x5a, 0x3c, 0x2f, + 0x64, 0x61, 0x74, 0x65, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, + 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, + 0x74, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x46, 0x6c, 0x61, 0x67, 0x3c, + 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x69, + 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x30, 0x3c, 0x2f, 0x69, 0x6e, + 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x2f, + 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x2f, 0x61, 0x72, + 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, + 0x3e, 0x0a, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, + 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, + 0x73, 0x75, 0x62, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x70, 0x61, + 0x70, 0x65, 0x72, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x5f, 0x74, 0x69, 0x63, + 0x6b, 0x65, 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x3c, + 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, + 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x67, 0x65, 0x46, 0x6f, 0x72, + 0x6d, 0x61, 0x74, 0x2e, 0x50, 0x4d, 0x41, 0x64, 0x6a, 0x75, 0x73, 0x74, + 0x65, 0x64, 0x50, 0x61, 0x67, 0x65, 0x52, 0x65, 0x63, 0x74, 0x3c, 0x2f, + 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, + 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, + 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, + 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x6f, 0x72, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, + 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, + 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, + 0x74, 0x69, 0x6e, 0x67, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x3c, + 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x09, + 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, + 0x6b, 0x65, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x41, 0x72, 0x72, 0x61, + 0x79, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, + 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, + 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, + 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x67, 0x65, + 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x2e, 0x50, 0x4d, 0x41, 0x64, 0x6a, + 0x75, 0x73, 0x74, 0x65, 0x64, 0x50, 0x61, 0x67, 0x65, 0x52, 0x65, 0x63, + 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x3c, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x30, 0x2e, 0x30, + 0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x30, 0x2e, 0x30, 0x3c, + 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x37, 0x33, 0x34, 0x3c, 0x2f, + 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x35, 0x37, 0x36, 0x3c, 0x2f, 0x72, + 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x2f, + 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, + 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x3c, 0x2f, + 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x73, + 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, + 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x69, 0x6e, 0x67, + 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x3c, 0x2f, 0x73, 0x74, 0x72, + 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, + 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, + 0x74, 0x2e, 0x6d, 0x6f, 0x64, 0x44, 0x61, 0x74, 0x65, 0x3c, 0x2f, 0x6b, + 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x61, + 0x74, 0x65, 0x3e, 0x32, 0x30, 0x30, 0x37, 0x2d, 0x30, 0x31, 0x2d, 0x33, + 0x30, 0x54, 0x32, 0x32, 0x3a, 0x30, 0x38, 0x3a, 0x34, 0x31, 0x5a, 0x3c, + 0x2f, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, + 0x6b, 0x65, 0x74, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x46, 0x6c, 0x61, + 0x67, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x3c, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x30, 0x3c, + 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x0a, 0x09, 0x09, + 0x09, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, + 0x09, 0x3c, 0x2f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, + 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x6b, + 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x67, 0x65, 0x46, + 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x2e, 0x50, 0x4d, 0x41, 0x64, 0x6a, 0x75, + 0x73, 0x74, 0x65, 0x64, 0x50, 0x61, 0x70, 0x65, 0x72, 0x52, 0x65, 0x63, + 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x64, + 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, + 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, + 0x63, 0x72, 0x65, 0x61, 0x74, 0x6f, 0x72, 0x3c, 0x2f, 0x6b, 0x65, 0x79, + 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, + 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x69, 0x6e, 0x74, 0x69, 0x6e, 0x67, 0x6d, 0x61, 0x6e, 0x61, 0x67, + 0x65, 0x72, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, + 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, + 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, + 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x41, + 0x72, 0x72, 0x61, 0x79, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, + 0x09, 0x09, 0x3c, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, + 0x09, 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, + 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, + 0x61, 0x67, 0x65, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x2e, 0x50, 0x4d, + 0x41, 0x64, 0x6a, 0x75, 0x73, 0x74, 0x65, 0x64, 0x50, 0x61, 0x70, 0x65, + 0x72, 0x52, 0x65, 0x63, 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, + 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, + 0x3e, 0x2d, 0x31, 0x38, 0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, + 0x2d, 0x31, 0x38, 0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x37, + 0x37, 0x34, 0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x35, 0x39, + 0x34, 0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x3c, 0x2f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, + 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, + 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x6c, 0x69, 0x65, + 0x6e, 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, + 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, + 0x74, 0x69, 0x6e, 0x67, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x3c, + 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, + 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, + 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x6d, 0x6f, 0x64, 0x44, 0x61, 0x74, + 0x65, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x3c, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x32, 0x30, 0x30, 0x37, 0x2d, + 0x30, 0x31, 0x2d, 0x33, 0x30, 0x54, 0x32, 0x32, 0x3a, 0x30, 0x38, 0x3a, + 0x34, 0x31, 0x5a, 0x3c, 0x2f, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x0a, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, + 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, + 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x73, 0x74, 0x61, 0x74, + 0x65, 0x46, 0x6c, 0x61, 0x67, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, + 0x72, 0x3e, 0x30, 0x3c, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, + 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, + 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x2f, 0x61, 0x72, 0x72, 0x61, 0x79, + 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, + 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, + 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, + 0x61, 0x70, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x50, 0x4d, 0x50, + 0x61, 0x70, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x3c, 0x2f, 0x6b, 0x65, + 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, + 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, + 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, + 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74, + 0x6f, 0x72, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, + 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, + 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, + 0x70, 0x6d, 0x2e, 0x50, 0x6f, 0x73, 0x74, 0x53, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, + 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, + 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, + 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x41, 0x72, + 0x72, 0x61, 0x79, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, + 0x09, 0x3c, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, + 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, + 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, + 0x70, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x50, 0x4d, 0x50, 0x61, + 0x70, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x3c, 0x2f, 0x6b, 0x65, 0x79, + 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, + 0x6e, 0x67, 0x3e, 0x6e, 0x61, 0x2d, 0x6c, 0x65, 0x74, 0x74, 0x65, 0x72, + 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, + 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, + 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, + 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, + 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, + 0x2e, 0x70, 0x6d, 0x2e, 0x50, 0x6f, 0x73, 0x74, 0x53, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, + 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, + 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x6d, 0x6f, 0x64, + 0x44, 0x61, 0x74, 0x65, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x32, 0x30, + 0x30, 0x33, 0x2d, 0x30, 0x37, 0x2d, 0x30, 0x31, 0x54, 0x31, 0x37, 0x3a, + 0x34, 0x39, 0x3a, 0x33, 0x36, 0x5a, 0x3c, 0x2f, 0x64, 0x61, 0x74, 0x65, + 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, + 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x73, + 0x74, 0x61, 0x74, 0x65, 0x46, 0x6c, 0x61, 0x67, 0x3c, 0x2f, 0x6b, 0x65, + 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x69, 0x6e, 0x74, + 0x65, 0x67, 0x65, 0x72, 0x3e, 0x31, 0x3c, 0x2f, 0x69, 0x6e, 0x74, 0x65, + 0x67, 0x65, 0x72, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x2f, 0x64, + 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x2f, 0x61, 0x72, + 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, + 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, + 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, + 0x74, 0x2e, 0x50, 0x61, 0x70, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x2e, + 0x50, 0x4d, 0x55, 0x6e, 0x61, 0x64, 0x6a, 0x75, 0x73, 0x74, 0x65, 0x64, + 0x50, 0x61, 0x67, 0x65, 0x52, 0x65, 0x63, 0x74, 0x3c, 0x2f, 0x6b, 0x65, + 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, + 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, + 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, + 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74, + 0x6f, 0x72, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, + 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, + 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, + 0x70, 0x6d, 0x2e, 0x50, 0x6f, 0x73, 0x74, 0x53, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, + 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, + 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, + 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x41, 0x72, + 0x72, 0x61, 0x79, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, + 0x09, 0x3c, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, + 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, + 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, + 0x70, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x50, 0x4d, 0x55, 0x6e, + 0x61, 0x64, 0x6a, 0x75, 0x73, 0x74, 0x65, 0x64, 0x50, 0x61, 0x67, 0x65, + 0x52, 0x65, 0x63, 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x3c, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, + 0x30, 0x2e, 0x30, 0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x30, + 0x2e, 0x30, 0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x37, 0x33, + 0x34, 0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x35, 0x37, 0x36, + 0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x3c, 0x2f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, + 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, + 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, + 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, + 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, + 0x69, 0x6e, 0x67, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x3c, 0x2f, + 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, + 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, + 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x6d, 0x6f, 0x64, 0x44, 0x61, 0x74, 0x65, + 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x3c, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x32, 0x30, 0x30, 0x37, 0x2d, 0x30, + 0x31, 0x2d, 0x33, 0x30, 0x54, 0x32, 0x32, 0x3a, 0x30, 0x38, 0x3a, 0x34, + 0x31, 0x5a, 0x3c, 0x2f, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x0a, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, + 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, + 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, + 0x46, 0x6c, 0x61, 0x67, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x3c, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, + 0x3e, 0x30, 0x3c, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, + 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, + 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x2f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, + 0x0a, 0x09, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, + 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, + 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, + 0x70, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x50, 0x4d, 0x55, 0x6e, + 0x61, 0x64, 0x6a, 0x75, 0x73, 0x74, 0x65, 0x64, 0x50, 0x61, 0x70, 0x65, + 0x72, 0x52, 0x65, 0x63, 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, + 0x09, 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, + 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, + 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74, 0x6f, 0x72, 0x3c, + 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x73, 0x74, + 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x70, 0x6d, 0x2e, + 0x50, 0x6f, 0x73, 0x74, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x3c, 0x2f, + 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, + 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, + 0x65, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x41, 0x72, 0x72, 0x61, 0x79, + 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x61, + 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x64, + 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, + 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x70, 0x65, 0x72, + 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x50, 0x4d, 0x55, 0x6e, 0x61, 0x64, 0x6a, + 0x75, 0x73, 0x74, 0x65, 0x64, 0x50, 0x61, 0x70, 0x65, 0x72, 0x52, 0x65, + 0x63, 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x3c, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x2d, 0x31, + 0x38, 0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x2d, 0x31, 0x38, + 0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x37, 0x37, 0x34, 0x3c, + 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x35, 0x39, 0x34, 0x3c, 0x2f, + 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, + 0x2f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, + 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, + 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x3c, + 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, + 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, + 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x69, 0x6e, + 0x67, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x3c, 0x2f, 0x73, 0x74, + 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, + 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, + 0x65, 0x74, 0x2e, 0x6d, 0x6f, 0x64, 0x44, 0x61, 0x74, 0x65, 0x3c, 0x2f, + 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x64, + 0x61, 0x74, 0x65, 0x3e, 0x32, 0x30, 0x30, 0x37, 0x2d, 0x30, 0x31, 0x2d, + 0x33, 0x30, 0x54, 0x32, 0x32, 0x3a, 0x30, 0x38, 0x3a, 0x34, 0x31, 0x5a, + 0x3c, 0x2f, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, + 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, + 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x46, 0x6c, + 0x61, 0x67, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x3c, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x30, + 0x3c, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x0a, 0x09, + 0x09, 0x09, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, + 0x09, 0x09, 0x3c, 0x2f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, + 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x3c, + 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x70, 0x65, + 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x70, 0x70, 0x64, 0x2e, 0x50, 0x4d, + 0x50, 0x61, 0x70, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x3c, 0x2f, 0x6b, + 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, + 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, + 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, + 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x72, 0x65, 0x61, + 0x74, 0x6f, 0x72, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, + 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, + 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, + 0x2e, 0x70, 0x6d, 0x2e, 0x50, 0x6f, 0x73, 0x74, 0x53, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, + 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, + 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, + 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x41, + 0x72, 0x72, 0x61, 0x79, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, + 0x09, 0x09, 0x3c, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, + 0x09, 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, + 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, + 0x61, 0x70, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x70, 0x70, 0x64, + 0x2e, 0x50, 0x4d, 0x50, 0x61, 0x70, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, + 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x55, 0x53, 0x20, 0x4c, + 0x65, 0x74, 0x74, 0x65, 0x72, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, + 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, + 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, + 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, + 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, + 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x70, 0x6d, 0x2e, 0x50, 0x6f, 0x73, + 0x74, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x3c, 0x2f, 0x73, 0x74, 0x72, + 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, + 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, + 0x74, 0x2e, 0x6d, 0x6f, 0x64, 0x44, 0x61, 0x74, 0x65, 0x3c, 0x2f, 0x6b, + 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x61, + 0x74, 0x65, 0x3e, 0x32, 0x30, 0x30, 0x33, 0x2d, 0x30, 0x37, 0x2d, 0x30, + 0x31, 0x54, 0x31, 0x37, 0x3a, 0x34, 0x39, 0x3a, 0x33, 0x36, 0x5a, 0x3c, + 0x2f, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, + 0x6b, 0x65, 0x74, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x46, 0x6c, 0x61, + 0x67, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x3c, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x31, 0x3c, + 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x0a, 0x09, 0x09, + 0x09, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, + 0x09, 0x3c, 0x2f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, + 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x6b, + 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, + 0x74, 0x2e, 0x41, 0x50, 0x49, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x73, 0x74, + 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x30, 0x30, 0x2e, 0x32, 0x30, 0x3c, 0x2f, + 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x6b, + 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, + 0x74, 0x2e, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4c, 0x6f, 0x63, + 0x6b, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x66, + 0x61, 0x6c, 0x73, 0x65, 0x2f, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x6b, 0x65, + 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, + 0x2e, 0x74, 0x79, 0x70, 0x65, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, + 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, + 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, + 0x74, 0x2e, 0x50, 0x61, 0x70, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x54, + 0x69, 0x63, 0x6b, 0x65, 0x74, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, + 0x67, 0x3e, 0x0a, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, + 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, + 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, + 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x41, 0x50, 0x49, 0x56, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x3c, + 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x30, 0x30, 0x2e, 0x32, 0x30, + 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x3c, + 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, + 0x65, 0x74, 0x2e, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4c, 0x6f, + 0x63, 0x6b, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x3c, 0x66, + 0x61, 0x6c, 0x73, 0x65, 0x2f, 0x3e, 0x0a, 0x09, 0x3c, 0x6b, 0x65, 0x79, + 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, + 0x74, 0x79, 0x70, 0x65, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, + 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, + 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, + 0x50, 0x61, 0x67, 0x65, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x54, 0x69, + 0x63, 0x6b, 0x65, 0x74, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, + 0x3e, 0x0a, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x3c, 0x2f, + 0x70, 0x6c, 0x69, 0x73, 0x74, 0x3e, 0x0a, 0x38, 0x42, 0x49, 0x4d, 0x03, + 0xe9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x48, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x02, 0xde, 0x02, 0x40, 0xff, + 0xee, 0xff, 0xee, 0x03, 0x06, 0x02, 0x52, 0x03, 0x67, 0x05, 0x28, 0x03, + 0xfc, 0x00, 0x02, 0x00, 0x00, 0x00, 0x48, 0x00, 0x48, 0x00, 0x00, 0x00, + 0x00, 0x02, 0xd8, 0x02, 0x28, 0x00, 0x01, 0x00, 0x00, 0x00, 0x64, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x01, 0x7f, + 0xff, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x08, 0x00, 0x19, 0x01, 0x90, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x42, 0x49, 0x4d, 0x03, + 0xed, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x48, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x38, + 0x42, 0x49, 0x4d, 0x04, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x80, 0x00, + 0x00, 0x38, 0x42, 0x49, 0x4d, 0x04, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x1e, 0x38, 0x42, 0x49, 0x4d, 0x04, 0x19, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x1e, 0x38, 0x42, 0x49, + 0x4d, 0x03, 0xf3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x38, 0x42, 0x49, 0x4d, 0x04, + 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x38, 0x42, 0x49, + 0x4d, 0x27, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x38, 0x42, 0x49, 0x4d, 0x03, + 0xf5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x2f, 0x66, 0x66, 0x00, + 0x01, 0x00, 0x6c, 0x66, 0x66, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x2f, 0x66, 0x66, 0x00, 0x01, 0x00, 0xa1, 0x99, 0x9a, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x32, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x35, 0x00, 0x00, 0x00, 0x01, 0x00, 0x2d, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x38, 0x42, 0x49, 0x4d, 0x03, + 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0xe8, 0x00, 0x00, 0x00, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, + 0xe8, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x03, 0xe8, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0xe8, 0x00, 0x00, 0x38, + 0x42, 0x49, 0x4d, 0x04, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0x02, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x38, 0x42, 0x49, 0x4d, 0x04, 0x1e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x38, 0x42, 0x49, 0x4d, 0x04, + 0x1a, 0x00, 0x00, 0x00, 0x00, 0x03, 0x45, 0x00, 0x00, 0x00, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, + 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x08, 0x00, 0x44, 0x00, 0x53, 0x00, + 0x43, 0x00, 0x30, 0x00, 0x32, 0x00, 0x33, 0x00, 0x32, 0x00, 0x35, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, + 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x6e, 0x75, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x06, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x73, 0x4f, 0x62, 0x6a, 0x63, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0x63, + 0x74, 0x31, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x54, 0x6f, + 0x70, 0x20, 0x6c, 0x6f, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x4c, 0x65, 0x66, 0x74, 0x6c, 0x6f, 0x6e, 0x67, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x74, 0x6f, 0x6d, 0x6c, 0x6f, + 0x6e, 0x67, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x52, 0x67, + 0x68, 0x74, 0x6c, 0x6f, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, + 0x00, 0x06, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x73, 0x56, 0x6c, 0x4c, 0x73, + 0x00, 0x00, 0x00, 0x01, 0x4f, 0x62, 0x6a, 0x63, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x00, + 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x07, 0x73, 0x6c, 0x69, 0x63, 0x65, + 0x49, 0x44, 0x6c, 0x6f, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x44, 0x6c, 0x6f, 0x6e, + 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x6f, 0x72, 0x69, + 0x67, 0x69, 0x6e, 0x65, 0x6e, 0x75, 0x6d, 0x00, 0x00, 0x00, 0x0c, 0x45, + 0x53, 0x6c, 0x69, 0x63, 0x65, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x00, + 0x00, 0x00, 0x0d, 0x61, 0x75, 0x74, 0x6f, 0x47, 0x65, 0x6e, 0x65, 0x72, + 0x61, 0x74, 0x65, 0x64, 0x00, 0x00, 0x00, 0x00, 0x54, 0x79, 0x70, 0x65, + 0x65, 0x6e, 0x75, 0x6d, 0x00, 0x00, 0x00, 0x0a, 0x45, 0x53, 0x6c, 0x69, + 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x00, 0x00, 0x00, 0x00, 0x49, 0x6d, + 0x67, 0x20, 0x00, 0x00, 0x00, 0x06, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x73, + 0x4f, 0x62, 0x6a, 0x63, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x52, 0x63, 0x74, 0x31, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x54, 0x6f, 0x70, 0x20, 0x6c, 0x6f, 0x6e, 0x67, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x65, 0x66, 0x74, 0x6c, 0x6f, + 0x6e, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x74, + 0x6f, 0x6d, 0x6c, 0x6f, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, + 0x00, 0x00, 0x52, 0x67, 0x68, 0x74, 0x6c, 0x6f, 0x6e, 0x67, 0x00, 0x00, + 0x00, 0x64, 0x00, 0x00, 0x00, 0x03, 0x75, 0x72, 0x6c, 0x54, 0x45, 0x58, + 0x54, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, + 0x75, 0x6c, 0x6c, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x4d, 0x73, 0x67, 0x65, 0x54, 0x45, 0x58, + 0x54, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x61, + 0x6c, 0x74, 0x54, 0x61, 0x67, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x63, 0x65, 0x6c, 0x6c, 0x54, + 0x65, 0x78, 0x74, 0x49, 0x73, 0x48, 0x54, 0x4d, 0x4c, 0x62, 0x6f, 0x6f, + 0x6c, 0x01, 0x00, 0x00, 0x00, 0x08, 0x63, 0x65, 0x6c, 0x6c, 0x54, 0x65, + 0x78, 0x74, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x09, 0x68, 0x6f, 0x72, 0x7a, 0x41, 0x6c, 0x69, 0x67, + 0x6e, 0x65, 0x6e, 0x75, 0x6d, 0x00, 0x00, 0x00, 0x0f, 0x45, 0x53, 0x6c, + 0x69, 0x63, 0x65, 0x48, 0x6f, 0x72, 0x7a, 0x41, 0x6c, 0x69, 0x67, 0x6e, + 0x00, 0x00, 0x00, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x00, + 0x00, 0x00, 0x09, 0x76, 0x65, 0x72, 0x74, 0x41, 0x6c, 0x69, 0x67, 0x6e, + 0x65, 0x6e, 0x75, 0x6d, 0x00, 0x00, 0x00, 0x0f, 0x45, 0x53, 0x6c, 0x69, + 0x63, 0x65, 0x56, 0x65, 0x72, 0x74, 0x41, 0x6c, 0x69, 0x67, 0x6e, 0x00, + 0x00, 0x00, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x00, 0x00, + 0x00, 0x0b, 0x62, 0x67, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x54, 0x79, 0x70, + 0x65, 0x65, 0x6e, 0x75, 0x6d, 0x00, 0x00, 0x00, 0x11, 0x45, 0x53, 0x6c, + 0x69, 0x63, 0x65, 0x42, 0x47, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x54, 0x79, + 0x70, 0x65, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x6f, 0x6e, 0x65, 0x00, 0x00, + 0x00, 0x09, 0x74, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x73, 0x65, 0x74, 0x6c, + 0x6f, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x6c, + 0x65, 0x66, 0x74, 0x4f, 0x75, 0x74, 0x73, 0x65, 0x74, 0x6c, 0x6f, 0x6e, + 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x62, 0x6f, 0x74, + 0x74, 0x6f, 0x6d, 0x4f, 0x75, 0x74, 0x73, 0x65, 0x74, 0x6c, 0x6f, 0x6e, + 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x72, 0x69, 0x67, + 0x68, 0x74, 0x4f, 0x75, 0x74, 0x73, 0x65, 0x74, 0x6c, 0x6f, 0x6e, 0x67, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x42, 0x49, 0x4d, 0x04, 0x11, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x38, 0x42, 0x49, 0x4d, 0x04, + 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x38, + 0x42, 0x49, 0x4d, 0x04, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x09, 0xf9, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x64, 0x00, + 0x00, 0x01, 0x2c, 0x00, 0x00, 0x75, 0x30, 0x00, 0x00, 0x09, 0xdd, 0x00, + 0x18, 0x00, 0x01, 0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49, + 0x46, 0x00, 0x01, 0x02, 0x01, 0x00, 0x48, 0x00, 0x48, 0x00, 0x00, 0xff, + 0xed, 0x00, 0x0c, 0x41, 0x64, 0x6f, 0x62, 0x65, 0x5f, 0x43, 0x4d, 0x00, + 0x02, 0xff, 0xee, 0x00, 0x0e, 0x41, 0x64, 0x6f, 0x62, 0x65, 0x00, 0x64, + 0x80, 0x00, 0x00, 0x00, 0x01, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x0c, 0x08, + 0x08, 0x08, 0x09, 0x08, 0x0c, 0x09, 0x09, 0x0c, 0x11, 0x0b, 0x0a, 0x0b, + 0x11, 0x15, 0x0f, 0x0c, 0x0c, 0x0f, 0x15, 0x18, 0x13, 0x13, 0x15, 0x13, + 0x13, 0x18, 0x11, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x11, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x01, 0x0d, 0x0b, 0x0b, 0x0d, 0x0e, 0x0d, 0x10, 0x0e, 0x0e, + 0x10, 0x14, 0x0e, 0x0e, 0x0e, 0x14, 0x14, 0x0e, 0x0e, 0x0e, 0x0e, 0x14, + 0x11, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x11, 0x11, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x11, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xff, 0xc0, 0x00, 0x11, 0x08, + 0x00, 0x64, 0x00, 0x64, 0x03, 0x01, 0x22, 0x00, 0x02, 0x11, 0x01, 0x03, + 0x11, 0x01, 0xff, 0xdd, 0x00, 0x04, 0x00, 0x07, 0xff, 0xc4, 0x01, 0x3f, + 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x02, 0x04, 0x05, 0x06, + 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x01, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x10, 0x00, + 0x01, 0x04, 0x01, 0x03, 0x02, 0x04, 0x02, 0x05, 0x07, 0x06, 0x08, 0x05, + 0x03, 0x0c, 0x33, 0x01, 0x00, 0x02, 0x11, 0x03, 0x04, 0x21, 0x12, 0x31, + 0x05, 0x41, 0x51, 0x61, 0x13, 0x22, 0x71, 0x81, 0x32, 0x06, 0x14, 0x91, + 0xa1, 0xb1, 0x42, 0x23, 0x24, 0x15, 0x52, 0xc1, 0x62, 0x33, 0x34, 0x72, + 0x82, 0xd1, 0x43, 0x07, 0x25, 0x92, 0x53, 0xf0, 0xe1, 0xf1, 0x63, 0x73, + 0x35, 0x16, 0xa2, 0xb2, 0x83, 0x26, 0x44, 0x93, 0x54, 0x64, 0x45, 0xc2, + 0xa3, 0x74, 0x36, 0x17, 0xd2, 0x55, 0xe2, 0x65, 0xf2, 0xb3, 0x84, 0xc3, + 0xd3, 0x75, 0xe3, 0xf3, 0x46, 0x27, 0x94, 0xa4, 0x85, 0xb4, 0x95, 0xc4, + 0xd4, 0xe4, 0xf4, 0xa5, 0xb5, 0xc5, 0xd5, 0xe5, 0xf5, 0x56, 0x66, 0x76, + 0x86, 0x96, 0xa6, 0xb6, 0xc6, 0xd6, 0xe6, 0xf6, 0x37, 0x47, 0x57, 0x67, + 0x77, 0x87, 0x97, 0xa7, 0xb7, 0xc7, 0xd7, 0xe7, 0xf7, 0x11, 0x00, 0x02, + 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x05, 0x06, 0x07, 0x07, 0x06, + 0x05, 0x35, 0x01, 0x00, 0x02, 0x11, 0x03, 0x21, 0x31, 0x12, 0x04, 0x41, + 0x51, 0x61, 0x71, 0x22, 0x13, 0x05, 0x32, 0x81, 0x91, 0x14, 0xa1, 0xb1, + 0x42, 0x23, 0xc1, 0x52, 0xd1, 0xf0, 0x33, 0x24, 0x62, 0xe1, 0x72, 0x82, + 0x92, 0x43, 0x53, 0x15, 0x63, 0x73, 0x34, 0xf1, 0x25, 0x06, 0x16, 0xa2, + 0xb2, 0x83, 0x07, 0x26, 0x35, 0xc2, 0xd2, 0x44, 0x93, 0x54, 0xa3, 0x17, + 0x64, 0x45, 0x55, 0x36, 0x74, 0x65, 0xe2, 0xf2, 0xb3, 0x84, 0xc3, 0xd3, + 0x75, 0xe3, 0xf3, 0x46, 0x94, 0xa4, 0x85, 0xb4, 0x95, 0xc4, 0xd4, 0xe4, + 0xf4, 0xa5, 0xb5, 0xc5, 0xd5, 0xe5, 0xf5, 0x56, 0x66, 0x76, 0x86, 0x96, + 0xa6, 0xb6, 0xc6, 0xd6, 0xe6, 0xf6, 0x27, 0x37, 0x47, 0x57, 0x67, 0x77, + 0x87, 0x97, 0xa7, 0xb7, 0xc7, 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, + 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00, 0xf2, 0xed, 0xb2, 0x8d, 0x4d, + 0x45, 0xcd, 0x2f, 0x3f, 0x44, 0x68, 0x93, 0xc3, 0x58, 0xc8, 0xf1, 0x1f, + 0x8a, 0x33, 0x86, 0xda, 0x58, 0xc1, 0xa0, 0x02, 0x4f, 0xc4, 0xa1, 0x69, + 0xa5, 0x9b, 0x5b, 0x4b, 0x84, 0x73, 0xdf, 0xc9, 0x15, 0xf8, 0xe3, 0xd1, + 0x0e, 0x07, 0x93, 0xf3, 0xd1, 0x0f, 0x1c, 0x17, 0xef, 0x2e, 0x3b, 0x5b, + 0xdc, 0xff, 0x00, 0xdf, 0x42, 0xbf, 0x8f, 0x8e, 0xdc, 0x82, 0xca, 0xd8, + 0x37, 0x11, 0xa9, 0x3d, 0x82, 0x69, 0x2b, 0xc4, 0x6d, 0xc9, 0x75, 0x25, + 0xbc, 0xf7, 0xec, 0xa1, 0xb5, 0x74, 0x19, 0x5d, 0x2e, 0x8a, 0x9a, 0x4b, + 0x89, 0x7d, 0xc4, 0x68, 0xc6, 0xf6, 0xfe, 0xb2, 0xa0, 0x30, 0x1d, 0x60, + 0x86, 0x88, 0x8d, 0x49, 0x3e, 0x01, 0x11, 0x20, 0xa3, 0x8c, 0xb9, 0xb1, + 0xaa, 0x62, 0xad, 0xbf, 0x18, 0x97, 0x43, 0x47, 0x1d, 0xd2, 0xaf, 0x04, + 0xd9, 0xb8, 0xc8, 0x0d, 0x68, 0xe4, 0xf7, 0x3e, 0x48, 0xf1, 0x05, 0xbc, + 0x25, 0xaa, 0x07, 0x71, 0xd9, 0x14, 0x78, 0xf6, 0x49, 0xb5, 0x90, 0xfd, + 0xa7, 0xc6, 0x14, 0xfd, 0x1b, 0x1c, 0xff, 0x00, 0x4d, 0x8d, 0x2e, 0x73, + 0x8c, 0x35, 0xa3, 0x52, 0x4f, 0x92, 0x48, 0xa6, 0x1a, 0x24, 0xb6, 0x2a, + 0xfa, 0xa5, 0x9e, 0x60, 0x64, 0x39, 0x94, 0x13, 0xcb, 0x27, 0x73, 0x80, + 0xf3, 0x0c, 0xf6, 0xff, 0x00, 0xd2, 0x5a, 0x78, 0xbf, 0x53, 0x71, 0xf6, + 0x01, 0x75, 0xb6, 0x97, 0x6a, 0x25, 0xa1, 0xad, 0x1f, 0xf4, 0xb7, 0x23, + 0x48, 0xb7, 0x94, 0x84, 0x97, 0x5b, 0xff, 0x00, 0x32, 0xa9, 0xdd, 0xfc, + 0xed, 0x9b, 0x7e, 0x0d, 0x9e, 0x52, 0x4a, 0x95, 0x61, 0xff, 0xd0, 0xf3, + 0x3b, 0xa7, 0x70, 0xee, 0x01, 0x8f, 0xb9, 0x59, 0xfa, 0x7e, 0xdf, 0xe4, + 0xc8, 0xf9, 0x2a, 0xc2, 0x5c, 0x63, 0xc3, 0x54, 0x67, 0x87, 0x6e, 0x10, + 0x35, 0x68, 0xd4, 0x79, 0x1e, 0x53, 0x4a, 0xe0, 0xdc, 0xe9, 0xb8, 0x1f, + 0x6a, 0xda, 0x6c, 0x25, 0x94, 0x37, 0xb0, 0xd0, 0xb8, 0xad, 0x67, 0xe4, + 0x55, 0x8a, 0x5b, 0x8b, 0x82, 0xc0, 0x6f, 0x76, 0x80, 0x34, 0x49, 0x05, + 0x2e, 0x9e, 0xc6, 0x1c, 0x66, 0x31, 0xba, 0x10, 0x23, 0xe0, 0xaf, 0xe1, + 0x61, 0x53, 0x43, 0x8d, 0x81, 0xb3, 0x67, 0xef, 0x9e, 0x49, 0x2a, 0x12, + 0x6c, 0xb6, 0x63, 0x1a, 0x0c, 0x31, 0xba, 0x55, 0xcd, 0xac, 0xfa, 0x8e, + 0xdf, 0x91, 0x6e, 0x91, 0xd9, 0xb3, 0xc9, 0x73, 0x90, 0x7a, 0xab, 0x6a, + 0xc2, 0xa4, 0x60, 0xe2, 0x8f, 0xd2, 0x38, 0x03, 0x7d, 0x9e, 0x0d, 0xff, + 0x00, 0xcc, 0xd6, 0xd3, 0x6b, 0x71, 0x67, 0xd2, 0x3e, 0x64, 0x72, 0xab, + 0xdb, 0x8d, 0x54, 0x39, 0xc5, 0x83, 0x6b, 0x3d, 0xee, 0x2e, 0xd4, 0x92, + 0x3c, 0x4a, 0x56, 0xba, 0xb4, 0x79, 0x5c, 0xf7, 0xb2, 0x96, 0x6c, 0x8d, + 0xaf, 0x80, 0x48, 0x3c, 0xf0, 0xb2, 0x1f, 0x63, 0x9c, 0xe9, 0x3f, 0x24, + 0x5c, 0xdb, 0xdd, 0x76, 0x43, 0xde, 0xfd, 0x5c, 0xe3, 0x24, 0xfc, 0x50, + 0x00, 0x93, 0x0a, 0x78, 0x8a, 0x0d, 0x49, 0xca, 0xcf, 0x93, 0x63, 0x1b, + 0x7d, 0xd7, 0x57, 0x50, 0xd5, 0xef, 0x70, 0x6b, 0x4f, 0xc7, 0x45, 0xdb, + 0x74, 0x9e, 0x8d, 0x5e, 0x33, 0x83, 0xd8, 0x37, 0xdd, 0xc3, 0xac, 0x3d, + 0xbf, 0x92, 0xc5, 0x5b, 0xea, 0xbf, 0xd5, 0x62, 0xc0, 0xdc, 0xbc, 0xbd, + 0x2d, 0x22, 0x5a, 0xcf, 0xdd, 0x69, 0xff, 0x00, 0xd1, 0x8e, 0x5d, 0xa5, + 0x38, 0xb5, 0xb0, 0x00, 0xc6, 0xc4, 0x24, 0x4a, 0xd6, 0x8d, 0x18, 0x04, + 0x49, 0x88, 0x9e, 0x55, 0xd6, 0x61, 0xb0, 0xc1, 0x70, 0x32, 0xdd, 0x3c, + 0x95, 0xda, 0xf1, 0xfe, 0xf5, 0x62, 0xbc, 0x76, 0x8e, 0x75, 0x28, 0x02, + 0xa2, 0xe7, 0x7d, 0x92, 0xb9, 0x84, 0x96, 0x96, 0xda, 0xf7, 0x70, 0x12, + 0x4e, 0x5a, 0xff, 0x00, 0xff, 0xd1, 0xf3, 0x7a, 0x21, 0xaf, 0xde, 0xef, + 0xa2, 0x22, 0x55, 0xfc, 0x5a, 0xbd, 0x42, 0xfb, 0x08, 0xfa, 0x67, 0x4f, + 0x82, 0xcd, 0x6d, 0x85, 0xc0, 0x56, 0x3b, 0x90, 0xb7, 0xf0, 0x2a, 0x0e, + 0x63, 0x58, 0x3b, 0xf2, 0xa3, 0x9e, 0x8c, 0xb8, 0x86, 0xbe, 0x49, 0xf1, + 0x2c, 0x0c, 0x86, 0xb4, 0x4c, 0x69, 0xe4, 0xaf, 0x6e, 0xcc, 0x6b, 0x7d, + 0x46, 0xb3, 0x70, 0xec, 0x38, 0x51, 0x7d, 0x02, 0x8a, 0xc7, 0xa6, 0xd9, + 0x20, 0x68, 0x0f, 0x8f, 0x8a, 0xcf, 0xc9, 0xc2, 0xea, 0x59, 0x5b, 0x48, + 0xb0, 0x91, 0xae, 0xe6, 0xc9, 0x03, 0xc9, 0x30, 0x51, 0x66, 0xd4, 0x0d, + 0xad, 0xbd, 0x5f, 0x53, 0xcc, 0x6b, 0xb6, 0x90, 0x5a, 0x3b, 0x83, 0x0b, + 0x43, 0x17, 0x31, 0xd6, 0xc3, 0x6e, 0x12, 0x3b, 0x79, 0xac, 0xc1, 0x89, + 0x47, 0xd9, 0xe8, 0x63, 0x98, 0x45, 0xed, 0x6c, 0x5a, 0xf1, 0xa0, 0x27, + 0xc5, 0x5b, 0xc3, 0x6f, 0xa6, 0xe0, 0x1c, 0x7d, 0xb3, 0xa2, 0x69, 0x34, + 0x7b, 0xae, 0x1a, 0x8d, 0x45, 0x17, 0x9d, 0xeb, 0xfd, 0x21, 0xd8, 0xb9, + 0xae, 0xb5, 0x80, 0xbb, 0x1e, 0xd2, 0x5c, 0xd7, 0x78, 0x13, 0xf9, 0xae, + 0x4b, 0xea, 0xc7, 0x4a, 0x39, 0xbd, 0x55, 0xb3, 0xed, 0x66, 0x38, 0xf5, + 0x09, 0x22, 0x41, 0x23, 0xe8, 0x37, 0xfb, 0x4b, 0xa1, 0xeb, 0xd6, 0xfe, + 0x88, 0x31, 0xbf, 0x41, 0xc0, 0xee, 0xd2, 0x74, 0x02, 0x78, 0x53, 0xfa, + 0x97, 0x43, 0x19, 0x85, 0x65, 0xff, 0x00, 0x9d, 0x71, 0x33, 0xe4, 0x1a, + 0x7d, 0x8d, 0x53, 0x42, 0x56, 0x35, 0x6b, 0xe5, 0x80, 0x06, 0xc7, 0x57, + 0xa7, 0xc4, 0xa9, 0xdb, 0xb6, 0x81, 0x1f, 0xeb, 0xd9, 0x69, 0x56, 0xc2, + 0xd0, 0x00, 0xe5, 0x55, 0xc0, 0x12, 0xc2, 0xd7, 0x4e, 0xa2, 0x5a, 0x7c, + 0x0a, 0xd0, 0x63, 0x9a, 0xd1, 0xaf, 0xd2, 0xe2, 0x3c, 0x12, 0x62, 0x66, + 0xc6, 0x42, 0x23, 0x5a, 0x49, 0x8f, 0x10, 0xa2, 0xd2, 0x3e, 0x28, 0x9d, + 0xc4, 0x88, 0x09, 0x29, 0x16, 0xc3, 0x3c, 0x24, 0x8d, 0xe6, 0x92, 0x72, + 0x1f, 0xff, 0xd2, 0xf3, 0xbb, 0xb0, 0xfe, 0xcb, 0x99, 0xe9, 0xce, 0xf6, + 0x88, 0x2d, 0x77, 0x91, 0x5b, 0x3d, 0x3d, 0xd0, 0xe6, 0x90, 0xa9, 0x65, + 0x57, 0x38, 0x95, 0xdd, 0xcb, 0x9a, 0x7d, 0xce, 0xf2, 0x3f, 0x44, 0x23, + 0x60, 0x58, 0x76, 0xe9, 0xca, 0x8c, 0xea, 0x1b, 0x31, 0x02, 0x32, 0x23, + 0xea, 0xee, 0xb1, 0xcd, 0xb0, 0xc7, 0x87, 0x74, 0x7a, 0xeb, 0x70, 0x1a, + 0x71, 0xe1, 0xfe, 0xe4, 0x1c, 0x1d, 0xae, 0xe5, 0x69, 0xd8, 0xfa, 0x99, + 0x50, 0x0d, 0x1a, 0xf7, 0x2a, 0x3a, 0x0c, 0xf4, 0x1a, 0x8e, 0xc7, 0x27, + 0x5d, 0xbf, 0x18, 0x41, 0xdc, 0xc2, 0xf0, 0x7f, 0x74, 0xf6, 0x3a, 0x22, + 0x66, 0xdb, 0x68, 0xc6, 0x80, 0x48, 0x6b, 0x88, 0x06, 0x39, 0x0d, 0xee, + 0xaa, 0x1f, 0xb3, 0xd5, 0x1b, 0x83, 0xd8, 0x3b, 0x38, 0x8f, 0x69, 0xfe, + 0xdf, 0xd1, 0x4d, 0x29, 0xa1, 0x4c, 0x7a, 0xf4, 0xbf, 0xa7, 0x92, 0xcf, + 0xa5, 0x20, 0x08, 0xf3, 0xf6, 0xff, 0x00, 0x15, 0xbb, 0xd1, 0x31, 0xd9, + 0x5e, 0x3d, 0x75, 0x56, 0x36, 0x88, 0x00, 0x81, 0xe0, 0x16, 0x5e, 0x55, + 0x74, 0x3f, 0x00, 0x9d, 0xe0, 0xcc, 0x69, 0xe7, 0x3a, 0x2d, 0xbe, 0x90, + 0x00, 0xa9, 0xae, 0xef, 0x1f, 0x95, 0x4b, 0x0d, 0x9a, 0xdc, 0xc7, 0x45, + 0xfe, 0xb1, 0x7d, 0x60, 0xa7, 0xa1, 0xe0, 0x1f, 0x4e, 0x1d, 0x99, 0x69, + 0x02, 0x9a, 0xcf, 0x1f, 0xca, 0x7b, 0xbf, 0x90, 0xc5, 0xc2, 0xb3, 0xeb, + 0x57, 0xd6, 0x03, 0x6b, 0xae, 0x39, 0xb6, 0x82, 0xe3, 0x31, 0xa1, 0x68, + 0xf2, 0x6b, 0x5c, 0x12, 0xfa, 0xe1, 0x91, 0x66, 0x47, 0x5d, 0xb8, 0x3b, + 0x4f, 0x44, 0x36, 0xb6, 0x8f, 0x28, 0xdd, 0xff, 0x00, 0x7e, 0x46, 0xab, + 0x12, 0x2b, 0x65, 0x55, 0x32, 0xa7, 0x62, 0xb6, 0xbd, 0xf7, 0x64, 0x10, + 0xdb, 0x03, 0x9f, 0x1b, 0x9e, 0xc7, 0xd9, 0xb8, 0x3b, 0x1f, 0x67, 0xf3, + 0x6c, 0x52, 0x80, 0xd7, 0x7d, 0x0f, 0xea, 0x7f, 0x5d, 0x1d, 0x67, 0xa6, + 0x0b, 0x1e, 0x47, 0xda, 0x69, 0x3b, 0x2e, 0x03, 0xc7, 0xf3, 0x5f, 0x1f, + 0xf0, 0x8b, 0xa1, 0x02, 0x46, 0xba, 0x79, 0xaf, 0x32, 0xff, 0x00, 0x16, + 0xad, 0xca, 0x1d, 0x57, 0x2a, 0xdc, 0x79, 0x18, 0x41, 0xb0, 0xf6, 0x9e, + 0xe4, 0x9f, 0xd0, 0x8f, 0xeb, 0x31, 0xab, 0xd2, 0x83, 0xa4, 0xcb, 0x8c, + 0xb8, 0xa0, 0x42, 0x12, 0x7b, 0x67, 0x9f, 0x2f, 0xf5, 0x09, 0x26, 0x96, + 0xc4, 0xce, 0xa9, 0x20, 0xa7, 0xff, 0xd3, 0xf3, 0x2f, 0xb4, 0x5d, 0xe9, + 0x0a, 0xb7, 0x9f, 0x4c, 0x19, 0xdb, 0x3a, 0x2d, 0x5e, 0x94, 0xfd, 0xc4, + 0xb7, 0xc5, 0x62, 0xf9, 0x2b, 0xfd, 0x2e, 0xe3, 0x5d, 0xe0, 0x7c, 0x13, + 0x48, 0xd1, 0x92, 0x12, 0xa9, 0x0b, 0x7a, 0xbc, 0x2d, 0xc2, 0x7f, 0x92, + 0x60, 0xab, 0x4e, 0x79, 0x2e, 0x00, 0xf0, 0xaa, 0xe1, 0xda, 0x3d, 0x43, + 0xfc, 0xad, 0x55, 0xbb, 0x80, 0x79, 0x81, 0xa0, 0xe6, 0x54, 0x32, 0x6d, + 0x02, 0xbe, 0xf3, 0x61, 0x81, 0xa8, 0x44, 0x14, 0x03, 0x59, 0x0e, 0x1c, + 0xf6, 0x1f, 0xdc, 0xb2, 0xec, 0xa3, 0x23, 0x77, 0xe8, 0x6e, 0x70, 0xf2, + 0x25, 0x1f, 0x1f, 0x17, 0xa9, 0x6d, 0x71, 0x36, 0x97, 0x47, 0x00, 0xa4, + 0x02, 0xe0, 0x2c, 0x7c, 0xc1, 0xab, 0xd5, 0x31, 0x85, 0x35, 0xd4, 0xe6, + 0x13, 0x02, 0xd6, 0x4b, 0x67, 0x48, 0x2b, 0xa9, 0xe9, 0x2e, 0x02, 0xb6, + 0x4f, 0x82, 0xe5, 0x7a, 0x95, 0x19, 0xc6, 0x87, 0x3d, 0xfb, 0xa2, 0xb8, + 0x79, 0x1e, 0x4d, 0x3b, 0x96, 0xcf, 0x4f, 0xbd, 0xcd, 0xa2, 0xa2, 0x1f, + 0xa0, 0x82, 0xd3, 0xfc, 0x97, 0x05, 0x24, 0x36, 0x6b, 0xf3, 0x31, 0xa2, + 0x35, 0x79, 0xef, 0xad, 0xf8, 0xae, 0xaf, 0xaf, 0xd8, 0xf2, 0xd8, 0x6d, + 0xed, 0x6b, 0xda, 0x7b, 0x18, 0x1b, 0x5d, 0xff, 0x00, 0x52, 0xb1, 0x6d, + 0xf0, 0x81, 0x31, 0xca, 0xf4, 0x6e, 0xb1, 0x80, 0xce, 0xb1, 0x84, 0xc0, + 0x21, 0xb7, 0xd6, 0x77, 0x31, 0xd1, 0x27, 0xc1, 0xcd, 0xfe, 0xd2, 0xe3, + 0xec, 0xe8, 0x1d, 0x45, 0x96, 0xb0, 0x9a, 0xb7, 0x87, 0x3f, 0x68, 0x2d, + 0xf7, 0x01, 0x1f, 0xbe, 0xd1, 0xf4, 0x7f, 0xb4, 0xa4, 0x0d, 0x77, 0xbb, + 0xfa, 0x8f, 0x80, 0x3a, 0x7f, 0x43, 0xaa, 0xe2, 0xdf, 0xd2, 0x65, 0x7e, + 0x95, 0xe4, 0x0f, 0x1f, 0xa1, 0xfe, 0x6b, 0x16, 0x9f, 0x52, 0xfa, 0xc1, + 0xd3, 0xba, 0x6d, 0x26, 0xdc, 0xac, 0x86, 0xd4, 0xd9, 0x0d, 0x31, 0x2e, + 0x74, 0x9e, 0xdb, 0x59, 0x2e, 0x55, 0xe8, 0xc9, 0xb2, 0x96, 0xd5, 0x4b, + 0x9f, 0xb8, 0x6d, 0xda, 0x1c, 0x04, 0x09, 0x03, 0xfe, 0x8a, 0xc6, 0xfa, + 0xd3, 0xf5, 0x6a, 0xbe, 0xbb, 0x5b, 0x2e, 0xc6, 0xb5, 0x94, 0xe6, 0xd5, + 0x20, 0x97, 0x7d, 0x1b, 0x1b, 0xf9, 0xad, 0x7c, 0x7d, 0x17, 0xb7, 0xf3, + 0x1e, 0x92, 0x1b, 0x7f, 0xf8, 0xe0, 0x7d, 0x59, 0xdd, 0xfd, 0x32, 0xd8, + 0x8f, 0xa5, 0xe8, 0x3a, 0x12, 0x5c, 0x3f, 0xfc, 0xc4, 0xfa, 0xc3, 0xb3, + 0x77, 0xa7, 0x56, 0xed, 0xdb, 0x76, 0x7a, 0x8d, 0xdd, 0x1f, 0xbf, 0xfd, + 0x44, 0x92, 0x56, 0x8f, 0xff, 0xd4, 0xf2, 0xe8, 0x86, 0x17, 0x1e, 0xfa, + 0x04, 0x56, 0x4b, 0x43, 0x6c, 0x6f, 0x2d, 0xe5, 0x46, 0x01, 0x64, 0x2b, + 0x14, 0x32, 0x5b, 0xb4, 0xa0, 0x52, 0x1d, 0xde, 0x9b, 0x94, 0xdb, 0xab, + 0x6b, 0x81, 0xf7, 0x05, 0xb0, 0xd7, 0x07, 0xb2, 0x27, 0x55, 0xc6, 0x57, + 0x65, 0xd8, 0x76, 0x6e, 0x64, 0xed, 0xee, 0x16, 0xce, 0x27, 0x57, 0x63, + 0xda, 0x0c, 0xc2, 0x8e, 0x51, 0x67, 0x84, 0xfa, 0x1d, 0xdd, 0x62, 0xc7, + 0x07, 0xe9, 0xf7, 0xa3, 0xd6, 0x6c, 0x02, 0x41, 0x55, 0x31, 0xf3, 0x2b, + 0xb3, 0xba, 0x2b, 0x2e, 0x68, 0x24, 0x1d, 0x47, 0x64, 0xca, 0xa6, 0x50, + 0x41, 0x65, 0x90, 0x6c, 0xb1, 0xa5, 0xae, 0x33, 0x23, 0x51, 0xe4, 0xab, + 0x7d, 0x5d, 0xcb, 0xb6, 0xcc, 0x37, 0xd0, 0x40, 0x73, 0x71, 0xde, 0x58, + 0x09, 0xe7, 0x6f, 0x2c, 0x44, 0xc9, 0xc9, 0xae, 0xba, 0x9d, 0x63, 0x88, + 0x01, 0xa0, 0x95, 0x9d, 0xf5, 0x3f, 0x2a, 0xe6, 0x67, 0xdb, 0x50, 0x83, + 0x55, 0xad, 0x36, 0x3e, 0x78, 0x10, 0x74, 0x77, 0xfd, 0x2d, 0xaa, 0x4c, + 0x7d, 0x58, 0x73, 0x91, 0xa0, 0x0f, 0x51, 0x45, 0xb7, 0x33, 0xdd, 0x58, + 0x69, 0x1d, 0xd8, 0x0c, 0x9f, 0x96, 0x88, 0x19, 0x99, 0x19, 0xac, 0xcf, + 0xa3, 0xd2, 0xad, 0xb5, 0xdb, 0x76, 0x8f, 0xad, 0xc4, 0xea, 0xcf, 0xdf, + 0x7e, 0xdf, 0xdd, 0xfc, 0xd5, 0xa3, 0x5e, 0x43, 0x2b, 0x6b, 0xb2, 0xad, + 0x3b, 0x6a, 0xa4, 0x13, 0xa7, 0x04, 0xac, 0x7a, 0x6f, 0xb3, 0x23, 0x26, + 0xcc, 0xfb, 0xb4, 0x75, 0x8e, 0x01, 0x83, 0xf7, 0x58, 0x3e, 0x8b, 0x53, + 0xa7, 0x2a, 0x1a, 0x31, 0x42, 0x36, 0x5d, 0x4c, 0x9a, 0xf2, 0xdc, 0xc6, + 0xfe, 0x98, 0xb4, 0x34, 0xcb, 0x48, 0x0a, 0x8f, 0xdb, 0xb2, 0xeb, 0x76, + 0xd6, 0x07, 0x5c, 0x59, 0xc9, 0x64, 0x8f, 0x93, 0xa7, 0x73, 0x16, 0x83, + 0xaf, 0x0e, 0xa4, 0x33, 0xef, 0x50, 0xc5, 0x0c, 0xda, 0x59, 0x10, 0x06, + 0x8a, 0x2e, 0x29, 0x0e, 0xac, 0xc2, 0x31, 0x3d, 0x36, 0x69, 0x7e, 0xd6, + 0xcc, 0xf5, 0x3d, 0x6f, 0xb3, 0xeb, 0x1b, 0x76, 0xef, 0x3b, 0xa3, 0xfa, + 0xc9, 0x2b, 0x5f, 0x66, 0x6f, 0xa9, 0x1e, 0x73, 0xf2, 0x49, 0x2e, 0x39, + 0xf7, 0x4f, 0xb7, 0x8d, 0xff, 0xd5, 0xf3, 0x26, 0xfe, 0x0a, 0xc5, 0x1b, + 0xa7, 0xcb, 0xb2, 0xcf, 0x49, 0x03, 0xb2, 0x46, 0xee, 0xd9, 0xd9, 0xb3, + 0xf4, 0x9f, 0x25, 0x4a, 0xdf, 0x4b, 0x77, 0xe8, 0x27, 0xd4, 0xef, 0x1c, + 0x2a, 0x29, 0x26, 0xc5, 0x7c, 0x9d, 0x6c, 0x7f, 0xb7, 0x6e, 0x1b, 0x26, + 0x7f, 0x05, 0xa3, 0xfe, 0x53, 0x8d, 0x62, 0x57, 0x30, 0x92, 0x12, 0xfa, + 0x2f, 0x86, 0xdf, 0xa4, 0xec, 0x67, 0xfe, 0xd0, 0xf4, 0xff, 0x00, 0x4d, + 0xfc, 0xdf, 0x78, 0xe1, 0x68, 0x7d, 0x54, 0x99, 0xbf, 0x6f, 0xf3, 0xbe, + 0xdf, 0x8e, 0xdd, 0x7f, 0xef, 0xeb, 0x97, 0x49, 0x3e, 0x3b, 0x7f, 0x06, + 0x2c, 0x9f, 0x37, 0x5f, 0xf0, 0x9f, 0x4c, 0xeb, 0x7b, 0xbf, 0x67, 0x55, + 0xe8, 0xff, 0x00, 0x31, 0xbc, 0x7a, 0x9e, 0x31, 0xdb, 0xfe, 0x92, 0xae, + 0x37, 0x7a, 0x4d, 0xdb, 0xe2, 0x17, 0x9d, 0xa4, 0xa3, 0xc9, 0xba, 0xfc, + 0x7b, 0x7d, 0x5f, 0x52, 0xa7, 0x7e, 0xd1, 0x28, 0xf8, 0xf3, 0xb0, 0xc7, + 0x32, 0xbc, 0x99, 0x24, 0xc5, 0xe3, 0xab, 0xeb, 0x1f, 0xa4, 0xf5, 0xfc, + 0xe1, 0x25, 0xe4, 0xe9, 0x24, 0x97, 0xff, 0xd9, 0x00, 0x38, 0x42, 0x49, + 0x4d, 0x04, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x41, 0x00, 0x64, 0x00, 0x6f, + 0x00, 0x62, 0x00, 0x65, 0x00, 0x20, 0x00, 0x50, 0x00, 0x68, 0x00, 0x6f, + 0x00, 0x74, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x68, 0x00, 0x6f, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x13, 0x00, 0x41, 0x00, 0x64, 0x00, 0x6f, 0x00, 0x62, + 0x00, 0x65, 0x00, 0x20, 0x00, 0x50, 0x00, 0x68, 0x00, 0x6f, 0x00, 0x74, + 0x00, 0x6f, 0x00, 0x73, 0x00, 0x68, 0x00, 0x6f, 0x00, 0x70, 0x00, 0x20, + 0x00, 0x37, 0x00, 0x2e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x38, + 0x42, 0x49, 0x4d, 0x04, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0xff, 0xe1, 0x15, 0x67, 0x68, + 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6e, 0x73, 0x2e, 0x61, 0x64, 0x6f, + 0x62, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x61, 0x70, 0x2f, 0x31, + 0x2e, 0x30, 0x2f, 0x00, 0x3c, 0x3f, 0x78, 0x70, 0x61, 0x63, 0x6b, 0x65, + 0x74, 0x20, 0x62, 0x65, 0x67, 0x69, 0x6e, 0x3d, 0x27, 0xef, 0xbb, 0xbf, + 0x27, 0x20, 0x69, 0x64, 0x3d, 0x27, 0x57, 0x35, 0x4d, 0x30, 0x4d, 0x70, + 0x43, 0x65, 0x68, 0x69, 0x48, 0x7a, 0x72, 0x65, 0x53, 0x7a, 0x4e, 0x54, + 0x63, 0x7a, 0x6b, 0x63, 0x39, 0x64, 0x27, 0x3f, 0x3e, 0x0a, 0x3c, 0x3f, + 0x61, 0x64, 0x6f, 0x62, 0x65, 0x2d, 0x78, 0x61, 0x70, 0x2d, 0x66, 0x69, + 0x6c, 0x74, 0x65, 0x72, 0x73, 0x20, 0x65, 0x73, 0x63, 0x3d, 0x22, 0x43, + 0x52, 0x22, 0x3f, 0x3e, 0x0a, 0x3c, 0x78, 0x3a, 0x78, 0x61, 0x70, 0x6d, + 0x65, 0x74, 0x61, 0x20, 0x78, 0x6d, 0x6c, 0x6e, 0x73, 0x3a, 0x78, 0x3d, + 0x27, 0x61, 0x64, 0x6f, 0x62, 0x65, 0x3a, 0x6e, 0x73, 0x3a, 0x6d, 0x65, + 0x74, 0x61, 0x2f, 0x27, 0x20, 0x78, 0x3a, 0x78, 0x61, 0x70, 0x74, 0x6b, + 0x3d, 0x27, 0x58, 0x4d, 0x50, 0x20, 0x74, 0x6f, 0x6f, 0x6c, 0x6b, 0x69, + 0x74, 0x20, 0x32, 0x2e, 0x38, 0x2e, 0x32, 0x2d, 0x33, 0x33, 0x2c, 0x20, + 0x66, 0x72, 0x61, 0x6d, 0x65, 0x77, 0x6f, 0x72, 0x6b, 0x20, 0x31, 0x2e, + 0x35, 0x27, 0x3e, 0x0a, 0x3c, 0x72, 0x64, 0x66, 0x3a, 0x52, 0x44, 0x46, + 0x20, 0x78, 0x6d, 0x6c, 0x6e, 0x73, 0x3a, 0x72, 0x64, 0x66, 0x3d, 0x27, + 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x77, + 0x33, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x31, 0x39, 0x39, 0x39, 0x2f, 0x30, + 0x32, 0x2f, 0x32, 0x32, 0x2d, 0x72, 0x64, 0x66, 0x2d, 0x73, 0x79, 0x6e, + 0x74, 0x61, 0x78, 0x2d, 0x6e, 0x73, 0x23, 0x27, 0x20, 0x78, 0x6d, 0x6c, + 0x6e, 0x73, 0x3a, 0x69, 0x58, 0x3d, 0x27, 0x68, 0x74, 0x74, 0x70, 0x3a, + 0x2f, 0x2f, 0x6e, 0x73, 0x2e, 0x61, 0x64, 0x6f, 0x62, 0x65, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x69, 0x58, 0x2f, 0x31, 0x2e, 0x30, 0x2f, 0x27, 0x3e, + 0x0a, 0x0a, 0x20, 0x3c, 0x72, 0x64, 0x66, 0x3a, 0x44, 0x65, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x61, 0x62, 0x6f, 0x75, + 0x74, 0x3d, 0x27, 0x75, 0x75, 0x69, 0x64, 0x3a, 0x32, 0x32, 0x64, 0x30, + 0x32, 0x62, 0x30, 0x61, 0x2d, 0x62, 0x32, 0x34, 0x39, 0x2d, 0x31, 0x31, + 0x64, 0x62, 0x2d, 0x38, 0x61, 0x66, 0x38, 0x2d, 0x39, 0x31, 0x64, 0x35, + 0x34, 0x30, 0x33, 0x66, 0x39, 0x32, 0x66, 0x39, 0x27, 0x0a, 0x20, 0x20, + 0x78, 0x6d, 0x6c, 0x6e, 0x73, 0x3a, 0x70, 0x64, 0x66, 0x3d, 0x27, 0x68, + 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6e, 0x73, 0x2e, 0x61, 0x64, 0x6f, + 0x62, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x64, 0x66, 0x2f, 0x31, + 0x2e, 0x33, 0x2f, 0x27, 0x3e, 0x0a, 0x20, 0x20, 0x3c, 0x21, 0x2d, 0x2d, + 0x20, 0x70, 0x64, 0x66, 0x3a, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, + 0x20, 0x69, 0x73, 0x20, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x64, 0x20, + 0x2d, 0x2d, 0x3e, 0x0a, 0x20, 0x3c, 0x2f, 0x72, 0x64, 0x66, 0x3a, 0x44, + 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x0a, + 0x0a, 0x20, 0x3c, 0x72, 0x64, 0x66, 0x3a, 0x44, 0x65, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x61, 0x62, 0x6f, 0x75, 0x74, + 0x3d, 0x27, 0x75, 0x75, 0x69, 0x64, 0x3a, 0x32, 0x32, 0x64, 0x30, 0x32, + 0x62, 0x30, 0x61, 0x2d, 0x62, 0x32, 0x34, 0x39, 0x2d, 0x31, 0x31, 0x64, + 0x62, 0x2d, 0x38, 0x61, 0x66, 0x38, 0x2d, 0x39, 0x31, 0x64, 0x35, 0x34, + 0x30, 0x33, 0x66, 0x39, 0x32, 0x66, 0x39, 0x27, 0x0a, 0x20, 0x20, 0x78, + 0x6d, 0x6c, 0x6e, 0x73, 0x3a, 0x70, 0x68, 0x6f, 0x74, 0x6f, 0x73, 0x68, + 0x6f, 0x70, 0x3d, 0x27, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6e, + 0x73, 0x2e, 0x61, 0x64, 0x6f, 0x62, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, + 0x70, 0x68, 0x6f, 0x74, 0x6f, 0x73, 0x68, 0x6f, 0x70, 0x2f, 0x31, 0x2e, + 0x30, 0x2f, 0x27, 0x3e, 0x0a, 0x20, 0x20, 0x3c, 0x21, 0x2d, 0x2d, 0x20, + 0x70, 0x68, 0x6f, 0x74, 0x6f, 0x73, 0x68, 0x6f, 0x70, 0x3a, 0x43, 0x61, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x73, 0x20, 0x61, 0x6c, 0x69, + 0x61, 0x73, 0x65, 0x64, 0x20, 0x2d, 0x2d, 0x3e, 0x0a, 0x20, 0x3c, 0x2f, + 0x72, 0x64, 0x66, 0x3a, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x3e, 0x0a, 0x0a, 0x20, 0x3c, 0x72, 0x64, 0x66, 0x3a, + 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x20, + 0x61, 0x62, 0x6f, 0x75, 0x74, 0x3d, 0x27, 0x75, 0x75, 0x69, 0x64, 0x3a, + 0x32, 0x32, 0x64, 0x30, 0x32, 0x62, 0x30, 0x61, 0x2d, 0x62, 0x32, 0x34, + 0x39, 0x2d, 0x31, 0x31, 0x64, 0x62, 0x2d, 0x38, 0x61, 0x66, 0x38, 0x2d, + 0x39, 0x31, 0x64, 0x35, 0x34, 0x30, 0x33, 0x66, 0x39, 0x32, 0x66, 0x39, + 0x27, 0x0a, 0x20, 0x20, 0x78, 0x6d, 0x6c, 0x6e, 0x73, 0x3a, 0x78, 0x61, + 0x70, 0x3d, 0x27, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6e, 0x73, + 0x2e, 0x61, 0x64, 0x6f, 0x62, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, + 0x61, 0x70, 0x2f, 0x31, 0x2e, 0x30, 0x2f, 0x27, 0x3e, 0x0a, 0x20, 0x20, + 0x3c, 0x21, 0x2d, 0x2d, 0x20, 0x78, 0x61, 0x70, 0x3a, 0x44, 0x65, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x73, 0x20, + 0x61, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x64, 0x20, 0x2d, 0x2d, 0x3e, 0x0a, + 0x20, 0x3c, 0x2f, 0x72, 0x64, 0x66, 0x3a, 0x44, 0x65, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x0a, 0x0a, 0x20, 0x3c, 0x72, + 0x64, 0x66, 0x3a, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x20, 0x61, 0x62, 0x6f, 0x75, 0x74, 0x3d, 0x27, 0x75, 0x75, + 0x69, 0x64, 0x3a, 0x32, 0x32, 0x64, 0x30, 0x32, 0x62, 0x30, 0x61, 0x2d, + 0x62, 0x32, 0x34, 0x39, 0x2d, 0x31, 0x31, 0x64, 0x62, 0x2d, 0x38, 0x61, + 0x66, 0x38, 0x2d, 0x39, 0x31, 0x64, 0x35, 0x34, 0x30, 0x33, 0x66, 0x39, + 0x32, 0x66, 0x39, 0x27, 0x0a, 0x20, 0x20, 0x78, 0x6d, 0x6c, 0x6e, 0x73, + 0x3a, 0x78, 0x61, 0x70, 0x4d, 0x4d, 0x3d, 0x27, 0x68, 0x74, 0x74, 0x70, + 0x3a, 0x2f, 0x2f, 0x6e, 0x73, 0x2e, 0x61, 0x64, 0x6f, 0x62, 0x65, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x61, 0x70, 0x2f, 0x31, 0x2e, 0x30, 0x2f, + 0x6d, 0x6d, 0x2f, 0x27, 0x3e, 0x0a, 0x20, 0x20, 0x3c, 0x78, 0x61, 0x70, + 0x4d, 0x4d, 0x3a, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x49, + 0x44, 0x3e, 0x61, 0x64, 0x6f, 0x62, 0x65, 0x3a, 0x64, 0x6f, 0x63, 0x69, + 0x64, 0x3a, 0x70, 0x68, 0x6f, 0x74, 0x6f, 0x73, 0x68, 0x6f, 0x70, 0x3a, + 0x32, 0x32, 0x64, 0x30, 0x32, 0x62, 0x30, 0x36, 0x2d, 0x62, 0x32, 0x34, + 0x39, 0x2d, 0x31, 0x31, 0x64, 0x62, 0x2d, 0x38, 0x61, 0x66, 0x38, 0x2d, + 0x39, 0x31, 0x64, 0x35, 0x34, 0x30, 0x33, 0x66, 0x39, 0x32, 0x66, 0x39, + 0x3c, 0x2f, 0x78, 0x61, 0x70, 0x4d, 0x4d, 0x3a, 0x44, 0x6f, 0x63, 0x75, + 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x44, 0x3e, 0x0a, 0x20, 0x3c, 0x2f, 0x72, + 0x64, 0x66, 0x3a, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x3e, 0x0a, 0x0a, 0x20, 0x3c, 0x72, 0x64, 0x66, 0x3a, 0x44, + 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x61, + 0x62, 0x6f, 0x75, 0x74, 0x3d, 0x27, 0x75, 0x75, 0x69, 0x64, 0x3a, 0x32, + 0x32, 0x64, 0x30, 0x32, 0x62, 0x30, 0x61, 0x2d, 0x62, 0x32, 0x34, 0x39, + 0x2d, 0x31, 0x31, 0x64, 0x62, 0x2d, 0x38, 0x61, 0x66, 0x38, 0x2d, 0x39, + 0x31, 0x64, 0x35, 0x34, 0x30, 0x33, 0x66, 0x39, 0x32, 0x66, 0x39, 0x27, + 0x0a, 0x20, 0x20, 0x78, 0x6d, 0x6c, 0x6e, 0x73, 0x3a, 0x64, 0x63, 0x3d, + 0x27, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x70, 0x75, 0x72, 0x6c, + 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x64, 0x63, 0x2f, 0x65, 0x6c, 0x65, 0x6d, + 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x31, 0x2e, 0x31, 0x2f, 0x27, 0x3e, 0x0a, + 0x20, 0x20, 0x3c, 0x64, 0x63, 0x3a, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x3c, 0x72, + 0x64, 0x66, 0x3a, 0x41, 0x6c, 0x74, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x3c, 0x72, 0x64, 0x66, 0x3a, 0x6c, 0x69, 0x20, 0x78, 0x6d, 0x6c, 0x3a, + 0x6c, 0x61, 0x6e, 0x67, 0x3d, 0x27, 0x78, 0x2d, 0x64, 0x65, 0x66, 0x61, + 0x75, 0x6c, 0x74, 0x27, 0x3e, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x3c, 0x2f, 0x72, 0x64, 0x66, 0x3a, 0x6c, 0x69, 0x3e, 0x0a, 0x20, 0x20, + 0x20, 0x3c, 0x2f, 0x72, 0x64, 0x66, 0x3a, 0x41, 0x6c, 0x74, 0x3e, 0x0a, + 0x20, 0x20, 0x3c, 0x2f, 0x64, 0x63, 0x3a, 0x64, 0x65, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x0a, 0x20, 0x3c, 0x2f, 0x72, + 0x64, 0x66, 0x3a, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x3e, 0x0a, 0x0a, 0x3c, 0x2f, 0x72, 0x64, 0x66, 0x3a, 0x52, + 0x44, 0x46, 0x3e, 0x0a, 0x3c, 0x2f, 0x78, 0x3a, 0x78, 0x61, 0x70, 0x6d, + 0x65, 0x74, 0x61, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x3c, 0x3f, 0x78, + 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x20, 0x65, 0x6e, 0x64, 0x3d, 0x27, + 0x77, 0x27, 0x3f, 0x3e, 0xff, 0xee, 0x00, 0x0e, 0x41, 0x64, 0x6f, 0x62, + 0x65, 0x00, 0x64, 0x40, 0x00, 0x00, 0x00, 0x01, 0xff, 0xdb, 0x00, 0x84, + 0x00, 0x04, 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x03, 0x03, 0x04, 0x06, + 0x04, 0x03, 0x04, 0x06, 0x07, 0x05, 0x04, 0x04, 0x05, 0x07, 0x08, 0x06, + 0x06, 0x07, 0x06, 0x06, 0x08, 0x0a, 0x08, 0x09, 0x09, 0x09, 0x09, 0x08, + 0x0a, 0x0a, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0a, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x01, 0x04, 0x05, 0x05, 0x08, 0x07, 0x08, + 0x0f, 0x0a, 0x0a, 0x0f, 0x14, 0x0e, 0x0e, 0x0e, 0x14, 0x14, 0x0e, 0x0e, + 0x0e, 0x0e, 0x14, 0x11, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x11, 0x11, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x11, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xff, 0xc0, + 0x00, 0x11, 0x08, 0x00, 0x64, 0x00, 0x64, 0x03, 0x01, 0x11, 0x00, 0x02, + 0x11, 0x01, 0x03, 0x11, 0x01, 0xff, 0xdd, 0x00, 0x04, 0x00, 0x0d, 0xff, + 0xc4, 0x01, 0xa2, 0x00, 0x00, 0x00, 0x07, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x05, 0x03, 0x02, + 0x06, 0x01, 0x00, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x01, 0x00, 0x02, 0x02, + 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, + 0x0b, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x02, 0x06, 0x07, + 0x03, 0x04, 0x02, 0x06, 0x02, 0x73, 0x01, 0x02, 0x03, 0x11, 0x04, 0x00, + 0x05, 0x21, 0x12, 0x31, 0x41, 0x51, 0x06, 0x13, 0x61, 0x22, 0x71, 0x81, + 0x14, 0x32, 0x91, 0xa1, 0x07, 0x15, 0xb1, 0x42, 0x23, 0xc1, 0x52, 0xd1, + 0xe1, 0x33, 0x16, 0x62, 0xf0, 0x24, 0x72, 0x82, 0xf1, 0x25, 0x43, 0x34, + 0x53, 0x92, 0xa2, 0xb2, 0x63, 0x73, 0xc2, 0x35, 0x44, 0x27, 0x93, 0xa3, + 0xb3, 0x36, 0x17, 0x54, 0x64, 0x74, 0xc3, 0xd2, 0xe2, 0x08, 0x26, 0x83, + 0x09, 0x0a, 0x18, 0x19, 0x84, 0x94, 0x45, 0x46, 0xa4, 0xb4, 0x56, 0xd3, + 0x55, 0x28, 0x1a, 0xf2, 0xe3, 0xf3, 0xc4, 0xd4, 0xe4, 0xf4, 0x65, 0x75, + 0x85, 0x95, 0xa5, 0xb5, 0xc5, 0xd5, 0xe5, 0xf5, 0x66, 0x76, 0x86, 0x96, + 0xa6, 0xb6, 0xc6, 0xd6, 0xe6, 0xf6, 0x37, 0x47, 0x57, 0x67, 0x77, 0x87, + 0x97, 0xa7, 0xb7, 0xc7, 0xd7, 0xe7, 0xf7, 0x38, 0x48, 0x58, 0x68, 0x78, + 0x88, 0x98, 0xa8, 0xb8, 0xc8, 0xd8, 0xe8, 0xf8, 0x29, 0x39, 0x49, 0x59, + 0x69, 0x79, 0x89, 0x99, 0xa9, 0xb9, 0xc9, 0xd9, 0xe9, 0xf9, 0x2a, 0x3a, + 0x4a, 0x5a, 0x6a, 0x7a, 0x8a, 0x9a, 0xaa, 0xba, 0xca, 0xda, 0xea, 0xfa, + 0x11, 0x00, 0x02, 0x02, 0x01, 0x02, 0x03, 0x05, 0x05, 0x04, 0x05, 0x06, + 0x04, 0x08, 0x03, 0x03, 0x6d, 0x01, 0x00, 0x02, 0x11, 0x03, 0x04, 0x21, + 0x12, 0x31, 0x41, 0x05, 0x51, 0x13, 0x61, 0x22, 0x06, 0x71, 0x81, 0x91, + 0x32, 0xa1, 0xb1, 0xf0, 0x14, 0xc1, 0xd1, 0xe1, 0x23, 0x42, 0x15, 0x52, + 0x62, 0x72, 0xf1, 0x33, 0x24, 0x34, 0x43, 0x82, 0x16, 0x92, 0x53, 0x25, + 0xa2, 0x63, 0xb2, 0xc2, 0x07, 0x73, 0xd2, 0x35, 0xe2, 0x44, 0x83, 0x17, + 0x54, 0x93, 0x08, 0x09, 0x0a, 0x18, 0x19, 0x26, 0x36, 0x45, 0x1a, 0x27, + 0x64, 0x74, 0x55, 0x37, 0xf2, 0xa3, 0xb3, 0xc3, 0x28, 0x29, 0xd3, 0xe3, + 0xf3, 0x84, 0x94, 0xa4, 0xb4, 0xc4, 0xd4, 0xe4, 0xf4, 0x65, 0x75, 0x85, + 0x95, 0xa5, 0xb5, 0xc5, 0xd5, 0xe5, 0xf5, 0x46, 0x56, 0x66, 0x76, 0x86, + 0x96, 0xa6, 0xb6, 0xc6, 0xd6, 0xe6, 0xf6, 0x47, 0x57, 0x67, 0x77, 0x87, + 0x97, 0xa7, 0xb7, 0xc7, 0xd7, 0xe7, 0xf7, 0x38, 0x48, 0x58, 0x68, 0x78, + 0x88, 0x98, 0xa8, 0xb8, 0xc8, 0xd8, 0xe8, 0xf8, 0x39, 0x49, 0x59, 0x69, + 0x79, 0x89, 0x99, 0xa9, 0xb9, 0xc9, 0xd9, 0xe9, 0xf9, 0x2a, 0x3a, 0x4a, + 0x5a, 0x6a, 0x7a, 0x8a, 0x9a, 0xaa, 0xba, 0xca, 0xda, 0xea, 0xfa, 0xff, + 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, + 0x00, 0xf0, 0x67, 0xa6, 0x5c, 0x0f, 0x01, 0xd4, 0x7e, 0x18, 0x12, 0x98, + 0xe9, 0xd6, 0x2d, 0x34, 0x6d, 0x70, 0xdf, 0xdc, 0xa1, 0xe3, 0xec, 0x5b, + 0xfb, 0x32, 0x24, 0xb2, 0x01, 0x1f, 0x15, 0xa4, 0x52, 0x4a, 0x82, 0x31, + 0xf1, 0xfe, 0xd1, 0x3d, 0x14, 0x64, 0x49, 0x64, 0x22, 0x98, 0xcf, 0xa5, + 0x46, 0x6c, 0x16, 0x55, 0x71, 0x56, 0x62, 0x28, 0x07, 0xc5, 0x45, 0x15, + 0xa0, 0xc8, 0x89, 0x33, 0xe1, 0x63, 0xd2, 0xd8, 0x34, 0x44, 0x17, 0xa0, + 0x2c, 0x4d, 0x16, 0xbb, 0xed, 0xdc, 0xf8, 0x64, 0xc1, 0x6b, 0x31, 0x42, + 0x18, 0x8e, 0xc7, 0xb5, 0x2a, 0x7d, 0xb2, 0x56, 0xc5, 0x61, 0x8c, 0xf2, + 0xa0, 0x1b, 0x1e, 0x83, 0x0d, 0xa1, 0x63, 0x50, 0x1f, 0x97, 0x7c, 0x2a, + 0xa9, 0x1a, 0x9a, 0x86, 0x4f, 0xb4, 0xb4, 0x38, 0x0a, 0xa6, 0x0b, 0xb8, + 0x0c, 0x05, 0x14, 0xf8, 0x76, 0x3e, 0x19, 0x14, 0xb6, 0x78, 0xf8, 0x8c, + 0x2a, 0xd5, 0x01, 0xdc, 0x6f, 0x8a, 0x1a, 0xe3, 0x8d, 0xab, 0xff, 0xd0, + 0xf0, 0xec, 0xe9, 0x15, 0xb5, 0xb9, 0x5a, 0x7c, 0x4c, 0xa2, 0x9e, 0x24, + 0xf5, 0xca, 0xc6, 0xe5, 0x99, 0xd9, 0x34, 0x99, 0x04, 0x3a, 0x7d, 0xb5, + 0xba, 0xd5, 0x51, 0x63, 0x0e, 0xc7, 0xc5, 0x9b, 0x73, 0xf8, 0xe4, 0x6f, + 0x76, 0xca, 0xd9, 0xda, 0x54, 0x6d, 0x72, 0x2e, 0x1a, 0x57, 0x11, 0x44, + 0x40, 0x0d, 0x27, 0x7a, 0x0f, 0xd9, 0x5f, 0x12, 0x69, 0x4c, 0x84, 0xcd, + 0x36, 0xe3, 0x85, 0xb2, 0xcd, 0x2f, 0x4a, 0x8b, 0x58, 0x36, 0xf6, 0x76, + 0xa8, 0x64, 0x64, 0x3c, 0xa4, 0x93, 0xaa, 0x25, 0x3c, 0x49, 0xda, 0xa4, + 0xe5, 0x26, 0x54, 0xe4, 0x8c, 0x7c, 0x5c, 0x93, 0x4d, 0x67, 0xc9, 0x3a, + 0x6e, 0x9f, 0x13, 0xb4, 0xce, 0xf7, 0x3a, 0x9b, 0xad, 0x52, 0xd6, 0x2a, + 0xd1, 0x49, 0xee, 0xc7, 0xf8, 0x64, 0x46, 0x42, 0x4e, 0xcd, 0x92, 0xc2, + 0x00, 0xdd, 0x8a, 0x47, 0xe5, 0x69, 0x6e, 0xd4, 0xa4, 0x08, 0x16, 0x83, + 0x9c, 0x8c, 0xdd, 0x95, 0x6b, 0xb9, 0xf6, 0xef, 0x97, 0x78, 0x94, 0xe3, + 0x78, 0x04, 0xa4, 0xf3, 0xe8, 0xee, 0x64, 0xe1, 0x12, 0x10, 0x05, 0x6a, + 0xc7, 0xc0, 0x6f, 0x53, 0xf3, 0xc9, 0x89, 0xb4, 0x9c, 0x4e, 0xb4, 0xf2, + 0xd3, 0xde, 0x7a, 0xd2, 0x19, 0x16, 0x38, 0x61, 0x5d, 0xd9, 0x88, 0x05, + 0x9c, 0xf4, 0x0a, 0x0f, 0x5f, 0x73, 0x84, 0xe4, 0xa4, 0xc7, 0x0d, 0xa5, + 0xf1, 0x59, 0xba, 0x5c, 0x08, 0x98, 0x6f, 0xc8, 0x20, 0xfa, 0x4e, 0x4e, + 0xf6, 0x69, 0xe1, 0xa2, 0x89, 0xfd, 0x1f, 0x77, 0x2c, 0xe6, 0xce, 0xd6, + 0x17, 0x9a, 0x69, 0xdb, 0xd3, 0x86, 0x18, 0xc1, 0x67, 0x77, 0x26, 0x80, + 0x28, 0x1b, 0x93, 0x88, 0x41, 0x0f, 0x40, 0xb0, 0xfc, 0x87, 0xf3, 0x43, + 0x98, 0xd7, 0x58, 0x96, 0xdb, 0x4d, 0x91, 0x88, 0xe5, 0x6c, 0x58, 0xdc, + 0x5c, 0x2a, 0xf7, 0x2c, 0xb1, 0xfc, 0x20, 0x8f, 0x02, 0xd9, 0x65, 0x06, + 0xbe, 0x26, 0x6f, 0xa2, 0x7f, 0xce, 0x3d, 0x69, 0x26, 0xdd, 0x13, 0x52, + 0xbf, 0xbd, 0x92, 0x62, 0x59, 0x4c, 0x90, 0xac, 0x50, 0x45, 0x5e, 0xbb, + 0x09, 0x03, 0x12, 0x29, 0x84, 0x00, 0xc4, 0xc9, 0x11, 0xff, 0x00, 0x42, + 0xe7, 0xa7, 0x7a, 0xd4, 0xfd, 0x21, 0x79, 0xe9, 0x78, 0x71, 0x8b, 0x95, + 0x39, 0x75, 0xaf, 0x4e, 0x98, 0x78, 0x42, 0x38, 0xdf, 0xff, 0xd1, 0xf0, + 0xe6, 0xa0, 0x58, 0xc8, 0x84, 0x9a, 0xaa, 0x30, 0x55, 0xf9, 0x0a, 0x6f, + 0x90, 0x0c, 0xca, 0x72, 0x48, 0xb8, 0x1e, 0x89, 0xa7, 0x23, 0x17, 0x24, + 0xff, 0x00, 0x61, 0xb6, 0x54, 0x76, 0x6e, 0x1b, 0xa7, 0xbe, 0x50, 0xf2, + 0xc1, 0xd7, 0x4c, 0x52, 0x5e, 0x33, 0x5b, 0xe9, 0x10, 0xf4, 0x54, 0x3c, + 0x5e, 0x77, 0xee, 0x49, 0xec, 0x2b, 0xb6, 0x63, 0xe4, 0xc9, 0xc3, 0xef, + 0x73, 0xf0, 0xe1, 0x32, 0x1b, 0xf2, 0x7a, 0x05, 0xce, 0xad, 0x65, 0xa1, + 0x98, 0xb4, 0x0f, 0x2a, 0x5b, 0x23, 0xeb, 0x12, 0x00, 0x88, 0xb0, 0xa8, + 0x66, 0x46, 0x3d, 0xea, 0x7b, 0xfb, 0x9e, 0x99, 0x89, 0xbc, 0x8d, 0x97, + 0x3a, 0x34, 0x05, 0x32, 0x5d, 0x1f, 0xc9, 0x1a, 0x8c, 0x36, 0x8c, 0x6f, + 0x66, 0xfa, 0xc6, 0xb7, 0x7d, 0xf0, 0x94, 0x04, 0xf0, 0x88, 0xc9, 0xd5, + 0x9d, 0x8d, 0x4b, 0x11, 0xd4, 0x9f, 0xbb, 0x25, 0xc5, 0xdc, 0xa2, 0x03, + 0x99, 0x4b, 0xbc, 0xf3, 0x0d, 0x97, 0x96, 0x74, 0xe5, 0xf2, 0xb6, 0x80, + 0x95, 0xbd, 0x99, 0x15, 0xf5, 0x4b, 0xd2, 0x37, 0x58, 0x46, 0xd4, 0x27, + 0xc5, 0xce, 0xc1, 0x7c, 0x30, 0x8e, 0x68, 0x94, 0x7b, 0x9e, 0x6d, 0xe6, + 0x7b, 0x9b, 0x5d, 0x3a, 0xd8, 0xdb, 0x32, 0xfa, 0x77, 0x65, 0x15, 0xe4, + 0x57, 0xa7, 0x21, 0x55, 0x04, 0x57, 0xef, 0xd8, 0x66, 0x56, 0x38, 0x19, + 0x1b, 0xe8, 0xe0, 0x67, 0x98, 0xc7, 0x1a, 0x1c, 0xde, 0x71, 0x71, 0x79, + 0x2c, 0xf2, 0xfa, 0x8c, 0x48, 0xec, 0xb5, 0x24, 0x9a, 0x0c, 0xce, 0x75, + 0x29, 0xae, 0x8c, 0x67, 0xd4, 0xb5, 0x0b, 0x4b, 0x04, 0x05, 0xef, 0x2e, + 0x66, 0x8e, 0x18, 0x08, 0x15, 0xdd, 0x8f, 0x11, 0xb0, 0xeb, 0x4c, 0x04, + 0x5b, 0x21, 0x2a, 0x7d, 0x41, 0xe4, 0x4f, 0xcb, 0xcb, 0x5d, 0x12, 0x45, + 0xb8, 0xb7, 0x53, 0x71, 0xaa, 0x9f, 0x86, 0x5b, 0xd6, 0x50, 0x4a, 0xed, + 0xba, 0x46, 0x77, 0x00, 0x13, 0xd4, 0x8c, 0x85, 0xd3, 0x12, 0x6d, 0xeb, + 0x1a, 0x67, 0x95, 0xd9, 0x39, 0x39, 0x50, 0xac, 0xff, 0x00, 0x6f, 0xc4, + 0xff, 0x00, 0x1c, 0x81, 0x92, 0xb2, 0x6b, 0x6d, 0x02, 0xdd, 0xbd, 0x36, + 0x92, 0x36, 0x2d, 0x1f, 0xc0, 0x2a, 0x0b, 0x28, 0x1b, 0x91, 0x41, 0xf4, + 0x9c, 0xb6, 0x25, 0x81, 0x46, 0xfe, 0x81, 0xb5, 0xad, 0x3d, 0xba, 0x57, + 0xb7, 0xf9, 0xf6, 0xc9, 0xb0, 0x7f, 0xff, 0xd2, 0xf0, 0xe2, 0x86, 0x95, + 0xc4, 0x67, 0x7e, 0x3f, 0x11, 0xf7, 0xa8, 0x19, 0x06, 0x69, 0x8d, 0xca, + 0xca, 0x24, 0x8f, 0xd3, 0x52, 0x24, 0x89, 0x47, 0x25, 0x1f, 0xcb, 0x20, + 0xf8, 0xb2, 0xb2, 0x76, 0x6e, 0x88, 0x36, 0xf6, 0x6f, 0x2a, 0xc1, 0x6e, + 0xfa, 0x45, 0xad, 0xbc, 0x3f, 0x0b, 0x46, 0x81, 0x4d, 0x46, 0xea, 0x7a, + 0x9a, 0x83, 0x9a, 0xa9, 0xdd, 0xbb, 0xec, 0x7b, 0x06, 0x5b, 0xe5, 0xcf, + 0x2e, 0x69, 0xfa, 0x5c, 0xcd, 0x7b, 0x14, 0x5e, 0xa5, 0xee, 0xf5, 0xb8, + 0x7d, 0xdd, 0x99, 0xba, 0xef, 0x91, 0x16, 0x5b, 0x36, 0xb6, 0x65, 0x0d, + 0xac, 0xb2, 0x5b, 0xed, 0x34, 0x81, 0x7a, 0xbb, 0x46, 0x40, 0x6a, 0x9e, + 0xb4, 0x39, 0x31, 0x13, 0x49, 0xda, 0xd2, 0x9b, 0xed, 0x1e, 0xc4, 0x24, + 0xb3, 0x35, 0xb2, 0x88, 0x60, 0x06, 0xe6, 0x56, 0x98, 0x96, 0x79, 0x1e, + 0x31, 0x51, 0xc9, 0x8f, 0xcb, 0x00, 0xe6, 0xb3, 0xe4, 0xf9, 0x2b, 0xcc, + 0x7a, 0x94, 0xda, 0x96, 0xa9, 0x71, 0x77, 0x70, 0x79, 0xcd, 0x33, 0x97, + 0x76, 0x3f, 0xcc, 0xc6, 0xa6, 0x9f, 0x2e, 0x99, 0xb9, 0xc6, 0x2a, 0x21, + 0xe6, 0x73, 0xca, 0xe6, 0x4a, 0x51, 0x1a, 0x99, 0x1c, 0x28, 0x04, 0x93, + 0xd0, 0x0e, 0xa4, 0xe4, 0xda, 0x5f, 0x50, 0xfe, 0x4a, 0xfe, 0x48, 0xb5, + 0xb2, 0xc1, 0xe6, 0x1f, 0x31, 0x7e, 0xef, 0x52, 0x91, 0x43, 0xc3, 0x6e, + 0x77, 0xf4, 0x22, 0x6d, 0xbf, 0xe4, 0x63, 0x0e, 0xbf, 0xca, 0x36, 0xeb, + 0x5c, 0x84, 0xa5, 0x48, 0x7d, 0x3b, 0x61, 0xa1, 0xdb, 0x5b, 0x2c, 0x71, + 0xda, 0x45, 0xc4, 0x28, 0x00, 0x81, 0xdb, 0x31, 0xc9, 0xb4, 0xb2, 0x3b, + 0x5d, 0x27, 0xa5, 0x05, 0x1b, 0xc7, 0xdb, 0x10, 0xa9, 0xbd, 0xa6, 0x93, + 0x0c, 0x75, 0xe4, 0x39, 0x35, 0x41, 0x3d, 0xc5, 0x06, 0xdb, 0x8e, 0xfd, + 0x46, 0x5b, 0x1d, 0x98, 0x95, 0x4f, 0x46, 0xdb, 0xd5, 0xfb, 0x29, 0x5e, + 0x9d, 0x0d, 0x32, 0xeb, 0x61, 0x4f, 0xff, 0xd3, 0xf1, 0x46, 0x9a, 0x16, + 0x1b, 0x91, 0x71, 0x28, 0xac, 0x4a, 0x14, 0x30, 0x3e, 0x19, 0x54, 0xb9, + 0x36, 0xc7, 0x9b, 0x2d, 0xd1, 0x6c, 0x45, 0xe3, 0xdc, 0xde, 0xc8, 0x95, + 0x5b, 0x87, 0xf8, 0x41, 0x1d, 0x10, 0x54, 0x01, 0x98, 0x79, 0x25, 0xd1, + 0xda, 0xe9, 0xe1, 0xb5, 0x9e, 0xac, 0xeb, 0x42, 0xba, 0x8e, 0xdf, 0x8c, + 0x31, 0x21, 0x70, 0xb4, 0x5d, 0xbe, 0xc5, 0x7c, 0x2b, 0xed, 0xe1, 0x94, + 0x18, 0xb9, 0x51, 0x3d, 0x03, 0x2c, 0x13, 0x6b, 0xf1, 0x42, 0x6e, 0xe2, + 0xb7, 0x12, 0xa0, 0xdd, 0x50, 0x9f, 0x4f, 0x6f, 0xa7, 0x6f, 0xc7, 0x03, + 0x61, 0xa0, 0x83, 0xb5, 0xf3, 0x97, 0x98, 0x20, 0x9c, 0x44, 0xea, 0xd0, + 0xad, 0x48, 0x64, 0x90, 0x21, 0xd8, 0x9f, 0xa7, 0xa6, 0x44, 0xca, 0x99, + 0xc6, 0x36, 0xcb, 0x74, 0x5d, 0x7e, 0x5b, 0xfe, 0x31, 0x6a, 0x31, 0xf3, + 0x8c, 0xd0, 0xad, 0x40, 0xa3, 0x1f, 0x7c, 0x44, 0xd6, 0x51, 0xd9, 0xe0, + 0x5f, 0x9a, 0x7e, 0x41, 0x9f, 0x40, 0xf3, 0x14, 0xba, 0x85, 0xba, 0x34, + 0xba, 0x2d, 0xfb, 0x34, 0xd0, 0xcf, 0x4f, 0xb0, 0xce, 0x6a, 0x51, 0xe9, + 0xb0, 0x20, 0xf4, 0xf1, 0x19, 0xb2, 0xc3, 0x90, 0x11, 0x4e, 0x97, 0x55, + 0x80, 0x83, 0xc4, 0x17, 0x7e, 0x4c, 0x79, 0x19, 0xfc, 0xd1, 0xe7, 0x78, + 0x4b, 0x91, 0x1d, 0xae, 0x92, 0xa6, 0xf6, 0x46, 0x75, 0xe4, 0xad, 0x22, + 0x1f, 0xdd, 0xa1, 0x07, 0xb3, 0x1e, 0xfe, 0xd9, 0x92, 0xeb, 0x4b, 0xed, + 0xfd, 0x0a, 0xc2, 0x63, 0x27, 0xa4, 0x88, 0x17, 0x60, 0x49, 0x35, 0xdc, + 0x8e, 0xa5, 0x7d, 0xab, 0xd3, 0x28, 0x90, 0x50, 0xcd, 0xed, 0x2d, 0xda, + 0x15, 0x55, 0x51, 0xf1, 0x1a, 0x0a, 0xf7, 0x39, 0x5d, 0xaa, 0x77, 0x6f, + 0x01, 0x8e, 0xa7, 0x7d, 0xfa, 0xff, 0x00, 0x66, 0x10, 0xa8, 0xb8, 0x63, + 0x76, 0x90, 0xa8, 0x20, 0x06, 0x56, 0xdb, 0x61, 0xda, 0xbd, 0x4f, 0xcb, + 0x24, 0x15, 0x0f, 0xf5, 0x66, 0xe5, 0x5f, 0x4c, 0x53, 0xc3, 0xb7, 0xce, + 0x99, 0x6b, 0x17, 0xff, 0xd4, 0xf0, 0xec, 0x57, 0x6f, 0x32, 0xa5, 0xa4, + 0x43, 0x76, 0x75, 0xa9, 0xf1, 0x03, 0xfa, 0x64, 0x08, 0x6c, 0x8e, 0xfb, + 0x3d, 0x7f, 0xcb, 0x16, 0x2b, 0x3d, 0xbc, 0x16, 0xa3, 0x66, 0x6d, 0x98, + 0xfb, 0x1e, 0xb9, 0xac, 0xc8, 0x77, 0xb7, 0x7d, 0x01, 0xb3, 0x37, 0xb8, + 0xd3, 0x46, 0x95, 0x68, 0x86, 0xd2, 0x2e, 0x4e, 0xab, 0xf0, 0x23, 0x11, + 0x4e, 0x5f, 0xcd, 0x98, 0xe7, 0x25, 0x96, 0x71, 0x83, 0x0f, 0xd6, 0x3c, + 0xb9, 0xe7, 0x0d, 0x7c, 0x41, 0x22, 0x5e, 0xb3, 0x20, 0x0c, 0x65, 0x80, + 0xc8, 0x63, 0x8e, 0xbb, 0x95, 0xa5, 0x07, 0xeb, 0xcc, 0xac, 0x73, 0x83, + 0x4e, 0x5c, 0x59, 0x09, 0xd8, 0xec, 0xc8, 0x57, 0x41, 0xd3, 0x4e, 0x95, + 0xa5, 0x5b, 0x4b, 0x6a, 0xcb, 0xab, 0x43, 0x10, 0x4b, 0xeb, 0x85, 0xa2, + 0x2c, 0x8e, 0x3f, 0x68, 0x54, 0xf5, 0x00, 0xd3, 0x97, 0x7a, 0x65, 0x79, + 0xa6, 0x24, 0x76, 0x6f, 0xd3, 0x62, 0x96, 0x30, 0x78, 0xcb, 0x21, 0xf2, + 0xf4, 0x22, 0xce, 0x54, 0x8e, 0x46, 0x26, 0x10, 0x7e, 0x0a, 0xf5, 0xd8, + 0xf5, 0x1f, 0x31, 0x98, 0x83, 0x73, 0xb3, 0x91, 0xcd, 0x67, 0xe6, 0x7d, + 0xe8, 0x16, 0x69, 0x6f, 0x10, 0x1f, 0x54, 0x9a, 0x37, 0xf5, 0x41, 0x5e, + 0x7f, 0x0a, 0x29, 0x62, 0x02, 0xf8, 0x9c, 0xc8, 0x8c, 0x77, 0x6a, 0x99, + 0xa0, 0x89, 0xff, 0x00, 0x9c, 0x74, 0xd2, 0xed, 0xed, 0xfc, 0xbb, 0x7b, + 0xaa, 0x9a, 0x7d, 0x62, 0xfe, 0x46, 0x2d, 0xfe, 0x4c, 0x51, 0x31, 0x11, + 0xa9, 0xf6, 0xef, 0x9b, 0x30, 0x5e, 0x7b, 0x38, 0xdd, 0xf4, 0x7f, 0x95, + 0x94, 0xbc, 0x12, 0x43, 0x30, 0x6a, 0xb2, 0xf3, 0x86, 0x40, 0x3e, 0xcb, + 0xd7, 0x6a, 0xd7, 0xb1, 0xe9, 0x8f, 0x37, 0x19, 0x97, 0x41, 0x2c, 0x71, + 0x20, 0xf5, 0x36, 0x9c, 0x55, 0x78, 0x1d, 0x8a, 0x91, 0xd7, 0x11, 0x14, + 0x5a, 0x3e, 0x19, 0x03, 0x10, 0x6b, 0xca, 0xbd, 0x86, 0xf8, 0x9d, 0x95, + 0x18, 0x36, 0x65, 0x2e, 0xbc, 0x54, 0x1f, 0xa2, 0x99, 0x00, 0x59, 0x2a, + 0x6f, 0x5e, 0x55, 0x15, 0xe9, 0x5f, 0xc3, 0x2f, 0xb6, 0x14, 0xff, 0x00, + 0xff, 0xd5, 0xf1, 0x95, 0xfe, 0x80, 0x74, 0x0d, 0x7c, 0xd9, 0x89, 0x3d, + 0x78, 0x57, 0x8b, 0xc5, 0x28, 0xe8, 0x55, 0xf7, 0x1f, 0x48, 0xca, 0x38, + 0xb8, 0x83, 0x9f, 0x93, 0x07, 0x85, 0x3a, 0x7a, 0x6f, 0x95, 0x66, 0x2b, + 0x2c, 0x4c, 0x0d, 0x14, 0x00, 0x3e, 0x9c, 0xc3, 0x98, 0x76, 0xb8, 0x45, + 0xbd, 0x02, 0xde, 0x48, 0xee, 0xdc, 0xa0, 0x15, 0xe2, 0x2b, 0xc8, 0x8a, + 0x8a, 0xfd, 0x3b, 0x66, 0x3f, 0x00, 0x73, 0x84, 0x2d, 0x36, 0xb5, 0xb5, + 0x9e, 0x35, 0x1c, 0x29, 0xc4, 0xfe, 0xc8, 0x04, 0x7f, 0xc4, 0x69, 0x91, + 0xe1, 0x67, 0x2c, 0x4a, 0xd2, 0xe9, 0x4e, 0xe3, 0xd4, 0xf4, 0x81, 0x5a, + 0x12, 0xc5, 0x41, 0x3f, 0x79, 0x38, 0x9b, 0x60, 0x20, 0x07, 0x34, 0xb0, + 0xc9, 0x03, 0x5c, 0x23, 0x03, 0x53, 0x13, 0x56, 0x88, 0xdf, 0x09, 0xda, + 0x9b, 0xd3, 0xb6, 0x52, 0x0e, 0xec, 0xe4, 0x29, 0x24, 0xfc, 0xd0, 0xe7, + 0x75, 0xe5, 0x57, 0x6b, 0x61, 0xfb, 0xf0, 0xca, 0xaa, 0x57, 0xa8, 0xe6, + 0x78, 0x1a, 0x7d, 0xf9, 0x95, 0x8a, 0x5e, 0xa0, 0xe3, 0x67, 0x8f, 0xa0, + 0xbd, 0x5b, 0xf2, 0xdf, 0x4a, 0x82, 0xcb, 0x4a, 0xb3, 0xb0, 0xb4, 0x41, + 0x0a, 0x70, 0x48, 0xd9, 0x57, 0x60, 0x51, 0x3a, 0x8f, 0xbc, 0xe6, 0x7b, + 0xcb, 0xe4, 0x3b, 0xa7, 0x3f, 0x9b, 0x9f, 0x9a, 0xba, 0x77, 0xe5, 0x5f, + 0x95, 0x9c, 0x59, 0x94, 0x9f, 0xcd, 0x37, 0x8c, 0xa9, 0xa6, 0xd9, 0x39, + 0xaa, 0xd0, 0x7d, 0xa9, 0x1c, 0x03, 0x5e, 0x09, 0xff, 0x00, 0x0c, 0x76, + 0xcb, 0x62, 0x2d, 0xa5, 0xf2, 0x85, 0xbf, 0xe7, 0x87, 0xe6, 0xa3, 0x5e, + 0x4d, 0xa8, 0xc9, 0xe6, 0x8b, 0xd5, 0x69, 0x5c, 0xb0, 0x4a, 0xab, 0xc4, + 0xb5, 0x35, 0x0a, 0xaa, 0xea, 0x40, 0x03, 0xa0, 0xf6, 0xcb, 0x40, 0x4d, + 0x3e, 0xdb, 0xff, 0x00, 0x9c, 0x7f, 0xfc, 0xce, 0x4f, 0xcc, 0xbf, 0x26, + 0x25, 0xe5, 0xd3, 0x2f, 0xe9, 0xdd, 0x3d, 0xfe, 0xab, 0xa9, 0xaa, 0xd2, + 0xa6, 0x40, 0x2a, 0xb2, 0x71, 0x00, 0x01, 0xea, 0x0d, 0xe8, 0x3a, 0x64, + 0x25, 0x16, 0x1c, 0x8b, 0xd9, 0x51, 0x39, 0x28, 0x12, 0x51, 0x41, 0xfd, + 0xa3, 0xd2, 0xb9, 0x4f, 0x0d, 0x33, 0xb5, 0xf4, 0x87, 0x9d, 0x79, 0x0e, + 0xb4, 0xaf, 0x6a, 0xf8, 0xf1, 0xf0, 0xc9, 0xda, 0xbf, 0xff, 0xd6, 0xf2, + 0xc6, 0xb5, 0x68, 0x64, 0xd0, 0x6d, 0x35, 0x20, 0x39, 0xcd, 0x13, 0x0f, + 0x5e, 0x61, 0xfc, 0x8f, 0x40, 0x8b, 0x5e, 0xe0, 0x66, 0x1c, 0x4f, 0xaa, + 0x9d, 0xe6, 0xa6, 0x1e, 0x91, 0x2e, 0xa9, 0x87, 0x95, 0xee, 0x9c, 0xc5, + 0x55, 0x34, 0x60, 0x40, 0xae, 0x57, 0x30, 0xd9, 0xa7, 0x95, 0xbd, 0x6f, + 0xcb, 0x26, 0x39, 0x40, 0x0d, 0x4e, 0xc0, 0x9f, 0x9e, 0x50, 0x5d, 0xac, + 0x79, 0x33, 0x8b, 0xbb, 0x9b, 0x3b, 0x6b, 0x35, 0x48, 0x54, 0x09, 0x29, + 0x56, 0x7f, 0xe1, 0x86, 0x72, 0x00, 0x2c, 0x6e, 0xf7, 0x63, 0x3e, 0x63, + 0xbd, 0xbd, 0x5d, 0x20, 0x2a, 0xb3, 0xa4, 0x33, 0x48, 0xab, 0x21, 0x43, + 0xf1, 0x2c, 0x47, 0xed, 0x1d, 0xbc, 0x73, 0x18, 0x9b, 0x64, 0x28, 0x96, + 0x3a, 0xc7, 0x49, 0xb0, 0xf4, 0xcc, 0xe9, 0x73, 0x6c, 0xb4, 0xf8, 0x67, + 0x92, 0x32, 0x21, 0x70, 0x7b, 0x89, 0x05, 0x57, 0xef, 0x38, 0x28, 0x94, + 0x4a, 0x7d, 0x13, 0x7d, 0x6a, 0xd3, 0x4c, 0xb8, 0xf2, 0xc3, 0xc8, 0x2e, + 0x03, 0xf3, 0xe2, 0x7d, 0x33, 0xb7, 0xc5, 0xcc, 0x71, 0x03, 0xc6, 0xb9, + 0x64, 0x06, 0xe2, 0x9a, 0xf2, 0x4f, 0xd2, 0x6d, 0xe9, 0xfe, 0x41, 0x45, + 0x5b, 0x18, 0x66, 0xa5, 0x64, 0x09, 0xf4, 0xd5, 0xb7, 0xcd, 0x93, 0xc7, + 0xcf, 0x9b, 0xe5, 0x6f, 0xf9, 0xc8, 0x0d, 0x56, 0xeb, 0x59, 0xfc, 0xce, + 0xd5, 0x12, 0x61, 0xc4, 0x69, 0xe9, 0x0d, 0xa4, 0x4b, 0xfe, 0x48, 0x40, + 0xd5, 0x3e, 0xe4, 0xb6, 0x64, 0x8e, 0x4c, 0x02, 0x61, 0x65, 0xa0, 0x14, + 0xb4, 0xb6, 0xb0, 0xb1, 0xb6, 0xb2, 0x97, 0xcb, 0xf1, 0x5a, 0x2d, 0xc6, + 0xa5, 0xac, 0xb4, 0x70, 0x5d, 0xc7, 0x3d, 0xc1, 0x51, 0x24, 0x91, 0xc9, + 0x31, 0x75, 0x6b, 0x70, 0x9f, 0x14, 0x68, 0x01, 0x46, 0xe4, 0xb5, 0xa3, + 0x17, 0xcb, 0x40, 0x61, 0x6f, 0x47, 0xff, 0x00, 0x9c, 0x3a, 0x8f, 0x5b, + 0x4f, 0x3c, 0x6b, 0xb7, 0xfa, 0x30, 0x91, 0x3c, 0xa4, 0xb1, 0x95, 0xb9, + 0x82, 0x42, 0x0a, 0xbc, 0x8e, 0xe4, 0xdb, 0xa9, 0xef, 0xc9, 0x17, 0x91, + 0x24, 0x7c, 0xb2, 0x05, 0x64, 0xfb, 0x75, 0x64, 0x32, 0x39, 0x69, 0x5b, + 0x9c, 0xad, 0xb9, 0xdb, 0xa7, 0xb5, 0x3b, 0x53, 0x2a, 0x21, 0x41, 0x44, + 0xf3, 0x8b, 0x8f, 0x2e, 0x43, 0x9d, 0x2b, 0xd4, 0x57, 0x23, 0x41, 0x36, + 0xff, 0x00, 0xff, 0xd7, 0xf0, 0xc0, 0xd5, 0xb5, 0x11, 0x64, 0xb6, 0x3f, + 0x59, 0x90, 0xd9, 0xab, 0x06, 0xf4, 0x79, 0x7c, 0x3b, 0x74, 0xc8, 0x08, + 0x8b, 0xb6, 0xe3, 0x96, 0x55, 0x57, 0xb3, 0x3e, 0xf2, 0x35, 0xc7, 0xd6, + 0x0b, 0x45, 0x5d, 0xdc, 0x8a, 0x7d, 0xd9, 0x8d, 0x94, 0x3b, 0x3d, 0x1c, + 0x9e, 0xc3, 0xe5, 0xc3, 0x2c, 0x7c, 0xc5, 0x0f, 0xee, 0xdb, 0x8b, 0x0c, + 0xc4, 0x26, 0x9d, 0xa0, 0x9a, 0x7d, 0x2c, 0xe5, 0xe4, 0x55, 0x7f, 0xee, + 0xc1, 0x15, 0x04, 0xd0, 0x12, 0x3c, 0x72, 0x89, 0x1b, 0x2c, 0xcc, 0xa8, + 0x2a, 0x8b, 0x87, 0xbb, 0x63, 0x1a, 0x28, 0x65, 0xf0, 0xed, 0xf2, 0xc3, + 0xc2, 0x0a, 0x06, 0x4a, 0x46, 0xc7, 0xa5, 0xa3, 0x59, 0xc8, 0xb2, 0xc7, + 0x45, 0x22, 0x9c, 0x14, 0x54, 0x10, 0x46, 0xf5, 0x1d, 0x32, 0x5c, 0x14, + 0x14, 0xe4, 0x32, 0x2f, 0x3a, 0xf3, 0xb6, 0x90, 0x9a, 0x6d, 0xae, 0x9f, + 0x3d, 0xab, 0xb8, 0x8a, 0x3b, 0xf8, 0x39, 0x44, 0x58, 0xf0, 0x08, 0xd5, + 0x14, 0xa5, 0x7b, 0x65, 0x98, 0x8e, 0xfb, 0xb5, 0x67, 0x87, 0xa5, 0xef, + 0x5e, 0x44, 0x96, 0x35, 0xb5, 0xb6, 0x59, 0x36, 0xfd, 0xd8, 0xa0, 0xf1, + 0x20, 0x53, 0x33, 0xc0, 0x79, 0x59, 0x73, 0x7c, 0xd7, 0xf9, 0xfb, 0xa2, + 0xcd, 0x67, 0xf9, 0xa7, 0x7b, 0x72, 0xf1, 0x71, 0x83, 0x53, 0x86, 0x0b, + 0x98, 0x24, 0x22, 0x8a, 0xcc, 0x88, 0x23, 0x7f, 0xb8, 0xae, 0xf9, 0x7c, + 0x50, 0x1e, 0x5f, 0x7c, 0x48, 0x21, 0x44, 0x6b, 0xce, 0x9b, 0xb0, 0x1b, + 0x9e, 0xf5, 0xaf, 0x8e, 0x4d, 0x5f, 0x7a, 0x7f, 0xce, 0x34, 0xf9, 0x5d, + 0x3c, 0xa3, 0xf9, 0x69, 0x63, 0xa9, 0x3c, 0x27, 0xeb, 0xda, 0xe1, 0x37, + 0xd7, 0x2e, 0xaa, 0xdb, 0x06, 0xda, 0x30, 0x49, 0xfe, 0x54, 0x03, 0x03, + 0x49, 0xdc, 0xb3, 0xaf, 0x38, 0xfe, 0x6a, 0xf9, 0x47, 0xc9, 0x3a, 0x74, + 0x97, 0xfa, 0xf6, 0xaf, 0x15, 0x85, 0xb8, 0x75, 0x89, 0xb8, 0x87, 0x9a, + 0x72, 0xee, 0x2a, 0x14, 0x24, 0x60, 0xb1, 0xa8, 0xdf, 0x07, 0x0b, 0x2d, + 0xcb, 0xcf, 0x7f, 0xe8, 0x6a, 0xff, 0x00, 0x26, 0xbd, 0x6a, 0x7f, 0x89, + 0x2f, 0xf8, 0x52, 0x9e, 0xb7, 0xe8, 0xb9, 0xb8, 0x57, 0xc2, 0x95, 0xe9, + 0x8f, 0x08, 0x5a, 0x2f, 0xff, 0xd0, 0xf0, 0x4d, 0x40, 0xaa, 0xd7, 0x00, + 0x64, 0xcb, 0x3c, 0x97, 0xa8, 0xb5, 0x9e, 0xa3, 0x1a, 0xd6, 0x84, 0x95, + 0x3f, 0x45, 0x72, 0x9c, 0xa2, 0xc3, 0x99, 0xa5, 0x9d, 0x49, 0xf4, 0x17, + 0x97, 0xaf, 0x63, 0x17, 0x52, 0x6f, 0xf0, 0xc8, 0x43, 0x6f, 0x9a, 0xe9, + 0x07, 0x70, 0x0e, 0xec, 0x83, 0x51, 0x44, 0xb8, 0x61, 0x1a, 0x9e, 0x11, + 0xd3, 0x91, 0x60, 0x68, 0x6b, 0xd3, 0x31, 0x4f, 0x36, 0xd3, 0x4c, 0x52, + 0xef, 0x4c, 0xd5, 0x0c, 0xc4, 0x69, 0xda, 0x94, 0xc8, 0x3a, 0xf0, 0x66, + 0x07, 0x73, 0xe0, 0x40, 0xfd, 0x79, 0x93, 0x12, 0x1c, 0x9c, 0x32, 0xc7, + 0xfc, 0x41, 0x33, 0xd2, 0xb4, 0x6f, 0x38, 0x98, 0x65, 0x76, 0xbf, 0x69, + 0x42, 0xd0, 0xaa, 0xc9, 0xde, 0x95, 0xad, 0x28, 0x46, 0x4e, 0xac, 0x39, + 0x77, 0x80, 0x11, 0xbf, 0xd8, 0xc7, 0x7c, 0xe1, 0xa5, 0xf9, 0x92, 0x4d, + 0x32, 0x5b, 0x8b, 0x93, 0x27, 0xa7, 0x68, 0x56, 0xe2, 0x45, 0xda, 0x85, + 0x61, 0x6e, 0x67, 0xad, 0x6b, 0xb0, 0x38, 0xc2, 0x81, 0xe4, 0xc7, 0x52, + 0x31, 0x1c, 0x67, 0x86, 0x5b, 0xbd, 0x37, 0xca, 0x7a, 0x94, 0xb1, 0x69, + 0xb6, 0x2e, 0xb7, 0x15, 0x48, 0xc2, 0xb4, 0x52, 0x53, 0xac, 0x32, 0xaf, + 0xb1, 0xed, 0x9b, 0x10, 0x36, 0x78, 0x5c, 0x9f, 0x51, 0x64, 0x1f, 0x98, + 0x3e, 0x58, 0xb6, 0xfc, 0xc8, 0xf2, 0xe5, 0xbc, 0x68, 0x52, 0x2d, 0x5a, + 0xd1, 0x84, 0xb6, 0xf3, 0x95, 0x0e, 0xc0, 0x85, 0xe2, 0xcb, 0xd8, 0xd1, + 0xbb, 0xe4, 0xc1, 0xa6, 0x97, 0xce, 0x17, 0x5f, 0x95, 0xde, 0x6d, 0xb6, + 0xbe, 0xb7, 0x69, 0x34, 0xf3, 0x3c, 0x72, 0xcf, 0xe8, 0xa3, 0x45, 0x49, + 0x95, 0x4a, 0x90, 0x3e, 0x35, 0x5a, 0x95, 0x1d, 0xfe, 0x21, 0x93, 0x4d, + 0xbe, 0xd2, 0xd2, 0xf5, 0x8b, 0xbd, 0x32, 0x2d, 0x3f, 0x4c, 0x9a, 0xe4, + 0xca, 0x9e, 0x90, 0x85, 0x65, 0x55, 0x08, 0x85, 0x91, 0x01, 0x3b, 0x0a, + 0x05, 0xe9, 0xb0, 0xc0, 0x5a, 0xc3, 0xcd, 0x3f, 0x3b, 0x7f, 0x26, 0xec, + 0xff, 0x00, 0x35, 0x6d, 0x6d, 0xb5, 0x3d, 0x16, 0xfe, 0x0d, 0x3b, 0xcd, + 0x96, 0x01, 0x92, 0x46, 0x9e, 0xa2, 0x0b, 0xc8, 0xb7, 0x28, 0x92, 0x71, + 0xfb, 0x2e, 0xa7, 0xec, 0x3d, 0x0f, 0xc2, 0x68, 0x71, 0x05, 0x95, 0xd3, + 0xe7, 0x9f, 0xfa, 0x16, 0x2f, 0xcd, 0x7f, 0x43, 0xd6, 0xfa, 0xa5, 0x97, + 0xab, 0xeb, 0x7a, 0x5f, 0x55, 0xfa, 0xec, 0x5e, 0xaf, 0x0f, 0xf7, 0xed, + 0x2b, 0x4e, 0x15, 0xff, 0x00, 0x65, 0xdf, 0x8e, 0x14, 0xf1, 0xbf, 0xff, + 0xd1, 0xf0, 0x5a, 0xa7, 0x18, 0x5e, 0x56, 0x1f, 0x68, 0x71, 0x5f, 0xa7, + 0xbe, 0x2a, 0x98, 0xdb, 0xfa, 0x90, 0x24, 0x37, 0xb0, 0xfd, 0xb8, 0xa8, + 0x58, 0x78, 0xae, 0x43, 0xc9, 0xb4, 0x6d, 0xbb, 0xda, 0x3c, 0xa1, 0xad, + 0x43, 0xa8, 0xda, 0xc5, 0x2a, 0x3d, 0x26, 0x5a, 0x02, 0x2b, 0xbe, 0x60, + 0x64, 0x8d, 0x17, 0x6f, 0x8b, 0x20, 0x90, 0x7a, 0x3c, 0x32, 0x8b, 0xa8, + 0x02, 0xf3, 0xfd, 0xe0, 0x1b, 0x11, 0x98, 0x66, 0x3b, 0xb9, 0x62, 0x54, + 0x83, 0x36, 0xf2, 0xa4, 0xe4, 0x29, 0x34, 0xeb, 0xc8, 0x74, 0xae, 0x0d, + 0xc3, 0x65, 0x82, 0x13, 0x6b, 0x57, 0xba, 0x54, 0xe4, 0x8c, 0x41, 0x1b, + 0x75, 0xa7, 0xe0, 0x72, 0x5c, 0x4c, 0x84, 0x50, 0x5a, 0xb3, 0xdd, 0xdd, + 0xc3, 0x24, 0x33, 0xb1, 0x60, 0xe0, 0x86, 0x52, 0x45, 0x38, 0xd2, 0x87, + 0x24, 0x26, 0x6d, 0x8c, 0xe1, 0x41, 0x25, 0xfc, 0xa3, 0xd7, 0x2f, 0x6f, + 0x3c, 0xbf, 0x73, 0xa5, 0xb2, 0x2c, 0xd1, 0x69, 0x17, 0x2f, 0x6b, 0x14, + 0x8c, 0x0f, 0x21, 0x0d, 0x79, 0x46, 0x09, 0x15, 0xed, 0xb7, 0x4e, 0xd9, + 0xb9, 0x8b, 0xcb, 0xe4, 0xa2, 0x5e, 0xa3, 0xa6, 0xdf, 0x6a, 0x36, 0xe4, + 0xcd, 0x69, 0x1c, 0x4e, 0x84, 0x7c, 0x76, 0xab, 0x21, 0x67, 0xa8, 0xa7, + 0xd9, 0xf8, 0x4d, 0x2b, 0xf3, 0xc3, 0x4d, 0x49, 0x57, 0x98, 0x75, 0x6f, + 0x31, 0xda, 0xf9, 0xa3, 0x4b, 0xfd, 0x1f, 0x69, 0x1d, 0xae, 0xa1, 0xa9, + 0x7e, 0xee, 0xe6, 0xd2, 0x79, 0x18, 0xf3, 0xb5, 0x1f, 0xee, 0xd9, 0x0a, + 0x01, 0x4e, 0x3f, 0xb3, 0x4d, 0xf2, 0x9c, 0xb9, 0x04, 0x05, 0xb7, 0xe2, + 0x87, 0x1e, 0xdd, 0x19, 0x3e, 0xaf, 0x6b, 0xae, 0xcb, 0x6d, 0x13, 0x0d, + 0x45, 0xa2, 0x8e, 0x06, 0xe5, 0x13, 0x2a, 0x02, 0x01, 0x5e, 0x82, 0xb5, + 0x04, 0xe6, 0x11, 0xd4, 0xcd, 0xda, 0x43, 0x49, 0x8e, 0xb7, 0xdc, 0xb1, + 0x51, 0xe6, 0x4d, 0x76, 0xd2, 0x61, 0x15, 0xaa, 0x4b, 0xa8, 0xc9, 0x6e, + 0x49, 0x79, 0x20, 0xe6, 0x8c, 0x49, 0xad, 0x43, 0x16, 0xe4, 0xa7, 0xaf, + 0x43, 0xd3, 0x26, 0x35, 0x75, 0xcd, 0xa8, 0xe8, 0x87, 0x46, 0xbf, 0xc7, + 0x9a, 0xff, 0x00, 0xd6, 0xbf, 0x48, 0xfe, 0x88, 0xfd, 0xe7, 0x0f, 0xab, + 0xfa, 0x3f, 0x58, 0x7f, 0x5f, 0x8d, 0x3f, 0x9f, 0xa7, 0x5e, 0xd4, 0xc3, + 0xf9, 0xd1, 0x7c, 0xb6, 0x47, 0xe4, 0x3a, 0x5b, 0xff, 0xd2, 0xf0, 0xb7, + 0xa6, 0x1e, 0xdf, 0xd3, 0xf6, 0xa5, 0x71, 0x54, 0xdb, 0x4b, 0x80, 0x3c, + 0x42, 0x26, 0xee, 0x29, 0xbe, 0x51, 0x23, 0x4e, 0x44, 0x05, 0x84, 0x45, + 0xa5, 0xd5, 0xf7, 0x97, 0x2e, 0xfd, 0x6b, 0x6a, 0x98, 0x09, 0xab, 0xc7, + 0xfc, 0x46, 0x3b, 0x4c, 0x26, 0x32, 0x30, 0x3e, 0x4f, 0x49, 0xd0, 0xfc, + 0xfb, 0x05, 0xd4, 0x4a, 0x7d, 0x40, 0xac, 0x3a, 0x8e, 0x84, 0x1c, 0xc5, + 0x96, 0x2a, 0x73, 0xe1, 0x9c, 0x16, 0x6d, 0xa5, 0x79, 0x86, 0xd6, 0xec, + 0x80, 0x5a, 0xa0, 0xf5, 0xca, 0xcc, 0x5c, 0xa1, 0x2b, 0x1b, 0x26, 0x30, + 0x6a, 0x31, 0x46, 0xcf, 0x1c, 0x87, 0x94, 0x64, 0x9e, 0x3d, 0xb6, 0xf0, + 0xca, 0xa8, 0x39, 0x51, 0x99, 0x42, 0x6b, 0x1a, 0xc5, 0xa5, 0xa5, 0x94, + 0xf7, 0x92, 0xc8, 0xaa, 0xb1, 0x23, 0x30, 0x04, 0xf8, 0x0e, 0x9f, 0x4e, + 0x4a, 0x11, 0xb2, 0xd5, 0x9b, 0x25, 0x06, 0x1b, 0xff, 0x00, 0x38, 0xfd, + 0xad, 0xdf, 0xda, 0xf9, 0xa2, 0xfe, 0xc5, 0x42, 0xbe, 0x9b, 0x7f, 0x0b, + 0xdd, 0xdd, 0x07, 0xaf, 0x14, 0x68, 0xd8, 0x71, 0x6d, 0xbb, 0x90, 0xfc, + 0x73, 0x6e, 0xf2, 0xf2, 0xdd, 0xf4, 0xad, 0xa6, 0xab, 0x6d, 0x69, 0x14, + 0xfa, 0xee, 0xa0, 0xe2, 0x0b, 0x0d, 0x39, 0x19, 0xfe, 0x11, 0xc5, 0x1a, + 0x4a, 0x1d, 0x8f, 0x73, 0x4f, 0xf8, 0x96, 0x0b, 0x40, 0x8d, 0xec, 0xf3, + 0x6d, 0x3f, 0x52, 0xba, 0xd6, 0x35, 0x8b, 0xbf, 0x36, 0x6a, 0x5f, 0x0d, + 0xc5, 0xdc, 0xa8, 0xb6, 0xa8, 0x7a, 0xc5, 0x6c, 0x9b, 0x22, 0x0f, 0xa3, + 0x73, 0x9a, 0xbc, 0xb3, 0xe2, 0x36, 0xed, 0xb1, 0x43, 0x80, 0x53, 0xd0, + 0xa7, 0xd4, 0x44, 0xfa, 0x7a, 0xda, 0x83, 0xbd, 0x3e, 0x2f, 0xa7, 0x2b, + 0xad, 0x9b, 0xb8, 0x8d, 0xa8, 0xe8, 0x91, 0xdb, 0xfa, 0x2d, 0x6f, 0xc3, + 0x8a, 0x2d, 0x56, 0xa3, 0xad, 0x4f, 0x5c, 0xa4, 0x0d, 0xdc, 0xa3, 0xca, + 0xd0, 0xbf, 0xa1, 0xe3, 0xfa, 0xe7, 0x0f, 0xf2, 0xb9, 0x57, 0xbf, 0x1a, + 0xe4, 0xb8, 0x57, 0xc5, 0xdd, 0xff, 0xd3, 0xf0, 0xcc, 0x5d, 0x7b, 0x70, + 0xc5, 0x53, 0x6d, 0x2f, 0xd5, 0xe4, 0x69, 0xfd, 0xdf, 0xec, 0xd7, 0xad, + 0x7d, 0xb2, 0x8c, 0x8d, 0xd8, 0xed, 0x91, 0x9f, 0x43, 0xea, 0xe7, 0xeb, + 0x94, 0xad, 0x3e, 0x1e, 0x95, 0xfc, 0x72, 0x81, 0x7d, 0x1c, 0x9d, 0xba, + 0xb1, 0x7b, 0xdf, 0xa9, 0x7a, 0xdf, 0xee, 0x2f, 0xd4, 0xfa, 0xe7, 0xed, + 0x7a, 0x7f, 0xdd, 0xff, 0x00, 0xb2, 0xae, 0x64, 0x0b, 0xea, 0xe3, 0x9a, + 0xbf, 0x4a, 0x6f, 0xa4, 0xff, 0x00, 0x89, 0xbd, 0x45, 0xfa, 0xb5, 0x79, + 0xf7, 0xeb, 0xc7, 0xe9, 0xae, 0x57, 0x2e, 0x17, 0x23, 0x1f, 0x89, 0xd1, + 0x99, 0x8f, 0xf1, 0xa7, 0x11, 0xcf, 0xd3, 0xf5, 0x29, 0xb5, 0x6b, 0xd3, + 0xe8, 0xcc, 0x7f, 0x45, 0xb9, 0xa3, 0xc5, 0x62, 0xbe, 0x68, 0xff, 0x00, + 0x15, 0xfd, 0x4c, 0xfe, 0x90, 0xaf, 0xd4, 0xab, 0xf1, 0x7a, 0x7f, 0x62, + 0x9d, 0xab, 0xdf, 0x32, 0xb1, 0x70, 0x5e, 0xdc, 0xdc, 0x2d, 0x47, 0x8b, + 0x5e, 0xae, 0x4c, 0xbf, 0xf2, 0x37, 0x9f, 0x3d, 0x5b, 0xd2, 0xff, 0x00, + 0x8e, 0x87, 0xee, 0x29, 0x5a, 0xf2, 0xf4, 0xaa, 0xd4, 0xa5, 0x36, 0xa7, + 0x3a, 0x57, 0xfd, 0x8e, 0x64, 0x3a, 0xf2, 0xf6, 0xbf, 0xcc, 0x7f, 0x5b, + 0xfc, 0x23, 0xa7, 0xfe, 0x8e, 0xff, 0x00, 0x8e, 0x37, 0xd6, 0x63, 0xfa, + 0xe5, 0x2b, 0xcb, 0x87, 0xec, 0xd6, 0xbd, 0xb9, 0x7d, 0xac, 0xc7, 0xcd, + 0x7c, 0x2d, 0xf8, 0x2b, 0x89, 0x26, 0x8f, 0xd4, 0xfa, 0x94, 0x3e, 0x85, + 0x29, 0xc9, 0x69, 0xfc, 0x33, 0x58, 0x5d, 0x9c, 0x79, 0xb2, 0xbb, 0x0f, + 0xac, 0x7a, 0x2b, 0xea, 0x75, 0xef, 0x92, 0x0c, 0x53, 0x3d, 0x2f, 0xd4, + 0xfa, 0xbb, 0xfa, 0x74, 0xf5, 0x39, 0x9a, 0xd7, 0xe7, 0x80, 0x53, 0x79, + 0xba, 0x5b, 0xfe, 0x97, 0xfa, 0x4b, 0xfc, 0xba, 0x7f, 0xb1, 0xc7, 0xab, + 0x1e, 0x8f, 0xff, 0xd9}; + +#endif // RTC_BASE_TEST_BASE64_H_ diff --git a/third_party/libwebrtc/rtc_base/test_certificate_verifier.h b/third_party/libwebrtc/rtc_base/test_certificate_verifier.h new file mode 100644 index 0000000000..9775615b5d --- /dev/null +++ b/third_party/libwebrtc/rtc_base/test_certificate_verifier.h @@ -0,0 +1,34 @@ +/* + * 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 RTC_BASE_TEST_CERTIFICATE_VERIFIER_H_ +#define RTC_BASE_TEST_CERTIFICATE_VERIFIER_H_ + +#include "rtc_base/ssl_certificate.h" + +namespace rtc { + +class TestCertificateVerifier : public SSLCertificateVerifier { + public: + TestCertificateVerifier() = default; + ~TestCertificateVerifier() override = default; + + bool Verify(const SSLCertificate& certificate) override { + call_count_++; + return verify_certificate_; + } + + size_t call_count_ = 0; + bool verify_certificate_ = true; +}; + +} // namespace rtc + +#endif // RTC_BASE_TEST_CERTIFICATE_VERIFIER_H_ diff --git a/third_party/libwebrtc/rtc_base/test_client.cc b/third_party/libwebrtc/rtc_base/test_client.cc new file mode 100644 index 0000000000..f23ac2aec0 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/test_client.cc @@ -0,0 +1,180 @@ +/* + * 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 "rtc_base/test_client.h" + +#include <string.h> + +#include <memory> +#include <utility> + +#include "rtc_base/gunit.h" +#include "rtc_base/thread.h" +#include "rtc_base/time_utils.h" + +namespace rtc { + +// DESIGN: Each packet received is put it into a list of packets. +// Callers can retrieve received packets from any thread by calling +// NextPacket. + +TestClient::TestClient(std::unique_ptr<AsyncPacketSocket> socket) + : TestClient(std::move(socket), nullptr) {} + +TestClient::TestClient(std::unique_ptr<AsyncPacketSocket> socket, + ThreadProcessingFakeClock* fake_clock) + : fake_clock_(fake_clock), + socket_(std::move(socket)), + prev_packet_timestamp_(-1) { + socket_->SignalReadPacket.connect(this, &TestClient::OnPacket); + socket_->SignalReadyToSend.connect(this, &TestClient::OnReadyToSend); +} + +TestClient::~TestClient() {} + +bool TestClient::CheckConnState(AsyncPacketSocket::State state) { + // Wait for our timeout value until the socket reaches the desired state. + int64_t end = TimeAfter(kTimeoutMs); + while (socket_->GetState() != state && TimeUntil(end) > 0) { + AdvanceTime(1); + } + return (socket_->GetState() == state); +} + +int TestClient::Send(const char* buf, size_t size) { + rtc::PacketOptions options; + return socket_->Send(buf, size, options); +} + +int TestClient::SendTo(const char* buf, + size_t size, + const SocketAddress& dest) { + rtc::PacketOptions options; + return socket_->SendTo(buf, size, dest, options); +} + +std::unique_ptr<TestClient::Packet> TestClient::NextPacket(int timeout_ms) { + // If no packets are currently available, we go into a get/dispatch loop for + // at most timeout_ms. If, during the loop, a packet arrives, then we can + // stop early and return it. + + // Note that the case where no packet arrives is important. We often want to + // test that a packet does not arrive. + + // Note also that we only try to pump our current thread's message queue. + // Pumping another thread's queue could lead to messages being dispatched from + // the wrong thread to non-thread-safe objects. + + int64_t end = TimeAfter(timeout_ms); + while (TimeUntil(end) > 0) { + { + webrtc::MutexLock lock(&mutex_); + if (packets_.size() != 0) { + break; + } + } + AdvanceTime(1); + } + + // Return the first packet placed in the queue. + std::unique_ptr<Packet> packet; + webrtc::MutexLock lock(&mutex_); + if (packets_.size() > 0) { + packet = std::move(packets_.front()); + packets_.erase(packets_.begin()); + } + + return packet; +} + +bool TestClient::CheckNextPacket(const char* buf, + size_t size, + SocketAddress* addr) { + bool res = false; + std::unique_ptr<Packet> packet = NextPacket(kTimeoutMs); + if (packet) { + res = (packet->size == size && memcmp(packet->buf, buf, size) == 0 && + CheckTimestamp(packet->packet_time_us)); + if (addr) + *addr = packet->addr; + } + return res; +} + +bool TestClient::CheckTimestamp(int64_t packet_timestamp) { + bool res = true; + if (packet_timestamp == -1) { + res = false; + } + if (prev_packet_timestamp_ != -1) { + if (packet_timestamp < prev_packet_timestamp_) { + res = false; + } + } + prev_packet_timestamp_ = packet_timestamp; + return res; +} + +void TestClient::AdvanceTime(int ms) { + // If the test is using a fake clock, we must advance the fake clock to + // advance time. Otherwise, ProcessMessages will work. + if (fake_clock_) { + SIMULATED_WAIT(false, ms, *fake_clock_); + } else { + Thread::Current()->ProcessMessages(1); + } +} + +bool TestClient::CheckNoPacket() { + return NextPacket(kNoPacketTimeoutMs) == nullptr; +} + +int TestClient::GetError() { + return socket_->GetError(); +} + +int TestClient::SetOption(Socket::Option opt, int value) { + return socket_->SetOption(opt, value); +} + +void TestClient::OnPacket(AsyncPacketSocket* socket, + const char* buf, + size_t size, + const SocketAddress& remote_addr, + const int64_t& packet_time_us) { + webrtc::MutexLock lock(&mutex_); + packets_.push_back( + std::make_unique<Packet>(remote_addr, buf, size, packet_time_us)); +} + +void TestClient::OnReadyToSend(AsyncPacketSocket* socket) { + ++ready_to_send_count_; +} + +TestClient::Packet::Packet(const SocketAddress& a, + const char* b, + size_t s, + int64_t packet_time_us) + : addr(a), buf(0), size(s), packet_time_us(packet_time_us) { + buf = new char[size]; + memcpy(buf, b, size); +} + +TestClient::Packet::Packet(const Packet& p) + : addr(p.addr), buf(0), size(p.size), packet_time_us(p.packet_time_us) { + buf = new char[size]; + memcpy(buf, p.buf, size); +} + +TestClient::Packet::~Packet() { + delete[] buf; +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/test_client.h b/third_party/libwebrtc/rtc_base/test_client.h new file mode 100644 index 0000000000..dd91d37ab9 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/test_client.h @@ -0,0 +1,119 @@ +/* + * 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 RTC_BASE_TEST_CLIENT_H_ +#define RTC_BASE_TEST_CLIENT_H_ + +#include <memory> +#include <vector> + +#include "rtc_base/async_udp_socket.h" +#include "rtc_base/fake_clock.h" +#include "rtc_base/synchronization/mutex.h" + +namespace rtc { + +// A simple client that can send TCP or UDP data and check that it receives +// what it expects to receive. Useful for testing server functionality. +class TestClient : public sigslot::has_slots<> { + public: + // Records the contents of a packet that was received. + struct Packet { + Packet(const SocketAddress& a, + const char* b, + size_t s, + int64_t packet_time_us); + Packet(const Packet& p); + virtual ~Packet(); + + SocketAddress addr; + char* buf; + size_t size; + int64_t packet_time_us; + }; + + // Default timeout for NextPacket reads. + static const int kTimeoutMs = 5000; + + // Creates a client that will send and receive with the given socket and + // will post itself messages with the given thread. + explicit TestClient(std::unique_ptr<AsyncPacketSocket> socket); + // Create a test client that will use a fake clock. NextPacket needs to wait + // for a packet to be received, and thus it needs to advance the fake clock + // if the test is using one, rather than just sleeping. + TestClient(std::unique_ptr<AsyncPacketSocket> socket, + ThreadProcessingFakeClock* fake_clock); + ~TestClient() override; + + TestClient(const TestClient&) = delete; + TestClient& operator=(const TestClient&) = delete; + + SocketAddress address() const { return socket_->GetLocalAddress(); } + SocketAddress remote_address() const { return socket_->GetRemoteAddress(); } + + // Checks that the socket moves to the specified connect state. + bool CheckConnState(AsyncPacketSocket::State state); + + // Checks that the socket is connected to the remote side. + bool CheckConnected() { + return CheckConnState(AsyncPacketSocket::STATE_CONNECTED); + } + + // Sends using the clients socket. + int Send(const char* buf, size_t size); + + // Sends using the clients socket to the given destination. + int SendTo(const char* buf, size_t size, const SocketAddress& dest); + + // Returns the next packet received by the client or null if none is received + // within the specified timeout. + std::unique_ptr<Packet> NextPacket(int timeout_ms); + + // Checks that the next packet has the given contents. Returns the remote + // address that the packet was sent from. + bool CheckNextPacket(const char* buf, size_t len, SocketAddress* addr); + + // Checks that no packets have arrived or will arrive in the next second. + bool CheckNoPacket(); + + int GetError(); + int SetOption(Socket::Option opt, int value); + + bool ready_to_send() const { return ready_to_send_count() > 0; } + + // How many times SignalReadyToSend has been fired. + int ready_to_send_count() const { return ready_to_send_count_; } + + private: + // Timeout for reads when no packet is expected. + static const int kNoPacketTimeoutMs = 1000; + // Workaround for the fact that AsyncPacketSocket::GetConnState doesn't exist. + Socket::ConnState GetState(); + // Slot for packets read on the socket. + void OnPacket(AsyncPacketSocket* socket, + const char* buf, + size_t len, + const SocketAddress& remote_addr, + const int64_t& packet_time_us); + void OnReadyToSend(AsyncPacketSocket* socket); + bool CheckTimestamp(int64_t packet_timestamp); + void AdvanceTime(int ms); + + ThreadProcessingFakeClock* fake_clock_ = nullptr; + webrtc::Mutex mutex_; + std::unique_ptr<AsyncPacketSocket> socket_; + std::vector<std::unique_ptr<Packet>> packets_; + int ready_to_send_count_ = 0; + int64_t prev_packet_timestamp_; +}; + +} // namespace rtc + +#endif // RTC_BASE_TEST_CLIENT_H_ diff --git a/third_party/libwebrtc/rtc_base/test_client_unittest.cc b/third_party/libwebrtc/rtc_base/test_client_unittest.cc new file mode 100644 index 0000000000..b2866a2d34 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/test_client_unittest.cc @@ -0,0 +1,108 @@ +/* + * Copyright 2006 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 "rtc_base/test_client.h" + +#include <utility> + +#include "absl/memory/memory.h" +#include "rtc_base/async_tcp_socket.h" +#include "rtc_base/async_udp_socket.h" +#include "rtc_base/logging.h" +#include "rtc_base/net_helpers.h" +#include "rtc_base/net_test_helpers.h" +#include "rtc_base/physical_socket_server.h" +#include "rtc_base/socket.h" +#include "rtc_base/test_echo_server.h" +#include "rtc_base/thread.h" +#include "test/gtest.h" + +namespace rtc { +namespace { + +#define MAYBE_SKIP_IPV4 \ + if (!HasIPv4Enabled()) { \ + RTC_LOG(LS_INFO) << "No IPv4... skipping"; \ + return; \ + } + +#define MAYBE_SKIP_IPV6 \ + if (!HasIPv6Enabled()) { \ + RTC_LOG(LS_INFO) << "No IPv6... skipping"; \ + return; \ + } + +void TestUdpInternal(const SocketAddress& loopback) { + rtc::PhysicalSocketServer socket_server; + rtc::AutoSocketServerThread main_thread(&socket_server); + Socket* socket = socket_server.CreateSocket(loopback.family(), SOCK_DGRAM); + socket->Bind(loopback); + + TestClient client(std::make_unique<AsyncUDPSocket>(socket)); + SocketAddress addr = client.address(), from; + EXPECT_EQ(3, client.SendTo("foo", 3, addr)); + EXPECT_TRUE(client.CheckNextPacket("foo", 3, &from)); + EXPECT_EQ(from, addr); + EXPECT_TRUE(client.CheckNoPacket()); +} + +void TestTcpInternal(const SocketAddress& loopback) { + rtc::PhysicalSocketServer socket_server; + rtc::AutoSocketServerThread main_thread(&socket_server); + TestEchoServer server(&main_thread, loopback); + + Socket* socket = socket_server.CreateSocket(loopback.family(), SOCK_STREAM); + std::unique_ptr<AsyncTCPSocket> tcp_socket = absl::WrapUnique( + AsyncTCPSocket::Create(socket, loopback, server.address())); + ASSERT_TRUE(tcp_socket != nullptr); + + TestClient client(std::move(tcp_socket)); + SocketAddress addr = client.address(), from; + EXPECT_TRUE(client.CheckConnected()); + EXPECT_EQ(3, client.Send("foo", 3)); + EXPECT_TRUE(client.CheckNextPacket("foo", 3, &from)); + EXPECT_EQ(from, server.address()); + EXPECT_TRUE(client.CheckNoPacket()); +} + +// Tests whether the TestClient can send UDP to itself. +TEST(TestClientTest, TestUdpIPv4) { + MAYBE_SKIP_IPV4; + TestUdpInternal(SocketAddress("127.0.0.1", 0)); +} + +#if defined(WEBRTC_LINUX) +#define MAYBE_TestUdpIPv6 DISABLED_TestUdpIPv6 +#else +#define MAYBE_TestUdpIPv6 TestUdpIPv6 +#endif +TEST(TestClientTest, MAYBE_TestUdpIPv6) { + MAYBE_SKIP_IPV6; + TestUdpInternal(SocketAddress("::1", 0)); +} + +// Tests whether the TestClient can connect to a server and exchange data. +TEST(TestClientTest, TestTcpIPv4) { + MAYBE_SKIP_IPV4; + TestTcpInternal(SocketAddress("127.0.0.1", 0)); +} + +#if defined(WEBRTC_LINUX) +#define MAYBE_TestTcpIPv6 DISABLED_TestTcpIPv6 +#else +#define MAYBE_TestTcpIPv6 TestTcpIPv6 +#endif +TEST(TestClientTest, MAYBE_TestTcpIPv6) { + MAYBE_SKIP_IPV6; + TestTcpInternal(SocketAddress("::1", 0)); +} + +} // namespace +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/test_echo_server.cc b/third_party/libwebrtc/rtc_base/test_echo_server.cc new file mode 100644 index 0000000000..feda4cd8ae --- /dev/null +++ b/third_party/libwebrtc/rtc_base/test_echo_server.cc @@ -0,0 +1,32 @@ +/* + * Copyright 2017 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 "rtc_base/test_echo_server.h" + +#include "rtc_base/socket_server.h" + +namespace rtc { + +TestEchoServer::TestEchoServer(Thread* thread, const SocketAddress& addr) + : server_socket_( + thread->socketserver()->CreateSocket(addr.family(), SOCK_STREAM)) { + server_socket_->Bind(addr); + server_socket_->Listen(5); + server_socket_->SignalReadEvent.connect(this, &TestEchoServer::OnAccept); +} + +TestEchoServer::~TestEchoServer() { + for (ClientList::iterator it = client_sockets_.begin(); + it != client_sockets_.end(); ++it) { + delete *it; + } +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/test_echo_server.h b/third_party/libwebrtc/rtc_base/test_echo_server.h new file mode 100644 index 0000000000..82817624a5 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/test_echo_server.h @@ -0,0 +1,77 @@ +/* + * 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 RTC_BASE_TEST_ECHO_SERVER_H_ +#define RTC_BASE_TEST_ECHO_SERVER_H_ + +#include <stddef.h> +#include <stdint.h> + +#include <list> +#include <memory> + +#include "absl/algorithm/container.h" +#include "absl/memory/memory.h" +#include "rtc_base/async_packet_socket.h" +#include "rtc_base/async_tcp_socket.h" +#include "rtc_base/socket.h" +#include "rtc_base/socket_address.h" +#include "rtc_base/third_party/sigslot/sigslot.h" +#include "rtc_base/thread.h" + +namespace rtc { + +// A test echo server, echoes back any packets sent to it. +// Useful for unit tests. +class TestEchoServer : public sigslot::has_slots<> { + public: + TestEchoServer(Thread* thread, const SocketAddress& addr); + ~TestEchoServer() override; + + TestEchoServer(const TestEchoServer&) = delete; + TestEchoServer& operator=(const TestEchoServer&) = delete; + + SocketAddress address() const { return server_socket_->GetLocalAddress(); } + + private: + void OnAccept(Socket* socket) { + Socket* raw_socket = socket->Accept(nullptr); + if (raw_socket) { + AsyncTCPSocket* packet_socket = new AsyncTCPSocket(raw_socket); + packet_socket->SignalReadPacket.connect(this, &TestEchoServer::OnPacket); + packet_socket->SubscribeCloseEvent( + this, [this](AsyncPacketSocket* s, int err) { OnClose(s, err); }); + client_sockets_.push_back(packet_socket); + } + } + void OnPacket(AsyncPacketSocket* socket, + const char* buf, + size_t size, + const SocketAddress& remote_addr, + const int64_t& /* packet_time_us */) { + rtc::PacketOptions options; + socket->Send(buf, size, options); + } + void OnClose(AsyncPacketSocket* socket, int err) { + ClientList::iterator it = absl::c_find(client_sockets_, socket); + client_sockets_.erase(it); + // `OnClose` is triggered by socket Close callback, deleting `socket` while + // processing that callback might be unsafe. + Thread::Current()->PostTask([socket = absl::WrapUnique(socket)] {}); + } + + typedef std::list<AsyncTCPSocket*> ClientList; + std::unique_ptr<Socket> server_socket_; + ClientList client_sockets_; +}; + +} // namespace rtc + +#endif // RTC_BASE_TEST_ECHO_SERVER_H_ diff --git a/third_party/libwebrtc/rtc_base/test_utils.cc b/third_party/libwebrtc/rtc_base/test_utils.cc new file mode 100644 index 0000000000..ecf2cfa6ec --- /dev/null +++ b/third_party/libwebrtc/rtc_base/test_utils.cc @@ -0,0 +1,20 @@ +/* + * Copyright 2007 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 "rtc_base/test_utils.h" + +namespace webrtc { +namespace testing { + +StreamSink::StreamSink() = default; +StreamSink::~StreamSink() = default; + +} // namespace testing +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/test_utils.h b/third_party/libwebrtc/rtc_base/test_utils.h new file mode 100644 index 0000000000..3f877fc9af --- /dev/null +++ b/third_party/libwebrtc/rtc_base/test_utils.h @@ -0,0 +1,99 @@ +/* + * 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 RTC_BASE_TEST_UTILS_H_ +#define RTC_BASE_TEST_UTILS_H_ + +// Utilities for testing rtc infrastructure in unittests + +#include <map> +#include <utility> + +#include "rtc_base/socket.h" +#include "rtc_base/third_party/sigslot/sigslot.h" + +namespace webrtc { +namespace testing { + +/////////////////////////////////////////////////////////////////////////////// +// StreamSink - Monitor asynchronously signalled events from Socket. +/////////////////////////////////////////////////////////////////////////////// + +// Note: Any event that is an error is treated as SSE_ERROR instead of that +// event. + +enum StreamSinkEvent { + SSE_OPEN = 1, + SSE_READ = 2, + SSE_WRITE = 4, + SSE_CLOSE = 8, + SSE_ERROR = 16 +}; + +class StreamSink : public sigslot::has_slots<> { + public: + StreamSink(); + ~StreamSink() override; + + void Monitor(rtc::Socket* socket) { + socket->SignalConnectEvent.connect(this, &StreamSink::OnConnectEvent); + socket->SignalReadEvent.connect(this, &StreamSink::OnReadEvent); + socket->SignalWriteEvent.connect(this, &StreamSink::OnWriteEvent); + socket->SignalCloseEvent.connect(this, &StreamSink::OnCloseEvent); + // In case you forgot to unmonitor a previous object with this address + events_.erase(socket); + } + void Unmonitor(rtc::Socket* socket) { + socket->SignalConnectEvent.disconnect(this); + socket->SignalReadEvent.disconnect(this); + socket->SignalWriteEvent.disconnect(this); + socket->SignalCloseEvent.disconnect(this); + events_.erase(socket); + } + bool Check(rtc::Socket* socket, StreamSinkEvent event, bool reset = true) { + return DoCheck(socket, event, reset); + } + + private: + typedef std::map<rtc::Socket*, int> EventMap; + + void OnConnectEvent(rtc::Socket* socket) { AddEvents(socket, SSE_OPEN); } + void OnReadEvent(rtc::Socket* socket) { AddEvents(socket, SSE_READ); } + void OnWriteEvent(rtc::Socket* socket) { AddEvents(socket, SSE_WRITE); } + void OnCloseEvent(rtc::Socket* socket, int error) { + AddEvents(socket, (0 == error) ? SSE_CLOSE : SSE_ERROR); + } + + void AddEvents(rtc::Socket* obj, int events) { + EventMap::iterator it = events_.find(obj); + if (events_.end() == it) { + events_.insert(EventMap::value_type(obj, events)); + } else { + it->second |= events; + } + } + bool DoCheck(rtc::Socket* obj, StreamSinkEvent event, bool reset) { + EventMap::iterator it = events_.find(obj); + if ((events_.end() == it) || (0 == (it->second & event))) { + return false; + } + if (reset) { + it->second &= ~event; + } + return true; + } + + EventMap events_; +}; + +} // namespace testing +} // namespace webrtc + +#endif // RTC_BASE_TEST_UTILS_H_ diff --git a/third_party/libwebrtc/rtc_base/third_party/base64/BUILD.gn b/third_party/libwebrtc/rtc_base/third_party/base64/BUILD.gn new file mode 100644 index 0000000000..d28338c6a0 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/third_party/base64/BUILD.gn @@ -0,0 +1,21 @@ +# 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("base64") { + sources = [ + "base64.cc", + "base64.h", + ] + deps = [ + "../..:checks", + "../../system:rtc_export", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/strings" ] +} diff --git a/third_party/libwebrtc/rtc_base/third_party/base64/LICENSE b/third_party/libwebrtc/rtc_base/third_party/base64/LICENSE new file mode 100644 index 0000000000..4ad21d1b71 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/third_party/base64/LICENSE @@ -0,0 +1,14 @@ +//********************************************************************* +//* Base64 - a simple base64 encoder and decoder. +//* +//* Copyright (c) 1999, Bob Withers - bwit@pobox.com +//* +//* This code may be freely used for any purpose, either personal +//* or commercial, provided the authors copyright notice remains +//* intact. +//* +//* Enhancements by Stanley Yamane: +//* o reverse lookup table for the decode function +//* o reserve string buffer space in advance +//* +//********************************************************************* diff --git a/third_party/libwebrtc/rtc_base/third_party/base64/README.chromium b/third_party/libwebrtc/rtc_base/third_party/base64/README.chromium new file mode 100644 index 0000000000..1f01511fee --- /dev/null +++ b/third_party/libwebrtc/rtc_base/third_party/base64/README.chromium @@ -0,0 +1,12 @@ +Name: A simple base64 encoder and decoder +Short Name: base64 +URL: +Version: 0 +Date: 2018-06-20 +License: Custom license +License File: LICENSE +Security Critical: yes +Shipped: yes + +Description: +A simple base64 encoder and decoder diff --git a/third_party/libwebrtc/rtc_base/third_party/base64/base64.cc b/third_party/libwebrtc/rtc_base/third_party/base64/base64.cc new file mode 100644 index 0000000000..9dc961ae52 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/third_party/base64/base64.cc @@ -0,0 +1,279 @@ + +//********************************************************************* +//* Base64 - a simple base64 encoder and decoder. +//* +//* Copyright (c) 1999, Bob Withers - bwit@pobox.com +//* +//* This code may be freely used for any purpose, either personal +//* or commercial, provided the authors copyright notice remains +//* intact. +//* +//* Enhancements by Stanley Yamane: +//* o reverse lookup table for the decode function +//* o reserve string buffer space in advance +//* +//********************************************************************* + +#include "rtc_base/third_party/base64/base64.h" + +#include <string.h> + +#include "absl/strings/string_view.h" +#include "rtc_base/checks.h" + +using std::vector; + +namespace rtc { + +static const char kPad = '='; +static const unsigned char pd = 0xFD; // Padding +static const unsigned char sp = 0xFE; // Whitespace +static const unsigned char il = 0xFF; // Illegal base64 character + +const char Base64::Base64Table[] = + // 0000000000111111111122222222223333333333444444444455555555556666 + // 0123456789012345678901234567890123456789012345678901234567890123 + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +// Decode Table gives the index of any valid base64 character in the +// Base64 table +// 65 == A, 97 == a, 48 == 0, 43 == +, 47 == / + +const unsigned char Base64::DecodeTable[] = { + // 0 1 2 3 4 5 6 7 8 9 + il, il, il, il, il, il, il, il, il, sp, // 0 - 9 + sp, sp, sp, sp, il, il, il, il, il, il, // 10 - 19 + il, il, il, il, il, il, il, il, il, il, // 20 - 29 + il, il, sp, il, il, il, il, il, il, il, // 30 - 39 + il, il, il, 62, il, il, il, 63, 52, 53, // 40 - 49 + 54, 55, 56, 57, 58, 59, 60, 61, il, il, // 50 - 59 + il, pd, il, il, il, 0, 1, 2, 3, 4, // 60 - 69 + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, // 70 - 79 + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, // 80 - 89 + 25, il, il, il, il, il, il, 26, 27, 28, // 90 - 99 + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, // 100 - 109 + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, // 110 - 119 + 49, 50, 51, il, il, il, il, il, il, il, // 120 - 129 + il, il, il, il, il, il, il, il, il, il, // 130 - 139 + il, il, il, il, il, il, il, il, il, il, // 140 - 149 + il, il, il, il, il, il, il, il, il, il, // 150 - 159 + il, il, il, il, il, il, il, il, il, il, // 160 - 169 + il, il, il, il, il, il, il, il, il, il, // 170 - 179 + il, il, il, il, il, il, il, il, il, il, // 180 - 189 + il, il, il, il, il, il, il, il, il, il, // 190 - 199 + il, il, il, il, il, il, il, il, il, il, // 200 - 209 + il, il, il, il, il, il, il, il, il, il, // 210 - 219 + il, il, il, il, il, il, il, il, il, il, // 220 - 229 + il, il, il, il, il, il, il, il, il, il, // 230 - 239 + il, il, il, il, il, il, il, il, il, il, // 240 - 249 + il, il, il, il, il, il // 250 - 255 +}; + +bool Base64::IsBase64Char(char ch) { + return (('A' <= ch) && (ch <= 'Z')) || (('a' <= ch) && (ch <= 'z')) || + (('0' <= ch) && (ch <= '9')) || (ch == '+') || (ch == '/'); +} + +bool Base64::GetNextBase64Char(char ch, char* next_ch) { + if (next_ch == nullptr) { + return false; + } + const char* p = strchr(Base64Table, ch); + if (!p) + return false; + ++p; + *next_ch = (*p) ? *p : Base64Table[0]; + return true; +} + +bool Base64::IsBase64Encoded(absl::string_view str) { + for (size_t i = 0; i < str.size(); ++i) { + if (!IsBase64Char(str.at(i))) + return false; + } + return true; +} + +void Base64::EncodeFromArray(const void* data, + size_t len, + std::string* result) { + RTC_DCHECK(result); + result->clear(); + result->resize(((len + 2) / 3) * 4); + const unsigned char* byte_data = static_cast<const unsigned char*>(data); + + unsigned char c; + size_t i = 0; + size_t dest_ix = 0; + while (i < len) { + c = (byte_data[i] >> 2) & 0x3f; + (*result)[dest_ix++] = Base64Table[c]; + + c = (byte_data[i] << 4) & 0x3f; + if (++i < len) { + c |= (byte_data[i] >> 4) & 0x0f; + } + (*result)[dest_ix++] = Base64Table[c]; + + if (i < len) { + c = (byte_data[i] << 2) & 0x3f; + if (++i < len) { + c |= (byte_data[i] >> 6) & 0x03; + } + (*result)[dest_ix++] = Base64Table[c]; + } else { + (*result)[dest_ix++] = kPad; + } + + if (i < len) { + c = byte_data[i] & 0x3f; + (*result)[dest_ix++] = Base64Table[c]; + ++i; + } else { + (*result)[dest_ix++] = kPad; + } + } +} + +size_t Base64::GetNextQuantum(DecodeFlags parse_flags, + bool illegal_pads, + const char* data, + size_t len, + size_t* dpos, + unsigned char qbuf[4], + bool* padded) { + size_t byte_len = 0, pad_len = 0, pad_start = 0; + for (; (byte_len < 4) && (*dpos < len); ++*dpos) { + qbuf[byte_len] = DecodeTable[static_cast<unsigned char>(data[*dpos])]; + if ((il == qbuf[byte_len]) || (illegal_pads && (pd == qbuf[byte_len]))) { + if (parse_flags != DO_PARSE_ANY) + break; + // Ignore illegal characters + } else if (sp == qbuf[byte_len]) { + if (parse_flags == DO_PARSE_STRICT) + break; + // Ignore spaces + } else if (pd == qbuf[byte_len]) { + if (byte_len < 2) { + if (parse_flags != DO_PARSE_ANY) + break; + // Ignore unexpected padding + } else if (byte_len + pad_len >= 4) { + if (parse_flags != DO_PARSE_ANY) + break; + // Ignore extra pads + } else { + if (1 == ++pad_len) { + pad_start = *dpos; + } + } + } else { + if (pad_len > 0) { + if (parse_flags != DO_PARSE_ANY) + break; + // Ignore pads which are followed by data + pad_len = 0; + } + ++byte_len; + } + } + for (size_t i = byte_len; i < 4; ++i) { + qbuf[i] = 0; + } + if (4 == byte_len + pad_len) { + *padded = true; + } else { + *padded = false; + if (pad_len) { + // Roll back illegal padding + *dpos = pad_start; + } + } + return byte_len; +} + +bool Base64::DecodeFromArray(const char* data, + size_t len, + DecodeFlags flags, + std::string* result, + size_t* data_used) { + return DecodeFromArrayTemplate<std::string>(data, len, flags, result, + data_used); +} + +bool Base64::DecodeFromArray(const char* data, + size_t len, + DecodeFlags flags, + vector<char>* result, + size_t* data_used) { + return DecodeFromArrayTemplate<vector<char>>(data, len, flags, result, + data_used); +} + +bool Base64::DecodeFromArray(const char* data, + size_t len, + DecodeFlags flags, + vector<uint8_t>* result, + size_t* data_used) { + return DecodeFromArrayTemplate<vector<uint8_t>>(data, len, flags, result, + data_used); +} + +template <typename T> +bool Base64::DecodeFromArrayTemplate(const char* data, + size_t len, + DecodeFlags flags, + T* result, + size_t* data_used) { + RTC_DCHECK(result); + RTC_DCHECK_LE(flags, (DO_PARSE_MASK | DO_PAD_MASK | DO_TERM_MASK)); + + const DecodeFlags parse_flags = flags & DO_PARSE_MASK; + const DecodeFlags pad_flags = flags & DO_PAD_MASK; + const DecodeFlags term_flags = flags & DO_TERM_MASK; + RTC_DCHECK_NE(0, parse_flags); + RTC_DCHECK_NE(0, pad_flags); + RTC_DCHECK_NE(0, term_flags); + + result->clear(); + result->reserve(len); + + size_t dpos = 0; + bool success = true, padded; + unsigned char c, qbuf[4]; + while (dpos < len) { + size_t qlen = GetNextQuantum(parse_flags, (DO_PAD_NO == pad_flags), data, + len, &dpos, qbuf, &padded); + c = (qbuf[0] << 2) | ((qbuf[1] >> 4) & 0x3); + if (qlen >= 2) { + result->push_back(c); + c = ((qbuf[1] << 4) & 0xf0) | ((qbuf[2] >> 2) & 0xf); + if (qlen >= 3) { + result->push_back(c); + c = ((qbuf[2] << 6) & 0xc0) | qbuf[3]; + if (qlen >= 4) { + result->push_back(c); + c = 0; + } + } + } + if (qlen < 4) { + if ((DO_TERM_ANY != term_flags) && (0 != c)) { + success = false; // unused bits + } + if ((DO_PAD_YES == pad_flags) && !padded) { + success = false; // expected padding + } + break; + } + } + if ((DO_TERM_BUFFER == term_flags) && (dpos != len)) { + success = false; // unused chars + } + if (data_used) { + *data_used = dpos; + } + return success; +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/third_party/base64/base64.h b/third_party/libwebrtc/rtc_base/third_party/base64/base64.h new file mode 100644 index 0000000000..5d42513323 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/third_party/base64/base64.h @@ -0,0 +1,128 @@ + +//********************************************************************* +//* C_Base64 - a simple base64 encoder and decoder. +//* +//* Copyright (c) 1999, Bob Withers - bwit@pobox.com +//* +//* This code may be freely used for any purpose, either personal +//* or commercial, provided the authors copyright notice remains +//* intact. +//********************************************************************* + +#ifndef RTC_BASE_THIRD_PARTY_BASE64_BASE64_H_ +#define RTC_BASE_THIRD_PARTY_BASE64_BASE64_H_ + +#include <cstddef> +#include <cstdint> +#include <string> +#include <vector> + +#include "absl/strings/string_view.h" +#include "rtc_base/system/rtc_export.h" + +namespace rtc { + +class Base64 { + public: + enum DecodeOption { + DO_PARSE_STRICT = 1, // Parse only base64 characters + DO_PARSE_WHITE = 2, // Parse only base64 and whitespace characters + DO_PARSE_ANY = 3, // Parse all characters + DO_PARSE_MASK = 3, + + DO_PAD_YES = 4, // Padding is required + DO_PAD_ANY = 8, // Padding is optional + DO_PAD_NO = 12, // Padding is disallowed + DO_PAD_MASK = 12, + + DO_TERM_BUFFER = 16, // Must termiante at end of buffer + DO_TERM_CHAR = 32, // May terminate at any character boundary + DO_TERM_ANY = 48, // May terminate at a sub-character bit offset + DO_TERM_MASK = 48, + + // Strictest interpretation + DO_STRICT = DO_PARSE_STRICT | DO_PAD_YES | DO_TERM_BUFFER, + + DO_LAX = DO_PARSE_ANY | DO_PAD_ANY | DO_TERM_CHAR, + }; + typedef int DecodeFlags; + + static bool IsBase64Char(char ch); + + // Get the char next to the `ch` from the Base64Table. + // If the `ch` is the last one in the Base64Table then returns + // the first one from the table. + // Expects the `ch` be a base64 char. + // The result will be saved in `next_ch`. + // Returns true on success. + static bool GetNextBase64Char(char ch, char* next_ch); + + // Determines whether the given string consists entirely of valid base64 + // encoded characters. + static bool IsBase64Encoded(absl::string_view str); + + RTC_EXPORT static void EncodeFromArray(const void* data, + size_t len, + std::string* result); + RTC_EXPORT static bool DecodeFromArray(const char* data, + size_t len, + DecodeFlags flags, + std::string* result, + size_t* data_used); + static bool DecodeFromArray(const char* data, + size_t len, + DecodeFlags flags, + std::vector<char>* result, + size_t* data_used); + static bool DecodeFromArray(const char* data, + size_t len, + DecodeFlags flags, + std::vector<uint8_t>* result, + size_t* data_used); + + // Convenience Methods + static inline std::string Encode(absl::string_view data) { + std::string result; + EncodeFromArray(data.data(), data.size(), &result); + return result; + } + static inline std::string Decode(absl::string_view data, DecodeFlags flags) { + std::string result; + DecodeFromArray(data.data(), data.size(), flags, &result, nullptr); + return result; + } + static inline bool Decode(absl::string_view data, + DecodeFlags flags, + std::string* result, + size_t* data_used) { + return DecodeFromArray(data.data(), data.size(), flags, result, data_used); + } + static inline bool Decode(absl::string_view data, + DecodeFlags flags, + std::vector<char>* result, + size_t* data_used) { + return DecodeFromArray(data.data(), data.size(), flags, result, data_used); + } + + private: + static const char Base64Table[]; + static const unsigned char DecodeTable[]; + + static size_t GetNextQuantum(DecodeFlags parse_flags, + bool illegal_pads, + const char* data, + size_t len, + size_t* dpos, + unsigned char qbuf[4], + bool* padded); + template <typename T> + static bool DecodeFromArrayTemplate(const char* data, + size_t len, + DecodeFlags flags, + T* result, + size_t* data_used); +}; + +} // namespace rtc + +#endif /* RTC_BASE_THIRD_PARTY_BASE64_BASE64_H_ */ diff --git a/third_party/libwebrtc/rtc_base/third_party/base64/base64_gn/moz.build b/third_party/libwebrtc/rtc_base/third_party/base64/base64_gn/moz.build new file mode 100644 index 0000000000..0d35da2f19 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/third_party/base64/base64_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/rtc_base/third_party/base64/base64.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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("base64_gn") diff --git a/third_party/libwebrtc/rtc_base/third_party/sigslot/BUILD.gn b/third_party/libwebrtc/rtc_base/third_party/sigslot/BUILD.gn new file mode 100644 index 0000000000..186a05c404 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/third_party/sigslot/BUILD.gn @@ -0,0 +1,17 @@ +# 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("sigslot") { + visibility = [ "*" ] + sources = [ + "sigslot.cc", + "sigslot.h", + ] +} diff --git a/third_party/libwebrtc/rtc_base/third_party/sigslot/LICENSE b/third_party/libwebrtc/rtc_base/third_party/sigslot/LICENSE new file mode 100644 index 0000000000..d1c66c7335 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/third_party/sigslot/LICENSE @@ -0,0 +1,7 @@ +// sigslot.h: Signal/Slot classes +// +// Written by Sarah Thompson (sarah@telergy.com) 2002. +// +// License: Public domain. You are free to use this code however you like, with +// the proviso that the author takes on no responsibility or liability for any +// use. diff --git a/third_party/libwebrtc/rtc_base/third_party/sigslot/README.chromium b/third_party/libwebrtc/rtc_base/third_party/sigslot/README.chromium new file mode 100644 index 0000000000..9867dd0320 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/third_party/sigslot/README.chromium @@ -0,0 +1,21 @@ +Name: C++ Signal/Slot Library +Short Name: sigslot +URL: http://sigslot.sourceforge.net/ +Version: 0 +Date: 2018-07-09 +License: Custom license +License File: LICENSE +Security Critical: yes +Shipped: yes + +Description: +C++ Signal/Slot Library + +This file has been modified such that has_slots and signalx do not have to be +using the same threading requirements. E.g. it is possible to connect a +has_slots<single_threaded> and signal0<multi_threaded_local> or +has_slots<multi_threaded_local> and signal0<single_threaded>. +If has_slots is single threaded the user must ensure that it is not trying +to connect or disconnect to signalx concurrently or data race may occur. +If signalx is single threaded the user must ensure that disconnect, connect +or signal is not happening concurrently or data race may occur. diff --git a/third_party/libwebrtc/rtc_base/third_party/sigslot/sigslot.cc b/third_party/libwebrtc/rtc_base/third_party/sigslot/sigslot.cc new file mode 100644 index 0000000000..d852a2b536 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/third_party/sigslot/sigslot.cc @@ -0,0 +1,22 @@ +// sigslot.h: Signal/Slot classes +// +// Written by Sarah Thompson (sarah@telergy.com) 2002. +// +// License: Public domain. You are free to use this code however you like, with +// the proviso that the author takes on no responsibility or liability for any +// use. + +#include "rtc_base/third_party/sigslot/sigslot.h" + +namespace sigslot { + +#ifdef _SIGSLOT_HAS_POSIX_THREADS + +pthread_mutex_t* multi_threaded_global::get_mutex() { + static pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER; + return &g_mutex; +} + +#endif // _SIGSLOT_HAS_POSIX_THREADS + +} // namespace sigslot diff --git a/third_party/libwebrtc/rtc_base/third_party/sigslot/sigslot.h b/third_party/libwebrtc/rtc_base/third_party/sigslot/sigslot.h new file mode 100644 index 0000000000..a4de0e6603 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/third_party/sigslot/sigslot.h @@ -0,0 +1,649 @@ +// sigslot.h: Signal/Slot classes +// +// Written by Sarah Thompson (sarah@telergy.com) 2002. +// +// License: Public domain. You are free to use this code however you like, with +// the proviso that the author takes on no responsibility or liability for any +// use. +// +// QUICK DOCUMENTATION +// +// (see also the full documentation at http://sigslot.sourceforge.net/) +// +// #define switches +// SIGSLOT_PURE_ISO: +// Define this to force ISO C++ compliance. This also disables all of +// the thread safety support on platforms where it is available. +// +// SIGSLOT_USE_POSIX_THREADS: +// Force use of Posix threads when using a C++ compiler other than gcc +// on a platform that supports Posix threads. (When using gcc, this is +// the default - use SIGSLOT_PURE_ISO to disable this if necessary) +// +// SIGSLOT_DEFAULT_MT_POLICY: +// Where thread support is enabled, this defaults to +// multi_threaded_global. Otherwise, the default is single_threaded. +// #define this yourself to override the default. In pure ISO mode, +// anything other than single_threaded will cause a compiler error. +// +// PLATFORM NOTES +// +// Win32: +// On Win32, the WEBRTC_WIN symbol must be #defined. Most mainstream +// compilers do this by default, but you may need to define it yourself +// if your build environment is less standard. This causes the Win32 +// thread support to be compiled in and used automatically. +// +// Unix/Linux/BSD, etc.: +// If you're using gcc, it is assumed that you have Posix threads +// available, so they are used automatically. You can override this (as +// under Windows) with the SIGSLOT_PURE_ISO switch. If you're using +// something other than gcc but still want to use Posix threads, you +// need to #define SIGSLOT_USE_POSIX_THREADS. +// +// ISO C++: +// If none of the supported platforms are detected, or if +// SIGSLOT_PURE_ISO is defined, all multithreading support is turned +// off, along with any code that might cause a pure ISO C++ environment +// to complain. Before you ask, gcc -ansi -pedantic won't compile this +// library, but gcc -ansi is fine. Pedantic mode seems to throw a lot of +// errors that aren't really there. If you feel like investigating this, +// please contact the author. +// +// +// THREADING MODES +// +// single_threaded: +// Your program is assumed to be single threaded from the point of view +// of signal/slot usage (i.e. all objects using signals and slots are +// created and destroyed from a single thread). Behaviour if objects are +// destroyed concurrently is undefined (i.e. you'll get the occasional +// segmentation fault/memory exception). +// +// multi_threaded_global: +// Your program is assumed to be multi threaded. Objects using signals +// and slots can be safely created and destroyed from any thread, even +// when connections exist. In multi_threaded_global mode, this is +// achieved by a single global mutex (actually a critical section on +// Windows because they are faster). This option uses less OS resources, +// but results in more opportunities for contention, possibly resulting +// in more context switches than are strictly necessary. +// +// multi_threaded_local: +// Behaviour in this mode is essentially the same as +// multi_threaded_global, except that each signal, and each object that +// inherits has_slots, all have their own mutex/critical section. In +// practice, this means that mutex collisions (and hence context +// switches) only happen if they are absolutely essential. However, on +// some platforms, creating a lot of mutexes can slow down the whole OS, +// so use this option with care. +// +// USING THE LIBRARY +// +// See the full documentation at http://sigslot.sourceforge.net/ +// +// Libjingle specific: +// +// This file has been modified such that has_slots and signalx do not have to be +// using the same threading requirements. E.g. it is possible to connect a +// has_slots<single_threaded> and signal0<multi_threaded_local> or +// has_slots<multi_threaded_local> and signal0<single_threaded>. +// If has_slots is single threaded the user must ensure that it is not trying +// to connect or disconnect to signalx concurrently or data race may occur. +// If signalx is single threaded the user must ensure that disconnect, connect +// or signal is not happening concurrently or data race may occur. + +#ifndef RTC_BASE_THIRD_PARTY_SIGSLOT_SIGSLOT_H_ +#define RTC_BASE_THIRD_PARTY_SIGSLOT_SIGSLOT_H_ + +#include <cstring> +#include <list> +#include <set> + +// On our copy of sigslot.h, we set single threading as default. +#define SIGSLOT_DEFAULT_MT_POLICY single_threaded + +#if defined(SIGSLOT_PURE_ISO) || \ + (!defined(WEBRTC_WIN) && !defined(__GNUG__) && \ + !defined(SIGSLOT_USE_POSIX_THREADS)) +#define _SIGSLOT_SINGLE_THREADED +#elif defined(WEBRTC_WIN) +#define _SIGSLOT_HAS_WIN32_THREADS +#include "windows.h" +#elif defined(__GNUG__) || defined(SIGSLOT_USE_POSIX_THREADS) +#define _SIGSLOT_HAS_POSIX_THREADS +#include <pthread.h> +#else +#define _SIGSLOT_SINGLE_THREADED +#endif + +#ifndef SIGSLOT_DEFAULT_MT_POLICY +#ifdef _SIGSLOT_SINGLE_THREADED +#define SIGSLOT_DEFAULT_MT_POLICY single_threaded +#else +#define SIGSLOT_DEFAULT_MT_POLICY multi_threaded_local +#endif +#endif + +// TODO: change this namespace to rtc? +namespace sigslot { + +class single_threaded { + public: + void lock() {} + void unlock() {} +}; + +#ifdef _SIGSLOT_HAS_WIN32_THREADS +// The multi threading policies only get compiled in if they are enabled. +class multi_threaded_global { + public: + multi_threaded_global() { + static bool isinitialised = false; + + if (!isinitialised) { + InitializeCriticalSection(get_critsec()); + isinitialised = true; + } + } + + void lock() { EnterCriticalSection(get_critsec()); } + + void unlock() { LeaveCriticalSection(get_critsec()); } + + private: + CRITICAL_SECTION* get_critsec() { + static CRITICAL_SECTION g_critsec; + return &g_critsec; + } +}; + +class multi_threaded_local { + public: + multi_threaded_local() { InitializeCriticalSection(&m_critsec); } + + multi_threaded_local(const multi_threaded_local&) { + InitializeCriticalSection(&m_critsec); + } + + ~multi_threaded_local() { DeleteCriticalSection(&m_critsec); } + + void lock() { EnterCriticalSection(&m_critsec); } + + void unlock() { LeaveCriticalSection(&m_critsec); } + + private: + CRITICAL_SECTION m_critsec; +}; +#endif // _SIGSLOT_HAS_WIN32_THREADS + +#ifdef _SIGSLOT_HAS_POSIX_THREADS +// The multi threading policies only get compiled in if they are enabled. +class multi_threaded_global { + public: + void lock() { pthread_mutex_lock(get_mutex()); } + void unlock() { pthread_mutex_unlock(get_mutex()); } + + private: + static pthread_mutex_t* get_mutex(); +}; + +class multi_threaded_local { + public: + multi_threaded_local() { pthread_mutex_init(&m_mutex, nullptr); } + multi_threaded_local(const multi_threaded_local&) { + pthread_mutex_init(&m_mutex, nullptr); + } + ~multi_threaded_local() { pthread_mutex_destroy(&m_mutex); } + void lock() { pthread_mutex_lock(&m_mutex); } + void unlock() { pthread_mutex_unlock(&m_mutex); } + + private: + pthread_mutex_t m_mutex; +}; +#endif // _SIGSLOT_HAS_POSIX_THREADS + +template <class mt_policy> +class lock_block { + public: + mt_policy* m_mutex; + + lock_block(mt_policy* mtx) : m_mutex(mtx) { m_mutex->lock(); } + + ~lock_block() { m_mutex->unlock(); } +}; + +class _signal_base_interface; + +class has_slots_interface { + private: + typedef void (*signal_connect_t)(has_slots_interface* self, + _signal_base_interface* sender); + typedef void (*signal_disconnect_t)(has_slots_interface* self, + _signal_base_interface* sender); + typedef void (*disconnect_all_t)(has_slots_interface* self); + + const signal_connect_t m_signal_connect; + const signal_disconnect_t m_signal_disconnect; + const disconnect_all_t m_disconnect_all; + + protected: + has_slots_interface(signal_connect_t conn, + signal_disconnect_t disc, + disconnect_all_t disc_all) + : m_signal_connect(conn), + m_signal_disconnect(disc), + m_disconnect_all(disc_all) {} + + // Doesn't really need to be virtual, but is for backwards compatibility + // (it was virtual in a previous version of sigslot). + virtual ~has_slots_interface() {} + + public: + void signal_connect(_signal_base_interface* sender) { + m_signal_connect(this, sender); + } + + void signal_disconnect(_signal_base_interface* sender) { + m_signal_disconnect(this, sender); + } + + void disconnect_all() { m_disconnect_all(this); } +}; + +class _signal_base_interface { + private: + typedef void (*slot_disconnect_t)(_signal_base_interface* self, + has_slots_interface* pslot); + typedef void (*slot_duplicate_t)(_signal_base_interface* self, + const has_slots_interface* poldslot, + has_slots_interface* pnewslot); + + const slot_disconnect_t m_slot_disconnect; + const slot_duplicate_t m_slot_duplicate; + + protected: + _signal_base_interface(slot_disconnect_t disc, slot_duplicate_t dupl) + : m_slot_disconnect(disc), m_slot_duplicate(dupl) {} + + ~_signal_base_interface() {} + + public: + void slot_disconnect(has_slots_interface* pslot) { + m_slot_disconnect(this, pslot); + } + + void slot_duplicate(const has_slots_interface* poldslot, + has_slots_interface* pnewslot) { + m_slot_duplicate(this, poldslot, pnewslot); + } +}; + +class _opaque_connection { + private: + typedef void (*emit_t)(const _opaque_connection*); + template <typename FromT, typename ToT> + union union_caster { + FromT from; + ToT to; + }; + + emit_t pemit; + has_slots_interface* pdest; + // Pointers to member functions may be up to 16 bytes (24 bytes for MSVC) + // for virtual classes, so make sure we have enough space to store it. +#if defined(_MSC_VER) && !defined(__clang__) + unsigned char pmethod[24]; +#else + unsigned char pmethod[16]; +#endif + + public: + template <typename DestT, typename... Args> + _opaque_connection(DestT* pd, void (DestT::*pm)(Args...)) : pdest(pd) { + typedef void (DestT::*pm_t)(Args...); + static_assert(sizeof(pm_t) <= sizeof(pmethod), + "Size of slot function pointer too large."); + + std::memcpy(pmethod, &pm, sizeof(pm_t)); + + typedef void (*em_t)(const _opaque_connection* self, Args...); + union_caster<em_t, emit_t> caster2; + caster2.from = &_opaque_connection::emitter<DestT, Args...>; + pemit = caster2.to; + } + + has_slots_interface* getdest() const { return pdest; } + + _opaque_connection duplicate(has_slots_interface* newtarget) const { + _opaque_connection res = *this; + res.pdest = newtarget; + return res; + } + + // Just calls the stored "emitter" function pointer stored at construction + // time. + template <typename... Args> + void emit(Args... args) const { + typedef void (*em_t)(const _opaque_connection*, Args...); + union_caster<emit_t, em_t> caster; + caster.from = pemit; + (caster.to)(this, args...); + } + + private: + template <typename DestT, typename... Args> + static void emitter(const _opaque_connection* self, Args... args) { + typedef void (DestT::*pm_t)(Args...); + pm_t pm; + static_assert(sizeof(pm_t) <= sizeof(pmethod), + "Size of slot function pointer too large."); + std::memcpy(&pm, self->pmethod, sizeof(pm_t)); + (static_cast<DestT*>(self->pdest)->*(pm))(args...); + } +}; + +template <class mt_policy> +class _signal_base : public _signal_base_interface, public mt_policy { + protected: + typedef std::list<_opaque_connection> connections_list; + + _signal_base() + : _signal_base_interface(&_signal_base::do_slot_disconnect, + &_signal_base::do_slot_duplicate), + m_current_iterator(m_connected_slots.end()) {} + + ~_signal_base() { disconnect_all(); } + + private: + _signal_base& operator=(_signal_base const& that); + + public: + _signal_base(const _signal_base& o) + : _signal_base_interface(&_signal_base::do_slot_disconnect, + &_signal_base::do_slot_duplicate), + m_current_iterator(m_connected_slots.end()) { + lock_block<mt_policy> lock(this); + for (const auto& connection : o.m_connected_slots) { + connection.getdest()->signal_connect(this); + m_connected_slots.push_back(connection); + } + } + + bool is_empty() { + lock_block<mt_policy> lock(this); + return m_connected_slots.empty(); + } + + void disconnect_all() { + lock_block<mt_policy> lock(this); + + while (!m_connected_slots.empty()) { + has_slots_interface* pdest = m_connected_slots.front().getdest(); + m_connected_slots.pop_front(); + pdest->signal_disconnect(static_cast<_signal_base_interface*>(this)); + } + // If disconnect_all is called while the signal is firing, advance the + // current slot iterator to the end to avoid an invalidated iterator from + // being dereferenced. + m_current_iterator = m_connected_slots.end(); + } + +#if !defined(NDEBUG) + bool connected(has_slots_interface* pclass) { + lock_block<mt_policy> lock(this); + connections_list::const_iterator it = m_connected_slots.begin(); + connections_list::const_iterator itEnd = m_connected_slots.end(); + while (it != itEnd) { + if (it->getdest() == pclass) + return true; + ++it; + } + return false; + } +#endif + + void disconnect(has_slots_interface* pclass) { + lock_block<mt_policy> lock(this); + connections_list::iterator it = m_connected_slots.begin(); + connections_list::iterator itEnd = m_connected_slots.end(); + + while (it != itEnd) { + if (it->getdest() == pclass) { + // If we're currently using this iterator because the signal is firing, + // advance it to avoid it being invalidated. + if (m_current_iterator == it) { + m_current_iterator = m_connected_slots.erase(it); + } else { + m_connected_slots.erase(it); + } + pclass->signal_disconnect(static_cast<_signal_base_interface*>(this)); + return; + } + ++it; + } + } + + private: + static void do_slot_disconnect(_signal_base_interface* p, + has_slots_interface* pslot) { + _signal_base* const self = static_cast<_signal_base*>(p); + lock_block<mt_policy> lock(self); + connections_list::iterator it = self->m_connected_slots.begin(); + connections_list::iterator itEnd = self->m_connected_slots.end(); + + while (it != itEnd) { + connections_list::iterator itNext = it; + ++itNext; + + if (it->getdest() == pslot) { + // If we're currently using this iterator because the signal is firing, + // advance it to avoid it being invalidated. + if (self->m_current_iterator == it) { + self->m_current_iterator = self->m_connected_slots.erase(it); + } else { + self->m_connected_slots.erase(it); + } + } + + it = itNext; + } + } + + static void do_slot_duplicate(_signal_base_interface* p, + const has_slots_interface* oldtarget, + has_slots_interface* newtarget) { + _signal_base* const self = static_cast<_signal_base*>(p); + lock_block<mt_policy> lock(self); + connections_list::iterator it = self->m_connected_slots.begin(); + connections_list::iterator itEnd = self->m_connected_slots.end(); + + while (it != itEnd) { + if (it->getdest() == oldtarget) { + self->m_connected_slots.push_back(it->duplicate(newtarget)); + } + + ++it; + } + } + + protected: + connections_list m_connected_slots; + + // Used to handle a slot being disconnected while a signal is + // firing (iterating m_connected_slots). + connections_list::iterator m_current_iterator; + bool m_erase_current_iterator = false; +}; + +template <class mt_policy = SIGSLOT_DEFAULT_MT_POLICY> +class has_slots : public has_slots_interface, public mt_policy { + private: + typedef std::set<_signal_base_interface*> sender_set; + typedef sender_set::const_iterator const_iterator; + + public: + has_slots() + : has_slots_interface(&has_slots::do_signal_connect, + &has_slots::do_signal_disconnect, + &has_slots::do_disconnect_all) {} + + has_slots(has_slots const& o) + : has_slots_interface(&has_slots::do_signal_connect, + &has_slots::do_signal_disconnect, + &has_slots::do_disconnect_all) { + lock_block<mt_policy> lock(this); + for (auto* sender : o.m_senders) { + sender->slot_duplicate(&o, this); + m_senders.insert(sender); + } + } + + ~has_slots() { this->disconnect_all(); } + + private: + has_slots& operator=(has_slots const&); + + static void do_signal_connect(has_slots_interface* p, + _signal_base_interface* sender) { + has_slots* const self = static_cast<has_slots*>(p); + lock_block<mt_policy> lock(self); + self->m_senders.insert(sender); + } + + static void do_signal_disconnect(has_slots_interface* p, + _signal_base_interface* sender) { + has_slots* const self = static_cast<has_slots*>(p); + lock_block<mt_policy> lock(self); + self->m_senders.erase(sender); + } + + static void do_disconnect_all(has_slots_interface* p) { + has_slots* const self = static_cast<has_slots*>(p); + lock_block<mt_policy> lock(self); + while (!self->m_senders.empty()) { + std::set<_signal_base_interface*> senders; + senders.swap(self->m_senders); + const_iterator it = senders.begin(); + const_iterator itEnd = senders.end(); + + while (it != itEnd) { + _signal_base_interface* s = *it; + ++it; + s->slot_disconnect(p); + } + } + } + + private: + sender_set m_senders; +}; + +template <class mt_policy, typename... Args> +class signal_with_thread_policy : public _signal_base<mt_policy> { + private: + typedef _signal_base<mt_policy> base; + + protected: + typedef typename base::connections_list connections_list; + + public: + signal_with_thread_policy() {} + + template <class desttype> + void connect(desttype* pclass, void (desttype::*pmemfun)(Args...)) { + lock_block<mt_policy> lock(this); + this->m_connected_slots.push_back(_opaque_connection(pclass, pmemfun)); + pclass->signal_connect(static_cast<_signal_base_interface*>(this)); + } + + void emit(Args... args) { + lock_block<mt_policy> lock(this); + this->m_current_iterator = this->m_connected_slots.begin(); + while (this->m_current_iterator != this->m_connected_slots.end()) { + _opaque_connection const& conn = *this->m_current_iterator; + ++(this->m_current_iterator); + conn.emit<Args...>(args...); + } + } + + void operator()(Args... args) { emit(args...); } +}; + +// Alias with default thread policy. Needed because both default arguments +// and variadic template arguments must go at the end of the list, so we +// can't have both at once. +template <typename... Args> +using signal = signal_with_thread_policy<SIGSLOT_DEFAULT_MT_POLICY, Args...>; + +// The previous verion of sigslot didn't use variadic templates, so you would +// need to write "sigslot::signal2<Arg1, Arg2>", for example. +// Now you can just write "sigslot::signal<Arg1, Arg2>", but these aliases +// exist for backwards compatibility. +template <typename mt_policy = SIGSLOT_DEFAULT_MT_POLICY> +using signal0 = signal_with_thread_policy<mt_policy>; + +template <typename A1, typename mt_policy = SIGSLOT_DEFAULT_MT_POLICY> +using signal1 = signal_with_thread_policy<mt_policy, A1>; + +template <typename A1, + typename A2, + typename mt_policy = SIGSLOT_DEFAULT_MT_POLICY> +using signal2 = signal_with_thread_policy<mt_policy, A1, A2>; + +template <typename A1, + typename A2, + typename A3, + typename mt_policy = SIGSLOT_DEFAULT_MT_POLICY> +using signal3 = signal_with_thread_policy<mt_policy, A1, A2, A3>; + +template <typename A1, + typename A2, + typename A3, + typename A4, + typename mt_policy = SIGSLOT_DEFAULT_MT_POLICY> +using signal4 = signal_with_thread_policy<mt_policy, A1, A2, A3, A4>; + +template <typename A1, + typename A2, + typename A3, + typename A4, + typename A5, + typename mt_policy = SIGSLOT_DEFAULT_MT_POLICY> +using signal5 = signal_with_thread_policy<mt_policy, A1, A2, A3, A4, A5>; + +template <typename A1, + typename A2, + typename A3, + typename A4, + typename A5, + typename A6, + typename mt_policy = SIGSLOT_DEFAULT_MT_POLICY> +using signal6 = signal_with_thread_policy<mt_policy, A1, A2, A3, A4, A5, A6>; + +template <typename A1, + typename A2, + typename A3, + typename A4, + typename A5, + typename A6, + typename A7, + typename mt_policy = SIGSLOT_DEFAULT_MT_POLICY> +using signal7 = + signal_with_thread_policy<mt_policy, A1, A2, A3, A4, A5, A6, A7>; + +template <typename A1, + typename A2, + typename A3, + typename A4, + typename A5, + typename A6, + typename A7, + typename A8, + typename mt_policy = SIGSLOT_DEFAULT_MT_POLICY> +using signal8 = + signal_with_thread_policy<mt_policy, A1, A2, A3, A4, A5, A6, A7, A8>; + +} // namespace sigslot + +#endif /* RTC_BASE_THIRD_PARTY_SIGSLOT_SIGSLOT_H_ */ diff --git a/third_party/libwebrtc/rtc_base/third_party/sigslot/sigslot_gn/moz.build b/third_party/libwebrtc/rtc_base/third_party/sigslot/sigslot_gn/moz.build new file mode 100644 index 0000000000..906a4a9e81 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/third_party/sigslot/sigslot_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/rtc_base/third_party/sigslot/sigslot.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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("sigslot_gn") diff --git a/third_party/libwebrtc/rtc_base/thread.cc b/third_party/libwebrtc/rtc_base/thread.cc new file mode 100644 index 0000000000..6f101ac8f4 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/thread.cc @@ -0,0 +1,939 @@ +/* + * 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 "rtc_base/thread.h" + +#include "absl/strings/string_view.h" +#include "api/task_queue/task_queue_base.h" +#include "api/units/time_delta.h" +#include "rtc_base/socket_server.h" + +#if defined(WEBRTC_WIN) +#include <comdef.h> +#elif defined(WEBRTC_POSIX) +#include <time.h> +#else +#error "Either WEBRTC_WIN or WEBRTC_POSIX needs to be defined." +#endif + +#if defined(WEBRTC_WIN) +// Disable warning that we don't care about: +// warning C4722: destructor never returns, potential memory leak +#pragma warning(disable : 4722) +#endif + +#include <stdio.h> + +#include <utility> + +#include "absl/algorithm/container.h" +#include "absl/cleanup/cleanup.h" +#include "api/sequence_checker.h" +#include "rtc_base/checks.h" +#include "rtc_base/event.h" +#include "rtc_base/internal/default_socket_server.h" +#include "rtc_base/logging.h" +#include "rtc_base/null_socket_server.h" +#include "rtc_base/synchronization/mutex.h" +#include "rtc_base/time_utils.h" +#include "rtc_base/trace_event.h" + +#if defined(WEBRTC_MAC) +#include "rtc_base/system/cocoa_threading.h" + +/* + * These are forward-declarations for methods that are part of the + * ObjC runtime. They are declared in the private header objc-internal.h. + * These calls are what clang inserts when using @autoreleasepool in ObjC, + * but here they are used directly in order to keep this file C++. + * https://clang.llvm.org/docs/AutomaticReferenceCounting.html#runtime-support + */ +extern "C" { +void* objc_autoreleasePoolPush(void); +void objc_autoreleasePoolPop(void* pool); +} + +namespace { +class ScopedAutoReleasePool { + public: + ScopedAutoReleasePool() : pool_(objc_autoreleasePoolPush()) {} + ~ScopedAutoReleasePool() { objc_autoreleasePoolPop(pool_); } + + private: + void* const pool_; +}; +} // namespace +#endif + +namespace rtc { + +using ::webrtc::MutexLock; +using ::webrtc::TimeDelta; + +ThreadManager* ThreadManager::Instance() { + static ThreadManager* const thread_manager = new ThreadManager(); + return thread_manager; +} + +ThreadManager::~ThreadManager() { + // By above RTC_DEFINE_STATIC_LOCAL. + RTC_DCHECK_NOTREACHED() << "ThreadManager should never be destructed."; +} + +// static +void ThreadManager::Add(Thread* message_queue) { + return Instance()->AddInternal(message_queue); +} +void ThreadManager::AddInternal(Thread* message_queue) { + MutexLock cs(&crit_); + message_queues_.push_back(message_queue); +} + +// static +void ThreadManager::Remove(Thread* message_queue) { + return Instance()->RemoveInternal(message_queue); +} +void ThreadManager::RemoveInternal(Thread* message_queue) { + { + MutexLock cs(&crit_); + std::vector<Thread*>::iterator iter; + iter = absl::c_find(message_queues_, message_queue); + if (iter != message_queues_.end()) { + message_queues_.erase(iter); + } +#if RTC_DCHECK_IS_ON + RemoveFromSendGraph(message_queue); +#endif + } +} + +#if RTC_DCHECK_IS_ON +void ThreadManager::RemoveFromSendGraph(Thread* thread) { + for (auto it = send_graph_.begin(); it != send_graph_.end();) { + if (it->first == thread) { + it = send_graph_.erase(it); + } else { + it->second.erase(thread); + ++it; + } + } +} + +void ThreadManager::RegisterSendAndCheckForCycles(Thread* source, + Thread* target) { + RTC_DCHECK(source); + RTC_DCHECK(target); + + MutexLock cs(&crit_); + std::deque<Thread*> all_targets({target}); + // We check the pre-existing who-sends-to-who graph for any path from target + // to source. This loop is guaranteed to terminate because per the send graph + // invariant, there are no cycles in the graph. + for (size_t i = 0; i < all_targets.size(); i++) { + const auto& targets = send_graph_[all_targets[i]]; + all_targets.insert(all_targets.end(), targets.begin(), targets.end()); + } + RTC_CHECK_EQ(absl::c_count(all_targets, source), 0) + << " send loop between " << source->name() << " and " << target->name(); + + // We may now insert source -> target without creating a cycle, since there + // was no path from target to source per the prior CHECK. + send_graph_[source].insert(target); +} +#endif + +// static +void ThreadManager::ProcessAllMessageQueuesForTesting() { + return Instance()->ProcessAllMessageQueuesInternal(); +} + +void ThreadManager::ProcessAllMessageQueuesInternal() { + // This works by posting a delayed message at the current time and waiting + // for it to be dispatched on all queues, which will ensure that all messages + // that came before it were also dispatched. + std::atomic<int> queues_not_done(0); + + { + MutexLock cs(&crit_); + for (Thread* queue : message_queues_) { + if (!queue->IsProcessingMessagesForTesting()) { + // If the queue is not processing messages, it can + // be ignored. If we tried to post a message to it, it would be dropped + // or ignored. + continue; + } + queues_not_done.fetch_add(1); + // Whether the task is processed, or the thread is simply cleared, + // queues_not_done gets decremented. + absl::Cleanup sub = [&queues_not_done] { queues_not_done.fetch_sub(1); }; + // Post delayed task instead of regular task to wait for all delayed tasks + // that are ready for processing. + queue->PostDelayedTask([sub = std::move(sub)] {}, TimeDelta::Zero()); + } + } + + rtc::Thread* current = rtc::Thread::Current(); + // Note: One of the message queues may have been on this thread, which is + // why we can't synchronously wait for queues_not_done to go to 0; we need + // to process messages as well. + while (queues_not_done.load() > 0) { + if (current) { + current->ProcessMessages(0); + } + } +} + +// static +Thread* Thread::Current() { + ThreadManager* manager = ThreadManager::Instance(); + Thread* thread = manager->CurrentThread(); + + return thread; +} + +#if defined(WEBRTC_POSIX) +ThreadManager::ThreadManager() { +#if defined(WEBRTC_MAC) + InitCocoaMultiThreading(); +#endif + pthread_key_create(&key_, nullptr); +} + +Thread* ThreadManager::CurrentThread() { + return static_cast<Thread*>(pthread_getspecific(key_)); +} + +void ThreadManager::SetCurrentThreadInternal(Thread* thread) { + pthread_setspecific(key_, thread); +} +#endif + +#if defined(WEBRTC_WIN) +ThreadManager::ThreadManager() : key_(TlsAlloc()) {} + +Thread* ThreadManager::CurrentThread() { + return static_cast<Thread*>(TlsGetValue(key_)); +} + +void ThreadManager::SetCurrentThreadInternal(Thread* thread) { + TlsSetValue(key_, thread); +} +#endif + +void ThreadManager::SetCurrentThread(Thread* thread) { +#if RTC_DLOG_IS_ON + if (CurrentThread() && thread) { + RTC_DLOG(LS_ERROR) << "SetCurrentThread: Overwriting an existing value?"; + } +#endif // RTC_DLOG_IS_ON + + if (thread) { + thread->EnsureIsCurrentTaskQueue(); + } else { + Thread* current = CurrentThread(); + if (current) { + // The current thread is being cleared, e.g. as a result of + // UnwrapCurrent() being called or when a thread is being stopped + // (see PreRun()). This signals that the Thread instance is being detached + // from the thread, which also means that TaskQueue::Current() must not + // return a pointer to the Thread instance. + current->ClearCurrentTaskQueue(); + } + } + + SetCurrentThreadInternal(thread); +} + +void rtc::ThreadManager::ChangeCurrentThreadForTest(rtc::Thread* thread) { + SetCurrentThreadInternal(thread); +} + +Thread* ThreadManager::WrapCurrentThread() { + Thread* result = CurrentThread(); + if (nullptr == result) { + result = new Thread(CreateDefaultSocketServer()); + result->WrapCurrentWithThreadManager(this, true); + } + return result; +} + +void ThreadManager::UnwrapCurrentThread() { + Thread* t = CurrentThread(); + if (t && !(t->IsOwned())) { + t->UnwrapCurrent(); + delete t; + } +} + +Thread::ScopedDisallowBlockingCalls::ScopedDisallowBlockingCalls() + : thread_(Thread::Current()), + previous_state_(thread_->SetAllowBlockingCalls(false)) {} + +Thread::ScopedDisallowBlockingCalls::~ScopedDisallowBlockingCalls() { + RTC_DCHECK(thread_->IsCurrent()); + thread_->SetAllowBlockingCalls(previous_state_); +} + +#if RTC_DCHECK_IS_ON +Thread::ScopedCountBlockingCalls::ScopedCountBlockingCalls( + std::function<void(uint32_t, uint32_t)> callback) + : thread_(Thread::Current()), + base_blocking_call_count_(thread_->GetBlockingCallCount()), + base_could_be_blocking_call_count_( + thread_->GetCouldBeBlockingCallCount()), + result_callback_(std::move(callback)) {} + +Thread::ScopedCountBlockingCalls::~ScopedCountBlockingCalls() { + if (GetTotalBlockedCallCount() >= min_blocking_calls_for_callback_) { + result_callback_(GetBlockingCallCount(), GetCouldBeBlockingCallCount()); + } +} + +uint32_t Thread::ScopedCountBlockingCalls::GetBlockingCallCount() const { + return thread_->GetBlockingCallCount() - base_blocking_call_count_; +} + +uint32_t Thread::ScopedCountBlockingCalls::GetCouldBeBlockingCallCount() const { + return thread_->GetCouldBeBlockingCallCount() - + base_could_be_blocking_call_count_; +} + +uint32_t Thread::ScopedCountBlockingCalls::GetTotalBlockedCallCount() const { + return GetBlockingCallCount() + GetCouldBeBlockingCallCount(); +} +#endif + +Thread::Thread(SocketServer* ss) : Thread(ss, /*do_init=*/true) {} + +Thread::Thread(std::unique_ptr<SocketServer> ss) + : Thread(std::move(ss), /*do_init=*/true) {} + +Thread::Thread(SocketServer* ss, bool do_init) + : delayed_next_num_(0), + fInitialized_(false), + fDestroyed_(false), + stop_(0), + ss_(ss) { + RTC_DCHECK(ss); + ss_->SetMessageQueue(this); + SetName("Thread", this); // default name + if (do_init) { + DoInit(); + } +} + +Thread::Thread(std::unique_ptr<SocketServer> ss, bool do_init) + : Thread(ss.get(), do_init) { + own_ss_ = std::move(ss); +} + +Thread::~Thread() { + Stop(); + DoDestroy(); +} + +void Thread::DoInit() { + if (fInitialized_) { + return; + } + + fInitialized_ = true; + ThreadManager::Add(this); +} + +void Thread::DoDestroy() { + if (fDestroyed_) { + return; + } + + fDestroyed_ = true; + // The signal is done from here to ensure + // that it always gets called when the queue + // is going away. + if (ss_) { + ss_->SetMessageQueue(nullptr); + } + ThreadManager::Remove(this); + // Clear. + CurrentTaskQueueSetter set_current(this); + messages_ = {}; + delayed_messages_ = {}; +} + +SocketServer* Thread::socketserver() { + return ss_; +} + +void Thread::WakeUpSocketServer() { + ss_->WakeUp(); +} + +void Thread::Quit() { + stop_.store(1, std::memory_order_release); + WakeUpSocketServer(); +} + +bool Thread::IsQuitting() { + return stop_.load(std::memory_order_acquire) != 0; +} + +void Thread::Restart() { + stop_.store(0, std::memory_order_release); +} + +absl::AnyInvocable<void() &&> Thread::Get(int cmsWait) { + // Get w/wait + timer scan / dispatch + socket / event multiplexer dispatch + + int64_t cmsTotal = cmsWait; + int64_t cmsElapsed = 0; + int64_t msStart = TimeMillis(); + int64_t msCurrent = msStart; + while (true) { + // Check for posted events + int64_t cmsDelayNext = kForever; + { + // All queue operations need to be locked, but nothing else in this loop + // can happen while holding the `mutex_`. + MutexLock lock(&mutex_); + // Check for delayed messages that have been triggered and calculate the + // next trigger time. + while (!delayed_messages_.empty()) { + if (msCurrent < delayed_messages_.top().run_time_ms) { + cmsDelayNext = + TimeDiff(delayed_messages_.top().run_time_ms, msCurrent); + break; + } + messages_.push(std::move(delayed_messages_.top().functor)); + delayed_messages_.pop(); + } + // Pull a message off the message queue, if available. + if (!messages_.empty()) { + absl::AnyInvocable<void()&&> task = std::move(messages_.front()); + messages_.pop(); + return task; + } + } + + if (IsQuitting()) + break; + + // Which is shorter, the delay wait or the asked wait? + + int64_t cmsNext; + if (cmsWait == kForever) { + cmsNext = cmsDelayNext; + } else { + cmsNext = std::max<int64_t>(0, cmsTotal - cmsElapsed); + if ((cmsDelayNext != kForever) && (cmsDelayNext < cmsNext)) + cmsNext = cmsDelayNext; + } + + { + // Wait and multiplex in the meantime + if (!ss_->Wait(cmsNext == kForever ? SocketServer::kForever + : webrtc::TimeDelta::Millis(cmsNext), + /*process_io=*/true)) + return nullptr; + } + + // If the specified timeout expired, return + + msCurrent = TimeMillis(); + cmsElapsed = TimeDiff(msCurrent, msStart); + if (cmsWait != kForever) { + if (cmsElapsed >= cmsWait) + return nullptr; + } + } + return nullptr; +} + +void Thread::PostTaskImpl(absl::AnyInvocable<void() &&> task, + const PostTaskTraits& traits, + const webrtc::Location& location) { + if (IsQuitting()) { + return; + } + + // Keep thread safe + // Add the message to the end of the queue + // Signal for the multiplexer to return + + { + MutexLock lock(&mutex_); + messages_.push(std::move(task)); + } + WakeUpSocketServer(); +} + +void Thread::PostDelayedTaskImpl(absl::AnyInvocable<void() &&> task, + webrtc::TimeDelta delay, + const PostDelayedTaskTraits& traits, + const webrtc::Location& location) { + if (IsQuitting()) { + return; + } + + // Keep thread safe + // Add to the priority queue. Gets sorted soonest first. + // Signal for the multiplexer to return. + + int64_t delay_ms = delay.RoundUpTo(webrtc::TimeDelta::Millis(1)).ms<int>(); + int64_t run_time_ms = TimeAfter(delay_ms); + { + MutexLock lock(&mutex_); + delayed_messages_.push({.delay_ms = delay_ms, + .run_time_ms = run_time_ms, + .message_number = delayed_next_num_, + .functor = std::move(task)}); + // If this message queue processes 1 message every millisecond for 50 days, + // we will wrap this number. Even then, only messages with identical times + // will be misordered, and then only briefly. This is probably ok. + ++delayed_next_num_; + RTC_DCHECK_NE(0, delayed_next_num_); + } + WakeUpSocketServer(); +} + +int Thread::GetDelay() { + MutexLock lock(&mutex_); + + if (!messages_.empty()) + return 0; + + if (!delayed_messages_.empty()) { + int delay = TimeUntil(delayed_messages_.top().run_time_ms); + if (delay < 0) + delay = 0; + return delay; + } + + return kForever; +} + +void Thread::Dispatch(absl::AnyInvocable<void() &&> task) { + TRACE_EVENT0("webrtc", "Thread::Dispatch"); + RTC_DCHECK_RUN_ON(this); + int64_t start_time = TimeMillis(); + std::move(task)(); + int64_t end_time = TimeMillis(); + int64_t diff = TimeDiff(end_time, start_time); + if (diff >= dispatch_warning_ms_) { + RTC_LOG(LS_INFO) << "Message to " << name() << " took " << diff + << "ms to dispatch."; + // To avoid log spew, move the warning limit to only give warning + // for delays that are larger than the one observed. + dispatch_warning_ms_ = diff + 1; + } +} + +bool Thread::IsCurrent() const { + return ThreadManager::Instance()->CurrentThread() == this; +} + +std::unique_ptr<Thread> Thread::CreateWithSocketServer() { + return std::unique_ptr<Thread>(new Thread(CreateDefaultSocketServer())); +} + +std::unique_ptr<Thread> Thread::Create() { + return std::unique_ptr<Thread>( + new Thread(std::unique_ptr<SocketServer>(new NullSocketServer()))); +} + +bool Thread::SleepMs(int milliseconds) { + AssertBlockingIsAllowedOnCurrentThread(); + +#if defined(WEBRTC_WIN) + ::Sleep(milliseconds); + return true; +#else + // POSIX has both a usleep() and a nanosleep(), but the former is deprecated, + // so we use nanosleep() even though it has greater precision than necessary. + struct timespec ts; + ts.tv_sec = milliseconds / 1000; + ts.tv_nsec = (milliseconds % 1000) * 1000000; + int ret = nanosleep(&ts, nullptr); + if (ret != 0) { + RTC_LOG_ERR(LS_WARNING) << "nanosleep() returning early"; + return false; + } + return true; +#endif +} + +bool Thread::SetName(absl::string_view name, const void* obj) { + RTC_DCHECK(!IsRunning()); + + name_ = std::string(name); + if (obj) { + // The %p specifier typically produce at most 16 hex digits, possibly with a + // 0x prefix. But format is implementation defined, so add some margin. + char buf[30]; + snprintf(buf, sizeof(buf), " 0x%p", obj); + name_ += buf; + } + return true; +} + +void Thread::SetDispatchWarningMs(int deadline) { + if (!IsCurrent()) { + PostTask([this, deadline]() { SetDispatchWarningMs(deadline); }); + return; + } + RTC_DCHECK_RUN_ON(this); + dispatch_warning_ms_ = deadline; +} + +bool Thread::Start() { + RTC_DCHECK(!IsRunning()); + + if (IsRunning()) + return false; + + Restart(); // reset IsQuitting() if the thread is being restarted + + // Make sure that ThreadManager is created on the main thread before + // we start a new thread. + ThreadManager::Instance(); + + owned_ = true; + +#if defined(WEBRTC_WIN) + thread_ = CreateThread(nullptr, 0, PreRun, this, 0, &thread_id_); + if (!thread_) { + return false; + } +#elif defined(WEBRTC_POSIX) + pthread_attr_t attr; + pthread_attr_init(&attr); + + int error_code = pthread_create(&thread_, &attr, PreRun, this); + if (0 != error_code) { + RTC_LOG(LS_ERROR) << "Unable to create pthread, error " << error_code; + thread_ = 0; + return false; + } + RTC_DCHECK(thread_); +#endif + return true; +} + +bool Thread::WrapCurrent() { + return WrapCurrentWithThreadManager(ThreadManager::Instance(), true); +} + +void Thread::UnwrapCurrent() { + // Clears the platform-specific thread-specific storage. + ThreadManager::Instance()->SetCurrentThread(nullptr); +#if defined(WEBRTC_WIN) + if (thread_ != nullptr) { + if (!CloseHandle(thread_)) { + RTC_LOG_GLE(LS_ERROR) + << "When unwrapping thread, failed to close handle."; + } + thread_ = nullptr; + thread_id_ = 0; + } +#elif defined(WEBRTC_POSIX) + thread_ = 0; +#endif +} + +void Thread::SafeWrapCurrent() { + WrapCurrentWithThreadManager(ThreadManager::Instance(), false); +} + +void Thread::Join() { + if (!IsRunning()) + return; + + RTC_DCHECK(!IsCurrent()); + if (Current() && !Current()->blocking_calls_allowed_) { + RTC_LOG(LS_WARNING) << "Waiting for the thread to join, " + "but blocking calls have been disallowed"; + } + +#if defined(WEBRTC_WIN) + RTC_DCHECK(thread_ != nullptr); + WaitForSingleObject(thread_, INFINITE); + CloseHandle(thread_); + thread_ = nullptr; + thread_id_ = 0; +#elif defined(WEBRTC_POSIX) + pthread_join(thread_, nullptr); + thread_ = 0; +#endif +} + +bool Thread::SetAllowBlockingCalls(bool allow) { + RTC_DCHECK(IsCurrent()); + bool previous = blocking_calls_allowed_; + blocking_calls_allowed_ = allow; + return previous; +} + +// static +void Thread::AssertBlockingIsAllowedOnCurrentThread() { +#if !defined(NDEBUG) + Thread* current = Thread::Current(); + RTC_DCHECK(!current || current->blocking_calls_allowed_); +#endif +} + +// static +#if defined(WEBRTC_WIN) +DWORD WINAPI Thread::PreRun(LPVOID pv) { +#else +void* Thread::PreRun(void* pv) { +#endif + Thread* thread = static_cast<Thread*>(pv); + ThreadManager::Instance()->SetCurrentThread(thread); + rtc::SetCurrentThreadName(thread->name_.c_str()); +#if defined(WEBRTC_MAC) + ScopedAutoReleasePool pool; +#endif + thread->Run(); + + ThreadManager::Instance()->SetCurrentThread(nullptr); +#ifdef WEBRTC_WIN + return 0; +#else + return nullptr; +#endif +} // namespace rtc + +void Thread::Run() { + ProcessMessages(kForever); +} + +bool Thread::IsOwned() { + RTC_DCHECK(IsRunning()); + return owned_; +} + +void Thread::Stop() { + Thread::Quit(); + Join(); +} + +void Thread::BlockingCallImpl(rtc::FunctionView<void()> functor, + const webrtc::Location& location) { + TRACE_EVENT0("webrtc", "Thread::BlockingCall"); + + RTC_DCHECK(!IsQuitting()); + if (IsQuitting()) + return; + + if (IsCurrent()) { +#if RTC_DCHECK_IS_ON + RTC_DCHECK(this->IsInvokeToThreadAllowed(this)); + RTC_DCHECK_RUN_ON(this); + could_be_blocking_call_count_++; +#endif + functor(); + return; + } + +#if RTC_DCHECK_IS_ON + if (Thread* current_thread = Thread::Current()) { + RTC_DCHECK_RUN_ON(current_thread); + RTC_DCHECK(current_thread->blocking_calls_allowed_); + current_thread->blocking_call_count_++; + RTC_DCHECK(current_thread->IsInvokeToThreadAllowed(this)); + ThreadManager::Instance()->RegisterSendAndCheckForCycles(current_thread, + this); + } +#endif + + Event done; + absl::Cleanup cleanup = [&done] { done.Set(); }; + PostTask([functor, cleanup = std::move(cleanup)] { functor(); }); + done.Wait(Event::kForever); +} + +// Called by the ThreadManager when being set as the current thread. +void Thread::EnsureIsCurrentTaskQueue() { + task_queue_registration_ = + std::make_unique<TaskQueueBase::CurrentTaskQueueSetter>(this); +} + +// Called by the ThreadManager when being set as the current thread. +void Thread::ClearCurrentTaskQueue() { + task_queue_registration_.reset(); +} + +void Thread::AllowInvokesToThread(Thread* thread) { +#if (!defined(NDEBUG) || RTC_DCHECK_IS_ON) + if (!IsCurrent()) { + PostTask([thread, this]() { AllowInvokesToThread(thread); }); + return; + } + RTC_DCHECK_RUN_ON(this); + allowed_threads_.push_back(thread); + invoke_policy_enabled_ = true; +#endif +} + +void Thread::DisallowAllInvokes() { +#if (!defined(NDEBUG) || RTC_DCHECK_IS_ON) + if (!IsCurrent()) { + PostTask([this]() { DisallowAllInvokes(); }); + return; + } + RTC_DCHECK_RUN_ON(this); + allowed_threads_.clear(); + invoke_policy_enabled_ = true; +#endif +} + +#if RTC_DCHECK_IS_ON +uint32_t Thread::GetBlockingCallCount() const { + RTC_DCHECK_RUN_ON(this); + return blocking_call_count_; +} +uint32_t Thread::GetCouldBeBlockingCallCount() const { + RTC_DCHECK_RUN_ON(this); + return could_be_blocking_call_count_; +} +#endif + +// Returns true if no policies added or if there is at least one policy +// that permits invocation to `target` thread. +bool Thread::IsInvokeToThreadAllowed(rtc::Thread* target) { +#if (!defined(NDEBUG) || RTC_DCHECK_IS_ON) + RTC_DCHECK_RUN_ON(this); + if (!invoke_policy_enabled_) { + return true; + } + for (const auto* thread : allowed_threads_) { + if (thread == target) { + return true; + } + } + return false; +#else + return true; +#endif +} + +void Thread::Delete() { + Stop(); + delete this; +} + +bool Thread::IsProcessingMessagesForTesting() { + return (owned_ || IsCurrent()) && !IsQuitting(); +} + +bool Thread::ProcessMessages(int cmsLoop) { + // Using ProcessMessages with a custom clock for testing and a time greater + // than 0 doesn't work, since it's not guaranteed to advance the custom + // clock's time, and may get stuck in an infinite loop. + RTC_DCHECK(GetClockForTesting() == nullptr || cmsLoop == 0 || + cmsLoop == kForever); + int64_t msEnd = (kForever == cmsLoop) ? 0 : TimeAfter(cmsLoop); + int cmsNext = cmsLoop; + + while (true) { +#if defined(WEBRTC_MAC) + ScopedAutoReleasePool pool; +#endif + absl::AnyInvocable<void()&&> task = Get(cmsNext); + if (!task) + return !IsQuitting(); + Dispatch(std::move(task)); + + if (cmsLoop != kForever) { + cmsNext = static_cast<int>(TimeUntil(msEnd)); + if (cmsNext < 0) + return true; + } + } +} + +bool Thread::WrapCurrentWithThreadManager(ThreadManager* thread_manager, + bool need_synchronize_access) { + RTC_DCHECK(!IsRunning()); + +#if defined(WEBRTC_WIN) + if (need_synchronize_access) { + // We explicitly ask for no rights other than synchronization. + // This gives us the best chance of succeeding. + thread_ = OpenThread(SYNCHRONIZE, FALSE, GetCurrentThreadId()); + if (!thread_) { + RTC_LOG_GLE(LS_ERROR) << "Unable to get handle to thread."; + return false; + } + thread_id_ = GetCurrentThreadId(); + } +#elif defined(WEBRTC_POSIX) + thread_ = pthread_self(); +#endif + owned_ = false; + thread_manager->SetCurrentThread(this); + return true; +} + +bool Thread::IsRunning() { +#if defined(WEBRTC_WIN) + return thread_ != nullptr; +#elif defined(WEBRTC_POSIX) + return thread_ != 0; +#endif +} + +AutoThread::AutoThread() + : Thread(CreateDefaultSocketServer(), /*do_init=*/false) { + if (!ThreadManager::Instance()->CurrentThread()) { + // DoInit registers with ThreadManager. Do that only if we intend to + // be rtc::Thread::Current(), otherwise ProcessAllMessageQueuesInternal will + // post a message to a queue that no running thread is serving. + DoInit(); + ThreadManager::Instance()->SetCurrentThread(this); + } +} + +AutoThread::~AutoThread() { + Stop(); + DoDestroy(); + if (ThreadManager::Instance()->CurrentThread() == this) { + ThreadManager::Instance()->SetCurrentThread(nullptr); + } +} + +AutoSocketServerThread::AutoSocketServerThread(SocketServer* ss) + : Thread(ss, /*do_init=*/false) { + DoInit(); + old_thread_ = ThreadManager::Instance()->CurrentThread(); + // Temporarily set the current thread to nullptr so that we can keep checks + // around that catch unintentional pointer overwrites. + rtc::ThreadManager::Instance()->SetCurrentThread(nullptr); + rtc::ThreadManager::Instance()->SetCurrentThread(this); + if (old_thread_) { + ThreadManager::Remove(old_thread_); + } +} + +AutoSocketServerThread::~AutoSocketServerThread() { + RTC_DCHECK(ThreadManager::Instance()->CurrentThread() == this); + // Stop and destroy the thread before clearing it as the current thread. + // Sometimes there are messages left in the Thread that will be + // destroyed by DoDestroy, and sometimes the destructors of the message and/or + // its contents rely on this thread still being set as the current thread. + Stop(); + DoDestroy(); + rtc::ThreadManager::Instance()->SetCurrentThread(nullptr); + rtc::ThreadManager::Instance()->SetCurrentThread(old_thread_); + if (old_thread_) { + ThreadManager::Add(old_thread_); + } +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/thread.h b/third_party/libwebrtc/rtc_base/thread.h new file mode 100644 index 0000000000..1f48b6d923 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/thread.h @@ -0,0 +1,571 @@ +/* + * 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 RTC_BASE_THREAD_H_ +#define RTC_BASE_THREAD_H_ + +#include <stdint.h> + +#include <list> +#include <map> +#include <memory> +#include <queue> +#include <set> +#include <string> +#include <type_traits> +#include <utility> +#include <vector> + +#include "absl/strings/string_view.h" + +#if defined(WEBRTC_POSIX) +#include <pthread.h> +#endif +#include "absl/base/attributes.h" +#include "absl/functional/any_invocable.h" +#include "api/function_view.h" +#include "api/location.h" +#include "api/task_queue/task_queue_base.h" +#include "api/units/time_delta.h" +#include "rtc_base/checks.h" +#include "rtc_base/platform_thread_types.h" +#include "rtc_base/socket_server.h" +#include "rtc_base/synchronization/mutex.h" +#include "rtc_base/system/rtc_export.h" +#include "rtc_base/thread_annotations.h" + +#if defined(WEBRTC_WIN) +#include "rtc_base/win32.h" +#endif + +#if RTC_DCHECK_IS_ON +// Counts how many `Thread::BlockingCall` are made from within a scope and logs +// the number of blocking calls at the end of the scope. +#define RTC_LOG_THREAD_BLOCK_COUNT() \ + rtc::Thread::ScopedCountBlockingCalls blocked_call_count_printer( \ + [func = __func__](uint32_t actual_block, uint32_t could_block) { \ + auto total = actual_block + could_block; \ + if (total) { \ + RTC_LOG(LS_WARNING) << "Blocking " << func << ": total=" << total \ + << " (actual=" << actual_block \ + << ", could=" << could_block << ")"; \ + } \ + }) + +// Adds an RTC_DCHECK_LE that checks that the number of blocking calls are +// less than or equal to a specific value. Use to avoid regressing in the +// number of blocking thread calls. +// Note: Use of this macro, requires RTC_LOG_THREAD_BLOCK_COUNT() to be called +// first. +#define RTC_DCHECK_BLOCK_COUNT_NO_MORE_THAN(x) \ + do { \ + blocked_call_count_printer.set_minimum_call_count_for_callback(x + 1); \ + RTC_DCHECK_LE(blocked_call_count_printer.GetTotalBlockedCallCount(), x); \ + } while (0) +#else +#define RTC_LOG_THREAD_BLOCK_COUNT() +#define RTC_DCHECK_BLOCK_COUNT_NO_MORE_THAN(x) +#endif + +namespace rtc { + +class Thread; + +class RTC_EXPORT ThreadManager { + public: + static const int kForever = -1; + + // Singleton, constructor and destructor are private. + static ThreadManager* Instance(); + + static void Add(Thread* message_queue); + static void Remove(Thread* message_queue); + + // For testing purposes, for use with a simulated clock. + // Ensures that all message queues have processed delayed messages + // up until the current point in time. + static void ProcessAllMessageQueuesForTesting(); + + Thread* CurrentThread(); + void SetCurrentThread(Thread* thread); + // Allows changing the current thread, this is intended for tests where we + // want to simulate multiple threads running on a single physical thread. + void ChangeCurrentThreadForTest(Thread* thread); + + // Returns a thread object with its thread_ ivar set + // to whatever the OS uses to represent the thread. + // If there already *is* a Thread object corresponding to this thread, + // this method will return that. Otherwise it creates a new Thread + // object whose wrapped() method will return true, and whose + // handle will, on Win32, be opened with only synchronization privileges - + // if you need more privilegs, rather than changing this method, please + // write additional code to adjust the privileges, or call a different + // factory method of your own devising, because this one gets used in + // unexpected contexts (like inside browser plugins) and it would be a + // shame to break it. It is also conceivable on Win32 that we won't even + // be able to get synchronization privileges, in which case the result + // will have a null handle. + Thread* WrapCurrentThread(); + void UnwrapCurrentThread(); + +#if RTC_DCHECK_IS_ON + // Registers that a Send operation is to be performed between `source` and + // `target`, while checking that this does not cause a send cycle that could + // potentially cause a deadlock. + void RegisterSendAndCheckForCycles(Thread* source, Thread* target); +#endif + + private: + ThreadManager(); + ~ThreadManager(); + + ThreadManager(const ThreadManager&) = delete; + ThreadManager& operator=(const ThreadManager&) = delete; + + void SetCurrentThreadInternal(Thread* thread); + void AddInternal(Thread* message_queue); + void RemoveInternal(Thread* message_queue); + void ProcessAllMessageQueuesInternal(); +#if RTC_DCHECK_IS_ON + void RemoveFromSendGraph(Thread* thread) RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_); +#endif + + // This list contains all live Threads. + std::vector<Thread*> message_queues_ RTC_GUARDED_BY(crit_); + + webrtc::Mutex crit_; + +#if RTC_DCHECK_IS_ON + // Represents all thread seand actions by storing all send targets per thread. + // This is used by RegisterSendAndCheckForCycles. This graph has no cycles + // since we will trigger a CHECK failure if a cycle is introduced. + std::map<Thread*, std::set<Thread*>> send_graph_ RTC_GUARDED_BY(crit_); +#endif + +#if defined(WEBRTC_POSIX) + pthread_key_t key_; +#endif + +#if defined(WEBRTC_WIN) + const DWORD key_; +#endif +}; + +// WARNING! SUBCLASSES MUST CALL Stop() IN THEIR DESTRUCTORS! See ~Thread(). + +class RTC_LOCKABLE RTC_EXPORT Thread : public webrtc::TaskQueueBase { + public: + static const int kForever = -1; + + // Create a new Thread and optionally assign it to the passed + // SocketServer. Subclasses that override Clear should pass false for + // init_queue and call DoInit() from their constructor to prevent races + // with the ThreadManager using the object while the vtable is still + // being created. + explicit Thread(SocketServer* ss); + explicit Thread(std::unique_ptr<SocketServer> ss); + + // Constructors meant for subclasses; they should call DoInit themselves and + // pass false for `do_init`, so that DoInit is called only on the fully + // instantiated class, which avoids a vptr data race. + Thread(SocketServer* ss, bool do_init); + Thread(std::unique_ptr<SocketServer> ss, bool do_init); + + // NOTE: ALL SUBCLASSES OF Thread MUST CALL Stop() IN THEIR DESTRUCTORS (or + // guarantee Stop() is explicitly called before the subclass is destroyed). + // This is required to avoid a data race between the destructor modifying the + // vtable, and the Thread::PreRun calling the virtual method Run(). + + // NOTE: SUBCLASSES OF Thread THAT OVERRIDE Clear MUST CALL + // DoDestroy() IN THEIR DESTRUCTORS! This is required to avoid a data race + // between the destructor modifying the vtable, and the ThreadManager + // calling Clear on the object from a different thread. + ~Thread() override; + + Thread(const Thread&) = delete; + Thread& operator=(const Thread&) = delete; + + static std::unique_ptr<Thread> CreateWithSocketServer(); + static std::unique_ptr<Thread> Create(); + static Thread* Current(); + + // Used to catch performance regressions. Use this to disallow BlockingCall + // for a given scope. If a synchronous call is made while this is in + // effect, an assert will be triggered. + // Note that this is a single threaded class. + class ScopedDisallowBlockingCalls { + public: + ScopedDisallowBlockingCalls(); + ScopedDisallowBlockingCalls(const ScopedDisallowBlockingCalls&) = delete; + ScopedDisallowBlockingCalls& operator=(const ScopedDisallowBlockingCalls&) = + delete; + ~ScopedDisallowBlockingCalls(); + + private: + Thread* const thread_; + const bool previous_state_; + }; + +#if RTC_DCHECK_IS_ON + class ScopedCountBlockingCalls { + public: + ScopedCountBlockingCalls(std::function<void(uint32_t, uint32_t)> callback); + ScopedCountBlockingCalls(const ScopedDisallowBlockingCalls&) = delete; + ScopedCountBlockingCalls& operator=(const ScopedDisallowBlockingCalls&) = + delete; + ~ScopedCountBlockingCalls(); + + uint32_t GetBlockingCallCount() const; + uint32_t GetCouldBeBlockingCallCount() const; + uint32_t GetTotalBlockedCallCount() const; + + void set_minimum_call_count_for_callback(uint32_t minimum) { + min_blocking_calls_for_callback_ = minimum; + } + + private: + Thread* const thread_; + const uint32_t base_blocking_call_count_; + const uint32_t base_could_be_blocking_call_count_; + // The minimum number of blocking calls required in order to issue the + // result_callback_. This is used by RTC_DCHECK_BLOCK_COUNT_NO_MORE_THAN to + // tame log spam. + // By default we always issue the callback, regardless of callback count. + uint32_t min_blocking_calls_for_callback_ = 0; + std::function<void(uint32_t, uint32_t)> result_callback_; + }; + + uint32_t GetBlockingCallCount() const; + uint32_t GetCouldBeBlockingCallCount() const; +#endif + + SocketServer* socketserver(); + + // Note: The behavior of Thread has changed. When a thread is stopped, + // futher Posts and Sends will fail. However, any pending Sends and *ready* + // Posts (as opposed to unexpired delayed Posts) will be delivered before + // Get (or Peek) returns false. By guaranteeing delivery of those messages, + // we eliminate the race condition when an MessageHandler and Thread + // may be destroyed independently of each other. + virtual void Quit(); + virtual bool IsQuitting(); + virtual void Restart(); + // Not all message queues actually process messages (such as SignalThread). + // In those cases, it's important to know, before posting, that it won't be + // Processed. Normally, this would be true until IsQuitting() is true. + virtual bool IsProcessingMessagesForTesting(); + + // Amount of time until the next message can be retrieved + virtual int GetDelay(); + + bool empty() const { return size() == 0u; } + size_t size() const { + webrtc::MutexLock lock(&mutex_); + return messages_.size() + delayed_messages_.size(); + } + + bool IsCurrent() const; + + // Sleeps the calling thread for the specified number of milliseconds, during + // which time no processing is performed. Returns false if sleeping was + // interrupted by a signal (POSIX only). + static bool SleepMs(int millis); + + // Sets the thread's name, for debugging. Must be called before Start(). + // If `obj` is non-null, its value is appended to `name`. + const std::string& name() const { return name_; } + bool SetName(absl::string_view name, const void* obj); + + // Sets the expected processing time in ms. The thread will write + // log messages when Dispatch() takes more time than this. + // Default is 50 ms. + void SetDispatchWarningMs(int deadline); + + // Starts the execution of the thread. + bool Start(); + + // Tells the thread to stop and waits until it is joined. + // Never call Stop on the current thread. Instead use the inherited Quit + // function which will exit the base Thread without terminating the + // underlying OS thread. + virtual void Stop(); + + // By default, Thread::Run() calls ProcessMessages(kForever). To do other + // work, override Run(). To receive and dispatch messages, call + // ProcessMessages occasionally. + virtual void Run(); + + // Convenience method to invoke a functor on another thread. + // Blocks the current thread until execution is complete. + // Ex: thread.BlockingCall([&] { result = MyFunctionReturningBool(); }); + // NOTE: This function can only be called when synchronous calls are allowed. + // See ScopedDisallowBlockingCalls for details. + // NOTE: Blocking calls are DISCOURAGED, consider if what you're doing can + // be achieved with PostTask() and callbacks instead. + void BlockingCall( + FunctionView<void()> functor, + const webrtc::Location& location = webrtc::Location::Current()) { + BlockingCallImpl(std::move(functor), location); + } + + template <typename Functor, + typename ReturnT = std::invoke_result_t<Functor>, + typename = typename std::enable_if_t<!std::is_void_v<ReturnT>>> + ReturnT BlockingCall( + Functor&& functor, + const webrtc::Location& location = webrtc::Location::Current()) { + ReturnT result; + BlockingCall([&] { result = std::forward<Functor>(functor)(); }, location); + return result; + } + + // Allows BlockingCall to specified `thread`. Thread never will be + // dereferenced and will be used only for reference-based comparison, so + // instance can be safely deleted. If NDEBUG is defined and RTC_DCHECK_IS_ON + // is undefined do nothing. + void AllowInvokesToThread(Thread* thread); + + // If NDEBUG is defined and RTC_DCHECK_IS_ON is undefined do nothing. + void DisallowAllInvokes(); + // Returns true if `target` was allowed by AllowInvokesToThread() or if no + // calls were made to AllowInvokesToThread and DisallowAllInvokes. Otherwise + // returns false. + // If NDEBUG is defined and RTC_DCHECK_IS_ON is undefined always returns + // true. + bool IsInvokeToThreadAllowed(rtc::Thread* target); + + // From TaskQueueBase + void Delete() override; + + // ProcessMessages will process I/O and dispatch messages until: + // 1) cms milliseconds have elapsed (returns true) + // 2) Stop() is called (returns false) + bool ProcessMessages(int cms); + + // Returns true if this is a thread that we created using the standard + // constructor, false if it was created by a call to + // ThreadManager::WrapCurrentThread(). The main thread of an application + // is generally not owned, since the OS representation of the thread + // obviously exists before we can get to it. + // You cannot call Start on non-owned threads. + bool IsOwned(); + + // Expose private method IsRunning() for tests. + // + // DANGER: this is a terrible public API. Most callers that might want to + // call this likely do not have enough control/knowledge of the Thread in + // question to guarantee that the returned value remains true for the duration + // of whatever code is conditionally executing because of the return value! + bool RunningForTest() { return IsRunning(); } + + // These functions are public to avoid injecting test hooks. Don't call them + // outside of tests. + // This method should be called when thread is created using non standard + // method, like derived implementation of rtc::Thread and it can not be + // started by calling Start(). This will set started flag to true and + // owned to false. This must be called from the current thread. + bool WrapCurrent(); + void UnwrapCurrent(); + + // Sets the per-thread allow-blocking-calls flag to false; this is + // irrevocable. Must be called on this thread. + void DisallowBlockingCalls() { SetAllowBlockingCalls(false); } + + protected: + class CurrentThreadSetter : CurrentTaskQueueSetter { + public: + explicit CurrentThreadSetter(Thread* thread) + : CurrentTaskQueueSetter(thread), + manager_(rtc::ThreadManager::Instance()), + previous_(manager_->CurrentThread()) { + manager_->ChangeCurrentThreadForTest(thread); + } + ~CurrentThreadSetter() { manager_->ChangeCurrentThreadForTest(previous_); } + + private: + rtc::ThreadManager* const manager_; + rtc::Thread* const previous_; + }; + + // DelayedMessage goes into a priority queue, sorted by trigger time. Messages + // with the same trigger time are processed in num_ (FIFO) order. + struct DelayedMessage { + bool operator<(const DelayedMessage& dmsg) const { + return (dmsg.run_time_ms < run_time_ms) || + ((dmsg.run_time_ms == run_time_ms) && + (dmsg.message_number < message_number)); + } + + int64_t delay_ms; // for debugging + int64_t run_time_ms; + // Monotonicaly incrementing number used for ordering of messages + // targeted to execute at the same time. + uint32_t message_number; + // std::priority_queue doesn't allow to extract elements, but functor + // is move-only and thus need to be changed when pulled out of the + // priority queue. That is ok because `functor` doesn't affect operator< + mutable absl::AnyInvocable<void() &&> functor; + }; + + // TaskQueueBase implementation. + void PostTaskImpl(absl::AnyInvocable<void() &&> task, + const PostTaskTraits& traits, + const webrtc::Location& location) override; + void PostDelayedTaskImpl(absl::AnyInvocable<void() &&> task, + webrtc::TimeDelta delay, + const PostDelayedTaskTraits& traits, + const webrtc::Location& location) override; + + virtual void BlockingCallImpl(FunctionView<void()> functor, + const webrtc::Location& location); + + // Perform initialization, subclasses must call this from their constructor + // if false was passed as init_queue to the Thread constructor. + void DoInit(); + + // Perform cleanup; subclasses must call this from the destructor, + // and are not expected to actually hold the lock. + void DoDestroy() RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + void WakeUpSocketServer(); + + // Same as WrapCurrent except that it never fails as it does not try to + // acquire the synchronization access of the thread. The caller should never + // call Stop() or Join() on this thread. + void SafeWrapCurrent(); + + // Blocks the calling thread until this thread has terminated. + void Join(); + + static void AssertBlockingIsAllowedOnCurrentThread(); + + friend class ScopedDisallowBlockingCalls; + + private: + static const int kSlowDispatchLoggingThreshold = 50; // 50 ms + + // Get() will process I/O until: + // 1) A task is available (returns it) + // 2) cmsWait seconds have elapsed (returns empty task) + // 3) Stop() is called (returns empty task) + absl::AnyInvocable<void() &&> Get(int cmsWait); + void Dispatch(absl::AnyInvocable<void() &&> task); + + // Sets the per-thread allow-blocking-calls flag and returns the previous + // value. Must be called on this thread. + bool SetAllowBlockingCalls(bool allow); + +#if defined(WEBRTC_WIN) + static DWORD WINAPI PreRun(LPVOID context); +#else + static void* PreRun(void* pv); +#endif + + // ThreadManager calls this instead WrapCurrent() because + // ThreadManager::Instance() cannot be used while ThreadManager is + // being created. + // The method tries to get synchronization rights of the thread on Windows if + // `need_synchronize_access` is true. + bool WrapCurrentWithThreadManager(ThreadManager* thread_manager, + bool need_synchronize_access); + + // Return true if the thread is currently running. + bool IsRunning(); + + // Called by the ThreadManager when being set as the current thread. + void EnsureIsCurrentTaskQueue(); + + // Called by the ThreadManager when being unset as the current thread. + void ClearCurrentTaskQueue(); + + std::queue<absl::AnyInvocable<void() &&>> messages_ RTC_GUARDED_BY(mutex_); + std::priority_queue<DelayedMessage> delayed_messages_ RTC_GUARDED_BY(mutex_); + uint32_t delayed_next_num_ RTC_GUARDED_BY(mutex_); +#if RTC_DCHECK_IS_ON + uint32_t blocking_call_count_ RTC_GUARDED_BY(this) = 0; + uint32_t could_be_blocking_call_count_ RTC_GUARDED_BY(this) = 0; + std::vector<Thread*> allowed_threads_ RTC_GUARDED_BY(this); + bool invoke_policy_enabled_ RTC_GUARDED_BY(this) = false; +#endif + mutable webrtc::Mutex mutex_; + bool fInitialized_; + bool fDestroyed_; + + std::atomic<int> stop_; + + // The SocketServer might not be owned by Thread. + SocketServer* const ss_; + // Used if SocketServer ownership lies with `this`. + std::unique_ptr<SocketServer> own_ss_; + + std::string name_; + + // TODO(tommi): Add thread checks for proper use of control methods. + // Ideally we should be able to just use PlatformThread. + +#if defined(WEBRTC_POSIX) + pthread_t thread_ = 0; +#endif + +#if defined(WEBRTC_WIN) + HANDLE thread_ = nullptr; + DWORD thread_id_ = 0; +#endif + + // Indicates whether or not ownership of the worker thread lies with + // this instance or not. (i.e. owned_ == !wrapped). + // Must only be modified when the worker thread is not running. + bool owned_ = true; + + // Only touched from the worker thread itself. + bool blocking_calls_allowed_ = true; + + std::unique_ptr<TaskQueueBase::CurrentTaskQueueSetter> + task_queue_registration_; + + friend class ThreadManager; + + int dispatch_warning_ms_ RTC_GUARDED_BY(this) = kSlowDispatchLoggingThreshold; +}; + +// AutoThread automatically installs itself at construction +// uninstalls at destruction, if a Thread object is +// _not already_ associated with the current OS thread. +// +// NOTE: *** This class should only be used by tests *** +// +class AutoThread : public Thread { + public: + AutoThread(); + ~AutoThread() override; + + AutoThread(const AutoThread&) = delete; + AutoThread& operator=(const AutoThread&) = delete; +}; + +// AutoSocketServerThread automatically installs itself at +// construction and uninstalls at destruction. If a Thread object is +// already associated with the current OS thread, it is temporarily +// disassociated and restored by the destructor. + +class AutoSocketServerThread : public Thread { + public: + explicit AutoSocketServerThread(SocketServer* ss); + ~AutoSocketServerThread() override; + + AutoSocketServerThread(const AutoSocketServerThread&) = delete; + AutoSocketServerThread& operator=(const AutoSocketServerThread&) = delete; + + private: + rtc::Thread* old_thread_; +}; +} // namespace rtc + +#endif // RTC_BASE_THREAD_H_ diff --git a/third_party/libwebrtc/rtc_base/thread_annotations.h b/third_party/libwebrtc/rtc_base/thread_annotations.h new file mode 100644 index 0000000000..689f6681cc --- /dev/null +++ b/third_party/libwebrtc/rtc_base/thread_annotations.h @@ -0,0 +1,98 @@ +// +// Copyright (c) 2013 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. +// +// Borrowed from +// https://code.google.com/p/gperftools/source/browse/src/base/thread_annotations.h +// but adapted for clang attributes instead of the gcc. +// +// This header file contains the macro definitions for thread safety +// annotations that allow the developers to document the locking policies +// of their multi-threaded code. The annotations can also help program +// analysis tools to identify potential thread safety issues. + +#ifndef RTC_BASE_THREAD_ANNOTATIONS_H_ +#define RTC_BASE_THREAD_ANNOTATIONS_H_ + +#if defined(__clang__) && (!defined(SWIG)) +#define RTC_THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x)) +#else +#define RTC_THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op +#endif + +// Document if a shared variable/field needs to be protected by a lock. +// GUARDED_BY allows the user to specify a particular lock that should be +// held when accessing the annotated variable. +#define RTC_GUARDED_BY(x) RTC_THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x)) + +// Document if the memory location pointed to by a pointer should be guarded +// by a lock when dereferencing the pointer. Note that a pointer variable to a +// shared memory location could itself be a shared variable. For example, if a +// shared global pointer q, which is guarded by mu1, points to a shared memory +// location that is guarded by mu2, q should be annotated as follows: +// int *q GUARDED_BY(mu1) PT_GUARDED_BY(mu2); +#define RTC_PT_GUARDED_BY(x) RTC_THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x)) + +// Document the acquisition order between locks that can be held +// simultaneously by a thread. For any two locks that need to be annotated +// to establish an acquisition order, only one of them needs the annotation. +// (i.e. You don't have to annotate both locks with both ACQUIRED_AFTER +// and ACQUIRED_BEFORE.) +#define RTC_ACQUIRED_AFTER(x) \ + RTC_THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(x)) +#define RTC_ACQUIRED_BEFORE(x) \ + RTC_THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(x)) + +// The following three annotations document the lock requirements for +// functions/methods. + +// Document if a function expects certain locks to be held before it is called +#define RTC_EXCLUSIVE_LOCKS_REQUIRED(...) \ + RTC_THREAD_ANNOTATION_ATTRIBUTE__(exclusive_locks_required(__VA_ARGS__)) +#define RTC_SHARED_LOCKS_REQUIRED(...) \ + RTC_THREAD_ANNOTATION_ATTRIBUTE__(shared_locks_required(__VA_ARGS__)) + +// Document the locks acquired in the body of the function. These locks +// cannot be held when calling this function (as google3's Mutex locks are +// non-reentrant). +#define RTC_LOCKS_EXCLUDED(...) \ + RTC_THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__)) + +// Document the lock the annotated function returns without acquiring it. +#define RTC_LOCK_RETURNED(x) RTC_THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x)) + +// Document if a class/type is a lockable type (such as the Mutex class). +#define RTC_LOCKABLE RTC_THREAD_ANNOTATION_ATTRIBUTE__(lockable) + +// Document if a class is a scoped lockable type (such as the MutexLock class). +#define RTC_SCOPED_LOCKABLE RTC_THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable) + +// The following annotations specify lock and unlock primitives. +#define RTC_EXCLUSIVE_LOCK_FUNCTION(...) \ + RTC_THREAD_ANNOTATION_ATTRIBUTE__(exclusive_lock_function(__VA_ARGS__)) + +#define RTC_SHARED_LOCK_FUNCTION(...) \ + RTC_THREAD_ANNOTATION_ATTRIBUTE__(shared_lock_function(__VA_ARGS__)) + +#define RTC_EXCLUSIVE_TRYLOCK_FUNCTION(...) \ + RTC_THREAD_ANNOTATION_ATTRIBUTE__(exclusive_trylock_function(__VA_ARGS__)) + +#define RTC_SHARED_TRYLOCK_FUNCTION(...) \ + RTC_THREAD_ANNOTATION_ATTRIBUTE__(shared_trylock_function(__VA_ARGS__)) + +#define RTC_UNLOCK_FUNCTION(...) \ + RTC_THREAD_ANNOTATION_ATTRIBUTE__(unlock_function(__VA_ARGS__)) + +#define RTC_ASSERT_EXCLUSIVE_LOCK(...) \ + RTC_THREAD_ANNOTATION_ATTRIBUTE__(assert_exclusive_lock(__VA_ARGS__)) + +// An escape hatch for thread safety analysis to ignore the annotated function. +#define RTC_NO_THREAD_SAFETY_ANALYSIS \ + RTC_THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis) + +#endif // RTC_BASE_THREAD_ANNOTATIONS_H_ diff --git a/third_party/libwebrtc/rtc_base/thread_annotations_unittest.cc b/third_party/libwebrtc/rtc_base/thread_annotations_unittest.cc new file mode 100644 index 0000000000..1b296dadd9 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/thread_annotations_unittest.cc @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2016 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 "rtc_base/thread_annotations.h" + +#include "test/gtest.h" + +namespace { + +class RTC_LOCKABLE Lock { + public: + void EnterWrite() const RTC_EXCLUSIVE_LOCK_FUNCTION() {} + void EnterRead() const RTC_SHARED_LOCK_FUNCTION() {} + bool TryEnterWrite() const RTC_EXCLUSIVE_TRYLOCK_FUNCTION(true) { + return true; + } + bool TryEnterRead() const RTC_SHARED_TRYLOCK_FUNCTION(true) { return true; } + void Leave() const RTC_UNLOCK_FUNCTION() {} +}; + +class RTC_SCOPED_LOCKABLE ScopeLock { + public: + explicit ScopeLock(const Lock& lock) RTC_EXCLUSIVE_LOCK_FUNCTION(lock) {} + ~ScopeLock() RTC_UNLOCK_FUNCTION() {} +}; + +class ThreadSafe { + public: + ThreadSafe() { pt_protected_by_lock_ = new int; } + + ~ThreadSafe() { delete pt_protected_by_lock_; } + + void LockInOrder() { + beforelock_.EnterWrite(); + lock_.EnterWrite(); + pt_lock_.EnterWrite(); + + pt_lock_.Leave(); + lock_.Leave(); + beforelock_.Leave(); + } + + void UnprotectedFunction() RTC_LOCKS_EXCLUDED(lock_, pt_lock_) { + // Can access unprotected Value. + unprotected_ = 15; + // Can access pointers themself, but not data they point to. + int* tmp = pt_protected_by_lock_; + pt_protected_by_lock_ = tmp; + } + + void ReadProtected() { + lock_.EnterRead(); + unprotected_ = protected_by_lock_; + lock_.Leave(); + + if (pt_lock_.TryEnterRead()) { + unprotected_ = *pt_protected_by_lock_; + pt_lock_.Leave(); + } + } + + void WriteProtected() { + lock_.EnterWrite(); + protected_by_lock_ = unprotected_; + lock_.Leave(); + + if (pt_lock_.TryEnterWrite()) { + *pt_protected_by_lock_ = unprotected_; + pt_lock_.Leave(); + } + } + + void CallReadProtectedFunction() { + lock_.EnterRead(); + pt_lock_.EnterRead(); + ReadProtectedFunction(); + pt_lock_.Leave(); + lock_.Leave(); + } + + void CallWriteProtectedFunction() { + ScopeLock scope_lock(GetLock()); + ScopeLock pt_scope_lock(pt_lock_); + WriteProtectedFunction(); + } + + private: + void ReadProtectedFunction() RTC_SHARED_LOCKS_REQUIRED(lock_, pt_lock_) { + unprotected_ = protected_by_lock_; + unprotected_ = *pt_protected_by_lock_; + } + + void WriteProtectedFunction() RTC_EXCLUSIVE_LOCKS_REQUIRED(lock_, pt_lock_) { + int x = protected_by_lock_; + *pt_protected_by_lock_ = x; + protected_by_lock_ = unprotected_; + } + + const Lock& GetLock() RTC_LOCK_RETURNED(lock_) { return lock_; } + + Lock beforelock_ RTC_ACQUIRED_BEFORE(lock_); + Lock lock_; + Lock pt_lock_ RTC_ACQUIRED_AFTER(lock_); + + int unprotected_ = 0; + + int protected_by_lock_ RTC_GUARDED_BY(lock_) = 0; + + int* pt_protected_by_lock_ RTC_PT_GUARDED_BY(pt_lock_); +}; + +} // namespace + +TEST(ThreadAnnotationsTest, Test) { + // This test ensure thread annotations doesn't break compilation. + // Thus no run-time expectations. + ThreadSafe t; + t.LockInOrder(); + t.UnprotectedFunction(); + t.ReadProtected(); + t.WriteProtected(); + t.CallReadProtectedFunction(); + t.CallWriteProtectedFunction(); +} diff --git a/third_party/libwebrtc/rtc_base/thread_unittest.cc b/third_party/libwebrtc/rtc_base/thread_unittest.cc new file mode 100644 index 0000000000..cd733db2cd --- /dev/null +++ b/third_party/libwebrtc/rtc_base/thread_unittest.cc @@ -0,0 +1,852 @@ +/* + * 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 "rtc_base/thread.h" + +#include <memory> + +#include "api/field_trials_view.h" +#include "api/task_queue/task_queue_factory.h" +#include "api/task_queue/task_queue_test.h" +#include "api/units/time_delta.h" +#include "rtc_base/async_udp_socket.h" +#include "rtc_base/checks.h" +#include "rtc_base/event.h" +#include "rtc_base/fake_clock.h" +#include "rtc_base/gunit.h" +#include "rtc_base/internal/default_socket_server.h" +#include "rtc_base/null_socket_server.h" +#include "rtc_base/physical_socket_server.h" +#include "rtc_base/ref_counted_object.h" +#include "rtc_base/socket_address.h" +#include "rtc_base/synchronization/mutex.h" +#include "rtc_base/third_party/sigslot/sigslot.h" +#include "test/gmock.h" +#include "test/testsupport/rtc_expect_death.h" + +#if defined(WEBRTC_WIN) +#include <comdef.h> // NOLINT + +#endif + +namespace rtc { +namespace { + +using ::testing::ElementsAre; +using ::webrtc::TimeDelta; + +// Generates a sequence of numbers (collaboratively). +class TestGenerator { + public: + TestGenerator() : last(0), count(0) {} + + int Next(int prev) { + int result = prev + last; + last = result; + count += 1; + return result; + } + + int last; + int count; +}; + +// Receives messages and sends on a socket. +class MessageClient : public TestGenerator { + public: + MessageClient(Thread* pth, Socket* socket) : socket_(socket) {} + + ~MessageClient() { delete socket_; } + + void OnValue(int value) { + int result = Next(value); + EXPECT_GE(socket_->Send(&result, sizeof(result)), 0); + } + + private: + Socket* socket_; +}; + +// Receives on a socket and sends by posting messages. +class SocketClient : public TestGenerator, public sigslot::has_slots<> { + public: + SocketClient(Socket* socket, + const SocketAddress& addr, + Thread* post_thread, + MessageClient* phandler) + : socket_(AsyncUDPSocket::Create(socket, addr)), + post_thread_(post_thread), + post_handler_(phandler) { + socket_->SignalReadPacket.connect(this, &SocketClient::OnPacket); + } + + ~SocketClient() override { delete socket_; } + + SocketAddress address() const { return socket_->GetLocalAddress(); } + + void OnPacket(AsyncPacketSocket* socket, + const char* buf, + size_t size, + const SocketAddress& remote_addr, + const int64_t& packet_time_us) { + EXPECT_EQ(size, sizeof(uint32_t)); + uint32_t prev = reinterpret_cast<const uint32_t*>(buf)[0]; + uint32_t result = Next(prev); + + post_thread_->PostDelayedTask([post_handler_ = post_handler_, + result] { post_handler_->OnValue(result); }, + TimeDelta::Millis(200)); + } + + private: + AsyncUDPSocket* socket_; + Thread* post_thread_; + MessageClient* post_handler_; +}; + +class CustomThread : public rtc::Thread { + public: + CustomThread() + : Thread(std::unique_ptr<SocketServer>(new rtc::NullSocketServer())) {} + ~CustomThread() override { Stop(); } + bool Start() { return false; } + + bool WrapCurrent() { return Thread::WrapCurrent(); } + void UnwrapCurrent() { Thread::UnwrapCurrent(); } +}; + +// A thread that does nothing when it runs and signals an event +// when it is destroyed. +class SignalWhenDestroyedThread : public Thread { + public: + SignalWhenDestroyedThread(Event* event) + : Thread(std::unique_ptr<SocketServer>(new NullSocketServer())), + event_(event) {} + + ~SignalWhenDestroyedThread() override { + Stop(); + event_->Set(); + } + + void Run() override { + // Do nothing. + } + + private: + Event* event_; +}; + +// See: https://code.google.com/p/webrtc/issues/detail?id=2409 +TEST(ThreadTest, DISABLED_Main) { + rtc::AutoThread main_thread; + const SocketAddress addr("127.0.0.1", 0); + + // Create the messaging client on its own thread. + auto th1 = Thread::CreateWithSocketServer(); + Socket* socket = th1->socketserver()->CreateSocket(addr.family(), SOCK_DGRAM); + MessageClient msg_client(th1.get(), socket); + + // Create the socket client on its own thread. + auto th2 = Thread::CreateWithSocketServer(); + Socket* asocket = + th2->socketserver()->CreateSocket(addr.family(), SOCK_DGRAM); + SocketClient sock_client(asocket, addr, th1.get(), &msg_client); + + socket->Connect(sock_client.address()); + + th1->Start(); + th2->Start(); + + // Get the messages started. + th1->PostDelayedTask([&msg_client] { msg_client.OnValue(1); }, + TimeDelta::Millis(100)); + + // Give the clients a little while to run. + // Messages will be processed at 100, 300, 500, 700, 900. + Thread* th_main = Thread::Current(); + th_main->ProcessMessages(1000); + + // Stop the sending client. Give the receiver a bit longer to run, in case + // it is running on a machine that is under load (e.g. the build machine). + th1->Stop(); + th_main->ProcessMessages(200); + th2->Stop(); + + // Make sure the results were correct + EXPECT_EQ(5, msg_client.count); + EXPECT_EQ(34, msg_client.last); + EXPECT_EQ(5, sock_client.count); + EXPECT_EQ(55, sock_client.last); +} + +TEST(ThreadTest, CountBlockingCalls) { + rtc::AutoThread current; + + // When the test runs, this will print out: + // (thread_unittest.cc:262): Blocking TestBody: total=2 (actual=1, could=1) + RTC_LOG_THREAD_BLOCK_COUNT(); +#if RTC_DCHECK_IS_ON + rtc::Thread::ScopedCountBlockingCalls blocked_calls( + [&](uint32_t actual_block, uint32_t could_block) { + EXPECT_EQ(1u, actual_block); + EXPECT_EQ(1u, could_block); + }); + + EXPECT_EQ(0u, blocked_calls.GetBlockingCallCount()); + EXPECT_EQ(0u, blocked_calls.GetCouldBeBlockingCallCount()); + EXPECT_EQ(0u, blocked_calls.GetTotalBlockedCallCount()); + + // Test invoking on the current thread. This should not count as an 'actual' + // invoke, but should still count as an invoke that could block since we + // that the call to `BlockingCall` serves a purpose in some configurations + // (and should not be used a general way to call methods on the same thread). + current.BlockingCall([]() {}); + EXPECT_EQ(0u, blocked_calls.GetBlockingCallCount()); + EXPECT_EQ(1u, blocked_calls.GetCouldBeBlockingCallCount()); + EXPECT_EQ(1u, blocked_calls.GetTotalBlockedCallCount()); + + // Create a new thread to invoke on. + auto thread = Thread::CreateWithSocketServer(); + thread->Start(); + EXPECT_EQ(42, thread->BlockingCall([]() { return 42; })); + EXPECT_EQ(1u, blocked_calls.GetBlockingCallCount()); + EXPECT_EQ(1u, blocked_calls.GetCouldBeBlockingCallCount()); + EXPECT_EQ(2u, blocked_calls.GetTotalBlockedCallCount()); + thread->Stop(); + RTC_DCHECK_BLOCK_COUNT_NO_MORE_THAN(2); +#else + RTC_DCHECK_BLOCK_COUNT_NO_MORE_THAN(0); + RTC_LOG(LS_INFO) << "Test not active in this config"; +#endif +} + +#if RTC_DCHECK_IS_ON +TEST(ThreadTest, CountBlockingCallsOneCallback) { + rtc::AutoThread current; + bool was_called_back = false; + { + rtc::Thread::ScopedCountBlockingCalls blocked_calls( + [&](uint32_t actual_block, uint32_t could_block) { + was_called_back = true; + }); + current.BlockingCall([]() {}); + } + EXPECT_TRUE(was_called_back); +} + +TEST(ThreadTest, CountBlockingCallsSkipCallback) { + rtc::AutoThread current; + bool was_called_back = false; + { + rtc::Thread::ScopedCountBlockingCalls blocked_calls( + [&](uint32_t actual_block, uint32_t could_block) { + was_called_back = true; + }); + // Changed `blocked_calls` to not issue the callback if there are 1 or + // fewer blocking calls (i.e. we set the minimum required number to 2). + blocked_calls.set_minimum_call_count_for_callback(2); + current.BlockingCall([]() {}); + } + // We should not have gotten a call back. + EXPECT_FALSE(was_called_back); +} +#endif + +// Test that setting thread names doesn't cause a malfunction. +// There's no easy way to verify the name was set properly at this time. +TEST(ThreadTest, Names) { + // Default name + auto thread = Thread::CreateWithSocketServer(); + EXPECT_TRUE(thread->Start()); + thread->Stop(); + // Name with no object parameter + thread = Thread::CreateWithSocketServer(); + EXPECT_TRUE(thread->SetName("No object", nullptr)); + EXPECT_TRUE(thread->Start()); + thread->Stop(); + // Really long name + thread = Thread::CreateWithSocketServer(); + EXPECT_TRUE(thread->SetName("Abcdefghijklmnopqrstuvwxyz1234567890", this)); + EXPECT_TRUE(thread->Start()); + thread->Stop(); +} + +TEST(ThreadTest, Wrap) { + Thread* current_thread = Thread::Current(); + ThreadManager::Instance()->SetCurrentThread(nullptr); + + { + CustomThread cthread; + EXPECT_TRUE(cthread.WrapCurrent()); + EXPECT_EQ(&cthread, Thread::Current()); + EXPECT_TRUE(cthread.RunningForTest()); + EXPECT_FALSE(cthread.IsOwned()); + cthread.UnwrapCurrent(); + EXPECT_FALSE(cthread.RunningForTest()); + } + ThreadManager::Instance()->SetCurrentThread(current_thread); +} + +#if (!defined(NDEBUG) || RTC_DCHECK_IS_ON) +TEST(ThreadTest, InvokeToThreadAllowedReturnsTrueWithoutPolicies) { + rtc::AutoThread main_thread; + // Create and start the thread. + auto thread1 = Thread::CreateWithSocketServer(); + auto thread2 = Thread::CreateWithSocketServer(); + + thread1->PostTask( + [&]() { EXPECT_TRUE(thread1->IsInvokeToThreadAllowed(thread2.get())); }); + main_thread.ProcessMessages(100); +} + +TEST(ThreadTest, InvokeAllowedWhenThreadsAdded) { + rtc::AutoThread main_thread; + // Create and start the thread. + auto thread1 = Thread::CreateWithSocketServer(); + auto thread2 = Thread::CreateWithSocketServer(); + auto thread3 = Thread::CreateWithSocketServer(); + auto thread4 = Thread::CreateWithSocketServer(); + + thread1->AllowInvokesToThread(thread2.get()); + thread1->AllowInvokesToThread(thread3.get()); + + thread1->PostTask([&]() { + EXPECT_TRUE(thread1->IsInvokeToThreadAllowed(thread2.get())); + EXPECT_TRUE(thread1->IsInvokeToThreadAllowed(thread3.get())); + EXPECT_FALSE(thread1->IsInvokeToThreadAllowed(thread4.get())); + }); + main_thread.ProcessMessages(100); +} + +TEST(ThreadTest, InvokesDisallowedWhenDisallowAllInvokes) { + rtc::AutoThread main_thread; + // Create and start the thread. + auto thread1 = Thread::CreateWithSocketServer(); + auto thread2 = Thread::CreateWithSocketServer(); + + thread1->DisallowAllInvokes(); + + thread1->PostTask( + [&]() { EXPECT_FALSE(thread1->IsInvokeToThreadAllowed(thread2.get())); }); + main_thread.ProcessMessages(100); +} +#endif // (!defined(NDEBUG) || RTC_DCHECK_IS_ON) + +TEST(ThreadTest, InvokesAllowedByDefault) { + rtc::AutoThread main_thread; + // Create and start the thread. + auto thread1 = Thread::CreateWithSocketServer(); + auto thread2 = Thread::CreateWithSocketServer(); + + thread1->PostTask( + [&]() { EXPECT_TRUE(thread1->IsInvokeToThreadAllowed(thread2.get())); }); + main_thread.ProcessMessages(100); +} + +TEST(ThreadTest, BlockingCall) { + // Create and start the thread. + auto thread = Thread::CreateWithSocketServer(); + thread->Start(); + // Try calling functors. + EXPECT_EQ(42, thread->BlockingCall([] { return 42; })); + bool called = false; + thread->BlockingCall([&] { called = true; }); + EXPECT_TRUE(called); + + // Try calling bare functions. + struct LocalFuncs { + static int Func1() { return 999; } + static void Func2() {} + }; + EXPECT_EQ(999, thread->BlockingCall(&LocalFuncs::Func1)); + thread->BlockingCall(&LocalFuncs::Func2); +} + +// Verifies that two threads calling Invoke on each other at the same time does +// not deadlock but crash. +#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID) +TEST(ThreadTest, TwoThreadsInvokeDeathTest) { + GTEST_FLAG_SET(death_test_style, "threadsafe"); + AutoThread thread; + Thread* main_thread = Thread::Current(); + auto other_thread = Thread::CreateWithSocketServer(); + other_thread->Start(); + other_thread->BlockingCall([main_thread] { + RTC_EXPECT_DEATH(main_thread->BlockingCall([] {}), "loop"); + }); +} + +TEST(ThreadTest, ThreeThreadsInvokeDeathTest) { + GTEST_FLAG_SET(death_test_style, "threadsafe"); + AutoThread thread; + Thread* first = Thread::Current(); + + auto second = Thread::Create(); + second->Start(); + auto third = Thread::Create(); + third->Start(); + + second->BlockingCall([&] { + third->BlockingCall( + [&] { RTC_EXPECT_DEATH(first->BlockingCall([] {}), "loop"); }); + }); +} + +#endif + +// Verifies that if thread A invokes a call on thread B and thread C is trying +// to invoke A at the same time, thread A does not handle C's invoke while +// invoking B. +TEST(ThreadTest, ThreeThreadsBlockingCall) { + AutoThread thread; + Thread* thread_a = Thread::Current(); + auto thread_b = Thread::CreateWithSocketServer(); + auto thread_c = Thread::CreateWithSocketServer(); + thread_b->Start(); + thread_c->Start(); + + class LockedBool { + public: + explicit LockedBool(bool value) : value_(value) {} + + void Set(bool value) { + webrtc::MutexLock lock(&mutex_); + value_ = value; + } + + bool Get() { + webrtc::MutexLock lock(&mutex_); + return value_; + } + + private: + webrtc::Mutex mutex_; + bool value_ RTC_GUARDED_BY(mutex_); + }; + + struct LocalFuncs { + static void Set(LockedBool* out) { out->Set(true); } + static void InvokeSet(Thread* thread, LockedBool* out) { + thread->BlockingCall([out] { Set(out); }); + } + + // Set `out` true and call InvokeSet on `thread`. + static void SetAndInvokeSet(LockedBool* out, + Thread* thread, + LockedBool* out_inner) { + out->Set(true); + InvokeSet(thread, out_inner); + } + + // Asynchronously invoke SetAndInvokeSet on `thread1` and wait until + // `thread1` starts the call. + static void AsyncInvokeSetAndWait(Thread* thread1, + Thread* thread2, + LockedBool* out) { + LockedBool async_invoked(false); + + thread1->PostTask([&async_invoked, thread2, out] { + SetAndInvokeSet(&async_invoked, thread2, out); + }); + + EXPECT_TRUE_WAIT(async_invoked.Get(), 2000); + } + }; + + LockedBool thread_a_called(false); + + // Start the sequence A --(invoke)--> B --(async invoke)--> C --(invoke)--> A. + // Thread B returns when C receives the call and C should be blocked until A + // starts to process messages. + Thread* thread_c_ptr = thread_c.get(); + thread_b->BlockingCall([thread_c_ptr, thread_a, &thread_a_called] { + LocalFuncs::AsyncInvokeSetAndWait(thread_c_ptr, thread_a, &thread_a_called); + }); + EXPECT_FALSE(thread_a_called.Get()); + + EXPECT_TRUE_WAIT(thread_a_called.Get(), 2000); +} + +static void DelayedPostsWithIdenticalTimesAreProcessedInFifoOrder( + FakeClock& clock, + Thread& q) { + std::vector<int> run_order; + + Event done; + int64_t now = TimeMillis(); + q.PostDelayedTask([&] { run_order.push_back(3); }, TimeDelta::Millis(3)); + q.PostDelayedTask([&] { run_order.push_back(0); }, TimeDelta::Millis(1)); + q.PostDelayedTask([&] { run_order.push_back(1); }, TimeDelta::Millis(2)); + q.PostDelayedTask([&] { run_order.push_back(4); }, TimeDelta::Millis(3)); + q.PostDelayedTask([&] { run_order.push_back(2); }, TimeDelta::Millis(2)); + q.PostDelayedTask([&] { done.Set(); }, TimeDelta::Millis(4)); + // Validate time was frozen while tasks were posted. + RTC_DCHECK_EQ(TimeMillis(), now); + + // Change time to make all tasks ready to run and wait for them. + clock.AdvanceTime(TimeDelta::Millis(4)); + ASSERT_TRUE(done.Wait(TimeDelta::Seconds(1))); + + EXPECT_THAT(run_order, ElementsAre(0, 1, 2, 3, 4)); +} + +TEST(ThreadTest, DelayedPostsWithIdenticalTimesAreProcessedInFifoOrder) { + ScopedBaseFakeClock clock; + Thread q(CreateDefaultSocketServer(), true); + q.Start(); + DelayedPostsWithIdenticalTimesAreProcessedInFifoOrder(clock, q); + + NullSocketServer nullss; + Thread q_nullss(&nullss, true); + q_nullss.Start(); + DelayedPostsWithIdenticalTimesAreProcessedInFifoOrder(clock, q_nullss); +} + +// Ensure that ProcessAllMessageQueues does its essential function; process +// all messages (both delayed and non delayed) up until the current time, on +// all registered message queues. +TEST(ThreadManager, ProcessAllMessageQueues) { + rtc::AutoThread main_thread; + Event entered_process_all_message_queues(true, false); + auto a = Thread::CreateWithSocketServer(); + auto b = Thread::CreateWithSocketServer(); + a->Start(); + b->Start(); + + std::atomic<int> messages_processed(0); + auto incrementer = [&messages_processed, + &entered_process_all_message_queues] { + // Wait for event as a means to ensure Increment doesn't occur outside + // of ProcessAllMessageQueues. The event is set by a message posted to + // the main thread, which is guaranteed to be handled inside + // ProcessAllMessageQueues. + entered_process_all_message_queues.Wait(Event::kForever); + messages_processed.fetch_add(1); + }; + auto event_signaler = [&entered_process_all_message_queues] { + entered_process_all_message_queues.Set(); + }; + + // Post messages (both delayed and non delayed) to both threads. + a->PostTask(incrementer); + b->PostTask(incrementer); + a->PostDelayedTask(incrementer, TimeDelta::Zero()); + b->PostDelayedTask(incrementer, TimeDelta::Zero()); + main_thread.PostTask(event_signaler); + + ThreadManager::ProcessAllMessageQueuesForTesting(); + EXPECT_EQ(4, messages_processed.load(std::memory_order_acquire)); +} + +// Test that ProcessAllMessageQueues doesn't hang if a thread is quitting. +TEST(ThreadManager, ProcessAllMessageQueuesWithQuittingThread) { + auto t = Thread::CreateWithSocketServer(); + t->Start(); + t->Quit(); + ThreadManager::ProcessAllMessageQueuesForTesting(); +} + +void WaitAndSetEvent(Event* wait_event, Event* set_event) { + wait_event->Wait(Event::kForever); + set_event->Set(); +} + +// A functor that keeps track of the number of copies and moves. +class LifeCycleFunctor { + public: + struct Stats { + size_t copy_count = 0; + size_t move_count = 0; + }; + + LifeCycleFunctor(Stats* stats, Event* event) : stats_(stats), event_(event) {} + LifeCycleFunctor(const LifeCycleFunctor& other) { *this = other; } + LifeCycleFunctor(LifeCycleFunctor&& other) { *this = std::move(other); } + + LifeCycleFunctor& operator=(const LifeCycleFunctor& other) { + stats_ = other.stats_; + event_ = other.event_; + ++stats_->copy_count; + return *this; + } + + LifeCycleFunctor& operator=(LifeCycleFunctor&& other) { + stats_ = other.stats_; + event_ = other.event_; + ++stats_->move_count; + return *this; + } + + void operator()() { event_->Set(); } + + private: + Stats* stats_; + Event* event_; +}; + +// A functor that verifies the thread it was destroyed on. +class DestructionFunctor { + public: + DestructionFunctor(Thread* thread, bool* thread_was_current, Event* event) + : thread_(thread), + thread_was_current_(thread_was_current), + event_(event) {} + ~DestructionFunctor() { + // Only signal the event if this was the functor that was invoked to avoid + // the event being signaled due to the destruction of temporary/moved + // versions of this object. + if (was_invoked_) { + *thread_was_current_ = thread_->IsCurrent(); + event_->Set(); + } + } + + void operator()() { was_invoked_ = true; } + + private: + Thread* thread_; + bool* thread_was_current_; + Event* event_; + bool was_invoked_ = false; +}; + +TEST(ThreadPostTaskTest, InvokesWithLambda) { + std::unique_ptr<rtc::Thread> background_thread(rtc::Thread::Create()); + background_thread->Start(); + + Event event; + background_thread->PostTask([&event] { event.Set(); }); + event.Wait(Event::kForever); +} + +TEST(ThreadPostTaskTest, InvokesWithCopiedFunctor) { + std::unique_ptr<rtc::Thread> background_thread(rtc::Thread::Create()); + background_thread->Start(); + + LifeCycleFunctor::Stats stats; + Event event; + LifeCycleFunctor functor(&stats, &event); + background_thread->PostTask(functor); + event.Wait(Event::kForever); + + EXPECT_EQ(1u, stats.copy_count); + EXPECT_EQ(0u, stats.move_count); +} + +TEST(ThreadPostTaskTest, InvokesWithMovedFunctor) { + std::unique_ptr<rtc::Thread> background_thread(rtc::Thread::Create()); + background_thread->Start(); + + LifeCycleFunctor::Stats stats; + Event event; + LifeCycleFunctor functor(&stats, &event); + background_thread->PostTask(std::move(functor)); + event.Wait(Event::kForever); + + EXPECT_EQ(0u, stats.copy_count); + EXPECT_EQ(1u, stats.move_count); +} + +TEST(ThreadPostTaskTest, InvokesWithReferencedFunctorShouldCopy) { + std::unique_ptr<rtc::Thread> background_thread(rtc::Thread::Create()); + background_thread->Start(); + + LifeCycleFunctor::Stats stats; + Event event; + LifeCycleFunctor functor(&stats, &event); + LifeCycleFunctor& functor_ref = functor; + background_thread->PostTask(functor_ref); + event.Wait(Event::kForever); + + EXPECT_EQ(1u, stats.copy_count); + EXPECT_EQ(0u, stats.move_count); +} + +TEST(ThreadPostTaskTest, InvokesWithCopiedFunctorDestroyedOnTargetThread) { + std::unique_ptr<rtc::Thread> background_thread(rtc::Thread::Create()); + background_thread->Start(); + + Event event; + bool was_invoked_on_background_thread = false; + DestructionFunctor functor(background_thread.get(), + &was_invoked_on_background_thread, &event); + background_thread->PostTask(functor); + event.Wait(Event::kForever); + + EXPECT_TRUE(was_invoked_on_background_thread); +} + +TEST(ThreadPostTaskTest, InvokesWithMovedFunctorDestroyedOnTargetThread) { + std::unique_ptr<rtc::Thread> background_thread(rtc::Thread::Create()); + background_thread->Start(); + + Event event; + bool was_invoked_on_background_thread = false; + DestructionFunctor functor(background_thread.get(), + &was_invoked_on_background_thread, &event); + background_thread->PostTask(std::move(functor)); + event.Wait(Event::kForever); + + EXPECT_TRUE(was_invoked_on_background_thread); +} + +TEST(ThreadPostTaskTest, + InvokesWithReferencedFunctorShouldCopyAndDestroyedOnTargetThread) { + std::unique_ptr<rtc::Thread> background_thread(rtc::Thread::Create()); + background_thread->Start(); + + Event event; + bool was_invoked_on_background_thread = false; + DestructionFunctor functor(background_thread.get(), + &was_invoked_on_background_thread, &event); + DestructionFunctor& functor_ref = functor; + background_thread->PostTask(functor_ref); + event.Wait(Event::kForever); + + EXPECT_TRUE(was_invoked_on_background_thread); +} + +TEST(ThreadPostTaskTest, InvokesOnBackgroundThread) { + std::unique_ptr<rtc::Thread> background_thread(rtc::Thread::Create()); + background_thread->Start(); + + Event event; + bool was_invoked_on_background_thread = false; + Thread* background_thread_ptr = background_thread.get(); + background_thread->PostTask( + [background_thread_ptr, &was_invoked_on_background_thread, &event] { + was_invoked_on_background_thread = background_thread_ptr->IsCurrent(); + event.Set(); + }); + event.Wait(Event::kForever); + + EXPECT_TRUE(was_invoked_on_background_thread); +} + +TEST(ThreadPostTaskTest, InvokesAsynchronously) { + std::unique_ptr<rtc::Thread> background_thread(rtc::Thread::Create()); + background_thread->Start(); + + // The first event ensures that SendSingleMessage() is not blocking this + // thread. The second event ensures that the message is processed. + Event event_set_by_test_thread; + Event event_set_by_background_thread; + background_thread->PostTask([&event_set_by_test_thread, + &event_set_by_background_thread] { + WaitAndSetEvent(&event_set_by_test_thread, &event_set_by_background_thread); + }); + event_set_by_test_thread.Set(); + event_set_by_background_thread.Wait(Event::kForever); +} + +TEST(ThreadPostTaskTest, InvokesInPostedOrder) { + std::unique_ptr<rtc::Thread> background_thread(rtc::Thread::Create()); + background_thread->Start(); + + Event first; + Event second; + Event third; + Event fourth; + + background_thread->PostTask( + [&first, &second] { WaitAndSetEvent(&first, &second); }); + background_thread->PostTask( + [&second, &third] { WaitAndSetEvent(&second, &third); }); + background_thread->PostTask( + [&third, &fourth] { WaitAndSetEvent(&third, &fourth); }); + + // All tasks have been posted before the first one is unblocked. + first.Set(); + // Only if the chain is invoked in posted order will the last event be set. + fourth.Wait(Event::kForever); +} + +TEST(ThreadPostDelayedTaskTest, InvokesAsynchronously) { + std::unique_ptr<rtc::Thread> background_thread(rtc::Thread::Create()); + background_thread->Start(); + + // The first event ensures that SendSingleMessage() is not blocking this + // thread. The second event ensures that the message is processed. + Event event_set_by_test_thread; + Event event_set_by_background_thread; + background_thread->PostDelayedTask( + [&event_set_by_test_thread, &event_set_by_background_thread] { + WaitAndSetEvent(&event_set_by_test_thread, + &event_set_by_background_thread); + }, + TimeDelta::Millis(10)); + event_set_by_test_thread.Set(); + event_set_by_background_thread.Wait(Event::kForever); +} + +TEST(ThreadPostDelayedTaskTest, InvokesInDelayOrder) { + ScopedFakeClock clock; + std::unique_ptr<rtc::Thread> background_thread(rtc::Thread::Create()); + background_thread->Start(); + + Event first; + Event second; + Event third; + Event fourth; + + background_thread->PostDelayedTask( + [&third, &fourth] { WaitAndSetEvent(&third, &fourth); }, + TimeDelta::Millis(11)); + background_thread->PostDelayedTask( + [&first, &second] { WaitAndSetEvent(&first, &second); }, + TimeDelta::Millis(9)); + background_thread->PostDelayedTask( + [&second, &third] { WaitAndSetEvent(&second, &third); }, + TimeDelta::Millis(10)); + + // All tasks have been posted before the first one is unblocked. + first.Set(); + // Only if the chain is invoked in delay order will the last event be set. + clock.AdvanceTime(TimeDelta::Millis(11)); + EXPECT_TRUE(fourth.Wait(TimeDelta::Zero())); +} + +TEST(ThreadPostDelayedTaskTest, IsCurrentTaskQueue) { + auto current_tq = webrtc::TaskQueueBase::Current(); + { + std::unique_ptr<rtc::Thread> thread(rtc::Thread::Create()); + thread->WrapCurrent(); + EXPECT_EQ(webrtc::TaskQueueBase::Current(), + static_cast<webrtc::TaskQueueBase*>(thread.get())); + thread->UnwrapCurrent(); + } + EXPECT_EQ(webrtc::TaskQueueBase::Current(), current_tq); +} + +class ThreadFactory : public webrtc::TaskQueueFactory { + public: + std::unique_ptr<webrtc::TaskQueueBase, webrtc::TaskQueueDeleter> + CreateTaskQueue(absl::string_view /* name */, + Priority /*priority*/) const override { + std::unique_ptr<Thread> thread = Thread::Create(); + thread->Start(); + return std::unique_ptr<webrtc::TaskQueueBase, webrtc::TaskQueueDeleter>( + thread.release()); + } +}; + +std::unique_ptr<webrtc::TaskQueueFactory> CreateDefaultThreadFactory( + const webrtc::FieldTrialsView*) { + return std::make_unique<ThreadFactory>(); +} + +using ::webrtc::TaskQueueTest; + +INSTANTIATE_TEST_SUITE_P(RtcThread, + TaskQueueTest, + ::testing::Values(CreateDefaultThreadFactory)); + +} // namespace +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/threading_gn/moz.build b/third_party/libwebrtc/rtc_base/threading_gn/moz.build new file mode 100644 index 0000000000..199af4b1d3 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/threading_gn/moz.build @@ -0,0 +1,238 @@ +# 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/rtc_base/async_resolver.cc", + "/third_party/libwebrtc/rtc_base/internal/default_socket_server.cc", + "/third_party/libwebrtc/rtc_base/network_monitor.cc", + "/third_party/libwebrtc/rtc_base/network_monitor_factory.cc", + "/third_party/libwebrtc/rtc_base/physical_socket_server.cc", + "/third_party/libwebrtc/rtc_base/thread.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_ENABLE_LIBEVENT"] = 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 += [ + "GLESv2", + "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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("threading_gn") diff --git a/third_party/libwebrtc/rtc_base/time_utils.cc b/third_party/libwebrtc/rtc_base/time_utils.cc new file mode 100644 index 0000000000..9f112e49c1 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/time_utils.cc @@ -0,0 +1,258 @@ +/* + * 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 <stdint.h> + +#if defined(WEBRTC_POSIX) +#include <sys/time.h> +#endif + +#include "rtc_base/checks.h" +#include "rtc_base/numerics/safe_conversions.h" +#include "rtc_base/system_time.h" +#include "rtc_base/time_utils.h" +#if defined(WEBRTC_WIN) +#include "rtc_base/win32.h" +#endif +#if defined(WEBRTC_WIN) +#include <minwinbase.h> +#endif + +namespace rtc { + +#if defined(WEBRTC_WIN) || defined(WINUWP) +// FileTime (January 1st 1601) to Unix time (January 1st 1970) +// offset in units of 100ns. +static constexpr uint64_t kFileTimeToUnixTimeEpochOffset = + 116444736000000000ULL; +static constexpr uint64_t kFileTimeToMicroSeconds = 10LL; +#endif + +ClockInterface* g_clock = nullptr; + +ClockInterface* SetClockForTesting(ClockInterface* clock) { + ClockInterface* prev = g_clock; + g_clock = clock; + return prev; +} + +ClockInterface* GetClockForTesting() { + return g_clock; +} + +#if defined(WINUWP) + +namespace { + +class TimeHelper final { + public: + TimeHelper(const TimeHelper&) = delete; + + // Resets the clock based upon an NTP server. This routine must be called + // prior to the main system start-up to ensure all clocks are based upon + // an NTP server time if NTP synchronization is required. No critical + // section is used thus this method must be called prior to any clock + // routines being used. + static void SyncWithNtp(int64_t ntp_server_time_ms) { + auto& singleton = Singleton(); + TIME_ZONE_INFORMATION time_zone; + GetTimeZoneInformation(&time_zone); + int64_t time_zone_bias_ns = + rtc::dchecked_cast<int64_t>(time_zone.Bias) * 60 * 1000 * 1000 * 1000; + singleton.app_start_time_ns_ = + (ntp_server_time_ms - kNTPTimeToUnixTimeEpochOffset) * 1000000 - + time_zone_bias_ns; + singleton.UpdateReferenceTime(); + } + + // Returns the number of nanoseconds that have passed since unix epoch. + static int64_t TicksNs() { + auto& singleton = Singleton(); + int64_t result = 0; + LARGE_INTEGER qpcnt; + QueryPerformanceCounter(&qpcnt); + result = rtc::dchecked_cast<int64_t>( + (rtc::dchecked_cast<uint64_t>(qpcnt.QuadPart) * 100000 / + rtc::dchecked_cast<uint64_t>(singleton.os_ticks_per_second_)) * + 10000); + result = singleton.app_start_time_ns_ + result - + singleton.time_since_os_start_ns_; + return result; + } + + private: + TimeHelper() { + TIME_ZONE_INFORMATION time_zone; + GetTimeZoneInformation(&time_zone); + int64_t time_zone_bias_ns = + rtc::dchecked_cast<int64_t>(time_zone.Bias) * 60 * 1000 * 1000 * 1000; + FILETIME ft; + // This will give us system file in UTC format. + GetSystemTimeAsFileTime(&ft); + LARGE_INTEGER li; + li.HighPart = ft.dwHighDateTime; + li.LowPart = ft.dwLowDateTime; + + app_start_time_ns_ = (li.QuadPart - kFileTimeToUnixTimeEpochOffset) * 100 - + time_zone_bias_ns; + + UpdateReferenceTime(); + } + + static TimeHelper& Singleton() { + static TimeHelper singleton; + return singleton; + } + + void UpdateReferenceTime() { + LARGE_INTEGER qpfreq; + QueryPerformanceFrequency(&qpfreq); + os_ticks_per_second_ = rtc::dchecked_cast<int64_t>(qpfreq.QuadPart); + + LARGE_INTEGER qpcnt; + QueryPerformanceCounter(&qpcnt); + time_since_os_start_ns_ = rtc::dchecked_cast<int64_t>( + (rtc::dchecked_cast<uint64_t>(qpcnt.QuadPart) * 100000 / + rtc::dchecked_cast<uint64_t>(os_ticks_per_second_)) * + 10000); + } + + private: + static constexpr uint64_t kNTPTimeToUnixTimeEpochOffset = 2208988800000L; + + // The number of nanoseconds since unix system epoch + int64_t app_start_time_ns_; + // The number of nanoseconds since the OS started + int64_t time_since_os_start_ns_; + // The OS calculated ticks per second + int64_t os_ticks_per_second_; +}; + +} // namespace + +void SyncWithNtp(int64_t time_from_ntp_server_ms) { + TimeHelper::SyncWithNtp(time_from_ntp_server_ms); +} + +int64_t WinUwpSystemTimeNanos() { + return TimeHelper::TicksNs(); +} + +#endif // defined(WINUWP) + +int64_t SystemTimeMillis() { + return static_cast<int64_t>(SystemTimeNanos() / kNumNanosecsPerMillisec); +} + +int64_t TimeNanos() { + if (g_clock) { + return g_clock->TimeNanos(); + } + return SystemTimeNanos(); +} + +uint32_t Time32() { + return static_cast<uint32_t>(TimeNanos() / kNumNanosecsPerMillisec); +} + +int64_t TimeMillis() { + return TimeNanos() / kNumNanosecsPerMillisec; +} + +int64_t TimeMicros() { + return TimeNanos() / kNumNanosecsPerMicrosec; +} + +int64_t TimeAfter(int64_t elapsed) { + RTC_DCHECK_GE(elapsed, 0); + return TimeMillis() + elapsed; +} + +int32_t TimeDiff32(uint32_t later, uint32_t earlier) { + return later - earlier; +} + +int64_t TimeDiff(int64_t later, int64_t earlier) { + return later - earlier; +} + +int64_t TmToSeconds(const tm& tm) { + static short int mdays[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + static short int cumul_mdays[12] = {0, 31, 59, 90, 120, 151, + 181, 212, 243, 273, 304, 334}; + int year = tm.tm_year + 1900; + int month = tm.tm_mon; + int day = tm.tm_mday - 1; // Make 0-based like the rest. + int hour = tm.tm_hour; + int min = tm.tm_min; + int sec = tm.tm_sec; + + bool expiry_in_leap_year = + (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)); + + if (year < 1970) + return -1; + if (month < 0 || month > 11) + return -1; + if (day < 0 || day >= mdays[month] + (expiry_in_leap_year && month == 2 - 1)) + return -1; + if (hour < 0 || hour > 23) + return -1; + if (min < 0 || min > 59) + return -1; + if (sec < 0 || sec > 59) + return -1; + + day += cumul_mdays[month]; + + // Add number of leap days between 1970 and the expiration year, inclusive. + day += ((year / 4 - 1970 / 4) - (year / 100 - 1970 / 100) + + (year / 400 - 1970 / 400)); + + // We will have added one day too much above if expiration is during a leap + // year, and expiration is in January or February. + if (expiry_in_leap_year && month <= 2 - 1) // `month` is zero based. + day -= 1; + + // Combine all variables into seconds from 1970-01-01 00:00 (except `month` + // which was accumulated into `day` above). + return (((static_cast<int64_t>(year - 1970) * 365 + day) * 24 + hour) * 60 + + min) * + 60 + + sec; +} + +int64_t TimeUTCMicros() { + if (g_clock) { + return g_clock->TimeNanos() / kNumNanosecsPerMicrosec; + } +#if defined(WEBRTC_POSIX) + struct timeval time; + gettimeofday(&time, nullptr); + // Convert from second (1.0) and microsecond (1e-6). + return (static_cast<int64_t>(time.tv_sec) * rtc::kNumMicrosecsPerSec + + time.tv_usec); +#elif defined(WEBRTC_WIN) + FILETIME ft; + // This will give us system file in UTC format in multiples of 100ns. + GetSystemTimeAsFileTime(&ft); + LARGE_INTEGER li; + li.HighPart = ft.dwHighDateTime; + li.LowPart = ft.dwLowDateTime; + return (li.QuadPart - kFileTimeToUnixTimeEpochOffset) / + kFileTimeToMicroSeconds; +#endif +} + +int64_t TimeUTCMillis() { + return TimeUTCMicros() / kNumMicrosecsPerMillisec; +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/time_utils.h b/third_party/libwebrtc/rtc_base/time_utils.h new file mode 100644 index 0000000000..271c1d6e93 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/time_utils.h @@ -0,0 +1,140 @@ +/* + * Copyright 2005 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 RTC_BASE_TIME_UTILS_H_ +#define RTC_BASE_TIME_UTILS_H_ + +#include <stdint.h> +#include <time.h> + +#include "rtc_base/checks.h" +#include "rtc_base/system/rtc_export.h" +#include "rtc_base/system_time.h" + +namespace rtc { + +static const int64_t kNumMillisecsPerSec = INT64_C(1000); +static const int64_t kNumMicrosecsPerSec = INT64_C(1000000); +static const int64_t kNumNanosecsPerSec = INT64_C(1000000000); + +static const int64_t kNumMicrosecsPerMillisec = + kNumMicrosecsPerSec / kNumMillisecsPerSec; +static const int64_t kNumNanosecsPerMillisec = + kNumNanosecsPerSec / kNumMillisecsPerSec; +static const int64_t kNumNanosecsPerMicrosec = + kNumNanosecsPerSec / kNumMicrosecsPerSec; + +// Elapsed milliseconds between NTP base, 1900 January 1 00:00 GMT +// (see https://tools.ietf.org/html/rfc868), and January 1 00:00 GMT 1970 +// epoch. This is useful when converting between the NTP time base and the +// time base used in RTCP reports. +constexpr int64_t kNtpJan1970Millisecs = 2'208'988'800 * kNumMillisecsPerSec; + +// TODO(honghaiz): Define a type for the time value specifically. + +class ClockInterface { + public: + virtual ~ClockInterface() {} + virtual int64_t TimeNanos() const = 0; +}; + +// Sets the global source of time. This is useful mainly for unit tests. +// +// Returns the previously set ClockInterface, or nullptr if none is set. +// +// Does not transfer ownership of the clock. SetClockForTesting(nullptr) +// should be called before the ClockInterface is deleted. +// +// This method is not thread-safe; it should only be used when no other thread +// is running (for example, at the start/end of a unit test, or start/end of +// main()). +// +// TODO(deadbeef): Instead of having functions that access this global +// ClockInterface, we may want to pass the ClockInterface into everything +// that uses it, eliminating the need for a global variable and this function. +RTC_EXPORT ClockInterface* SetClockForTesting(ClockInterface* clock); + +// Returns previously set clock, or nullptr if no custom clock is being used. +RTC_EXPORT ClockInterface* GetClockForTesting(); + +#if defined(WINUWP) +// Synchronizes the current clock based upon an NTP server's epoch in +// milliseconds. +void SyncWithNtp(int64_t time_from_ntp_server_ms); + +// Returns the current time in nanoseconds. The clock is synchonized with the +// system wall clock time upon instatiation. It may also be synchronized using +// the SyncWithNtp() function above. Please note that the clock will most likely +// drift away from the system wall clock time as time goes by. +int64_t WinUwpSystemTimeNanos(); +#endif // defined(WINUWP) + +// Returns the actual system time, even if a clock is set for testing. +// Useful for timeouts while using a test clock, or for logging. +int64_t SystemTimeMillis(); + +// Returns the current time in milliseconds in 32 bits. +uint32_t Time32(); + +// Returns the current time in milliseconds in 64 bits. +RTC_EXPORT int64_t TimeMillis(); +// Deprecated. Do not use this in any new code. +inline int64_t Time() { + return TimeMillis(); +} + +// Returns the current time in microseconds. +RTC_EXPORT int64_t TimeMicros(); + +// Returns the current time in nanoseconds. +RTC_EXPORT int64_t TimeNanos(); + +// Returns a future timestamp, 'elapsed' milliseconds from now. +int64_t TimeAfter(int64_t elapsed); + +// Number of milliseconds that would elapse between 'earlier' and 'later' +// timestamps. The value is negative if 'later' occurs before 'earlier'. +int64_t TimeDiff(int64_t later, int64_t earlier); +int32_t TimeDiff32(uint32_t later, uint32_t earlier); + +// The number of milliseconds that have elapsed since 'earlier'. +inline int64_t TimeSince(int64_t earlier) { + return TimeMillis() - earlier; +} + +// The number of milliseconds that will elapse between now and 'later'. +inline int64_t TimeUntil(int64_t later) { + return later - TimeMillis(); +} + +// Convert from tm, which is relative to 1900-01-01 00:00 to number of +// seconds from 1970-01-01 00:00 ("epoch"). Don't return time_t since that +// is still 32 bits on many systems. +int64_t TmToSeconds(const tm& tm); + +// Return the number of microseconds since January 1, 1970, UTC. +// Useful mainly when producing logs to be correlated with other +// devices, and when the devices in question all have properly +// synchronized clocks. +// +// Note that this function obeys the system's idea about what the time +// is. It is not guaranteed to be monotonic; it will jump in case the +// system time is changed, e.g., by some other process calling +// settimeofday. Always use rtc::TimeMicros(), not this function, for +// measuring time intervals and timeouts. +int64_t TimeUTCMicros(); + +// Return the number of milliseconds since January 1, 1970, UTC. +// See above. +int64_t TimeUTCMillis(); + +} // namespace rtc + +#endif // RTC_BASE_TIME_UTILS_H_ diff --git a/third_party/libwebrtc/rtc_base/time_utils_unittest.cc b/third_party/libwebrtc/rtc_base/time_utils_unittest.cc new file mode 100644 index 0000000000..09fb816636 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/time_utils_unittest.cc @@ -0,0 +1,241 @@ +/* + * 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 "rtc_base/time_utils.h" + +#include <memory> + +#include "api/units/time_delta.h" +#include "rtc_base/event.h" +#include "rtc_base/fake_clock.h" +#include "rtc_base/helpers.h" +#include "rtc_base/thread.h" +#include "test/gtest.h" + +namespace rtc { +using ::webrtc::TimeDelta; + +TEST(TimeTest, TimeInMs) { + int64_t ts_earlier = TimeMillis(); + Thread::SleepMs(100); + int64_t ts_now = TimeMillis(); + // Allow for the thread to wakeup ~20ms early. + EXPECT_GE(ts_now, ts_earlier + 80); + // Make sure the Time is not returning in smaller unit like microseconds. + EXPECT_LT(ts_now, ts_earlier + 1000); +} + +TEST(TimeTest, Intervals) { + int64_t ts_earlier = TimeMillis(); + int64_t ts_later = TimeAfter(500); + + // We can't depend on ts_later and ts_earlier to be exactly 500 apart + // since time elapses between the calls to TimeMillis() and TimeAfter(500) + EXPECT_LE(500, TimeDiff(ts_later, ts_earlier)); + EXPECT_GE(-500, TimeDiff(ts_earlier, ts_later)); + + // Time has elapsed since ts_earlier + EXPECT_GE(TimeSince(ts_earlier), 0); + + // ts_earlier is earlier than now, so TimeUntil ts_earlier is -ve + EXPECT_LE(TimeUntil(ts_earlier), 0); + + // ts_later likely hasn't happened yet, so TimeSince could be -ve + // but within 500 + EXPECT_GE(TimeSince(ts_later), -500); + + // TimeUntil ts_later is at most 500 + EXPECT_LE(TimeUntil(ts_later), 500); +} + +TEST(TimeTest, TestTimeDiff64) { + int64_t ts_diff = 100; + int64_t ts_earlier = rtc::TimeMillis(); + int64_t ts_later = ts_earlier + ts_diff; + EXPECT_EQ(ts_diff, rtc::TimeDiff(ts_later, ts_earlier)); + EXPECT_EQ(-ts_diff, rtc::TimeDiff(ts_earlier, ts_later)); +} + +class TmToSeconds : public ::testing::Test { + public: + TmToSeconds() { + // Set use of the test RNG to get deterministic expiration timestamp. + rtc::SetRandomTestMode(true); + } + ~TmToSeconds() override { + // Put it back for the next test. + rtc::SetRandomTestMode(false); + } + + void TestTmToSeconds(int times) { + static char mdays[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + for (int i = 0; i < times; i++) { + // First generate something correct and check that TmToSeconds is happy. + int year = rtc::CreateRandomId() % 400 + 1970; + + bool leap_year = false; + if (year % 4 == 0) + leap_year = true; + if (year % 100 == 0) + leap_year = false; + if (year % 400 == 0) + leap_year = true; + + std::tm tm; + tm.tm_year = year - 1900; // std::tm is year 1900 based. + tm.tm_mon = rtc::CreateRandomId() % 12; + tm.tm_mday = rtc::CreateRandomId() % mdays[tm.tm_mon] + 1; + tm.tm_hour = rtc::CreateRandomId() % 24; + tm.tm_min = rtc::CreateRandomId() % 60; + tm.tm_sec = rtc::CreateRandomId() % 60; + int64_t t = rtc::TmToSeconds(tm); + EXPECT_TRUE(t >= 0); + + // Now damage a random field and check that TmToSeconds is unhappy. + switch (rtc::CreateRandomId() % 11) { + case 0: + tm.tm_year = 1969 - 1900; + break; + case 1: + tm.tm_mon = -1; + break; + case 2: + tm.tm_mon = 12; + break; + case 3: + tm.tm_mday = 0; + break; + case 4: + tm.tm_mday = mdays[tm.tm_mon] + (leap_year && tm.tm_mon == 1) + 1; + break; + case 5: + tm.tm_hour = -1; + break; + case 6: + tm.tm_hour = 24; + break; + case 7: + tm.tm_min = -1; + break; + case 8: + tm.tm_min = 60; + break; + case 9: + tm.tm_sec = -1; + break; + case 10: + tm.tm_sec = 60; + break; + } + EXPECT_EQ(rtc::TmToSeconds(tm), -1); + } + // Check consistency with the system gmtime_r. With time_t, we can only + // portably test dates until 2038, which is achieved by the % 0x80000000. + for (int i = 0; i < times; i++) { + time_t t = rtc::CreateRandomId() % 0x80000000; +#if defined(WEBRTC_WIN) + std::tm* tm = std::gmtime(&t); + EXPECT_TRUE(tm); + EXPECT_TRUE(rtc::TmToSeconds(*tm) == t); +#else + std::tm tm; + EXPECT_TRUE(gmtime_r(&t, &tm)); + EXPECT_TRUE(rtc::TmToSeconds(tm) == t); +#endif + } + } +}; + +TEST_F(TmToSeconds, TestTmToSeconds) { + TestTmToSeconds(100000); +} + +// Test that all the time functions exposed by TimeUtils get time from the +// fake clock when it's set. +TEST(FakeClock, TimeFunctionsUseFakeClock) { + FakeClock clock; + SetClockForTesting(&clock); + + clock.SetTime(webrtc::Timestamp::Micros(987654)); + EXPECT_EQ(987u, Time32()); + EXPECT_EQ(987, TimeMillis()); + EXPECT_EQ(987654, TimeMicros()); + EXPECT_EQ(987654000, TimeNanos()); + EXPECT_EQ(1000u, TimeAfter(13)); + + SetClockForTesting(nullptr); + // After it's unset, we should get a normal time. + EXPECT_NE(987, TimeMillis()); +} + +TEST(FakeClock, InitialTime) { + FakeClock clock; + EXPECT_EQ(0, clock.TimeNanos()); +} + +TEST(FakeClock, SetTime) { + FakeClock clock; + clock.SetTime(webrtc::Timestamp::Micros(123)); + EXPECT_EQ(123000, clock.TimeNanos()); + clock.SetTime(webrtc::Timestamp::Micros(456)); + EXPECT_EQ(456000, clock.TimeNanos()); +} + +TEST(FakeClock, AdvanceTime) { + FakeClock clock; + clock.AdvanceTime(webrtc::TimeDelta::Micros(1u)); + EXPECT_EQ(1000, clock.TimeNanos()); + clock.AdvanceTime(webrtc::TimeDelta::Micros(2222u)); + EXPECT_EQ(2223000, clock.TimeNanos()); + clock.AdvanceTime(webrtc::TimeDelta::Millis(3333u)); + EXPECT_EQ(3335223000, clock.TimeNanos()); + clock.AdvanceTime(webrtc::TimeDelta::Seconds(4444u)); + EXPECT_EQ(4447335223000, clock.TimeNanos()); +} + +// When the clock is advanced, threads that are waiting in a socket select +// should wake up and look at the new time. This allows tests using the +// fake clock to run much faster, if the test is bound by time constraints +// (such as a test for a STUN ping timeout). +TEST(FakeClock, SettingTimeWakesThreads) { + int64_t real_start_time_ms = TimeMillis(); + + ThreadProcessingFakeClock clock; + SetClockForTesting(&clock); + + std::unique_ptr<Thread> worker(Thread::CreateWithSocketServer()); + worker->Start(); + + // Post an event that won't be executed for 10 seconds. + Event message_handler_dispatched; + worker->PostDelayedTask( + [&message_handler_dispatched] { message_handler_dispatched.Set(); }, + TimeDelta::Seconds(60)); + + // Wait for a bit for the worker thread to be started and enter its socket + // select(). Otherwise this test would be trivial since the worker thread + // would process the event as soon as it was started. + Thread::Current()->SleepMs(1000); + + // Advance the fake clock, expecting the worker thread to wake up + // and dispatch the message instantly. + clock.AdvanceTime(webrtc::TimeDelta::Seconds(60u)); + EXPECT_TRUE(message_handler_dispatched.Wait(webrtc::TimeDelta::Zero())); + worker->Stop(); + + SetClockForTesting(nullptr); + + // The message should have been dispatched long before the 60 seconds fully + // elapsed (just a sanity check). + int64_t real_end_time_ms = TimeMillis(); + EXPECT_LT(real_end_time_ms - real_start_time_ms, 10000); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/timestamp_aligner.cc b/third_party/libwebrtc/rtc_base/timestamp_aligner.cc new file mode 100644 index 0000000000..6c7ac1f839 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/timestamp_aligner.cc @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2016 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 "rtc_base/timestamp_aligner.h" + +#include <cstdlib> +#include <limits> + +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" +#include "rtc_base/time_utils.h" + +namespace rtc { + +TimestampAligner::TimestampAligner() + : frames_seen_(0), + offset_us_(0), + clip_bias_us_(0), + prev_translated_time_us_(std::numeric_limits<int64_t>::min()), + prev_time_offset_us_(0) {} + +TimestampAligner::~TimestampAligner() {} + +int64_t TimestampAligner::TranslateTimestamp(int64_t capturer_time_us, + int64_t system_time_us) { + const int64_t translated_timestamp = ClipTimestamp( + capturer_time_us + UpdateOffset(capturer_time_us, system_time_us), + system_time_us); + prev_time_offset_us_ = translated_timestamp - capturer_time_us; + return translated_timestamp; +} + +int64_t TimestampAligner::TranslateTimestamp(int64_t capturer_time_us) const { + return capturer_time_us + prev_time_offset_us_; +} + +int64_t TimestampAligner::UpdateOffset(int64_t capturer_time_us, + int64_t system_time_us) { + // Estimate the offset between system monotonic time and the capturer's + // time. The capturer is assumed to provide more + // accurate timestamps than we get from the system time. But the + // capturer may use its own free-running clock with a large offset and + // a small drift compared to the system clock. So the model is + // basically + // + // y_k = c_0 + c_1 * x_k + v_k + // + // where x_k is the capturer's timestamp, believed to be accurate in its + // own scale. y_k is our reading of the system clock. v_k is the + // measurement noise, i.e., the delay from frame capture until the + // system clock was read. + // + // It's possible to do (weighted) least-squares estimation of both + // c_0 and c_1. Then we get the constants as c_1 = Cov(x,y) / + // Var(x), and c_0 = mean(y) - c_1 * mean(x). Substituting this c_0, + // we can rearrange the model as + // + // y_k = mean(y) + (x_k - mean(x)) + (c_1 - 1) * (x_k - mean(x)) + v_k + // + // Now if we use a weighted average which gradually forgets old + // values, x_k - mean(x) is bounded, of the same order as the time + // constant (and close to constant for a steady frame rate). In + // addition, the frequency error |c_1 - 1| should be small. Cameras + // with a frequency error up to 3000 ppm (3 ms drift per second) + // have been observed, but frequency errors below 100 ppm could be + // expected of any cheap crystal. + // + // Bottom line is that we ignore the c_1 term, and use only the estimator + // + // x_k + mean(y-x) + // + // where mean is plain averaging for initial samples, followed by + // exponential averaging. + + // The input for averaging, y_k - x_k in the above notation. + int64_t diff_us = system_time_us - capturer_time_us; + // The deviation from the current average. + int64_t error_us = diff_us - offset_us_; + + // If the current difference is far from the currently estimated + // offset, the filter is reset. This could happen, e.g., if the + // capturer's clock is reset, cameras are plugged in and out, or + // the application process is temporarily suspended. Expected to + // happen for the very first timestamp (`frames_seen_` = 0). The + // threshold of 300 ms should make this unlikely in normal + // operation, and at the same time, converging gradually rather than + // resetting the filter should be tolerable for jumps in capturer's time + // below this threshold. + static const int64_t kResetThresholdUs = 300000; + if (std::abs(error_us) > kResetThresholdUs) { + RTC_LOG(LS_INFO) << "Resetting timestamp translation after averaging " + << frames_seen_ << " frames. Old offset: " << offset_us_ + << ", new offset: " << diff_us; + frames_seen_ = 0; + clip_bias_us_ = 0; + } + + static const int kWindowSize = 100; + if (frames_seen_ < kWindowSize) { + ++frames_seen_; + } + offset_us_ += error_us / frames_seen_; + return offset_us_; +} + +int64_t TimestampAligner::ClipTimestamp(int64_t filtered_time_us, + int64_t system_time_us) { + // Clip to make sure we don't produce timestamps in the future. + int64_t time_us = filtered_time_us - clip_bias_us_; + if (time_us > system_time_us) { + clip_bias_us_ += time_us - system_time_us; + time_us = system_time_us; + } + // Make timestamps monotonic, with a minimum inter-frame interval of 1 ms. + else if (time_us < prev_translated_time_us_ + kMinFrameIntervalUs) { + time_us = prev_translated_time_us_ + kMinFrameIntervalUs; + if (time_us > system_time_us) { + // In the anomalous case that this function is called with values of + // `system_time_us` less than `kMinFrameIntervalUs` apart, we may output + // timestamps with with too short inter-frame interval. We may even return + // duplicate timestamps in case this function is called several times with + // exactly the same `system_time_us`. + RTC_LOG(LS_WARNING) << "too short translated timestamp interval: " + "system time (us) = " + << system_time_us << ", interval (us) = " + << system_time_us - prev_translated_time_us_; + time_us = system_time_us; + } + } + RTC_DCHECK_GE(time_us, prev_translated_time_us_); + RTC_DCHECK_LE(time_us, system_time_us); + prev_translated_time_us_ = time_us; + return time_us; +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/timestamp_aligner.h b/third_party/libwebrtc/rtc_base/timestamp_aligner.h new file mode 100644 index 0000000000..636afcd659 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/timestamp_aligner.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2016 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 RTC_BASE_TIMESTAMP_ALIGNER_H_ +#define RTC_BASE_TIMESTAMP_ALIGNER_H_ + +#include <stdint.h> + +#include "rtc_base/system/rtc_export.h" +#include "rtc_base/time_utils.h" + +namespace rtc { + +// The TimestampAligner class helps translating timestamps of a capture system +// into the same timescale as is used by rtc::TimeMicros(). Some capture systems +// provide timestamps, which comes from the capturing hardware (camera or sound +// card) or stamped close to the capturing hardware. Such timestamps are more +// accurate (less jittery) than reading the system clock, but may have a +// different epoch and unknown clock drift. Frame timestamps in webrtc should +// use rtc::TimeMicros (system monotonic time), and this class provides a filter +// which lets us use the rtc::TimeMicros timescale, and at the same time take +// advantage of higher accuracy of the capturer's clock. + +// This class is not thread safe, so all calls to it must be synchronized +// externally. +class RTC_EXPORT TimestampAligner { + public: + TimestampAligner(); + ~TimestampAligner(); + + TimestampAligner(const TimestampAligner&) = delete; + TimestampAligner& operator=(const TimestampAligner&) = delete; + + public: + // Minimum difference of two timestamps generated by + // "TranslateTimestamp(int64_t capturer_time_us, int64_t system_time_us)" + // This avoids the caller from getting two timestamps with the same + // millisecond. + static constexpr int64_t kMinFrameIntervalUs = rtc::kNumMicrosecsPerMillisec; + + // Translates timestamps of a capture system to the same timescale as is used + // by rtc::TimeMicros(). `capturer_time_us` is assumed to be accurate, but + // with an unknown epoch and clock drift. `system_time_us` is + // time according to rtc::TimeMicros(), preferably read as soon as + // possible when the frame is captured. It may have poor accuracy + // due to poor resolution or scheduling delays. Returns the + // translated timestamp. + int64_t TranslateTimestamp(int64_t capturer_time_us, int64_t system_time_us); + + // Returns the translated timestamp without updating the states. This is to + // allow TimestampAligner to translate capturer time into system clock based + // on earlier observations. It won't guarantee monotonicity. + int64_t TranslateTimestamp(int64_t capturer_time_us) const; + + protected: + // Update the estimated offset between capturer's time and system monotonic + // time. + int64_t UpdateOffset(int64_t capturer_time_us, int64_t system_time_us); + + // Clip timestamp, return value is always + // <= `system_time_us`, and + // >= min(`prev_translated_time_us_` + `kMinFrameIntervalUs`, + // `system_time_us`). + int64_t ClipTimestamp(int64_t filtered_time_us, int64_t system_time_us); + + private: + // State for the timestamp translation. + int frames_seen_; + // Estimated offset between capturer's time and system monotonic time. + int64_t offset_us_; + + // State for the ClipTimestamp method, applied after the filter. + // A large negative clock drift of the capturer tends to push translated + // timestamps into the future. `clip_bias_us_` is subtracted from the + // translated timestamps, to get them back from the future. + int64_t clip_bias_us_; + // Used to ensure that translated timestamps are monotonous. + int64_t prev_translated_time_us_; + // Offset between `prev_translated_time_us_` and the corresponding capturer + // time. + int64_t prev_time_offset_us_; +}; + +} // namespace rtc + +#endif // RTC_BASE_TIMESTAMP_ALIGNER_H_ diff --git a/third_party/libwebrtc/rtc_base/timestamp_aligner_unittest.cc b/third_party/libwebrtc/rtc_base/timestamp_aligner_unittest.cc new file mode 100644 index 0000000000..ca91b62625 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/timestamp_aligner_unittest.cc @@ -0,0 +1,207 @@ +/* + * Copyright 2016 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 "rtc_base/timestamp_aligner.h" + +#include <math.h> + +#include <algorithm> +#include <limits> + +#include "rtc_base/random.h" +#include "rtc_base/time_utils.h" +#include "test/gtest.h" + +namespace rtc { + +namespace { +// Computes the difference x_k - mean(x), when x_k is the linear sequence x_k = +// k, and the "mean" is plain mean for the first `window_size` samples, followed +// by exponential averaging with weight 1 / `window_size` for each new sample. +// This is needed to predict the effect of camera clock drift on the timestamp +// translation. See the comment on TimestampAligner::UpdateOffset for more +// context. +double MeanTimeDifference(int nsamples, int window_size) { + if (nsamples <= window_size) { + // Plain averaging. + return nsamples / 2.0; + } else { + // Exponential convergence towards + // interval_error * (window_size - 1) + double alpha = 1.0 - 1.0 / window_size; + + return ((window_size - 1) - + (window_size / 2.0 - 1) * pow(alpha, nsamples - window_size)); + } +} + +class TimestampAlignerForTest : public TimestampAligner { + // Make internal methods accessible to testing. + public: + using TimestampAligner::ClipTimestamp; + using TimestampAligner::UpdateOffset; +}; + +void TestTimestampFilter(double rel_freq_error) { + TimestampAlignerForTest timestamp_aligner_for_test; + TimestampAligner timestamp_aligner; + const int64_t kEpoch = 10000; + const int64_t kJitterUs = 5000; + const int64_t kIntervalUs = 33333; // 30 FPS + const int kWindowSize = 100; + const int kNumFrames = 3 * kWindowSize; + + int64_t interval_error_us = kIntervalUs * rel_freq_error; + int64_t system_start_us = rtc::TimeMicros(); + webrtc::Random random(17); + + int64_t prev_translated_time_us = system_start_us; + + for (int i = 0; i < kNumFrames; i++) { + // Camera time subject to drift. + int64_t camera_time_us = kEpoch + i * (kIntervalUs + interval_error_us); + int64_t system_time_us = system_start_us + i * kIntervalUs; + // And system time readings are subject to jitter. + int64_t system_measured_us = system_time_us + random.Rand(kJitterUs); + + int64_t offset_us = timestamp_aligner_for_test.UpdateOffset( + camera_time_us, system_measured_us); + + int64_t filtered_time_us = camera_time_us + offset_us; + int64_t translated_time_us = timestamp_aligner_for_test.ClipTimestamp( + filtered_time_us, system_measured_us); + + // Check that we get identical result from the all-in-one helper method. + ASSERT_EQ(translated_time_us, timestamp_aligner.TranslateTimestamp( + camera_time_us, system_measured_us)); + + EXPECT_LE(translated_time_us, system_measured_us); + EXPECT_GE(translated_time_us, + prev_translated_time_us + rtc::kNumMicrosecsPerMillisec); + + // The relative frequency error contributes to the expected error + // by a factor which is the difference between the current time + // and the average of earlier sample times. + int64_t expected_error_us = + kJitterUs / 2 + + rel_freq_error * kIntervalUs * MeanTimeDifference(i, kWindowSize); + + int64_t bias_us = filtered_time_us - translated_time_us; + EXPECT_GE(bias_us, 0); + + if (i == 0) { + EXPECT_EQ(translated_time_us, system_measured_us); + } else { + EXPECT_NEAR(filtered_time_us, system_time_us + expected_error_us, + 2.0 * kJitterUs / sqrt(std::max(i, kWindowSize))); + } + // If the camera clock runs too fast (rel_freq_error > 0.0), The + // bias is expected to roughly cancel the expected error from the + // clock drift, as this grows. Otherwise, it reflects the + // measurement noise. The tolerances here were selected after some + // trial and error. + if (i < 10 || rel_freq_error <= 0.0) { + EXPECT_LE(bias_us, 3000); + } else { + EXPECT_NEAR(bias_us, expected_error_us, 1500); + } + prev_translated_time_us = translated_time_us; + } +} + +} // Anonymous namespace + +TEST(TimestampAlignerTest, AttenuateTimestampJitterNoDrift) { + TestTimestampFilter(0.0); +} + +// 100 ppm is a worst case for a reasonable crystal. +TEST(TimestampAlignerTest, AttenuateTimestampJitterSmallPosDrift) { + TestTimestampFilter(0.0001); +} + +TEST(TimestampAlignerTest, AttenuateTimestampJitterSmallNegDrift) { + TestTimestampFilter(-0.0001); +} + +// 3000 ppm, 3 ms / s, is the worst observed drift, see +// https://bugs.chromium.org/p/webrtc/issues/detail?id=5456 +TEST(TimestampAlignerTest, AttenuateTimestampJitterLargePosDrift) { + TestTimestampFilter(0.003); +} + +TEST(TimestampAlignerTest, AttenuateTimestampJitterLargeNegDrift) { + TestTimestampFilter(-0.003); +} + +// Exhibits a mostly hypothetical problem, where certain inputs to the +// TimestampAligner.UpdateOffset filter result in non-monotonous +// translated timestamps. This test verifies that the ClipTimestamp +// logic handles this case correctly. +TEST(TimestampAlignerTest, ClipToMonotonous) { + TimestampAlignerForTest timestamp_aligner; + + // For system time stamps { 0, s1, s1 + s2 }, and camera timestamps + // {0, c1, c1 + c2}, we exhibit non-monotonous behaviour if and only + // if c1 > s1 + 2 s2 + 4 c2. + const int kNumSamples = 3; + const int64_t kCaptureTimeUs[kNumSamples] = {0, 80000, 90001}; + const int64_t kSystemTimeUs[kNumSamples] = {0, 10000, 20000}; + const int64_t expected_offset_us[kNumSamples] = {0, -35000, -46667}; + + // Non-monotonic translated timestamps can happen when only for + // translated timestamps in the future. Which is tolerated if + // `timestamp_aligner.clip_bias_us` is large enough. Instead of + // changing that private member for this test, just add the bias to + // `kSystemTimeUs` when calling ClipTimestamp. + const int64_t kClipBiasUs = 100000; + + bool did_clip = false; + int64_t prev_timestamp_us = std::numeric_limits<int64_t>::min(); + for (int i = 0; i < kNumSamples; i++) { + int64_t offset_us = + timestamp_aligner.UpdateOffset(kCaptureTimeUs[i], kSystemTimeUs[i]); + EXPECT_EQ(offset_us, expected_offset_us[i]); + + int64_t translated_timestamp_us = kCaptureTimeUs[i] + offset_us; + int64_t clip_timestamp_us = timestamp_aligner.ClipTimestamp( + translated_timestamp_us, kSystemTimeUs[i] + kClipBiasUs); + if (translated_timestamp_us <= prev_timestamp_us) { + did_clip = true; + EXPECT_EQ(clip_timestamp_us, + prev_timestamp_us + rtc::kNumMicrosecsPerMillisec); + } else { + // No change from clipping. + EXPECT_EQ(clip_timestamp_us, translated_timestamp_us); + } + prev_timestamp_us = clip_timestamp_us; + } + EXPECT_TRUE(did_clip); +} + +TEST(TimestampAlignerTest, TranslateTimestampWithoutStateUpdate) { + TimestampAligner timestamp_aligner; + + constexpr int kNumSamples = 4; + constexpr int64_t kCaptureTimeUs[kNumSamples] = {0, 80000, 90001, 100000}; + constexpr int64_t kSystemTimeUs[kNumSamples] = {0, 10000, 20000, 30000}; + constexpr int64_t kQueryCaptureTimeOffsetUs[kNumSamples] = {0, 123, -321, + 345}; + + for (int i = 0; i < kNumSamples; i++) { + int64_t reference_timestamp = timestamp_aligner.TranslateTimestamp( + kCaptureTimeUs[i], kSystemTimeUs[i]); + EXPECT_EQ(reference_timestamp - kQueryCaptureTimeOffsetUs[i], + timestamp_aligner.TranslateTimestamp( + kCaptureTimeUs[i] - kQueryCaptureTimeOffsetUs[i])); + } +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/timeutils_gn/moz.build b/third_party/libwebrtc/rtc_base/timeutils_gn/moz.build new file mode 100644 index 0000000000..c4eb7ac8de --- /dev/null +++ b/third_party/libwebrtc/rtc_base/timeutils_gn/moz.build @@ -0,0 +1,234 @@ +# 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_EXCLUDE_SYSTEM_TIME"] = True +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/rtc_base/system_time.cc", + "/third_party/libwebrtc/rtc_base/time_utils.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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("timeutils_gn") diff --git a/third_party/libwebrtc/rtc_base/trace_event.h b/third_party/libwebrtc/rtc_base/trace_event.h new file mode 100644 index 0000000000..b34df0c93f --- /dev/null +++ b/third_party/libwebrtc/rtc_base/trace_event.h @@ -0,0 +1,3 @@ +// This header is diverted to a similar header in Gecko, that is defining the +// same macros, modified to talk to the Gecko Profiler. +#include "GeckoTraceEvent.h" diff --git a/third_party/libwebrtc/rtc_base/type_traits.h b/third_party/libwebrtc/rtc_base/type_traits.h new file mode 100644 index 0000000000..0cb899c47f --- /dev/null +++ b/third_party/libwebrtc/rtc_base/type_traits.h @@ -0,0 +1,140 @@ +/* + * Copyright 2016 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 RTC_BASE_TYPE_TRAITS_H_ +#define RTC_BASE_TYPE_TRAITS_H_ + +#include <cstddef> +#include <type_traits> + +namespace rtc { + +// Determines if the given class has zero-argument .data() and .size() methods +// whose return values are convertible to T* and size_t, respectively. +template <typename DS, typename T> +class HasDataAndSize { + private: + template < + typename C, + typename std::enable_if< + std::is_convertible<decltype(std::declval<C>().data()), T*>::value && + std::is_convertible<decltype(std::declval<C>().size()), + std::size_t>::value>::type* = nullptr> + static int Test(int); + + template <typename> + static char Test(...); + + public: + static constexpr bool value = std::is_same<decltype(Test<DS>(0)), int>::value; +}; + +namespace test_has_data_and_size { + +template <typename DR, typename SR> +struct Test1 { + DR data(); + SR size(); +}; +static_assert(HasDataAndSize<Test1<int*, int>, int>::value, ""); +static_assert(HasDataAndSize<Test1<int*, int>, const int>::value, ""); +static_assert(HasDataAndSize<Test1<const int*, int>, const int>::value, ""); +static_assert(!HasDataAndSize<Test1<const int*, int>, int>::value, + "implicit cast of const int* to int*"); +static_assert(!HasDataAndSize<Test1<char*, size_t>, int>::value, + "implicit cast of char* to int*"); + +struct Test2 { + int* data; + size_t size; +}; +static_assert(!HasDataAndSize<Test2, int>::value, + ".data and .size aren't functions"); + +struct Test3 { + int* data(); +}; +static_assert(!HasDataAndSize<Test3, int>::value, ".size() is missing"); + +class Test4 { + int* data(); + size_t size(); +}; +static_assert(!HasDataAndSize<Test4, int>::value, + ".data() and .size() are private"); + +} // namespace test_has_data_and_size + +namespace type_traits_impl { + +// Determines if the given type is an enum that converts implicitly to +// an integral type. +template <typename T> +struct IsIntEnum { + private: + // This overload is used if the type is an enum, and unary plus + // compiles and turns it into an integral type. + template <typename X, + typename std::enable_if< + std::is_enum<X>::value && + std::is_integral<decltype(+std::declval<X>())>::value>::type* = + nullptr> + static int Test(int); + + // Otherwise, this overload is used. + template <typename> + static char Test(...); + + public: + static constexpr bool value = + std::is_same<decltype(Test<typename std::remove_reference<T>::type>(0)), + int>::value; +}; + +} // namespace type_traits_impl + +// Determines if the given type is integral, or an enum that +// converts implicitly to an integral type. +template <typename T> +struct IsIntlike { + private: + using X = typename std::remove_reference<T>::type; + + public: + static constexpr bool value = + std::is_integral<X>::value || type_traits_impl::IsIntEnum<X>::value; +}; + +namespace test_enum_intlike { + +enum E1 { e1 }; +enum { e2 }; +enum class E3 { e3 }; +struct S {}; + +static_assert(type_traits_impl::IsIntEnum<E1>::value, ""); +static_assert(type_traits_impl::IsIntEnum<decltype(e2)>::value, ""); +static_assert(!type_traits_impl::IsIntEnum<E3>::value, ""); +static_assert(!type_traits_impl::IsIntEnum<int>::value, ""); +static_assert(!type_traits_impl::IsIntEnum<float>::value, ""); +static_assert(!type_traits_impl::IsIntEnum<S>::value, ""); + +static_assert(IsIntlike<E1>::value, ""); +static_assert(IsIntlike<decltype(e2)>::value, ""); +static_assert(!IsIntlike<E3>::value, ""); +static_assert(IsIntlike<int>::value, ""); +static_assert(!IsIntlike<float>::value, ""); +static_assert(!IsIntlike<S>::value, ""); + +} // namespace test_enum_intlike + +} // namespace rtc + +#endif // RTC_BASE_TYPE_TRAITS_H_ diff --git a/third_party/libwebrtc/rtc_base/type_traits_gn/moz.build b/third_party/libwebrtc/rtc_base/type_traits_gn/moz.build new file mode 100644 index 0000000000..1f72327af3 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/type_traits_gn/moz.build @@ -0,0 +1,205 @@ +# 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("type_traits_gn") diff --git a/third_party/libwebrtc/rtc_base/unique_id_generator.cc b/third_party/libwebrtc/rtc_base/unique_id_generator.cc new file mode 100644 index 0000000000..e68c643dbe --- /dev/null +++ b/third_party/libwebrtc/rtc_base/unique_id_generator.cc @@ -0,0 +1,72 @@ +/* + * 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. + */ + +#include "rtc_base/unique_id_generator.h" + +#include <limits> +#include <vector> + +#include "absl/strings/string_view.h" +#include "rtc_base/helpers.h" +#include "rtc_base/string_encode.h" +#include "rtc_base/string_to_number.h" + +namespace rtc { + +UniqueRandomIdGenerator::UniqueRandomIdGenerator() : known_ids_() {} +UniqueRandomIdGenerator::UniqueRandomIdGenerator(ArrayView<uint32_t> known_ids) + : known_ids_(known_ids.begin(), known_ids.end()) {} + +UniqueRandomIdGenerator::~UniqueRandomIdGenerator() = default; + +uint32_t UniqueRandomIdGenerator::GenerateId() { + webrtc::MutexLock lock(&mutex_); + + RTC_CHECK_LT(known_ids_.size(), std::numeric_limits<uint32_t>::max() - 1); + while (true) { + auto pair = known_ids_.insert(CreateRandomNonZeroId()); + if (pair.second) { + return *pair.first; + } + } +} + +bool UniqueRandomIdGenerator::AddKnownId(uint32_t value) { + webrtc::MutexLock lock(&mutex_); + return known_ids_.insert(value).second; +} + +UniqueStringGenerator::UniqueStringGenerator() : unique_number_generator_() {} +UniqueStringGenerator::UniqueStringGenerator(ArrayView<std::string> known_ids) { + for (const std::string& str : known_ids) { + AddKnownId(str); + } +} + +UniqueStringGenerator::~UniqueStringGenerator() = default; + +std::string UniqueStringGenerator::GenerateString() { + return ToString(unique_number_generator_.GenerateNumber()); +} + +bool UniqueStringGenerator::AddKnownId(absl::string_view value) { + // TODO(webrtc:13579): remove string copy here once absl::string_view version + // of StringToNumber is available. + absl::optional<uint32_t> int_value = + StringToNumber<uint32_t>(std::string(value)); + // The underlying generator works for uint32_t values, so if the provided + // value is not a uint32_t it will never be generated anyway. + if (int_value.has_value()) { + return unique_number_generator_.AddKnownId(int_value.value()); + } + return false; +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/unique_id_generator.h b/third_party/libwebrtc/rtc_base/unique_id_generator.h new file mode 100644 index 0000000000..10dd4d3151 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/unique_id_generator.h @@ -0,0 +1,150 @@ +/* + * 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 RTC_BASE_UNIQUE_ID_GENERATOR_H_ +#define RTC_BASE_UNIQUE_ID_GENERATOR_H_ + +#include <limits> +#include <set> +#include <string> + +#include "absl/strings/string_view.h" +#include "api/array_view.h" +#include "api/sequence_checker.h" +#include "rtc_base/synchronization/mutex.h" +#include "rtc_base/system/no_unique_address.h" + +namespace rtc { + +// This class will generate numbers. A common use case is for identifiers. +// The generated numbers will be unique, in the local scope of the generator. +// This means that a generator will never generate the same number twice. +// The generator can also be initialized with a sequence of known ids. +// In such a case, it will never generate an id from that list. +// Recommendedations: +// * Prefer unsigned types. +// * Prefer larger types (uint8_t will run out quickly). +template <typename TIntegral> +class UniqueNumberGenerator { + public: + typedef TIntegral value_type; + UniqueNumberGenerator(); + // Creates a generator that will never return any value from the given list. + explicit UniqueNumberGenerator(ArrayView<TIntegral> known_ids); + ~UniqueNumberGenerator(); + + // Generates a number that this generator has never produced before. + // If there are no available numbers to generate, this method will fail + // with an `RTC_CHECK`. + TIntegral GenerateNumber(); + + // Alias for GenerateId, used for allowing typed testing + TIntegral Generate() { return GenerateNumber(); } + + // Adds an id that this generator should no longer generate. + // Return value indicates whether the ID was hitherto unknown. + bool AddKnownId(TIntegral value); + + private: + RTC_NO_UNIQUE_ADDRESS webrtc::SequenceChecker sequence_checker_{ + webrtc::SequenceChecker::kDetached}; + static_assert(std::is_integral<TIntegral>::value, "Must be integral type."); + TIntegral counter_ RTC_GUARDED_BY(sequence_checker_); + std::set<TIntegral> known_ids_ RTC_GUARDED_BY(sequence_checker_); +}; + +// This class will generate unique ids. Ids are 32 bit unsigned integers. +// The generated ids will be unique, in the local scope of the generator. +// This means that a generator will never generate the same id twice. +// The generator can also be initialized with a sequence of known ids. +// In such a case, it will never generate an id from that list. +class UniqueRandomIdGenerator { + public: + typedef uint32_t value_type; + UniqueRandomIdGenerator(); + // Create a generator that will never return any value from the given list. + explicit UniqueRandomIdGenerator(ArrayView<uint32_t> known_ids); + ~UniqueRandomIdGenerator(); + + // Generates a random id that this generator has never produced before. + // This method becomes more expensive with each use, as the probability of + // collision for the randomly generated numbers increases. + uint32_t GenerateId(); + + // Alias for GenerateId, used for allowing typed testing + uint32_t Generate() { return GenerateId(); } + + // Adds an id that this generator should no longer generate. + // Return value indicates whether the ID was hitherto unknown. + bool AddKnownId(uint32_t value); + + private: + // TODO(bugs.webrtc.org/12666): This lock is needed due to an instance in + // SdpOfferAnswerHandler being shared between threads. + webrtc::Mutex mutex_; + std::set<uint32_t> known_ids_ RTC_GUARDED_BY(&mutex_); +}; + +// This class will generate strings. A common use case is for identifiers. +// The generated strings will be unique, in the local scope of the generator. +// This means that a generator will never generate the same string twice. +// The generator can also be initialized with a sequence of known ids. +// In such a case, it will never generate an id from that list. +class UniqueStringGenerator { + public: + typedef std::string value_type; + UniqueStringGenerator(); + explicit UniqueStringGenerator(ArrayView<std::string> known_ids); + ~UniqueStringGenerator(); + + std::string GenerateString(); + // Alias for GenerateString, used for allowing typed testing + std::string Generate() { return GenerateString(); } + + // Adds an id that this generator should no longer generate. + // Return value indicates whether the ID was hitherto unknown. + bool AddKnownId(absl::string_view value); + + private: + // This implementation will be simple and will generate "0", "1", ... + UniqueNumberGenerator<uint32_t> unique_number_generator_; +}; + +template <typename TIntegral> +UniqueNumberGenerator<TIntegral>::UniqueNumberGenerator() : counter_(0) {} + +template <typename TIntegral> +UniqueNumberGenerator<TIntegral>::UniqueNumberGenerator( + ArrayView<TIntegral> known_ids) + : counter_(0), known_ids_(known_ids.begin(), known_ids.end()) {} + +template <typename TIntegral> +UniqueNumberGenerator<TIntegral>::~UniqueNumberGenerator() {} + +template <typename TIntegral> +TIntegral UniqueNumberGenerator<TIntegral>::GenerateNumber() { + RTC_DCHECK_RUN_ON(&sequence_checker_); + while (true) { + RTC_CHECK_LT(counter_, std::numeric_limits<TIntegral>::max()); + auto pair = known_ids_.insert(counter_++); + if (pair.second) { + return *pair.first; + } + } +} + +template <typename TIntegral> +bool UniqueNumberGenerator<TIntegral>::AddKnownId(TIntegral value) { + RTC_DCHECK_RUN_ON(&sequence_checker_); + return known_ids_.insert(value).second; +} +} // namespace rtc + +#endif // RTC_BASE_UNIQUE_ID_GENERATOR_H_ diff --git a/third_party/libwebrtc/rtc_base/unique_id_generator_gn/moz.build b/third_party/libwebrtc/rtc_base/unique_id_generator_gn/moz.build new file mode 100644 index 0000000000..975562a208 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/unique_id_generator_gn/moz.build @@ -0,0 +1,205 @@ +# 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("unique_id_generator_gn") diff --git a/third_party/libwebrtc/rtc_base/unique_id_generator_unittest.cc b/third_party/libwebrtc/rtc_base/unique_id_generator_unittest.cc new file mode 100644 index 0000000000..a6ae8ec9f5 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/unique_id_generator_unittest.cc @@ -0,0 +1,211 @@ +/* + * 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. + */ + +#include "rtc_base/unique_id_generator.h" + +#include <string> +#include <vector> + +#include "absl/algorithm/container.h" +#include "absl/functional/any_invocable.h" +#include "api/array_view.h" +#include "api/task_queue/task_queue_base.h" +#include "api/units/time_delta.h" +#include "rtc_base/gunit.h" +#include "rtc_base/helpers.h" +#include "test/gmock.h" + +using ::testing::IsEmpty; +using ::testing::Test; + +namespace rtc { +namespace { +// Utility class that registers itself as the currently active task queue. +class FakeTaskQueue : public webrtc::TaskQueueBase { + public: + FakeTaskQueue() : task_queue_setter_(this) {} + + void Delete() override {} + void PostTaskImpl(absl::AnyInvocable<void() &&> task, + const PostTaskTraits& traits, + const webrtc::Location& location) override {} + void PostDelayedTaskImpl(absl::AnyInvocable<void() &&> task, + webrtc::TimeDelta delay, + const PostDelayedTaskTraits& traits, + const webrtc::Location& location) override {} + + private: + CurrentTaskQueueSetter task_queue_setter_; +}; +} // namespace + +template <typename Generator> +class UniqueIdGeneratorTest : public Test {}; + +using test_types = ::testing::Types<UniqueNumberGenerator<uint8_t>, + UniqueNumberGenerator<uint16_t>, + UniqueNumberGenerator<uint32_t>, + UniqueNumberGenerator<int>, + UniqueRandomIdGenerator, + UniqueStringGenerator>; + +TYPED_TEST_SUITE(UniqueIdGeneratorTest, test_types); + +TYPED_TEST(UniqueIdGeneratorTest, ElementsDoNotRepeat) { + typedef TypeParam Generator; + const size_t num_elements = 255; + Generator generator; + std::vector<typename Generator::value_type> values; + for (size_t i = 0; i < num_elements; i++) { + values.push_back(generator.Generate()); + } + + EXPECT_EQ(num_elements, values.size()); + // Use a set to check uniqueness. + std::set<typename Generator::value_type> set(values.begin(), values.end()); + EXPECT_EQ(values.size(), set.size()) << "Returned values were not unique."; +} + +TYPED_TEST(UniqueIdGeneratorTest, KnownElementsAreNotGenerated) { + typedef TypeParam Generator; + const size_t num_elements = 100; + rtc::InitRandom(0); + Generator generator1; + std::vector<typename Generator::value_type> known_values; + for (size_t i = 0; i < num_elements; i++) { + known_values.push_back(generator1.Generate()); + } + EXPECT_EQ(num_elements, known_values.size()); + + rtc::InitRandom(0); + Generator generator2(known_values); + + std::vector<typename Generator::value_type> values; + for (size_t i = 0; i < num_elements; i++) { + values.push_back(generator2.Generate()); + } + EXPECT_THAT(values, ::testing::SizeIs(num_elements)); + absl::c_sort(values); + absl::c_sort(known_values); + std::vector<typename Generator::value_type> intersection; + absl::c_set_intersection(values, known_values, + std::back_inserter(intersection)); + EXPECT_THAT(intersection, IsEmpty()); +} + +TYPED_TEST(UniqueIdGeneratorTest, AddedElementsAreNotGenerated) { + typedef TypeParam Generator; + const size_t num_elements = 100; + rtc::InitRandom(0); + Generator generator1; + std::vector<typename Generator::value_type> known_values; + for (size_t i = 0; i < num_elements; i++) { + known_values.push_back(generator1.Generate()); + } + EXPECT_EQ(num_elements, known_values.size()); + + rtc::InitRandom(0); + Generator generator2; + + for (const typename Generator::value_type& value : known_values) { + generator2.AddKnownId(value); + } + + std::vector<typename Generator::value_type> values; + for (size_t i = 0; i < num_elements; i++) { + values.push_back(generator2.Generate()); + } + EXPECT_THAT(values, ::testing::SizeIs(num_elements)); + absl::c_sort(values); + absl::c_sort(known_values); + std::vector<typename Generator::value_type> intersection; + absl::c_set_intersection(values, known_values, + std::back_inserter(intersection)); + EXPECT_THAT(intersection, IsEmpty()); +} + +TYPED_TEST(UniqueIdGeneratorTest, AddKnownIdOnNewIdReturnsTrue) { + typedef TypeParam Generator; + + rtc::InitRandom(0); + Generator generator1; + const typename Generator::value_type id = generator1.Generate(); + + rtc::InitRandom(0); + Generator generator2; + EXPECT_TRUE(generator2.AddKnownId(id)); +} + +TYPED_TEST(UniqueIdGeneratorTest, AddKnownIdCalledAgainForSameIdReturnsFalse) { + typedef TypeParam Generator; + + rtc::InitRandom(0); + Generator generator1; + const typename Generator::value_type id = generator1.Generate(); + + rtc::InitRandom(0); + Generator generator2; + ASSERT_TRUE(generator2.AddKnownId(id)); + EXPECT_FALSE(generator2.AddKnownId(id)); +} + +TYPED_TEST(UniqueIdGeneratorTest, + AddKnownIdOnIdProvidedAsKnownToCtorReturnsFalse) { + typedef TypeParam Generator; + + rtc::InitRandom(0); + Generator generator1; + const typename Generator::value_type id = generator1.Generate(); + std::vector<typename Generator::value_type> known_values = {id}; + + rtc::InitRandom(0); + Generator generator2(known_values); + EXPECT_FALSE(generator2.AddKnownId(id)); +} + +// Tests that it's OK to construct the generator in one execution environment +// (thread/task queue) but use it in another. +TEST(UniqueNumberGenerator, UsedOnSecondaryThread) { + const auto* current_tq = webrtc::TaskQueueBase::Current(); + // Construct the generator before `fake_task_queue` to ensure that it is + // constructed in a different execution environment than what + // `fake_task_queue` will represent. + UniqueNumberGenerator<uint32_t> generator; + + FakeTaskQueue fake_task_queue; + // Sanity check to make sure we're in a different runtime environment. + ASSERT_NE(current_tq, webrtc::TaskQueueBase::Current()); + + // Generating an id should be fine in this context. + generator.Generate(); +} + +#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID) +TEST(UniqueNumberGeneratorDeathTest, FailsWhenUsedInWrongContext) { + // Instantiate the generator before the `loop`. This ensures that + // thread/sequence checkers will pick up a different thread environment than + // `fake_task_queue` will represent. + UniqueNumberGenerator<uint32_t> generator; + + // Instantiate a fake task queue that will register itself as the current tq. + FakeTaskQueue initial_fake_task_queue; + // Generate an ID on the current thread. This causes the generator to attach + // to the current thread context. + generator.Generate(); + + // Instantiate a fake task queue that will register itself as the current tq. + FakeTaskQueue fake_task_queue; + + // Attempting to generate an id should now trigger a dcheck. + EXPECT_DEATH(generator.Generate(), ""); +} +#endif + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/units/BUILD.gn b/third_party/libwebrtc/rtc_base/units/BUILD.gn new file mode 100644 index 0000000000..bbb87a009a --- /dev/null +++ b/third_party/libwebrtc/rtc_base/units/BUILD.gn @@ -0,0 +1,34 @@ +# 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_source_set("unit_base") { + visibility = [ + ":*", + "../../api/units:*", + ] + sources = [ "unit_base.h" ] + + deps = [ + "../../rtc_base:checks", + "../../rtc_base:divide_round", + "../../rtc_base:safe_conversions", + ] +} + +if (rtc_include_tests) { + rtc_library("units_unittests") { + testonly = true + sources = [ "unit_base_unittest.cc" ] + deps = [ + ":unit_base", + "../../test:test_support", + ] + } +} diff --git a/third_party/libwebrtc/rtc_base/units/OWNERS b/third_party/libwebrtc/rtc_base/units/OWNERS new file mode 100644 index 0000000000..53e076b20b --- /dev/null +++ b/third_party/libwebrtc/rtc_base/units/OWNERS @@ -0,0 +1 @@ +srte@webrtc.org diff --git a/third_party/libwebrtc/rtc_base/units/unit_base.h b/third_party/libwebrtc/rtc_base/units/unit_base.h new file mode 100644 index 0000000000..a6bdbf547d --- /dev/null +++ b/third_party/libwebrtc/rtc_base/units/unit_base.h @@ -0,0 +1,311 @@ +/* + * 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 RTC_BASE_UNITS_UNIT_BASE_H_ +#define RTC_BASE_UNITS_UNIT_BASE_H_ + +#include <stdint.h> + +#include <algorithm> +#include <cmath> +#include <limits> +#include <type_traits> + +#include "rtc_base/checks.h" +#include "rtc_base/numerics/divide_round.h" +#include "rtc_base/numerics/safe_conversions.h" + +namespace webrtc { +namespace rtc_units_impl { + +// UnitBase is a base class for implementing custom value types with a specific +// unit. It provides type safety and commonly useful operations. The underlying +// storage is always an int64_t, it's up to the unit implementation to choose +// what scale it represents. +// +// It's used like: +// class MyUnit: public UnitBase<MyUnit> {...}; +// +// Unit_T is the subclass representing the specific unit. +template <class Unit_T> +class UnitBase { + public: + UnitBase() = delete; + static constexpr Unit_T Zero() { return Unit_T(0); } + static constexpr Unit_T PlusInfinity() { return Unit_T(PlusInfinityVal()); } + static constexpr Unit_T MinusInfinity() { return Unit_T(MinusInfinityVal()); } + + constexpr bool IsZero() const { return value_ == 0; } + constexpr bool IsFinite() const { return !IsInfinite(); } + constexpr bool IsInfinite() const { + return value_ == PlusInfinityVal() || value_ == MinusInfinityVal(); + } + constexpr bool IsPlusInfinity() const { return value_ == PlusInfinityVal(); } + constexpr bool IsMinusInfinity() const { + return value_ == MinusInfinityVal(); + } + + constexpr bool operator==(const UnitBase<Unit_T>& other) const { + return value_ == other.value_; + } + constexpr bool operator!=(const UnitBase<Unit_T>& other) const { + return value_ != other.value_; + } + constexpr bool operator<=(const UnitBase<Unit_T>& other) const { + return value_ <= other.value_; + } + constexpr bool operator>=(const UnitBase<Unit_T>& other) const { + return value_ >= other.value_; + } + constexpr bool operator>(const UnitBase<Unit_T>& other) const { + return value_ > other.value_; + } + constexpr bool operator<(const UnitBase<Unit_T>& other) const { + return value_ < other.value_; + } + constexpr Unit_T RoundTo(const Unit_T& resolution) const { + RTC_DCHECK(IsFinite()); + RTC_DCHECK(resolution.IsFinite()); + RTC_DCHECK_GT(resolution.value_, 0); + return Unit_T((value_ + resolution.value_ / 2) / resolution.value_) * + resolution.value_; + } + constexpr Unit_T RoundUpTo(const Unit_T& resolution) const { + RTC_DCHECK(IsFinite()); + RTC_DCHECK(resolution.IsFinite()); + RTC_DCHECK_GT(resolution.value_, 0); + return Unit_T((value_ + resolution.value_ - 1) / resolution.value_) * + resolution.value_; + } + constexpr Unit_T RoundDownTo(const Unit_T& resolution) const { + RTC_DCHECK(IsFinite()); + RTC_DCHECK(resolution.IsFinite()); + RTC_DCHECK_GT(resolution.value_, 0); + return Unit_T(value_ / resolution.value_) * resolution.value_; + } + + protected: + template < + typename T, + typename std::enable_if<std::is_integral<T>::value>::type* = nullptr> + static constexpr Unit_T FromValue(T value) { + if (Unit_T::one_sided) + RTC_DCHECK_GE(value, 0); + RTC_DCHECK_GT(value, MinusInfinityVal()); + RTC_DCHECK_LT(value, PlusInfinityVal()); + return Unit_T(rtc::dchecked_cast<int64_t>(value)); + } + template <typename T, + typename std::enable_if<std::is_floating_point<T>::value>::type* = + nullptr> + static constexpr Unit_T FromValue(T value) { + if (value == std::numeric_limits<T>::infinity()) { + return PlusInfinity(); + } else if (value == -std::numeric_limits<T>::infinity()) { + return MinusInfinity(); + } else { + RTC_DCHECK(!std::isnan(value)); + return FromValue(rtc::dchecked_cast<int64_t>(value)); + } + } + + template < + typename T, + typename std::enable_if<std::is_integral<T>::value>::type* = nullptr> + static constexpr Unit_T FromFraction(int64_t denominator, T value) { + if (Unit_T::one_sided) + RTC_DCHECK_GE(value, 0); + RTC_DCHECK_GT(value, MinusInfinityVal() / denominator); + RTC_DCHECK_LT(value, PlusInfinityVal() / denominator); + return Unit_T(rtc::dchecked_cast<int64_t>(value * denominator)); + } + template <typename T, + typename std::enable_if<std::is_floating_point<T>::value>::type* = + nullptr> + static constexpr Unit_T FromFraction(int64_t denominator, T value) { + return FromValue(value * denominator); + } + + template <typename T = int64_t> + constexpr typename std::enable_if<std::is_integral<T>::value, T>::type + ToValue() const { + RTC_DCHECK(IsFinite()); + return rtc::dchecked_cast<T>(value_); + } + template <typename T> + constexpr typename std::enable_if<std::is_floating_point<T>::value, T>::type + ToValue() const { + return IsPlusInfinity() ? std::numeric_limits<T>::infinity() + : IsMinusInfinity() ? -std::numeric_limits<T>::infinity() + : value_; + } + template <typename T> + constexpr T ToValueOr(T fallback_value) const { + return IsFinite() ? value_ : fallback_value; + } + + template <int64_t Denominator, typename T = int64_t> + constexpr typename std::enable_if<std::is_integral<T>::value, T>::type + ToFraction() const { + RTC_DCHECK(IsFinite()); + return rtc::dchecked_cast<T>(DivideRoundToNearest(value_, Denominator)); + } + template <int64_t Denominator, typename T> + constexpr typename std::enable_if<std::is_floating_point<T>::value, T>::type + ToFraction() const { + return ToValue<T>() * (1 / static_cast<T>(Denominator)); + } + + template <int64_t Denominator> + constexpr int64_t ToFractionOr(int64_t fallback_value) const { + return IsFinite() ? DivideRoundToNearest(value_, Denominator) + : fallback_value; + } + + template <int64_t Factor, typename T = int64_t> + constexpr typename std::enable_if<std::is_integral<T>::value, T>::type + ToMultiple() const { + RTC_DCHECK_GE(ToValue(), std::numeric_limits<T>::min() / Factor); + RTC_DCHECK_LE(ToValue(), std::numeric_limits<T>::max() / Factor); + return rtc::dchecked_cast<T>(ToValue() * Factor); + } + template <int64_t Factor, typename T> + constexpr typename std::enable_if<std::is_floating_point<T>::value, T>::type + ToMultiple() const { + return ToValue<T>() * Factor; + } + + explicit constexpr UnitBase(int64_t value) : value_(value) {} + + private: + template <class RelativeUnit_T> + friend class RelativeUnit; + + static inline constexpr int64_t PlusInfinityVal() { + return std::numeric_limits<int64_t>::max(); + } + static inline constexpr int64_t MinusInfinityVal() { + return std::numeric_limits<int64_t>::min(); + } + + constexpr Unit_T& AsSubClassRef() { return static_cast<Unit_T&>(*this); } + constexpr const Unit_T& AsSubClassRef() const { + return static_cast<const Unit_T&>(*this); + } + + int64_t value_; +}; + +// Extends UnitBase to provide operations for relative units, that is, units +// that have a meaningful relation between values such that a += b is a +// sensible thing to do. For a,b <- same unit. +template <class Unit_T> +class RelativeUnit : public UnitBase<Unit_T> { + public: + constexpr Unit_T Clamped(Unit_T min_value, Unit_T max_value) const { + return std::max(min_value, + std::min(UnitBase<Unit_T>::AsSubClassRef(), max_value)); + } + constexpr void Clamp(Unit_T min_value, Unit_T max_value) { + *this = Clamped(min_value, max_value); + } + constexpr Unit_T operator+(const Unit_T other) const { + if (this->IsPlusInfinity() || other.IsPlusInfinity()) { + RTC_DCHECK(!this->IsMinusInfinity()); + RTC_DCHECK(!other.IsMinusInfinity()); + return this->PlusInfinity(); + } else if (this->IsMinusInfinity() || other.IsMinusInfinity()) { + RTC_DCHECK(!this->IsPlusInfinity()); + RTC_DCHECK(!other.IsPlusInfinity()); + return this->MinusInfinity(); + } + return UnitBase<Unit_T>::FromValue(this->ToValue() + other.ToValue()); + } + constexpr Unit_T operator-(const Unit_T other) const { + if (this->IsPlusInfinity() || other.IsMinusInfinity()) { + RTC_DCHECK(!this->IsMinusInfinity()); + RTC_DCHECK(!other.IsPlusInfinity()); + return this->PlusInfinity(); + } else if (this->IsMinusInfinity() || other.IsPlusInfinity()) { + RTC_DCHECK(!this->IsPlusInfinity()); + RTC_DCHECK(!other.IsMinusInfinity()); + return this->MinusInfinity(); + } + return UnitBase<Unit_T>::FromValue(this->ToValue() - other.ToValue()); + } + constexpr Unit_T& operator+=(const Unit_T other) { + *this = *this + other; + return this->AsSubClassRef(); + } + constexpr Unit_T& operator-=(const Unit_T other) { + *this = *this - other; + return this->AsSubClassRef(); + } + constexpr double operator/(const Unit_T other) const { + return UnitBase<Unit_T>::template ToValue<double>() / + other.template ToValue<double>(); + } + template <typename T, + typename std::enable_if_t<std::is_floating_point_v<T>>* = nullptr> + constexpr Unit_T operator/(T scalar) const { + return UnitBase<Unit_T>::FromValue(std::llround(this->ToValue() / scalar)); + } + template <typename T, + typename std::enable_if_t<std::is_integral_v<T>>* = nullptr> + constexpr Unit_T operator/(T scalar) const { + return UnitBase<Unit_T>::FromValue(this->ToValue() / scalar); + } + constexpr Unit_T operator*(double scalar) const { + return UnitBase<Unit_T>::FromValue(std::llround(this->ToValue() * scalar)); + } + constexpr Unit_T operator*(int64_t scalar) const { + return UnitBase<Unit_T>::FromValue(this->ToValue() * scalar); + } + constexpr Unit_T operator*(int32_t scalar) const { + return UnitBase<Unit_T>::FromValue(this->ToValue() * scalar); + } + constexpr Unit_T operator*(size_t scalar) const { + return UnitBase<Unit_T>::FromValue(this->ToValue() * scalar); + } + + protected: + using UnitBase<Unit_T>::UnitBase; +}; + +template <class Unit_T> +inline constexpr Unit_T operator*(double scalar, RelativeUnit<Unit_T> other) { + return other * scalar; +} +template <class Unit_T> +inline constexpr Unit_T operator*(int64_t scalar, RelativeUnit<Unit_T> other) { + return other * scalar; +} +template <class Unit_T> +inline constexpr Unit_T operator*(int32_t scalar, RelativeUnit<Unit_T> other) { + return other * scalar; +} +template <class Unit_T> +inline constexpr Unit_T operator*(size_t scalar, RelativeUnit<Unit_T> other) { + return other * scalar; +} + +template <class Unit_T> +inline constexpr Unit_T operator-(RelativeUnit<Unit_T> other) { + if (other.IsPlusInfinity()) + return UnitBase<Unit_T>::MinusInfinity(); + if (other.IsMinusInfinity()) + return UnitBase<Unit_T>::PlusInfinity(); + return -1 * other; +} + +} // namespace rtc_units_impl + +} // namespace webrtc + +#endif // RTC_BASE_UNITS_UNIT_BASE_H_ diff --git a/third_party/libwebrtc/rtc_base/units/unit_base_gn/moz.build b/third_party/libwebrtc/rtc_base/units/unit_base_gn/moz.build new file mode 100644 index 0000000000..bb68c4ea3c --- /dev/null +++ b/third_party/libwebrtc/rtc_base/units/unit_base_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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("unit_base_gn") diff --git a/third_party/libwebrtc/rtc_base/units/unit_base_unittest.cc b/third_party/libwebrtc/rtc_base/units/unit_base_unittest.cc new file mode 100644 index 0000000000..258d7d1268 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/units/unit_base_unittest.cc @@ -0,0 +1,251 @@ +/* + * 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 "rtc_base/units/unit_base.h" + +#include "test/gtest.h" + +namespace webrtc { +namespace { +class TestUnit final : public rtc_units_impl::RelativeUnit<TestUnit> { + public: + TestUnit() = delete; + + using UnitBase::FromValue; + using UnitBase::ToValue; + using UnitBase::ToValueOr; + + template <typename T> + static constexpr TestUnit FromKilo(T kilo) { + return FromFraction(1000, kilo); + } + template <typename T = int64_t> + T ToKilo() const { + return UnitBase::ToFraction<1000, T>(); + } + constexpr int64_t ToKiloOr(int64_t fallback) const { + return UnitBase::ToFractionOr<1000>(fallback); + } + template <typename T> + constexpr T ToMilli() const { + return UnitBase::ToMultiple<1000, T>(); + } + + private: + friend class rtc_units_impl::UnitBase<TestUnit>; + static constexpr bool one_sided = false; + using RelativeUnit<TestUnit>::RelativeUnit; +}; +constexpr TestUnit TestUnitAddKilo(TestUnit value, int add_kilo) { + value += TestUnit::FromKilo(add_kilo); + return value; +} +} // namespace +namespace test { +TEST(UnitBaseTest, ConstExpr) { + constexpr int64_t kValue = -12345; + constexpr TestUnit kTestUnitZero = TestUnit::Zero(); + constexpr TestUnit kTestUnitPlusInf = TestUnit::PlusInfinity(); + constexpr TestUnit kTestUnitMinusInf = TestUnit::MinusInfinity(); + static_assert(kTestUnitZero.IsZero(), ""); + static_assert(kTestUnitPlusInf.IsPlusInfinity(), ""); + static_assert(kTestUnitMinusInf.IsMinusInfinity(), ""); + static_assert(kTestUnitPlusInf.ToKiloOr(-1) == -1, ""); + + static_assert(kTestUnitPlusInf > kTestUnitZero, ""); + + constexpr TestUnit kTestUnitKilo = TestUnit::FromKilo(kValue); + constexpr TestUnit kTestUnitValue = TestUnit::FromValue(kValue); + + static_assert(kTestUnitKilo.ToKiloOr(0) == kValue, ""); + static_assert(kTestUnitValue.ToValueOr(0) == kValue, ""); + static_assert(TestUnitAddKilo(kTestUnitValue, 2).ToValue() == kValue + 2000, + ""); + static_assert(TestUnit::FromValue(500) / 2 == TestUnit::FromValue(250)); +} + +TEST(UnitBaseTest, GetBackSameValues) { + const int64_t kValue = 499; + for (int sign = -1; sign <= 1; ++sign) { + int64_t value = kValue * sign; + EXPECT_EQ(TestUnit::FromKilo(value).ToKilo(), value); + EXPECT_EQ(TestUnit::FromValue(value).ToValue<int64_t>(), value); + } + EXPECT_EQ(TestUnit::Zero().ToValue<int64_t>(), 0); +} + +TEST(UnitBaseTest, GetDifferentPrefix) { + const int64_t kValue = 3000000; + EXPECT_EQ(TestUnit::FromValue(kValue).ToKilo(), kValue / 1000); + EXPECT_EQ(TestUnit::FromKilo(kValue).ToValue<int64_t>(), kValue * 1000); +} + +TEST(UnitBaseTest, IdentityChecks) { + const int64_t kValue = 3000; + EXPECT_TRUE(TestUnit::Zero().IsZero()); + EXPECT_FALSE(TestUnit::FromKilo(kValue).IsZero()); + + EXPECT_TRUE(TestUnit::PlusInfinity().IsInfinite()); + EXPECT_TRUE(TestUnit::MinusInfinity().IsInfinite()); + EXPECT_FALSE(TestUnit::Zero().IsInfinite()); + EXPECT_FALSE(TestUnit::FromKilo(-kValue).IsInfinite()); + EXPECT_FALSE(TestUnit::FromKilo(kValue).IsInfinite()); + + EXPECT_FALSE(TestUnit::PlusInfinity().IsFinite()); + EXPECT_FALSE(TestUnit::MinusInfinity().IsFinite()); + EXPECT_TRUE(TestUnit::FromKilo(-kValue).IsFinite()); + EXPECT_TRUE(TestUnit::FromKilo(kValue).IsFinite()); + EXPECT_TRUE(TestUnit::Zero().IsFinite()); + + EXPECT_TRUE(TestUnit::PlusInfinity().IsPlusInfinity()); + EXPECT_FALSE(TestUnit::MinusInfinity().IsPlusInfinity()); + + EXPECT_TRUE(TestUnit::MinusInfinity().IsMinusInfinity()); + EXPECT_FALSE(TestUnit::PlusInfinity().IsMinusInfinity()); +} + +TEST(UnitBaseTest, ComparisonOperators) { + const int64_t kSmall = 450; + const int64_t kLarge = 451; + const TestUnit small = TestUnit::FromKilo(kSmall); + const TestUnit large = TestUnit::FromKilo(kLarge); + + EXPECT_EQ(TestUnit::Zero(), TestUnit::FromKilo(0)); + EXPECT_EQ(TestUnit::PlusInfinity(), TestUnit::PlusInfinity()); + EXPECT_EQ(small, TestUnit::FromKilo(kSmall)); + EXPECT_LE(small, TestUnit::FromKilo(kSmall)); + EXPECT_GE(small, TestUnit::FromKilo(kSmall)); + EXPECT_NE(small, TestUnit::FromKilo(kLarge)); + EXPECT_LE(small, TestUnit::FromKilo(kLarge)); + EXPECT_LT(small, TestUnit::FromKilo(kLarge)); + EXPECT_GE(large, TestUnit::FromKilo(kSmall)); + EXPECT_GT(large, TestUnit::FromKilo(kSmall)); + EXPECT_LT(TestUnit::Zero(), small); + EXPECT_GT(TestUnit::Zero(), TestUnit::FromKilo(-kSmall)); + EXPECT_GT(TestUnit::Zero(), TestUnit::FromKilo(-kSmall)); + + EXPECT_GT(TestUnit::PlusInfinity(), large); + EXPECT_LT(TestUnit::MinusInfinity(), TestUnit::Zero()); +} + +TEST(UnitBaseTest, Clamping) { + const TestUnit upper = TestUnit::FromKilo(800); + const TestUnit lower = TestUnit::FromKilo(100); + const TestUnit under = TestUnit::FromKilo(100); + const TestUnit inside = TestUnit::FromKilo(500); + const TestUnit over = TestUnit::FromKilo(1000); + EXPECT_EQ(under.Clamped(lower, upper), lower); + EXPECT_EQ(inside.Clamped(lower, upper), inside); + EXPECT_EQ(over.Clamped(lower, upper), upper); + + TestUnit mutable_delta = lower; + mutable_delta.Clamp(lower, upper); + EXPECT_EQ(mutable_delta, lower); + mutable_delta = inside; + mutable_delta.Clamp(lower, upper); + EXPECT_EQ(mutable_delta, inside); + mutable_delta = over; + mutable_delta.Clamp(lower, upper); + EXPECT_EQ(mutable_delta, upper); +} + +TEST(UnitBaseTest, CanBeInititializedFromLargeInt) { + const int kMaxInt = std::numeric_limits<int>::max(); + EXPECT_EQ(TestUnit::FromKilo(kMaxInt).ToValue<int64_t>(), + static_cast<int64_t>(kMaxInt) * 1000); +} + +TEST(UnitBaseTest, ConvertsToAndFromDouble) { + const int64_t kValue = 17017; + const double kMilliDouble = kValue * 1e3; + const double kValueDouble = kValue; + const double kKiloDouble = kValue * 1e-3; + + EXPECT_EQ(TestUnit::FromValue(kValue).ToKilo<double>(), kKiloDouble); + EXPECT_EQ(TestUnit::FromKilo(kKiloDouble).ToValue<int64_t>(), kValue); + + EXPECT_EQ(TestUnit::FromValue(kValue).ToValue<double>(), kValueDouble); + EXPECT_EQ(TestUnit::FromValue(kValueDouble).ToValue<int64_t>(), kValue); + + EXPECT_NEAR(TestUnit::FromValue(kValue).ToMilli<double>(), kMilliDouble, 1); + + const double kPlusInfinity = std::numeric_limits<double>::infinity(); + const double kMinusInfinity = -kPlusInfinity; + + EXPECT_EQ(TestUnit::PlusInfinity().ToKilo<double>(), kPlusInfinity); + EXPECT_EQ(TestUnit::MinusInfinity().ToKilo<double>(), kMinusInfinity); + EXPECT_EQ(TestUnit::PlusInfinity().ToValue<double>(), kPlusInfinity); + EXPECT_EQ(TestUnit::MinusInfinity().ToValue<double>(), kMinusInfinity); + EXPECT_EQ(TestUnit::PlusInfinity().ToMilli<double>(), kPlusInfinity); + EXPECT_EQ(TestUnit::MinusInfinity().ToMilli<double>(), kMinusInfinity); + + EXPECT_TRUE(TestUnit::FromKilo(kPlusInfinity).IsPlusInfinity()); + EXPECT_TRUE(TestUnit::FromKilo(kMinusInfinity).IsMinusInfinity()); + EXPECT_TRUE(TestUnit::FromValue(kPlusInfinity).IsPlusInfinity()); + EXPECT_TRUE(TestUnit::FromValue(kMinusInfinity).IsMinusInfinity()); +} + +TEST(UnitBaseTest, MathOperations) { + const int64_t kValueA = 267; + const int64_t kValueB = 450; + const TestUnit delta_a = TestUnit::FromKilo(kValueA); + const TestUnit delta_b = TestUnit::FromKilo(kValueB); + EXPECT_EQ((delta_a + delta_b).ToKilo(), kValueA + kValueB); + EXPECT_EQ((delta_a - delta_b).ToKilo(), kValueA - kValueB); + + const int32_t kInt32Value = 123; + const double kFloatValue = 123.0; + EXPECT_EQ((TestUnit::FromValue(kValueA) * kValueB).ToValue<int64_t>(), + kValueA * kValueB); + EXPECT_EQ((TestUnit::FromValue(kValueA) * kInt32Value).ToValue<int64_t>(), + kValueA * kInt32Value); + EXPECT_EQ((TestUnit::FromValue(kValueA) * kFloatValue).ToValue<int64_t>(), + kValueA * kFloatValue); + + EXPECT_EQ((delta_b / 10).ToKilo(), kValueB / 10); + EXPECT_EQ(delta_b / delta_a, static_cast<double>(kValueB) / kValueA); + + TestUnit mutable_delta = TestUnit::FromKilo(kValueA); + mutable_delta += TestUnit::FromKilo(kValueB); + EXPECT_EQ(mutable_delta, TestUnit::FromKilo(kValueA + kValueB)); + mutable_delta -= TestUnit::FromKilo(kValueB); + EXPECT_EQ(mutable_delta, TestUnit::FromKilo(kValueA)); + + // Division by an int rounds towards zero to follow regular int division. + EXPECT_EQ(TestUnit::FromValue(789) / 10, TestUnit::FromValue(78)); + EXPECT_EQ(TestUnit::FromValue(-789) / 10, TestUnit::FromValue(-78)); +} + +TEST(UnitBaseTest, InfinityOperations) { + const int64_t kValue = 267; + const TestUnit finite = TestUnit::FromKilo(kValue); + EXPECT_TRUE((TestUnit::PlusInfinity() + finite).IsPlusInfinity()); + EXPECT_TRUE((TestUnit::PlusInfinity() - finite).IsPlusInfinity()); + EXPECT_TRUE((finite + TestUnit::PlusInfinity()).IsPlusInfinity()); + EXPECT_TRUE((finite - TestUnit::MinusInfinity()).IsPlusInfinity()); + + EXPECT_TRUE((TestUnit::MinusInfinity() + finite).IsMinusInfinity()); + EXPECT_TRUE((TestUnit::MinusInfinity() - finite).IsMinusInfinity()); + EXPECT_TRUE((finite + TestUnit::MinusInfinity()).IsMinusInfinity()); + EXPECT_TRUE((finite - TestUnit::PlusInfinity()).IsMinusInfinity()); +} + +TEST(UnitBaseTest, UnaryMinus) { + const int64_t kValue = 1337; + const TestUnit unit = TestUnit::FromValue(kValue); + EXPECT_EQ(-unit.ToValue(), -kValue); + + // Check infinity. + EXPECT_EQ(-TestUnit::PlusInfinity(), TestUnit::MinusInfinity()); + EXPECT_EQ(-TestUnit::MinusInfinity(), TestUnit::PlusInfinity()); +} + +} // namespace test +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/untyped_function.h b/third_party/libwebrtc/rtc_base/untyped_function.h new file mode 100644 index 0000000000..c1f59458b9 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/untyped_function.h @@ -0,0 +1,324 @@ +/* + * 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 RTC_BASE_UNTYPED_FUNCTION_H_ +#define RTC_BASE_UNTYPED_FUNCTION_H_ + +#include <cstddef> +#include <cstring> +#include <memory> +#include <type_traits> +#include <utility> + +#include "rtc_base/system/assume.h" + +namespace webrtc { +namespace webrtc_function_impl { + +using FunVoid = void(); + +// Inline storage size is this many machine words. +enum : size_t { kInlineStorageWords = 4 }; + +union VoidUnion { + void* void_ptr; + FunVoid* fun_ptr; + typename std::aligned_storage<kInlineStorageWords * sizeof(uintptr_t)>::type + inline_storage; +}; + +// Returns the number of elements of the `inline_storage` array required to +// store an object of type T. +template <typename T> +constexpr size_t InlineStorageSize() { + // sizeof(T) / sizeof(uintptr_t), but rounded up. + return (sizeof(T) + sizeof(uintptr_t) - 1) / sizeof(uintptr_t); +} + +template <typename T> +struct CallHelpers; +template <typename RetT, typename... ArgT> +struct CallHelpers<RetT(ArgT...)> { + // Return type of the three helpers below. + using return_type = RetT; + // Complete function type of the three helpers below. + using function_type = RetT(VoidUnion*, ArgT...); + // Helper for calling the `void_ptr` case of VoidUnion. + template <typename F> + static RetT CallVoidPtr(VoidUnion* vu, ArgT... args) { + return (*static_cast<F*>(vu->void_ptr))(std::forward<ArgT>(args)...); + } + // Helper for calling the `fun_ptr` case of VoidUnion. + static RetT CallFunPtr(VoidUnion* vu, ArgT... args) { + return (reinterpret_cast<RetT (*)(ArgT...)>(vu->fun_ptr))( + std::forward<ArgT>(args)...); + } + // Helper for calling the `inline_storage` case of VoidUnion. + template <typename F> + static RetT CallInlineStorage(VoidUnion* vu, ArgT... args) { + return (*reinterpret_cast<F*>(&vu->inline_storage))( + std::forward<ArgT>(args)...); + } +}; + +} // namespace webrtc_function_impl + +// A class that holds (and owns) any callable. The same function call signature +// must be provided when constructing and calling the object. +// +// The point of not having the call signature as a class template parameter is +// to have one single concrete type for all signatures; this reduces binary +// size. +class UntypedFunction final { + public: + // Callables of at most this size can be stored inline, if they are trivial. + // (Useful in tests and benchmarks; avoid using this in production code.) + enum : size_t { + kInlineStorageSize = sizeof(webrtc_function_impl::VoidUnion::inline_storage) + }; + static_assert(kInlineStorageSize == + webrtc_function_impl::kInlineStorageWords * + sizeof(uintptr_t), + ""); + + // The *UntypedFunctionArgs structs are used to transfer arguments from + // PrepareArgs() to Create(). They are trivial, but may own heap allocations, + // so make sure to pass them to Create() exactly once! + // + // The point of doing Create(PrepareArgs(foo)) instead of just Create(foo) is + // to separate the code that has to be inlined (PrepareArgs) from the code + // that can be noninlined (Create); the *UntypedFunctionArgs types are + // designed to efficiently carry the required information from one to the + // other. + template <size_t N> + struct TrivialUntypedFunctionArgs { + static_assert(N >= 1, ""); + static_assert(N <= webrtc_function_impl::kInlineStorageWords, ""); + // We use an uintptr_t array here instead of std::aligned_storage, because + // the former can be efficiently passed in registers when using + // TrivialUntypedFunctionArgs as a function argument. (We can't do the same + // in VoidUnion, because std::aligned_storage but not uintptr_t can be + // legally reinterpret_casted to arbitrary types. + // TrivialUntypedFunctionArgs, on the other hand, only needs to handle + // placement new and memcpy.) + alignas(std::max_align_t) uintptr_t inline_storage[N]; + webrtc_function_impl::FunVoid* call; + }; + struct NontrivialUntypedFunctionArgs { + void* void_ptr; + webrtc_function_impl::FunVoid* call; + void (*del)(webrtc_function_impl::VoidUnion*); + }; + struct FunctionPointerUntypedFunctionArgs { + webrtc_function_impl::FunVoid* fun_ptr; + webrtc_function_impl::FunVoid* call; + }; + + // Create function for lambdas and other callables that are trivial and small; + // it accepts every type of argument except those noted in its enable_if call. + template < + typename Signature, + typename F, + typename F_deref = typename std::remove_reference<F>::type, + typename std::enable_if< + // Not for function pointers; we have another overload for that below. + !std::is_function< + typename std::remove_pointer<F_deref>::type>::value && + + // Not for nullptr; we have a constructor for that below. + !std::is_same<std::nullptr_t, + typename std::remove_cv<F>::type>::value && + + // Not for UntypedFunction objects; use move construction or + // assignment. + !std::is_same<UntypedFunction, + typename std::remove_cv<F_deref>::type>::value && + + // Only for trivial callables that will fit in inline storage. + std::is_trivially_move_constructible<F_deref>::value && + std::is_trivially_destructible<F_deref>::value && + sizeof(F_deref) <= kInlineStorageSize>::type* = nullptr, + size_t InlineSize = webrtc_function_impl::InlineStorageSize<F_deref>()> + static TrivialUntypedFunctionArgs<InlineSize> PrepareArgs(F&& f) { + // The callable is trivial and small enough, so we just store its bytes + // in the inline storage. + TrivialUntypedFunctionArgs<InlineSize> args; + new (&args.inline_storage) F_deref(std::forward<F>(f)); + args.call = reinterpret_cast<webrtc_function_impl::FunVoid*>( + webrtc_function_impl::CallHelpers< + Signature>::template CallInlineStorage<F_deref>); + return args; + } + template <size_t InlineSize> + static UntypedFunction Create(TrivialUntypedFunctionArgs<InlineSize> args) { + webrtc_function_impl::VoidUnion vu; + std::memcpy(&vu.inline_storage, args.inline_storage, + sizeof(args.inline_storage)); + return UntypedFunction(vu, args.call, nullptr); + } + + // Create function for lambdas and other callables that are nontrivial or + // large; it accepts every type of argument except those noted in its + // enable_if call. + template <typename Signature, + typename F, + typename F_deref = typename std::remove_reference<F>::type, + typename std::enable_if< + // Not for function pointers; we have another overload for that + // below. + !std::is_function< + typename std::remove_pointer<F_deref>::type>::value && + + // Not for nullptr; we have a constructor for that below. + !std::is_same<std::nullptr_t, + typename std::remove_cv<F>::type>::value && + + // Not for UntypedFunction objects; use move construction or + // assignment. + !std::is_same<UntypedFunction, + typename std::remove_cv<F_deref>::type>::value && + + // Only for nontrivial callables, or callables that won't fit in + // inline storage. + !(std::is_trivially_move_constructible<F_deref>::value && + std::is_trivially_destructible<F_deref>::value && + sizeof(F_deref) <= kInlineStorageSize)>::type* = nullptr> + static NontrivialUntypedFunctionArgs PrepareArgs(F&& f) { + // The callable is either nontrivial or too large, so we can't keep it + // in the inline storage; use the heap instead. + NontrivialUntypedFunctionArgs args; + args.void_ptr = new F_deref(std::forward<F>(f)); + args.call = reinterpret_cast<webrtc_function_impl::FunVoid*>( + webrtc_function_impl::CallHelpers<Signature>::template CallVoidPtr< + F_deref>); + args.del = static_cast<void (*)(webrtc_function_impl::VoidUnion*)>( + [](webrtc_function_impl::VoidUnion* vu) { + // Assuming that this pointer isn't null allows the + // compiler to eliminate a null check in the (inlined) + // delete operation. + RTC_ASSUME(vu->void_ptr != nullptr); + delete reinterpret_cast<F_deref*>(vu->void_ptr); + }); + return args; + } + static UntypedFunction Create(NontrivialUntypedFunctionArgs args) { + webrtc_function_impl::VoidUnion vu; + vu.void_ptr = args.void_ptr; + return UntypedFunction(vu, args.call, args.del); + } + + // Create function that accepts function pointers. If the argument is null, + // the result is an empty UntypedFunction. + template <typename Signature> + static FunctionPointerUntypedFunctionArgs PrepareArgs(Signature* f) { + FunctionPointerUntypedFunctionArgs args; + args.fun_ptr = reinterpret_cast<webrtc_function_impl::FunVoid*>(f); + args.call = reinterpret_cast<webrtc_function_impl::FunVoid*>( + webrtc_function_impl::CallHelpers<Signature>::CallFunPtr); + return args; + } + static UntypedFunction Create(FunctionPointerUntypedFunctionArgs args) { + webrtc_function_impl::VoidUnion vu; + vu.fun_ptr = args.fun_ptr; + return UntypedFunction(vu, args.fun_ptr == nullptr ? nullptr : args.call, + nullptr); + } + + // Prepares arguments and creates an UntypedFunction in one go. + template <typename Signature, typename F> + static UntypedFunction Create(F&& f) { + return Create(PrepareArgs<Signature>(std::forward<F>(f))); + } + + // Default constructor. Creates an empty UntypedFunction. + UntypedFunction() : call_(nullptr), delete_(nullptr) {} + + // Nullptr constructor and assignment. Creates an empty UntypedFunction. + UntypedFunction(std::nullptr_t) // NOLINT(runtime/explicit) + : call_(nullptr), delete_(nullptr) {} + UntypedFunction& operator=(std::nullptr_t) { + call_ = nullptr; + if (delete_) { + delete_(&f_); + delete_ = nullptr; + } + return *this; + } + + // Not copyable. + UntypedFunction(const UntypedFunction&) = delete; + UntypedFunction& operator=(const UntypedFunction&) = delete; + + // Move construction and assignment. + UntypedFunction(UntypedFunction&& other) + : f_(other.f_), call_(other.call_), delete_(other.delete_) { + other.delete_ = nullptr; + } + UntypedFunction& operator=(UntypedFunction&& other) { + if (delete_) { + delete_(&f_); + } + f_ = other.f_; + call_ = other.call_; + delete_ = other.delete_; + other.delete_ = nullptr; + return *this; + } + + ~UntypedFunction() { + if (delete_) { + delete_(&f_); + } + } + + friend void swap(UntypedFunction& a, UntypedFunction& b) { + using std::swap; + swap(a.f_, b.f_); + swap(a.call_, b.call_); + swap(a.delete_, b.delete_); + } + + // Returns true if we have a function, false if we don't (i.e., we're null). + explicit operator bool() const { return call_ != nullptr; } + + template <typename Signature, typename... ArgT> + typename webrtc_function_impl::CallHelpers<Signature>::return_type Call( + ArgT&&... args) { + return reinterpret_cast< + typename webrtc_function_impl::CallHelpers<Signature>::function_type*>( + call_)(&f_, std::forward<ArgT>(args)...); + } + + // Returns true iff we don't need to call a destructor. This is guaranteed + // to hold for a moved-from object. + bool IsTriviallyDestructible() { return delete_ == nullptr; } + + private: + UntypedFunction(webrtc_function_impl::VoidUnion f, + webrtc_function_impl::FunVoid* call, + void (*del)(webrtc_function_impl::VoidUnion*)) + : f_(f), call_(call), delete_(del) {} + + // The callable thing, or a pointer to it. + webrtc_function_impl::VoidUnion f_; + + // Pointer to a dispatch function that knows the type of the callable thing + // that's stored in f_, and how to call it. An UntypedFunction object is empty + // (null) iff call_ is null. + webrtc_function_impl::FunVoid* call_; + + // Pointer to a function that knows how to delete the callable thing that's + // stored in f_. Null if `f_` is trivially deletable. + void (*delete_)(webrtc_function_impl::VoidUnion*); +}; + +} // namespace webrtc + +#endif // RTC_BASE_UNTYPED_FUNCTION_H_ diff --git a/third_party/libwebrtc/rtc_base/untyped_function_unittest.cc b/third_party/libwebrtc/rtc_base/untyped_function_unittest.cc new file mode 100644 index 0000000000..8ea26e7a43 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/untyped_function_unittest.cc @@ -0,0 +1,309 @@ +/* + * 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 "rtc_base/untyped_function.h" + +#include <memory> +#include <vector> + +#include "test/gmock.h" +#include "test/gtest.h" + +namespace webrtc { +namespace { + +using ::testing::Pointee; + +TEST(UntypedFunction, Empty1) { + UntypedFunction uf; + EXPECT_FALSE(uf); + EXPECT_TRUE(uf.IsTriviallyDestructible()); +} + +TEST(UntypedFunction, Empty2) { + UntypedFunction uf = nullptr; + EXPECT_FALSE(uf); + EXPECT_TRUE(uf.IsTriviallyDestructible()); +} + +TEST(UntypedFunction, Empty3) { + UntypedFunction uf = UntypedFunction::Create<int(int)>(nullptr); + EXPECT_FALSE(uf); + EXPECT_TRUE(uf.IsTriviallyDestructible()); +} + +TEST(UntypedFunction, CallTrivialWithInt) { + auto uf = UntypedFunction::Create<int(int)>([](int x) { return x + 5; }); + EXPECT_TRUE(uf); + EXPECT_TRUE(uf.IsTriviallyDestructible()); + EXPECT_EQ(uf.Call<int(int)>(17), 22); +} + +TEST(UntypedFunction, CallTrivialWithPointer) { + auto uf = UntypedFunction::Create<int(int*)>([](int* x) { return *x; }); + EXPECT_TRUE(uf); + EXPECT_TRUE(uf.IsTriviallyDestructible()); + int x = 12; + EXPECT_EQ(uf.Call<int(int*)>(&x), 12); +} + +TEST(UntypedFunction, CallTrivialWithReference) { + auto uf = UntypedFunction::Create<void(int&)>([](int& x) { x = 3; }); + EXPECT_TRUE(uf); + EXPECT_TRUE(uf.IsTriviallyDestructible()); + int x = 12; + uf.Call<void(int&)>(x); + EXPECT_EQ(x, 3); +} + +TEST(UntypedFunction, CallTrivialWithRvalueReference) { + auto uf = UntypedFunction::Create<int(int&&)>([](int&& x) { return x - 2; }); + EXPECT_TRUE(uf); + EXPECT_TRUE(uf.IsTriviallyDestructible()); + EXPECT_EQ(uf.Call<int(int&&)>(34), 32); +} + +TEST(UntypedFunction, CallNontrivialWithInt) { + std::vector<int> list; + auto uf = UntypedFunction::Create<int(int)>([list](int x) mutable { + list.push_back(x); + return list.size(); + }); + EXPECT_TRUE(uf); + EXPECT_FALSE(uf.IsTriviallyDestructible()); + EXPECT_EQ(uf.Call<int(int)>(17), 1); + EXPECT_EQ(uf.Call<int(int)>(17), 2); +} + +TEST(UntypedFunction, CallNontrivialWithPointer) { + std::vector<int> list; + auto uf = UntypedFunction::Create<int*(int*)>([list](int* x) mutable { + list.push_back(*x); + return list.data(); + }); + EXPECT_TRUE(uf); + EXPECT_FALSE(uf.IsTriviallyDestructible()); + int x = 12; + EXPECT_THAT(uf.Call<int*(int*)>(&x), Pointee(12)); +} + +TEST(UntypedFunction, CallNontrivialWithReference) { + std::vector<int> list = {34, 35, 36}; + auto uf = + UntypedFunction::Create<void(int&)>([list](int& x) { x = list[1]; }); + EXPECT_TRUE(uf); + EXPECT_FALSE(uf.IsTriviallyDestructible()); + int x = 12; + uf.Call<void(int&)>(x); + EXPECT_EQ(x, 35); +} + +TEST(UntypedFunction, CallNontrivialWithRvalueReference) { + std::vector<int> list; + auto uf = UntypedFunction::Create<int(int&&)>([list](int&& x) mutable { + list.push_back(x); + return list.size(); + }); + EXPECT_TRUE(uf); + EXPECT_FALSE(uf.IsTriviallyDestructible()); + EXPECT_EQ(uf.Call<int(int&&)>(34), 1); + EXPECT_EQ(uf.Call<int(int&&)>(34), 2); +} + +int AddFive(int x) { + return x + 5; +} +int DereferencePointer(int* x) { + return *x; +} +void AssignThree(int& x) { + x = 3; +} +int SubtractTwo(int&& x) { + return x - 2; +} + +TEST(UntypedFunction, CallFunctionPointerWithInt) { + auto uf = UntypedFunction::Create<int(int)>(AddFive); + EXPECT_TRUE(uf); + EXPECT_TRUE(uf.IsTriviallyDestructible()); + EXPECT_EQ(uf.Call<int(int)>(17), 22); +} + +TEST(UntypedFunction, CallFunctionPointerWithPointer) { + auto uf = UntypedFunction::Create<int(int*)>(DereferencePointer); + EXPECT_TRUE(uf); + EXPECT_TRUE(uf.IsTriviallyDestructible()); + int x = 12; + EXPECT_EQ(uf.Call<int(int*)>(&x), 12); +} + +TEST(UntypedFunction, CallFunctionPointerWithReference) { + auto uf = UntypedFunction::Create<void(int&)>(AssignThree); + EXPECT_TRUE(uf); + EXPECT_TRUE(uf.IsTriviallyDestructible()); + int x = 12; + uf.Call<void(int&)>(x); + EXPECT_EQ(x, 3); +} + +TEST(UntypedFunction, CallFunctionPointerWithRvalueReference) { + auto uf = UntypedFunction::Create<int(int&&)>(SubtractTwo); + EXPECT_TRUE(uf); + EXPECT_TRUE(uf.IsTriviallyDestructible()); + EXPECT_EQ(uf.Call<int(int&&)>(34), 32); +} + +TEST(UntypedFunction, CallTrivialWithNoArgs) { + int arr[] = {1, 2, 3}; + static_assert(sizeof(arr) <= UntypedFunction::kInlineStorageSize, ""); + auto uf = UntypedFunction::Create<int()>([arr] { return arr[1]; }); + EXPECT_TRUE(uf); + EXPECT_TRUE(uf.IsTriviallyDestructible()); + EXPECT_EQ(uf.Call<int()>(), 2); +} + +TEST(UntypedFunction, CallLargeTrivialWithNoArgs) { + int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0}; + static_assert(sizeof(arr) > UntypedFunction::kInlineStorageSize, ""); + auto uf = UntypedFunction::Create<int()>([arr] { return arr[4]; }); + EXPECT_TRUE(uf); + EXPECT_FALSE(uf.IsTriviallyDestructible()); + EXPECT_EQ(uf.Call<int()>(), 5); +} + +TEST(UntypedFunction, MoveonlyReturnValue) { + auto uf = UntypedFunction::Create<std::unique_ptr<int>()>( + [] { return std::make_unique<int>(567); }); + EXPECT_THAT(uf.Call<std::unique_ptr<int>()>(), Pointee(567)); +} + +TEST(UntypedFunction, MoveonlyArgument) { + auto uf = UntypedFunction::Create<int(std::unique_ptr<int>)>( + [](std::unique_ptr<int> x) { return *x + 19; }); + EXPECT_EQ(uf.Call<int(std::unique_ptr<int>)>(std::make_unique<int>(40)), 59); +} + +TEST(UntypedFunction, MoveOnlyCallable) { + auto uf = UntypedFunction::Create<int()>( + [x = std::make_unique<int>(17)] { return ++*x; }); + EXPECT_TRUE(uf); + EXPECT_FALSE(uf.IsTriviallyDestructible()); + EXPECT_EQ(uf.Call<int()>(), 18); + EXPECT_EQ(uf.Call<int()>(), 19); + UntypedFunction uf2 = std::move(uf); + EXPECT_TRUE(uf); + EXPECT_TRUE(uf.IsTriviallyDestructible()); + EXPECT_FALSE(uf2.IsTriviallyDestructible()); + EXPECT_EQ(uf.Call<int()>(), 20); + EXPECT_EQ(uf.Call<int()>(), 21); +} + +class Destroyer { + public: + explicit Destroyer(int& destroy_count) : destroy_count_(&destroy_count) {} + ~Destroyer() { ++*destroy_count_; } + int operator()() { return 72; } + int* destroy_count_; +}; + +TEST(UntypedFunction, CallableIsDestroyed) { + int destroy_count = 0; + { + auto uf = UntypedFunction::Create<int()>(Destroyer(destroy_count)); + // Destruction count is 1 here, because the temporary we created above was + // destroyed. + EXPECT_EQ(destroy_count, 1); + { + auto uf2 = std::move(uf); + EXPECT_EQ(destroy_count, 1); + } + // `uf2` was destroyed. + EXPECT_EQ(destroy_count, 2); + } + // `uf` was destroyed, but it didn't contain a Destroyer since we moved it to + // `uf2` above. + EXPECT_EQ(destroy_count, 2); +} + +TEST(UntypedFunction, MoveAssign) { + int destroy_count = 0; + auto uf = UntypedFunction::Create<int()>(Destroyer(destroy_count)); + EXPECT_TRUE(uf); + EXPECT_FALSE(uf.IsTriviallyDestructible()); + // Destruction count is 1 here, because the temporary we created above was + // destroyed. + EXPECT_EQ(destroy_count, 1); + UntypedFunction uf2 = nullptr; + EXPECT_FALSE(uf2); + EXPECT_TRUE(uf2.IsTriviallyDestructible()); + + uf2 = std::move(uf); + EXPECT_TRUE(uf.IsTriviallyDestructible()); + EXPECT_TRUE(uf2); + EXPECT_FALSE(uf2.IsTriviallyDestructible()); + EXPECT_EQ(destroy_count, 1); // The callable was not destroyed. + EXPECT_EQ(uf2.Call<int()>(), 72); + + UntypedFunction uf3 = nullptr; + uf2 = std::move(uf3); + EXPECT_FALSE(uf2); + EXPECT_TRUE(uf2.IsTriviallyDestructible()); + EXPECT_EQ(destroy_count, 2); // The callable was destroyed by the assignment. +} + +TEST(UntypedFunction, NullptrAssign) { + int destroy_count = 0; + auto uf = UntypedFunction::Create<int()>(Destroyer(destroy_count)); + EXPECT_TRUE(uf); + EXPECT_FALSE(uf.IsTriviallyDestructible()); + // Destruction count is 1 here, because the temporary we created above was + // destroyed. + EXPECT_EQ(destroy_count, 1); + + uf = nullptr; + EXPECT_FALSE(uf); + EXPECT_TRUE(uf.IsTriviallyDestructible()); + EXPECT_EQ(destroy_count, 2); // The callable was destroyed by the assignment. +} + +TEST(UntypedFunction, Swap) { + int x = 13; + auto uf = UntypedFunction::Create<int()>([x]() mutable { return ++x; }); + EXPECT_TRUE(uf); + EXPECT_TRUE(uf.IsTriviallyDestructible()); + auto y = std::make_unique<int>(113); + auto uf2 = + UntypedFunction::Create<int()>([y = std::move(y)] { return ++*y; }); + EXPECT_TRUE(uf2); + EXPECT_FALSE(uf2.IsTriviallyDestructible()); + UntypedFunction uf3 = nullptr; + EXPECT_FALSE(uf3); + EXPECT_TRUE(uf3.IsTriviallyDestructible()); + + EXPECT_EQ(uf.Call<int()>(), 14); + swap(uf, uf2); + EXPECT_TRUE(uf); + EXPECT_FALSE(uf.IsTriviallyDestructible()); + EXPECT_TRUE(uf2); + EXPECT_TRUE(uf2.IsTriviallyDestructible()); + EXPECT_EQ(uf.Call<int()>(), 114); + EXPECT_EQ(uf2.Call<int()>(), 15); + + swap(uf, uf3); + EXPECT_FALSE(uf); + EXPECT_TRUE(uf.IsTriviallyDestructible()); + EXPECT_TRUE(uf3); + EXPECT_FALSE(uf3.IsTriviallyDestructible()); + EXPECT_EQ(uf3.Call<int()>(), 115); +} + +} // namespace +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/virtual_socket_server.cc b/third_party/libwebrtc/rtc_base/virtual_socket_server.cc new file mode 100644 index 0000000000..efc206b219 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/virtual_socket_server.cc @@ -0,0 +1,1383 @@ +/* + * 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 "rtc_base/virtual_socket_server.h" + +#include <errno.h> +#include <math.h> + +#include <map> +#include <memory> +#include <vector> + +#include "absl/algorithm/container.h" +#include "api/units/time_delta.h" +#include "rtc_base/checks.h" +#include "rtc_base/event.h" +#include "rtc_base/fake_clock.h" +#include "rtc_base/logging.h" +#include "rtc_base/physical_socket_server.h" +#include "rtc_base/socket_address_pair.h" +#include "rtc_base/thread.h" +#include "rtc_base/time_utils.h" + +namespace rtc { + +using ::webrtc::MutexLock; +using ::webrtc::TaskQueueBase; +using ::webrtc::TimeDelta; + +#if defined(WEBRTC_WIN) +const in_addr kInitialNextIPv4 = {{{0x01, 0, 0, 0}}}; +#else +// This value is entirely arbitrary, hence the lack of concern about endianness. +const in_addr kInitialNextIPv4 = {0x01000000}; +#endif +// Starts at ::2 so as to not cause confusion with ::1. +const in6_addr kInitialNextIPv6 = { + {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2}}}; + +const uint16_t kFirstEphemeralPort = 49152; +const uint16_t kLastEphemeralPort = 65535; +const uint16_t kEphemeralPortCount = + kLastEphemeralPort - kFirstEphemeralPort + 1; +const uint32_t kDefaultNetworkCapacity = 64 * 1024; +const uint32_t kDefaultTcpBufferSize = 32 * 1024; + +const uint32_t UDP_HEADER_SIZE = 28; // IP + UDP headers +const uint32_t TCP_HEADER_SIZE = 40; // IP + TCP headers +const uint32_t TCP_MSS = 1400; // Maximum segment size + +// Note: The current algorithm doesn't work for sample sizes smaller than this. +const int NUM_SAMPLES = 1000; + +// Packets are passed between sockets as messages. We copy the data just like +// the kernel does. +class Packet { + public: + Packet(const char* data, size_t size, const SocketAddress& from) + : size_(size), consumed_(0), from_(from) { + RTC_DCHECK(nullptr != data); + data_ = new char[size_]; + memcpy(data_, data, size_); + } + + ~Packet() { delete[] data_; } + + const char* data() const { return data_ + consumed_; } + size_t size() const { return size_ - consumed_; } + const SocketAddress& from() const { return from_; } + + // Remove the first size bytes from the data. + void Consume(size_t size) { + RTC_DCHECK(size + consumed_ < size_); + consumed_ += size; + } + + private: + char* data_; + size_t size_, consumed_; + SocketAddress from_; +}; + +VirtualSocket::VirtualSocket(VirtualSocketServer* server, int family, int type) + : server_(server), + type_(type), + state_(CS_CLOSED), + error_(0), + network_size_(0), + recv_buffer_size_(0), + bound_(false), + was_any_(false) { + RTC_DCHECK((type_ == SOCK_DGRAM) || (type_ == SOCK_STREAM)); + server->SignalReadyToSend.connect(this, + &VirtualSocket::OnSocketServerReadyToSend); +} + +VirtualSocket::~VirtualSocket() { + Close(); +} + +SocketAddress VirtualSocket::GetLocalAddress() const { + return local_addr_; +} + +SocketAddress VirtualSocket::GetRemoteAddress() const { + return remote_addr_; +} + +void VirtualSocket::SetLocalAddress(const SocketAddress& addr) { + local_addr_ = addr; +} + +int VirtualSocket::Bind(const SocketAddress& addr) { + if (!local_addr_.IsNil()) { + error_ = EINVAL; + return -1; + } + local_addr_ = server_->AssignBindAddress(addr); + int result = server_->Bind(this, local_addr_); + if (result != 0) { + local_addr_.Clear(); + error_ = EADDRINUSE; + } else { + bound_ = true; + was_any_ = addr.IsAnyIP(); + } + return result; +} + +int VirtualSocket::Connect(const SocketAddress& addr) { + return InitiateConnect(addr, true); +} + +VirtualSocket::SafetyBlock::SafetyBlock(VirtualSocket* socket) + : socket_(*socket) {} + +VirtualSocket::SafetyBlock::~SafetyBlock() { + // Ensure `SetNotAlive` was called and there is nothing left to cleanup. + RTC_DCHECK(!alive_); + RTC_DCHECK(posted_connects_.empty()); + RTC_DCHECK(recv_buffer_.empty()); + RTC_DCHECK(!listen_queue_.has_value()); +} + +void VirtualSocket::SafetyBlock::SetNotAlive() { + VirtualSocketServer* const server = socket_.server_; + const SocketAddress& local_addr = socket_.local_addr_; + + MutexLock lock(&mutex_); + // Cancel pending sockets + if (listen_queue_.has_value()) { + for (const SocketAddress& remote_addr : *listen_queue_) { + server->Disconnect(remote_addr); + } + listen_queue_ = absl::nullopt; + } + + // Cancel potential connects + for (const SocketAddress& remote_addr : posted_connects_) { + // Lookup remote side. + VirtualSocket* lookup_socket = + server->LookupConnection(local_addr, remote_addr); + if (lookup_socket) { + // Server socket, remote side is a socket retreived by accept. Accepted + // sockets are not bound so we will not find it by looking in the + // bindings table. + server->Disconnect(lookup_socket); + server->RemoveConnection(local_addr, remote_addr); + } else { + server->Disconnect(remote_addr); + } + } + posted_connects_.clear(); + + recv_buffer_.clear(); + + alive_ = false; +} + +void VirtualSocket::SafetyBlock::PostSignalReadEvent() { + if (pending_read_signal_event_) { + // Avoid posting multiple times. + return; + } + + pending_read_signal_event_ = true; + rtc::scoped_refptr<SafetyBlock> safety(this); + socket_.server_->msg_queue_->PostTask( + [safety = std::move(safety)] { safety->MaybeSignalReadEvent(); }); +} + +void VirtualSocket::SafetyBlock::MaybeSignalReadEvent() { + { + MutexLock lock(&mutex_); + pending_read_signal_event_ = false; + if (!alive_ || recv_buffer_.empty()) { + return; + } + } + socket_.SignalReadEvent(&socket_); +} + +int VirtualSocket::Close() { + if (!local_addr_.IsNil() && bound_) { + // Remove from the binding table. + server_->Unbind(local_addr_, this); + bound_ = false; + } + + // Disconnect stream sockets + if (state_ == CS_CONNECTED && type_ == SOCK_STREAM) { + server_->Disconnect(local_addr_, remote_addr_); + } + + safety_->SetNotAlive(); + + state_ = CS_CLOSED; + local_addr_.Clear(); + remote_addr_.Clear(); + return 0; +} + +int VirtualSocket::Send(const void* pv, size_t cb) { + if (CS_CONNECTED != state_) { + error_ = ENOTCONN; + return -1; + } + if (SOCK_DGRAM == type_) { + return SendUdp(pv, cb, remote_addr_); + } else { + return SendTcp(pv, cb); + } +} + +int VirtualSocket::SendTo(const void* pv, + size_t cb, + const SocketAddress& addr) { + if (SOCK_DGRAM == type_) { + return SendUdp(pv, cb, addr); + } else { + if (CS_CONNECTED != state_) { + error_ = ENOTCONN; + return -1; + } + return SendTcp(pv, cb); + } +} + +int VirtualSocket::Recv(void* pv, size_t cb, int64_t* timestamp) { + SocketAddress addr; + return RecvFrom(pv, cb, &addr, timestamp); +} + +int VirtualSocket::RecvFrom(void* pv, + size_t cb, + SocketAddress* paddr, + int64_t* timestamp) { + if (timestamp) { + *timestamp = -1; + } + + int data_read = safety_->RecvFrom(pv, cb, *paddr); + if (data_read < 0) { + error_ = EAGAIN; + return -1; + } + + if (type_ == SOCK_STREAM) { + bool was_full = (recv_buffer_size_ == server_->recv_buffer_capacity()); + recv_buffer_size_ -= data_read; + if (was_full) { + server_->SendTcp(remote_addr_); + } + } + + return data_read; +} + +int VirtualSocket::SafetyBlock::RecvFrom(void* buffer, + size_t size, + SocketAddress& addr) { + MutexLock lock(&mutex_); + // If we don't have a packet, then either error or wait for one to arrive. + if (recv_buffer_.empty()) { + return -1; + } + + // Return the packet at the front of the queue. + Packet& packet = *recv_buffer_.front(); + size_t data_read = std::min(size, packet.size()); + memcpy(buffer, packet.data(), data_read); + addr = packet.from(); + + if (data_read < packet.size()) { + packet.Consume(data_read); + } else { + recv_buffer_.pop_front(); + } + + // To behave like a real socket, SignalReadEvent should fire if there's still + // data buffered. + if (!recv_buffer_.empty()) { + PostSignalReadEvent(); + } + + return data_read; +} + +int VirtualSocket::Listen(int backlog) { + RTC_DCHECK(SOCK_STREAM == type_); + RTC_DCHECK(CS_CLOSED == state_); + if (local_addr_.IsNil()) { + error_ = EINVAL; + return -1; + } + safety_->Listen(); + state_ = CS_CONNECTING; + return 0; +} + +void VirtualSocket::SafetyBlock::Listen() { + MutexLock lock(&mutex_); + RTC_DCHECK(!listen_queue_.has_value()); + listen_queue_.emplace(); +} + +VirtualSocket* VirtualSocket::Accept(SocketAddress* paddr) { + SafetyBlock::AcceptResult result = safety_->Accept(); + if (result.error != 0) { + error_ = result.error; + return nullptr; + } + if (paddr) { + *paddr = result.remote_addr; + } + return result.socket.release(); +} + +VirtualSocket::SafetyBlock::AcceptResult VirtualSocket::SafetyBlock::Accept() { + AcceptResult result; + MutexLock lock(&mutex_); + RTC_DCHECK(alive_); + if (!listen_queue_.has_value()) { + result.error = EINVAL; + return result; + } + while (!listen_queue_->empty()) { + auto socket = std::make_unique<VirtualSocket>(socket_.server_, AF_INET, + socket_.type_); + + // Set the new local address to the same as this server socket. + socket->SetLocalAddress(socket_.local_addr_); + // Sockets made from a socket that 'was Any' need to inherit that. + socket->set_was_any(socket_.was_any()); + SocketAddress remote_addr = listen_queue_->front(); + listen_queue_->pop_front(); + if (socket->InitiateConnect(remote_addr, false) != 0) { + continue; + } + socket->CompleteConnect(remote_addr); + result.socket = std::move(socket); + result.remote_addr = remote_addr; + return result; + } + result.error = EWOULDBLOCK; + return result; +} + +int VirtualSocket::GetError() const { + return error_; +} + +void VirtualSocket::SetError(int error) { + error_ = error; +} + +Socket::ConnState VirtualSocket::GetState() const { + return state_; +} + +int VirtualSocket::GetOption(Option opt, int* value) { + OptionsMap::const_iterator it = options_map_.find(opt); + if (it == options_map_.end()) { + return -1; + } + *value = it->second; + return 0; // 0 is success to emulate getsockopt() +} + +int VirtualSocket::SetOption(Option opt, int value) { + options_map_[opt] = value; + return 0; // 0 is success to emulate setsockopt() +} + +void VirtualSocket::PostPacket(TimeDelta delay, + std::unique_ptr<Packet> packet) { + rtc::scoped_refptr<SafetyBlock> safety = safety_; + VirtualSocket* socket = this; + server_->msg_queue_->PostDelayedTask( + [safety = std::move(safety), socket, + packet = std::move(packet)]() mutable { + if (safety->AddPacket(std::move(packet))) { + socket->SignalReadEvent(socket); + } + }, + delay); +} + +bool VirtualSocket::SafetyBlock::AddPacket(std::unique_ptr<Packet> packet) { + MutexLock lock(&mutex_); + if (alive_) { + recv_buffer_.push_back(std::move(packet)); + } + return alive_; +} + +void VirtualSocket::PostConnect(TimeDelta delay, + const SocketAddress& remote_addr) { + safety_->PostConnect(delay, remote_addr); +} + +void VirtualSocket::SafetyBlock::PostConnect(TimeDelta delay, + const SocketAddress& remote_addr) { + rtc::scoped_refptr<SafetyBlock> safety(this); + + MutexLock lock(&mutex_); + RTC_DCHECK(alive_); + // Save addresses of the pending connects to allow propertly disconnect them + // if socket closes before delayed task below runs. + // `posted_connects_` is an std::list, thus its iterators are valid while the + // element is in the list. It can be removed either in the `Connect` just + // below or by calling SetNotAlive function, thus inside `Connect` `it` should + // be valid when alive_ == true. + auto it = posted_connects_.insert(posted_connects_.end(), remote_addr); + auto task = [safety = std::move(safety), it] { + switch (safety->Connect(it)) { + case Signal::kNone: + break; + case Signal::kReadEvent: + safety->socket_.SignalReadEvent(&safety->socket_); + break; + case Signal::kConnectEvent: + safety->socket_.SignalConnectEvent(&safety->socket_); + break; + } + }; + socket_.server_->msg_queue_->PostDelayedTask(std::move(task), delay); +} + +VirtualSocket::SafetyBlock::Signal VirtualSocket::SafetyBlock::Connect( + VirtualSocket::SafetyBlock::PostedConnects::iterator remote_addr_it) { + MutexLock lock(&mutex_); + if (!alive_) { + return Signal::kNone; + } + RTC_DCHECK(!posted_connects_.empty()); + SocketAddress remote_addr = *remote_addr_it; + posted_connects_.erase(remote_addr_it); + + if (listen_queue_.has_value()) { + listen_queue_->push_back(remote_addr); + return Signal::kReadEvent; + } + if (socket_.type_ == SOCK_STREAM && socket_.state_ == CS_CONNECTING) { + socket_.CompleteConnect(remote_addr); + return Signal::kConnectEvent; + } + RTC_LOG(LS_VERBOSE) << "Socket at " << socket_.local_addr_.ToString() + << " is not listening"; + socket_.server_->Disconnect(remote_addr); + return Signal::kNone; +} + +bool VirtualSocket::SafetyBlock::IsAlive() { + MutexLock lock(&mutex_); + return alive_; +} + +void VirtualSocket::PostDisconnect(TimeDelta delay) { + // Posted task may outlive this. Use different name for `this` inside the task + // to avoid accidental unsafe `this->safety_` instead of safe `safety` + VirtualSocket* socket = this; + rtc::scoped_refptr<SafetyBlock> safety = safety_; + auto task = [safety = std::move(safety), socket] { + if (!safety->IsAlive()) { + return; + } + RTC_DCHECK_EQ(socket->type_, SOCK_STREAM); + if (socket->state_ == CS_CLOSED) { + return; + } + int error_to_signal = (socket->state_ == CS_CONNECTING) ? ECONNREFUSED : 0; + socket->state_ = CS_CLOSED; + socket->remote_addr_.Clear(); + socket->SignalCloseEvent(socket, error_to_signal); + }; + server_->msg_queue_->PostDelayedTask(std::move(task), delay); +} + +int VirtualSocket::InitiateConnect(const SocketAddress& addr, bool use_delay) { + if (!remote_addr_.IsNil()) { + error_ = (CS_CONNECTED == state_) ? EISCONN : EINPROGRESS; + return -1; + } + if (local_addr_.IsNil()) { + // If there's no local address set, grab a random one in the correct AF. + int result = 0; + if (addr.ipaddr().family() == AF_INET) { + result = Bind(SocketAddress("0.0.0.0", 0)); + } else if (addr.ipaddr().family() == AF_INET6) { + result = Bind(SocketAddress("::", 0)); + } + if (result != 0) { + return result; + } + } + if (type_ == SOCK_DGRAM) { + remote_addr_ = addr; + state_ = CS_CONNECTED; + } else { + int result = server_->Connect(this, addr, use_delay); + if (result != 0) { + error_ = EHOSTUNREACH; + return -1; + } + state_ = CS_CONNECTING; + } + return 0; +} + +void VirtualSocket::CompleteConnect(const SocketAddress& addr) { + RTC_DCHECK(CS_CONNECTING == state_); + remote_addr_ = addr; + state_ = CS_CONNECTED; + server_->AddConnection(remote_addr_, local_addr_, this); +} + +int VirtualSocket::SendUdp(const void* pv, + size_t cb, + const SocketAddress& addr) { + // If we have not been assigned a local port, then get one. + if (local_addr_.IsNil()) { + local_addr_ = server_->AssignBindAddress( + EmptySocketAddressWithFamily(addr.ipaddr().family())); + int result = server_->Bind(this, local_addr_); + if (result != 0) { + local_addr_.Clear(); + error_ = EADDRINUSE; + return result; + } + } + + // Send the data in a message to the appropriate socket. + return server_->SendUdp(this, static_cast<const char*>(pv), cb, addr); +} + +int VirtualSocket::SendTcp(const void* pv, size_t cb) { + size_t capacity = server_->send_buffer_capacity() - send_buffer_.size(); + if (0 == capacity) { + ready_to_send_ = false; + error_ = EWOULDBLOCK; + return -1; + } + size_t consumed = std::min(cb, capacity); + const char* cpv = static_cast<const char*>(pv); + send_buffer_.insert(send_buffer_.end(), cpv, cpv + consumed); + server_->SendTcp(this); + return static_cast<int>(consumed); +} + +void VirtualSocket::OnSocketServerReadyToSend() { + if (ready_to_send_) { + // This socket didn't encounter EWOULDBLOCK, so there's nothing to do. + return; + } + if (type_ == SOCK_DGRAM) { + ready_to_send_ = true; + SignalWriteEvent(this); + } else { + RTC_DCHECK(type_ == SOCK_STREAM); + // This will attempt to empty the full send buffer, and will fire + // SignalWriteEvent if successful. + server_->SendTcp(this); + } +} + +void VirtualSocket::SetToBlocked() { + ready_to_send_ = false; + error_ = EWOULDBLOCK; +} + +void VirtualSocket::UpdateRecv(size_t data_size) { + recv_buffer_size_ += data_size; +} + +void VirtualSocket::UpdateSend(size_t data_size) { + size_t new_buffer_size = send_buffer_.size() - data_size; + // Avoid undefined access beyond the last element of the vector. + // This only happens when new_buffer_size is 0. + if (data_size < send_buffer_.size()) { + // memmove is required for potentially overlapping source/destination. + memmove(&send_buffer_[0], &send_buffer_[data_size], new_buffer_size); + } + send_buffer_.resize(new_buffer_size); +} + +void VirtualSocket::MaybeSignalWriteEvent(size_t capacity) { + if (!ready_to_send_ && (send_buffer_.size() < capacity)) { + ready_to_send_ = true; + SignalWriteEvent(this); + } +} + +uint32_t VirtualSocket::AddPacket(int64_t cur_time, size_t packet_size) { + network_size_ += packet_size; + uint32_t send_delay = + server_->SendDelay(static_cast<uint32_t>(network_size_)); + + NetworkEntry entry; + entry.size = packet_size; + entry.done_time = cur_time + send_delay; + network_.push_back(entry); + + return send_delay; +} + +int64_t VirtualSocket::UpdateOrderedDelivery(int64_t ts) { + // Ensure that new packets arrive after previous ones + ts = std::max(ts, last_delivery_time_); + // A socket should not have both ordered and unordered delivery, so its last + // delivery time only needs to be updated when it has ordered delivery. + last_delivery_time_ = ts; + return ts; +} + +size_t VirtualSocket::PurgeNetworkPackets(int64_t cur_time) { + while (!network_.empty() && (network_.front().done_time <= cur_time)) { + RTC_DCHECK(network_size_ >= network_.front().size); + network_size_ -= network_.front().size; + network_.pop_front(); + } + return network_size_; +} + +VirtualSocketServer::VirtualSocketServer() : VirtualSocketServer(nullptr) {} + +VirtualSocketServer::VirtualSocketServer(ThreadProcessingFakeClock* fake_clock) + : fake_clock_(fake_clock), + msg_queue_(nullptr), + stop_on_idle_(false), + next_ipv4_(kInitialNextIPv4), + next_ipv6_(kInitialNextIPv6), + next_port_(kFirstEphemeralPort), + bindings_(new AddressMap()), + connections_(new ConnectionMap()), + bandwidth_(0), + network_capacity_(kDefaultNetworkCapacity), + send_buffer_capacity_(kDefaultTcpBufferSize), + recv_buffer_capacity_(kDefaultTcpBufferSize), + delay_mean_(0), + delay_stddev_(0), + delay_samples_(NUM_SAMPLES), + drop_prob_(0.0) { + UpdateDelayDistribution(); +} + +VirtualSocketServer::~VirtualSocketServer() { + delete bindings_; + delete connections_; +} + +IPAddress VirtualSocketServer::GetNextIP(int family) { + if (family == AF_INET) { + IPAddress next_ip(next_ipv4_); + next_ipv4_.s_addr = HostToNetwork32(NetworkToHost32(next_ipv4_.s_addr) + 1); + return next_ip; + } else if (family == AF_INET6) { + IPAddress next_ip(next_ipv6_); + uint32_t* as_ints = reinterpret_cast<uint32_t*>(&next_ipv6_.s6_addr); + as_ints[3] += 1; + return next_ip; + } + return IPAddress(); +} + +uint16_t VirtualSocketServer::GetNextPort() { + uint16_t port = next_port_; + if (next_port_ < kLastEphemeralPort) { + ++next_port_; + } else { + next_port_ = kFirstEphemeralPort; + } + return port; +} + +void VirtualSocketServer::SetSendingBlocked(bool blocked) { + { + webrtc::MutexLock lock(&mutex_); + if (blocked == sending_blocked_) { + // Unchanged; nothing to do. + return; + } + sending_blocked_ = blocked; + } + if (!blocked) { + // Sending was blocked, but is now unblocked. This signal gives sockets a + // chance to fire SignalWriteEvent, and for TCP, send buffered data. + SignalReadyToSend(); + } +} + +VirtualSocket* VirtualSocketServer::CreateSocket(int family, int type) { + return new VirtualSocket(this, family, type); +} + +void VirtualSocketServer::SetMessageQueue(Thread* msg_queue) { + msg_queue_ = msg_queue; +} + +bool VirtualSocketServer::Wait(webrtc::TimeDelta max_wait_duration, + bool process_io) { + RTC_DCHECK_RUN_ON(msg_queue_); + if (stop_on_idle_ && Thread::Current()->empty()) { + return false; + } + // Note: we don't need to do anything with `process_io` since we don't have + // any real I/O. Received packets come in the form of queued messages, so + // Thread will ensure WakeUp is called if another thread sends a + // packet. + wakeup_.Wait(max_wait_duration); + return true; +} + +void VirtualSocketServer::WakeUp() { + wakeup_.Set(); +} + +void VirtualSocketServer::SetAlternativeLocalAddress( + const rtc::IPAddress& address, + const rtc::IPAddress& alternative) { + alternative_address_mapping_[address] = alternative; +} + +bool VirtualSocketServer::ProcessMessagesUntilIdle() { + RTC_DCHECK_RUN_ON(msg_queue_); + stop_on_idle_ = true; + while (!msg_queue_->empty()) { + if (fake_clock_) { + // If using a fake clock, advance it in millisecond increments until the + // queue is empty. + fake_clock_->AdvanceTime(webrtc::TimeDelta::Millis(1)); + } else { + // Otherwise, run a normal message loop. + msg_queue_->ProcessMessages(Thread::kForever); + } + } + stop_on_idle_ = false; + return !msg_queue_->IsQuitting(); +} + +void VirtualSocketServer::SetNextPortForTesting(uint16_t port) { + next_port_ = port; +} + +bool VirtualSocketServer::CloseTcpConnections( + const SocketAddress& addr_local, + const SocketAddress& addr_remote) { + VirtualSocket* socket = LookupConnection(addr_local, addr_remote); + if (!socket) { + return false; + } + // Signal the close event on the local connection first. + socket->SignalCloseEvent(socket, 0); + + // Trigger the remote connection's close event. + socket->Close(); + + return true; +} + +int VirtualSocketServer::Bind(VirtualSocket* socket, + const SocketAddress& addr) { + RTC_DCHECK(nullptr != socket); + // Address must be completely specified at this point + RTC_DCHECK(!IPIsUnspec(addr.ipaddr())); + RTC_DCHECK(addr.port() != 0); + + // Normalize the address (turns v6-mapped addresses into v4-addresses). + SocketAddress normalized(addr.ipaddr().Normalized(), addr.port()); + + AddressMap::value_type entry(normalized, socket); + return bindings_->insert(entry).second ? 0 : -1; +} + +SocketAddress VirtualSocketServer::AssignBindAddress( + const SocketAddress& app_addr) { + RTC_DCHECK(!IPIsUnspec(app_addr.ipaddr())); + + // Normalize the IP. + SocketAddress addr; + addr.SetIP(app_addr.ipaddr().Normalized()); + + // If the IP appears in `alternative_address_mapping_`, meaning the test has + // configured sockets bound to this IP to actually use another IP, replace + // the IP here. + auto alternative = alternative_address_mapping_.find(addr.ipaddr()); + if (alternative != alternative_address_mapping_.end()) { + addr.SetIP(alternative->second); + } + + if (app_addr.port() != 0) { + addr.SetPort(app_addr.port()); + } else { + // Assign a port. + for (int i = 0; i < kEphemeralPortCount; ++i) { + addr.SetPort(GetNextPort()); + if (bindings_->find(addr) == bindings_->end()) { + break; + } + } + } + + return addr; +} + +VirtualSocket* VirtualSocketServer::LookupBinding(const SocketAddress& addr) { + SocketAddress normalized(addr.ipaddr().Normalized(), addr.port()); + AddressMap::iterator it = bindings_->find(normalized); + if (it != bindings_->end()) { + return it->second; + } + + IPAddress default_ip = GetDefaultSourceAddress(addr.ipaddr().family()); + if (!IPIsUnspec(default_ip) && addr.ipaddr() == default_ip) { + // If we can't find a binding for the packet which is sent to the interface + // corresponding to the default route, it should match a binding with the + // correct port to the any address. + SocketAddress sock_addr = + EmptySocketAddressWithFamily(addr.ipaddr().family()); + sock_addr.SetPort(addr.port()); + return LookupBinding(sock_addr); + } + + return nullptr; +} + +int VirtualSocketServer::Unbind(const SocketAddress& addr, + VirtualSocket* socket) { + SocketAddress normalized(addr.ipaddr().Normalized(), addr.port()); + RTC_DCHECK((*bindings_)[normalized] == socket); + bindings_->erase(bindings_->find(normalized)); + return 0; +} + +void VirtualSocketServer::AddConnection(const SocketAddress& local, + const SocketAddress& remote, + VirtualSocket* remote_socket) { + // Add this socket pair to our routing table. This will allow + // multiple clients to connect to the same server address. + SocketAddress local_normalized(local.ipaddr().Normalized(), local.port()); + SocketAddress remote_normalized(remote.ipaddr().Normalized(), remote.port()); + SocketAddressPair address_pair(local_normalized, remote_normalized); + connections_->insert(std::pair<SocketAddressPair, VirtualSocket*>( + address_pair, remote_socket)); +} + +VirtualSocket* VirtualSocketServer::LookupConnection( + const SocketAddress& local, + const SocketAddress& remote) { + SocketAddress local_normalized(local.ipaddr().Normalized(), local.port()); + SocketAddress remote_normalized(remote.ipaddr().Normalized(), remote.port()); + SocketAddressPair address_pair(local_normalized, remote_normalized); + ConnectionMap::iterator it = connections_->find(address_pair); + return (connections_->end() != it) ? it->second : nullptr; +} + +void VirtualSocketServer::RemoveConnection(const SocketAddress& local, + const SocketAddress& remote) { + SocketAddress local_normalized(local.ipaddr().Normalized(), local.port()); + SocketAddress remote_normalized(remote.ipaddr().Normalized(), remote.port()); + SocketAddressPair address_pair(local_normalized, remote_normalized); + connections_->erase(address_pair); +} + +static double Random() { + return static_cast<double>(rand()) / RAND_MAX; +} + +int VirtualSocketServer::Connect(VirtualSocket* socket, + const SocketAddress& remote_addr, + bool use_delay) { + RTC_DCHECK(msg_queue_); + + TimeDelta delay = TimeDelta::Millis(use_delay ? GetTransitDelay(socket) : 0); + VirtualSocket* remote = LookupBinding(remote_addr); + if (!CanInteractWith(socket, remote)) { + RTC_LOG(LS_INFO) << "Address family mismatch between " + << socket->GetLocalAddress().ToString() << " and " + << remote_addr.ToString(); + return -1; + } + if (remote != nullptr) { + remote->PostConnect(delay, socket->GetLocalAddress()); + } else { + RTC_LOG(LS_INFO) << "No one listening at " << remote_addr.ToString(); + socket->PostDisconnect(delay); + } + return 0; +} + +bool VirtualSocketServer::Disconnect(VirtualSocket* socket) { + if (!socket || !msg_queue_) + return false; + + // If we simulate packets being delayed, we should simulate the + // equivalent of a FIN being delayed as well. + socket->PostDisconnect(TimeDelta::Millis(GetTransitDelay(socket))); + return true; +} + +bool VirtualSocketServer::Disconnect(const SocketAddress& addr) { + return Disconnect(LookupBinding(addr)); +} + +bool VirtualSocketServer::Disconnect(const SocketAddress& local_addr, + const SocketAddress& remote_addr) { + // Disconnect remote socket, check if it is a child of a server socket. + VirtualSocket* socket = LookupConnection(local_addr, remote_addr); + if (!socket) { + // Not a server socket child, then see if it is bound. + // TODO(tbd): If this is indeed a server socket that has no + // children this will cause the server socket to be + // closed. This might lead to unexpected results, how to fix this? + socket = LookupBinding(remote_addr); + } + Disconnect(socket); + + // Remove mapping for both directions. + RemoveConnection(remote_addr, local_addr); + RemoveConnection(local_addr, remote_addr); + return socket != nullptr; +} + +int VirtualSocketServer::SendUdp(VirtualSocket* socket, + const char* data, + size_t data_size, + const SocketAddress& remote_addr) { + { + webrtc::MutexLock lock(&mutex_); + ++sent_packets_; + if (sending_blocked_) { + socket->SetToBlocked(); + return -1; + } + + // See if we want to drop this packet. + if (data_size > max_udp_payload_) { + RTC_LOG(LS_VERBOSE) << "Dropping too large UDP payload of size " + << data_size << ", UDP payload limit is " + << max_udp_payload_; + // Return as if send was successful; packet disappears. + return data_size; + } + + if (Random() < drop_prob_) { + RTC_LOG(LS_VERBOSE) << "Dropping packet: bad luck"; + return static_cast<int>(data_size); + } + } + + VirtualSocket* recipient = LookupBinding(remote_addr); + if (!recipient) { + // Make a fake recipient for address family checking. + std::unique_ptr<VirtualSocket> dummy_socket( + CreateSocket(AF_INET, SOCK_DGRAM)); + dummy_socket->SetLocalAddress(remote_addr); + if (!CanInteractWith(socket, dummy_socket.get())) { + RTC_LOG(LS_VERBOSE) << "Incompatible address families: " + << socket->GetLocalAddress().ToString() << " and " + << remote_addr.ToString(); + return -1; + } + RTC_LOG(LS_VERBOSE) << "No one listening at " << remote_addr.ToString(); + return static_cast<int>(data_size); + } + + if (!CanInteractWith(socket, recipient)) { + RTC_LOG(LS_VERBOSE) << "Incompatible address families: " + << socket->GetLocalAddress().ToString() << " and " + << remote_addr.ToString(); + return -1; + } + + { + int64_t cur_time = TimeMillis(); + size_t network_size = socket->PurgeNetworkPackets(cur_time); + + // Determine whether we have enough bandwidth to accept this packet. To do + // this, we need to update the send queue. Once we know it's current size, + // we know whether we can fit this packet. + // + // NOTE: There are better algorithms for maintaining such a queue (such as + // "Derivative Random Drop"); however, this algorithm is a more accurate + // simulation of what a normal network would do. + { + webrtc::MutexLock lock(&mutex_); + size_t packet_size = data_size + UDP_HEADER_SIZE; + if (network_size + packet_size > network_capacity_) { + RTC_LOG(LS_VERBOSE) << "Dropping packet: network capacity exceeded"; + return static_cast<int>(data_size); + } + } + + AddPacketToNetwork(socket, recipient, cur_time, data, data_size, + UDP_HEADER_SIZE, false); + + return static_cast<int>(data_size); + } +} + +void VirtualSocketServer::SendTcp(VirtualSocket* socket) { + { + webrtc::MutexLock lock(&mutex_); + ++sent_packets_; + if (sending_blocked_) { + // Eventually the socket's buffer will fill and VirtualSocket::SendTcp + // will set EWOULDBLOCK. + return; + } + } + + // TCP can't send more data than will fill up the receiver's buffer. + // We track the data that is in the buffer plus data in flight using the + // recipient's recv_buffer_size_. Anything beyond that must be stored in the + // sender's buffer. We will trigger the buffered data to be sent when data + // is read from the recv_buffer. + + // Lookup the local/remote pair in the connections table. + VirtualSocket* recipient = + LookupConnection(socket->GetLocalAddress(), socket->GetRemoteAddress()); + if (!recipient) { + RTC_LOG(LS_VERBOSE) << "Sending data to no one."; + return; + } + + int64_t cur_time = TimeMillis(); + socket->PurgeNetworkPackets(cur_time); + + while (true) { + size_t available = recv_buffer_capacity() - recipient->recv_buffer_size(); + size_t max_data_size = + std::min<size_t>(available, TCP_MSS - TCP_HEADER_SIZE); + size_t data_size = std::min(socket->send_buffer_size(), max_data_size); + if (0 == data_size) + break; + + AddPacketToNetwork(socket, recipient, cur_time, socket->send_buffer_data(), + data_size, TCP_HEADER_SIZE, true); + recipient->UpdateRecv(data_size); + socket->UpdateSend(data_size); + } + + socket->MaybeSignalWriteEvent(send_buffer_capacity()); +} + +void VirtualSocketServer::SendTcp(const SocketAddress& addr) { + VirtualSocket* sender = LookupBinding(addr); + RTC_DCHECK(nullptr != sender); + SendTcp(sender); +} + +void VirtualSocketServer::AddPacketToNetwork(VirtualSocket* sender, + VirtualSocket* recipient, + int64_t cur_time, + const char* data, + size_t data_size, + size_t header_size, + bool ordered) { + RTC_DCHECK(msg_queue_); + uint32_t send_delay = sender->AddPacket(cur_time, data_size + header_size); + + // Find the delay for crossing the many virtual hops of the network. + uint32_t transit_delay = GetTransitDelay(sender); + + // When the incoming packet is from a binding of the any address, translate it + // to the default route here such that the recipient will see the default + // route. + SocketAddress sender_addr = sender->GetLocalAddress(); + IPAddress default_ip = GetDefaultSourceAddress(sender_addr.ipaddr().family()); + if (sender_addr.IsAnyIP() && !IPIsUnspec(default_ip)) { + sender_addr.SetIP(default_ip); + } + + int64_t ts = cur_time + send_delay + transit_delay; + if (ordered) { + ts = sender->UpdateOrderedDelivery(ts); + } + recipient->PostPacket(TimeDelta::Millis(ts - cur_time), + std::make_unique<Packet>(data, data_size, sender_addr)); +} + +uint32_t VirtualSocketServer::SendDelay(uint32_t size) { + webrtc::MutexLock lock(&mutex_); + if (bandwidth_ == 0) + return 0; + else + return 1000 * size / bandwidth_; +} + +#if 0 +void PrintFunction(std::vector<std::pair<double, double> >* f) { + return; + double sum = 0; + for (uint32_t i = 0; i < f->size(); ++i) { + std::cout << (*f)[i].first << '\t' << (*f)[i].second << std::endl; + sum += (*f)[i].second; + } + if (!f->empty()) { + const double mean = sum / f->size(); + double sum_sq_dev = 0; + for (uint32_t i = 0; i < f->size(); ++i) { + double dev = (*f)[i].second - mean; + sum_sq_dev += dev * dev; + } + std::cout << "Mean = " << mean << " StdDev = " + << sqrt(sum_sq_dev / f->size()) << std::endl; + } +} +#endif // <unused> + +void VirtualSocketServer::UpdateDelayDistribution() { + webrtc::MutexLock lock(&mutex_); + delay_dist_ = CreateDistribution(delay_mean_, delay_stddev_, delay_samples_); +} + +static double PI = 4 * atan(1.0); + +static double Normal(double x, double mean, double stddev) { + double a = (x - mean) * (x - mean) / (2 * stddev * stddev); + return exp(-a) / (stddev * sqrt(2 * PI)); +} + +#if 0 // static unused gives a warning +static double Pareto(double x, double min, double k) { + if (x < min) + return 0; + else + return k * std::pow(min, k) / std::pow(x, k+1); +} +#endif + +std::unique_ptr<VirtualSocketServer::Function> +VirtualSocketServer::CreateDistribution(uint32_t mean, + uint32_t stddev, + uint32_t samples) { + auto f = std::make_unique<Function>(); + + if (0 == stddev) { + f->push_back(Point(mean, 1.0)); + } else { + double start = 0; + if (mean >= 4 * static_cast<double>(stddev)) + start = mean - 4 * static_cast<double>(stddev); + double end = mean + 4 * static_cast<double>(stddev); + + for (uint32_t i = 0; i < samples; i++) { + double x = start + (end - start) * i / (samples - 1); + double y = Normal(x, mean, stddev); + f->push_back(Point(x, y)); + } + } + return Resample(Invert(Accumulate(std::move(f))), 0, 1, samples); +} + +uint32_t VirtualSocketServer::GetTransitDelay(Socket* socket) { + // Use the delay based on the address if it is set. + auto iter = delay_by_ip_.find(socket->GetLocalAddress().ipaddr()); + if (iter != delay_by_ip_.end()) { + return static_cast<uint32_t>(iter->second); + } + // Otherwise, use the delay from the distribution distribution. + size_t index = rand() % delay_dist_->size(); + double delay = (*delay_dist_)[index].second; + // RTC_LOG_F(LS_INFO) << "random[" << index << "] = " << delay; + return static_cast<uint32_t>(delay); +} + +struct FunctionDomainCmp { + bool operator()(const VirtualSocketServer::Point& p1, + const VirtualSocketServer::Point& p2) { + return p1.first < p2.first; + } + bool operator()(double v1, const VirtualSocketServer::Point& p2) { + return v1 < p2.first; + } + bool operator()(const VirtualSocketServer::Point& p1, double v2) { + return p1.first < v2; + } +}; + +std::unique_ptr<VirtualSocketServer::Function> VirtualSocketServer::Accumulate( + std::unique_ptr<Function> f) { + RTC_DCHECK(f->size() >= 1); + double v = 0; + for (Function::size_type i = 0; i < f->size() - 1; ++i) { + double dx = (*f)[i + 1].first - (*f)[i].first; + double avgy = ((*f)[i + 1].second + (*f)[i].second) / 2; + (*f)[i].second = v; + v = v + dx * avgy; + } + (*f)[f->size() - 1].second = v; + return f; +} + +std::unique_ptr<VirtualSocketServer::Function> VirtualSocketServer::Invert( + std::unique_ptr<Function> f) { + for (Function::size_type i = 0; i < f->size(); ++i) + std::swap((*f)[i].first, (*f)[i].second); + + absl::c_sort(*f, FunctionDomainCmp()); + return f; +} + +std::unique_ptr<VirtualSocketServer::Function> VirtualSocketServer::Resample( + std::unique_ptr<Function> f, + double x1, + double x2, + uint32_t samples) { + auto g = std::make_unique<Function>(); + + for (size_t i = 0; i < samples; i++) { + double x = x1 + (x2 - x1) * i / (samples - 1); + double y = Evaluate(f.get(), x); + g->push_back(Point(x, y)); + } + + return g; +} + +double VirtualSocketServer::Evaluate(const Function* f, double x) { + Function::const_iterator iter = + absl::c_lower_bound(*f, x, FunctionDomainCmp()); + if (iter == f->begin()) { + return (*f)[0].second; + } else if (iter == f->end()) { + RTC_DCHECK(f->size() >= 1); + return (*f)[f->size() - 1].second; + } else if (iter->first == x) { + return iter->second; + } else { + double x1 = (iter - 1)->first; + double y1 = (iter - 1)->second; + double x2 = iter->first; + double y2 = iter->second; + return y1 + (y2 - y1) * (x - x1) / (x2 - x1); + } +} + +bool VirtualSocketServer::CanInteractWith(VirtualSocket* local, + VirtualSocket* remote) { + if (!local || !remote) { + return false; + } + IPAddress local_ip = local->GetLocalAddress().ipaddr(); + IPAddress remote_ip = remote->GetLocalAddress().ipaddr(); + IPAddress local_normalized = local_ip.Normalized(); + IPAddress remote_normalized = remote_ip.Normalized(); + // Check if the addresses are the same family after Normalization (turns + // mapped IPv6 address into IPv4 addresses). + // This will stop unmapped V6 addresses from talking to mapped V6 addresses. + if (local_normalized.family() == remote_normalized.family()) { + return true; + } + + // If ip1 is IPv4 and ip2 is :: and ip2 is not IPV6_V6ONLY. + int remote_v6_only = 0; + remote->GetOption(Socket::OPT_IPV6_V6ONLY, &remote_v6_only); + if (local_ip.family() == AF_INET && !remote_v6_only && IPIsAny(remote_ip)) { + return true; + } + // Same check, backwards. + int local_v6_only = 0; + local->GetOption(Socket::OPT_IPV6_V6ONLY, &local_v6_only); + if (remote_ip.family() == AF_INET && !local_v6_only && IPIsAny(local_ip)) { + return true; + } + + // Check to see if either socket was explicitly bound to IPv6-any. + // These sockets can talk with anyone. + if (local_ip.family() == AF_INET6 && local->was_any()) { + return true; + } + if (remote_ip.family() == AF_INET6 && remote->was_any()) { + return true; + } + + return false; +} + +IPAddress VirtualSocketServer::GetDefaultSourceAddress(int family) { + if (family == AF_INET) { + return default_source_address_v4_; + } + if (family == AF_INET6) { + return default_source_address_v6_; + } + return IPAddress(); +} +void VirtualSocketServer::SetDefaultSourceAddress(const IPAddress& from_addr) { + RTC_DCHECK(!IPIsAny(from_addr)); + if (from_addr.family() == AF_INET) { + default_source_address_v4_ = from_addr; + } else if (from_addr.family() == AF_INET6) { + default_source_address_v6_ = from_addr; + } +} + +void VirtualSocketServer::set_bandwidth(uint32_t bandwidth) { + webrtc::MutexLock lock(&mutex_); + bandwidth_ = bandwidth; +} +void VirtualSocketServer::set_network_capacity(uint32_t capacity) { + webrtc::MutexLock lock(&mutex_); + network_capacity_ = capacity; +} + +uint32_t VirtualSocketServer::send_buffer_capacity() const { + webrtc::MutexLock lock(&mutex_); + return send_buffer_capacity_; +} +void VirtualSocketServer::set_send_buffer_capacity(uint32_t capacity) { + webrtc::MutexLock lock(&mutex_); + send_buffer_capacity_ = capacity; +} + +uint32_t VirtualSocketServer::recv_buffer_capacity() const { + webrtc::MutexLock lock(&mutex_); + return recv_buffer_capacity_; +} +void VirtualSocketServer::set_recv_buffer_capacity(uint32_t capacity) { + webrtc::MutexLock lock(&mutex_); + recv_buffer_capacity_ = capacity; +} + +void VirtualSocketServer::set_delay_mean(uint32_t delay_mean) { + webrtc::MutexLock lock(&mutex_); + delay_mean_ = delay_mean; +} +void VirtualSocketServer::set_delay_stddev(uint32_t delay_stddev) { + webrtc::MutexLock lock(&mutex_); + delay_stddev_ = delay_stddev; +} +void VirtualSocketServer::set_delay_samples(uint32_t delay_samples) { + webrtc::MutexLock lock(&mutex_); + delay_samples_ = delay_samples; +} + +void VirtualSocketServer::set_drop_probability(double drop_prob) { + RTC_DCHECK_GE(drop_prob, 0.0); + RTC_DCHECK_LE(drop_prob, 1.0); + + webrtc::MutexLock lock(&mutex_); + drop_prob_ = drop_prob; +} + +void VirtualSocketServer::set_max_udp_payload(size_t payload_size) { + webrtc::MutexLock lock(&mutex_); + max_udp_payload_ = payload_size; +} + +uint32_t VirtualSocketServer::sent_packets() const { + webrtc::MutexLock lock(&mutex_); + return sent_packets_; +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/virtual_socket_server.h b/third_party/libwebrtc/rtc_base/virtual_socket_server.h new file mode 100644 index 0000000000..93ef288826 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/virtual_socket_server.h @@ -0,0 +1,482 @@ +/* + * 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 RTC_BASE_VIRTUAL_SOCKET_SERVER_H_ +#define RTC_BASE_VIRTUAL_SOCKET_SERVER_H_ + +#include <deque> +#include <map> +#include <vector> + +#include "absl/types/optional.h" +#include "api/make_ref_counted.h" +#include "api/ref_counted_base.h" +#include "api/scoped_refptr.h" +#include "api/task_queue/task_queue_base.h" +#include "rtc_base/checks.h" +#include "rtc_base/event.h" +#include "rtc_base/fake_clock.h" +#include "rtc_base/socket_server.h" +#include "rtc_base/synchronization/mutex.h" + +namespace rtc { + +class Packet; +class VirtualSocketServer; +class SocketAddressPair; + +// Implements the socket interface using the virtual network. Packets are +// passed in tasks using the thread of the socket server. +class VirtualSocket : public Socket, public sigslot::has_slots<> { + public: + VirtualSocket(VirtualSocketServer* server, int family, int type); + ~VirtualSocket() override; + + SocketAddress GetLocalAddress() const override; + SocketAddress GetRemoteAddress() const override; + + int Bind(const SocketAddress& addr) override; + int Connect(const SocketAddress& addr) override; + int Close() override; + int Send(const void* pv, size_t cb) override; + int SendTo(const void* pv, size_t cb, const SocketAddress& addr) override; + int Recv(void* pv, size_t cb, int64_t* timestamp) override; + int RecvFrom(void* pv, + size_t cb, + SocketAddress* paddr, + int64_t* timestamp) override; + int Listen(int backlog) override; + VirtualSocket* Accept(SocketAddress* paddr) override; + + int GetError() const override; + void SetError(int error) override; + ConnState GetState() const override; + int GetOption(Option opt, int* value) override; + int SetOption(Option opt, int value) override; + + size_t recv_buffer_size() const { return recv_buffer_size_; } + size_t send_buffer_size() const { return send_buffer_.size(); } + const char* send_buffer_data() const { return send_buffer_.data(); } + + // Used by server sockets to set the local address without binding. + void SetLocalAddress(const SocketAddress& addr); + + bool was_any() { return was_any_; } + void set_was_any(bool was_any) { was_any_ = was_any; } + + void SetToBlocked(); + + void UpdateRecv(size_t data_size); + void UpdateSend(size_t data_size); + + void MaybeSignalWriteEvent(size_t capacity); + + // Adds a packet to be sent. Returns delay, based on network_size_. + uint32_t AddPacket(int64_t cur_time, size_t packet_size); + + int64_t UpdateOrderedDelivery(int64_t ts); + + // Removes stale packets from the network. Returns current size. + size_t PurgeNetworkPackets(int64_t cur_time); + + void PostPacket(webrtc::TimeDelta delay, std::unique_ptr<Packet> packet); + void PostConnect(webrtc::TimeDelta delay, const SocketAddress& remote_addr); + void PostDisconnect(webrtc::TimeDelta delay); + + private: + // Struct shared with pending tasks that may outlive VirtualSocket. + class SafetyBlock : public RefCountedNonVirtual<SafetyBlock> { + public: + explicit SafetyBlock(VirtualSocket* socket); + SafetyBlock(const SafetyBlock&) = delete; + SafetyBlock& operator=(const SafetyBlock&) = delete; + ~SafetyBlock(); + + // Prohibits posted delayed task to access owning VirtualSocket and + // cleanups members protected by the `mutex`. + void SetNotAlive(); + bool IsAlive(); + + // Copies up to `size` bytes into buffer from the next received packet + // and fills `addr` with remote address of that received packet. + // Returns number of bytes copied or negative value on failure. + int RecvFrom(void* buffer, size_t size, SocketAddress& addr); + + void Listen(); + + struct AcceptResult { + int error = 0; + std::unique_ptr<VirtualSocket> socket; + SocketAddress remote_addr; + }; + AcceptResult Accept(); + + bool AddPacket(std::unique_ptr<Packet> packet); + void PostConnect(webrtc::TimeDelta delay, const SocketAddress& remote_addr); + + private: + enum class Signal { kNone, kReadEvent, kConnectEvent }; + // `PostConnect` rely on the fact that std::list iterators are not + // invalidated on any changes to other elements in the container. + using PostedConnects = std::list<SocketAddress>; + + void PostSignalReadEvent() RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_); + void MaybeSignalReadEvent(); + Signal Connect(PostedConnects::iterator remote_addr_it); + + webrtc::Mutex mutex_; + VirtualSocket& socket_; + bool alive_ RTC_GUARDED_BY(mutex_) = true; + // Flag indicating if async Task to signal SignalReadEvent is posted. + // To avoid posting multiple such tasks. + bool pending_read_signal_event_ RTC_GUARDED_BY(mutex_) = false; + + // Members below do not need to outlive VirtualSocket, but are used by the + // posted tasks. Keeping them in the VirtualSocket confuses thread + // annotations because they can't detect that locked mutex is the same mutex + // this members are guarded by. + + // Addresses of the sockets for potential connect. For each address there + // is a posted task that should finilze the connect. + PostedConnects posted_connects_ RTC_GUARDED_BY(mutex_); + + // Data which has been received from the network + std::list<std::unique_ptr<Packet>> recv_buffer_ RTC_GUARDED_BY(mutex_); + + // Pending sockets which can be Accepted + absl::optional<std::deque<SocketAddress>> listen_queue_ + RTC_GUARDED_BY(mutex_); + }; + + struct NetworkEntry { + size_t size; + int64_t done_time; + }; + + typedef std::deque<NetworkEntry> NetworkQueue; + typedef std::vector<char> SendBuffer; + typedef std::map<Option, int> OptionsMap; + + int InitiateConnect(const SocketAddress& addr, bool use_delay); + void CompleteConnect(const SocketAddress& addr); + int SendUdp(const void* pv, size_t cb, const SocketAddress& addr); + int SendTcp(const void* pv, size_t cb); + + void OnSocketServerReadyToSend(); + + VirtualSocketServer* const server_; + const int type_; + ConnState state_; + int error_; + SocketAddress local_addr_; + SocketAddress remote_addr_; + + const scoped_refptr<SafetyBlock> safety_ = + make_ref_counted<SafetyBlock>(this); + + // Data which tcp has buffered for sending + SendBuffer send_buffer_; + // Set to false if the last attempt to send resulted in EWOULDBLOCK. + // Set back to true when the socket can send again. + bool ready_to_send_ = true; + + // Network model that enforces bandwidth and capacity constraints + NetworkQueue network_; + size_t network_size_; + // The scheduled delivery time of the last packet sent on this socket. + // It is used to ensure ordered delivery of packets sent on this socket. + int64_t last_delivery_time_ = 0; + + // The amount of data which is in flight or in recv_buffer_ + size_t recv_buffer_size_; + + // Is this socket bound? + bool bound_; + + // When we bind a socket to Any, VSS's Bind gives it another address. For + // dual-stack sockets, we want to distinguish between sockets that were + // explicitly given a particular address and sockets that had one picked + // for them by VSS. + bool was_any_; + + // Store the options that are set + OptionsMap options_map_; +}; + +// Simulates a network in the same manner as a loopback interface. The +// interface can create as many addresses as you want. All of the sockets +// created by this network will be able to communicate with one another, unless +// they are bound to addresses from incompatible families. +class VirtualSocketServer : public SocketServer { + public: + VirtualSocketServer(); + // This constructor needs to be used if the test uses a fake clock and + // ProcessMessagesUntilIdle, since ProcessMessagesUntilIdle needs a way of + // advancing time. + explicit VirtualSocketServer(ThreadProcessingFakeClock* fake_clock); + ~VirtualSocketServer() override; + + VirtualSocketServer(const VirtualSocketServer&) = delete; + VirtualSocketServer& operator=(const VirtualSocketServer&) = delete; + + // The default source address specifies which local address to use when a + // socket is bound to the 'any' address, e.g. 0.0.0.0. (If not set, the 'any' + // address is used as the source address on outgoing virtual packets, exposed + // to recipient's RecvFrom). + IPAddress GetDefaultSourceAddress(int family); + void SetDefaultSourceAddress(const IPAddress& from_addr); + + // Limits the network bandwidth (maximum bytes per second). Zero means that + // all sends occur instantly. Defaults to 0. + void set_bandwidth(uint32_t bandwidth) RTC_LOCKS_EXCLUDED(mutex_); + + // Limits the amount of data which can be in flight on the network without + // packet loss (on a per sender basis). Defaults to 64 KB. + void set_network_capacity(uint32_t capacity) RTC_LOCKS_EXCLUDED(mutex_); + + // The amount of data which can be buffered by tcp on the sender's side + uint32_t send_buffer_capacity() const RTC_LOCKS_EXCLUDED(mutex_); + void set_send_buffer_capacity(uint32_t capacity) RTC_LOCKS_EXCLUDED(mutex_); + + // The amount of data which can be buffered by tcp on the receiver's side + uint32_t recv_buffer_capacity() const RTC_LOCKS_EXCLUDED(mutex_); + void set_recv_buffer_capacity(uint32_t capacity) RTC_LOCKS_EXCLUDED(mutex_); + + // Controls the (transit) delay for packets sent in the network. This does + // not inclue the time required to sit in the send queue. Both of these + // values are measured in milliseconds. Defaults to no delay. + void set_delay_mean(uint32_t delay_mean) RTC_LOCKS_EXCLUDED(mutex_); + void set_delay_stddev(uint32_t delay_stddev) RTC_LOCKS_EXCLUDED(mutex_); + void set_delay_samples(uint32_t delay_samples) RTC_LOCKS_EXCLUDED(mutex_); + + // If the (transit) delay parameters are modified, this method should be + // called to recompute the new distribution. + void UpdateDelayDistribution() RTC_LOCKS_EXCLUDED(mutex_); + + // Controls the (uniform) probability that any sent packet is dropped. This + // is separate from calculations to drop based on queue size. + void set_drop_probability(double drop_prob) RTC_LOCKS_EXCLUDED(mutex_); + + // Controls the maximum UDP payload for the networks simulated + // by this server. Any UDP payload sent that is larger than this will + // be dropped. + void set_max_udp_payload(size_t payload_size) RTC_LOCKS_EXCLUDED(mutex_); + + // If `blocked` is true, subsequent attempts to send will result in -1 being + // returned, with the socket error set to EWOULDBLOCK. + // + // If this method is later called with `blocked` set to false, any sockets + // that previously failed to send with EWOULDBLOCK will emit SignalWriteEvent. + // + // This can be used to simulate the send buffer on a network interface being + // full, and test functionality related to EWOULDBLOCK/SignalWriteEvent. + void SetSendingBlocked(bool blocked) RTC_LOCKS_EXCLUDED(mutex_); + + // SocketFactory: + VirtualSocket* CreateSocket(int family, int type) override; + + // SocketServer: + void SetMessageQueue(Thread* queue) override; + bool Wait(webrtc::TimeDelta max_wait_duration, bool process_io) override; + void WakeUp() override; + + void SetDelayOnAddress(const rtc::SocketAddress& address, int delay_ms) { + delay_by_ip_[address.ipaddr()] = delay_ms; + } + + // Used by TurnPortTest and TcpPortTest (for example), to mimic a case where + // a proxy returns the local host address instead of the original one the + // port was bound against. Please see WebRTC issue 3927 for more detail. + // + // If SetAlternativeLocalAddress(A, B) is called, then when something + // attempts to bind a socket to address A, it will get a socket bound to + // address B instead. + void SetAlternativeLocalAddress(const rtc::IPAddress& address, + const rtc::IPAddress& alternative); + + typedef std::pair<double, double> Point; + typedef std::vector<Point> Function; + + static std::unique_ptr<Function> CreateDistribution(uint32_t mean, + uint32_t stddev, + uint32_t samples); + + // Similar to Thread::ProcessMessages, but it only processes messages until + // there are no immediate messages or pending network traffic. Returns false + // if Thread::Stop() was called. + bool ProcessMessagesUntilIdle(); + + // Sets the next port number to use for testing. + void SetNextPortForTesting(uint16_t port); + + // Close a pair of Tcp connections by addresses. Both connections will have + // its own OnClose invoked. + bool CloseTcpConnections(const SocketAddress& addr_local, + const SocketAddress& addr_remote); + + // Number of packets that clients have attempted to send through this virtual + // socket server. Intended to be used for test assertions. + uint32_t sent_packets() const RTC_LOCKS_EXCLUDED(mutex_); + + // Assign IP and Port if application's address is unspecified. Also apply + // `alternative_address_mapping_`. + SocketAddress AssignBindAddress(const SocketAddress& app_addr); + + // Binds the given socket to the given (fully-defined) address. + int Bind(VirtualSocket* socket, const SocketAddress& addr); + + int Unbind(const SocketAddress& addr, VirtualSocket* socket); + + // Adds a mapping between this socket pair and the socket. + void AddConnection(const SocketAddress& client, + const SocketAddress& server, + VirtualSocket* socket); + + // Connects the given socket to the socket at the given address + int Connect(VirtualSocket* socket, + const SocketAddress& remote_addr, + bool use_delay); + + // Sends a disconnect message to the socket at the given address + bool Disconnect(VirtualSocket* socket); + + // Lookup address, and disconnect corresponding socket. + bool Disconnect(const SocketAddress& addr); + + // Lookup connection, close corresponding socket. + bool Disconnect(const SocketAddress& local_addr, + const SocketAddress& remote_addr); + + // Sends the given packet to the socket at the given address (if one exists). + int SendUdp(VirtualSocket* socket, + const char* data, + size_t data_size, + const SocketAddress& remote_addr); + + // Moves as much data as possible from the sender's buffer to the network + void SendTcp(VirtualSocket* socket) RTC_LOCKS_EXCLUDED(mutex_); + + // Like above, but lookup sender by address. + void SendTcp(const SocketAddress& addr) RTC_LOCKS_EXCLUDED(mutex_); + + // Computes the number of milliseconds required to send a packet of this size. + uint32_t SendDelay(uint32_t size) RTC_LOCKS_EXCLUDED(mutex_); + + // Sending was previously blocked, but now isn't. + sigslot::signal0<> SignalReadyToSend; + + protected: + // Returns a new IP not used before in this network. + IPAddress GetNextIP(int family); + + // Find the socket bound to the given address + VirtualSocket* LookupBinding(const SocketAddress& addr); + + private: + friend VirtualSocket; + uint16_t GetNextPort(); + + // Find the socket pair corresponding to this server address. + VirtualSocket* LookupConnection(const SocketAddress& client, + const SocketAddress& server); + + void RemoveConnection(const SocketAddress& client, + const SocketAddress& server); + + // Places a packet on the network. + void AddPacketToNetwork(VirtualSocket* socket, + VirtualSocket* recipient, + int64_t cur_time, + const char* data, + size_t data_size, + size_t header_size, + bool ordered); + + // If the delay has been set for the address of the socket, returns the set + // delay. Otherwise, returns a random transit delay chosen from the + // appropriate distribution. + uint32_t GetTransitDelay(Socket* socket); + + // Basic operations on functions. + static std::unique_ptr<Function> Accumulate(std::unique_ptr<Function> f); + static std::unique_ptr<Function> Invert(std::unique_ptr<Function> f); + static std::unique_ptr<Function> Resample(std::unique_ptr<Function> f, + double x1, + double x2, + uint32_t samples); + static double Evaluate(const Function* f, double x); + + // Determine if two sockets should be able to communicate. + // We don't (currently) specify an address family for sockets; instead, + // the currently bound address is used to infer the address family. + // Any socket that is not explicitly bound to an IPv4 address is assumed to be + // dual-stack capable. + // This function tests if two addresses can communicate, as well as the + // sockets to which they may be bound (the addresses may or may not yet be + // bound to the sockets). + // First the addresses are tested (after normalization): + // If both have the same family, then communication is OK. + // If only one is IPv4 then false, unless the other is bound to ::. + // This applies even if the IPv4 address is 0.0.0.0. + // The socket arguments are optional; the sockets are checked to see if they + // were explicitly bound to IPv6-any ('::'), and if so communication is + // permitted. + // NB: This scheme doesn't permit non-dualstack IPv6 sockets. + static bool CanInteractWith(VirtualSocket* local, VirtualSocket* remote); + + typedef std::map<SocketAddress, VirtualSocket*> AddressMap; + typedef std::map<SocketAddressPair, VirtualSocket*> ConnectionMap; + + // May be null if the test doesn't use a fake clock, or it does but doesn't + // use ProcessMessagesUntilIdle. + ThreadProcessingFakeClock* fake_clock_ = nullptr; + + // Used to implement Wait/WakeUp. + Event wakeup_; + Thread* msg_queue_; + bool stop_on_idle_; + in_addr next_ipv4_; + in6_addr next_ipv6_; + uint16_t next_port_; + AddressMap* bindings_; + ConnectionMap* connections_; + + IPAddress default_source_address_v4_; + IPAddress default_source_address_v6_; + + mutable webrtc::Mutex mutex_; + + uint32_t bandwidth_ RTC_GUARDED_BY(mutex_); + uint32_t network_capacity_ RTC_GUARDED_BY(mutex_); + uint32_t send_buffer_capacity_ RTC_GUARDED_BY(mutex_); + uint32_t recv_buffer_capacity_ RTC_GUARDED_BY(mutex_); + uint32_t delay_mean_ RTC_GUARDED_BY(mutex_); + uint32_t delay_stddev_ RTC_GUARDED_BY(mutex_); + uint32_t delay_samples_ RTC_GUARDED_BY(mutex_); + + // Used for testing. + uint32_t sent_packets_ RTC_GUARDED_BY(mutex_) = 0; + + std::map<rtc::IPAddress, int> delay_by_ip_; + std::map<rtc::IPAddress, rtc::IPAddress> alternative_address_mapping_; + std::unique_ptr<Function> delay_dist_; + + double drop_prob_ RTC_GUARDED_BY(mutex_); + // The largest UDP payload permitted on this virtual socket server. + // The default is the max size of IPv4 fragmented UDP packet payload: + // 65535 bytes - 8 bytes UDP header - 20 bytes IP header. + size_t max_udp_payload_ RTC_GUARDED_BY(mutex_) = 65507; + + bool sending_blocked_ RTC_GUARDED_BY(mutex_) = false; +}; + +} // namespace rtc + +#endif // RTC_BASE_VIRTUAL_SOCKET_SERVER_H_ diff --git a/third_party/libwebrtc/rtc_base/virtual_socket_unittest.cc b/third_party/libwebrtc/rtc_base/virtual_socket_unittest.cc new file mode 100644 index 0000000000..67585b1fcd --- /dev/null +++ b/third_party/libwebrtc/rtc_base/virtual_socket_unittest.cc @@ -0,0 +1,1125 @@ +/* + * Copyright 2006 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 <math.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#if defined(WEBRTC_POSIX) +#include <netinet/in.h> +#endif + +#include <algorithm> +#include <memory> +#include <utility> + +#include "absl/memory/memory.h" +#include "api/units/time_delta.h" +#include "rtc_base/arraysize.h" +#include "rtc_base/async_packet_socket.h" +#include "rtc_base/async_udp_socket.h" +#include "rtc_base/fake_clock.h" +#include "rtc_base/gunit.h" +#include "rtc_base/ip_address.h" +#include "rtc_base/logging.h" +#include "rtc_base/socket.h" +#include "rtc_base/socket_address.h" +#include "rtc_base/task_utils/repeating_task.h" +#include "rtc_base/test_client.h" +#include "rtc_base/test_utils.h" +#include "rtc_base/third_party/sigslot/sigslot.h" +#include "rtc_base/thread.h" +#include "rtc_base/time_utils.h" +#include "rtc_base/virtual_socket_server.h" +#include "test/gtest.h" + +namespace rtc { +namespace { + +using ::webrtc::RepeatingTaskHandle; +using ::webrtc::TimeDelta; +using ::webrtc::testing::SSE_CLOSE; +using ::webrtc::testing::SSE_ERROR; +using ::webrtc::testing::SSE_OPEN; +using ::webrtc::testing::SSE_READ; +using ::webrtc::testing::SSE_WRITE; +using ::webrtc::testing::StreamSink; + +// Sends at a constant rate but with random packet sizes. +struct Sender { + Sender(Thread* th, Socket* s, uint32_t rt) + : thread(th), + socket(std::make_unique<AsyncUDPSocket>(s)), + rate(rt), + count(0) { + last_send = rtc::TimeMillis(); + + periodic = RepeatingTaskHandle::DelayedStart(thread, NextDelay(), [this] { + int64_t cur_time = rtc::TimeMillis(); + int64_t delay = cur_time - last_send; + uint32_t size = + std::clamp<uint32_t>(rate * delay / 1000, sizeof(uint32_t), 4096); + count += size; + memcpy(dummy, &cur_time, sizeof(cur_time)); + socket->Send(dummy, size, options); + + last_send = cur_time; + return NextDelay(); + }); + } + + TimeDelta NextDelay() { + int size = (rand() % 4096) + 1; + return TimeDelta::Seconds(1) * size / rate; + } + + Thread* thread; + std::unique_ptr<AsyncUDPSocket> socket; + rtc::PacketOptions options; + RepeatingTaskHandle periodic; + uint32_t rate; // bytes per second + uint32_t count; + int64_t last_send; + char dummy[4096]; +}; + +struct Receiver : public sigslot::has_slots<> { + Receiver(Thread* th, Socket* s, uint32_t bw) + : thread(th), + socket(std::make_unique<AsyncUDPSocket>(s)), + bandwidth(bw), + count(0), + sec_count(0), + sum(0), + sum_sq(0), + samples(0) { + socket->SignalReadPacket.connect(this, &Receiver::OnReadPacket); + periodic = RepeatingTaskHandle::DelayedStart( + thread, TimeDelta::Seconds(1), [this] { + // It is always possible for us to receive more than expected because + // packets can be further delayed in delivery. + if (bandwidth > 0) { + EXPECT_LE(sec_count, 5 * bandwidth / 4); + } + sec_count = 0; + return TimeDelta::Seconds(1); + }); + } + + ~Receiver() override { periodic.Stop(); } + + void OnReadPacket(AsyncPacketSocket* s, + const char* data, + size_t size, + const SocketAddress& remote_addr, + const int64_t& /* packet_time_us */) { + ASSERT_EQ(socket.get(), s); + ASSERT_GE(size, 4U); + + count += size; + sec_count += size; + + uint32_t send_time = *reinterpret_cast<const uint32_t*>(data); + uint32_t recv_time = rtc::TimeMillis(); + uint32_t delay = recv_time - send_time; + sum += delay; + sum_sq += delay * delay; + samples += 1; + } + + Thread* thread; + std::unique_ptr<AsyncUDPSocket> socket; + uint32_t bandwidth; + RepeatingTaskHandle periodic; + size_t count; + size_t sec_count; + double sum; + double sum_sq; + uint32_t samples; +}; + +// Note: This test uses a fake clock in addition to a virtual network. +class VirtualSocketServerTest : public ::testing::Test { + public: + VirtualSocketServerTest() + : ss_(&fake_clock_), + thread_(&ss_), + kIPv4AnyAddress(IPAddress(INADDR_ANY), 0), + kIPv6AnyAddress(IPAddress(in6addr_any), 0) {} + + void CheckPortIncrementalization(const SocketAddress& post, + const SocketAddress& pre) { + EXPECT_EQ(post.port(), pre.port() + 1); + IPAddress post_ip = post.ipaddr(); + IPAddress pre_ip = pre.ipaddr(); + EXPECT_EQ(pre_ip.family(), post_ip.family()); + if (post_ip.family() == AF_INET) { + in_addr pre_ipv4 = pre_ip.ipv4_address(); + in_addr post_ipv4 = post_ip.ipv4_address(); + EXPECT_EQ(post_ipv4.s_addr, pre_ipv4.s_addr); + } else if (post_ip.family() == AF_INET6) { + in6_addr post_ip6 = post_ip.ipv6_address(); + in6_addr pre_ip6 = pre_ip.ipv6_address(); + uint32_t* post_as_ints = reinterpret_cast<uint32_t*>(&post_ip6.s6_addr); + uint32_t* pre_as_ints = reinterpret_cast<uint32_t*>(&pre_ip6.s6_addr); + EXPECT_EQ(post_as_ints[3], pre_as_ints[3]); + } + } + + // Test a client can bind to the any address, and all sent packets will have + // the default source address. Also, it can receive packets sent to the + // default address. + void TestDefaultSourceAddress(const IPAddress& default_address) { + ss_.SetDefaultSourceAddress(default_address); + + // Create client1 bound to the any address. + Socket* socket = ss_.CreateSocket(default_address.family(), SOCK_DGRAM); + socket->Bind(EmptySocketAddressWithFamily(default_address.family())); + SocketAddress client1_any_addr = socket->GetLocalAddress(); + EXPECT_TRUE(client1_any_addr.IsAnyIP()); + auto client1 = std::make_unique<TestClient>( + std::make_unique<AsyncUDPSocket>(socket), &fake_clock_); + + // Create client2 bound to the address route. + Socket* socket2 = ss_.CreateSocket(default_address.family(), SOCK_DGRAM); + socket2->Bind(SocketAddress(default_address, 0)); + SocketAddress client2_addr = socket2->GetLocalAddress(); + EXPECT_FALSE(client2_addr.IsAnyIP()); + auto client2 = std::make_unique<TestClient>( + std::make_unique<AsyncUDPSocket>(socket2), &fake_clock_); + + // Client1 sends to client2, client2 should see the default address as + // client1's address. + SocketAddress client1_addr; + EXPECT_EQ(6, client1->SendTo("bizbaz", 6, client2_addr)); + EXPECT_TRUE(client2->CheckNextPacket("bizbaz", 6, &client1_addr)); + EXPECT_EQ(client1_addr, + SocketAddress(default_address, client1_any_addr.port())); + + // Client2 can send back to client1's default address. + EXPECT_EQ(3, client2->SendTo("foo", 3, client1_addr)); + EXPECT_TRUE(client1->CheckNextPacket("foo", 3, &client2_addr)); + } + + void BasicTest(const SocketAddress& initial_addr) { + Socket* socket = ss_.CreateSocket(initial_addr.family(), SOCK_DGRAM); + socket->Bind(initial_addr); + SocketAddress server_addr = socket->GetLocalAddress(); + // Make sure VSS didn't switch families on us. + EXPECT_EQ(server_addr.family(), initial_addr.family()); + + auto client1 = std::make_unique<TestClient>( + std::make_unique<AsyncUDPSocket>(socket), &fake_clock_); + Socket* socket2 = ss_.CreateSocket(initial_addr.family(), SOCK_DGRAM); + auto client2 = std::make_unique<TestClient>( + std::make_unique<AsyncUDPSocket>(socket2), &fake_clock_); + + SocketAddress client2_addr; + EXPECT_EQ(3, client2->SendTo("foo", 3, server_addr)); + EXPECT_TRUE(client1->CheckNextPacket("foo", 3, &client2_addr)); + + SocketAddress client1_addr; + EXPECT_EQ(6, client1->SendTo("bizbaz", 6, client2_addr)); + EXPECT_TRUE(client2->CheckNextPacket("bizbaz", 6, &client1_addr)); + EXPECT_EQ(client1_addr, server_addr); + + SocketAddress empty = EmptySocketAddressWithFamily(initial_addr.family()); + for (int i = 0; i < 10; i++) { + client2 = std::make_unique<TestClient>( + absl::WrapUnique(AsyncUDPSocket::Create(&ss_, empty)), &fake_clock_); + + SocketAddress next_client2_addr; + EXPECT_EQ(3, client2->SendTo("foo", 3, server_addr)); + EXPECT_TRUE(client1->CheckNextPacket("foo", 3, &next_client2_addr)); + CheckPortIncrementalization(next_client2_addr, client2_addr); + // EXPECT_EQ(next_client2_addr.port(), client2_addr.port() + 1); + + SocketAddress server_addr2; + EXPECT_EQ(6, client1->SendTo("bizbaz", 6, next_client2_addr)); + EXPECT_TRUE(client2->CheckNextPacket("bizbaz", 6, &server_addr2)); + EXPECT_EQ(server_addr2, server_addr); + + client2_addr = next_client2_addr; + } + } + + // initial_addr should be made from either INADDR_ANY or in6addr_any. + void ConnectTest(const SocketAddress& initial_addr) { + StreamSink sink; + SocketAddress accept_addr; + const SocketAddress kEmptyAddr = + EmptySocketAddressWithFamily(initial_addr.family()); + + // Create client + std::unique_ptr<Socket> client = + absl::WrapUnique(ss_.CreateSocket(initial_addr.family(), SOCK_STREAM)); + sink.Monitor(client.get()); + EXPECT_EQ(client->GetState(), Socket::CS_CLOSED); + EXPECT_TRUE(client->GetLocalAddress().IsNil()); + + // Create server + std::unique_ptr<Socket> server = + absl::WrapUnique(ss_.CreateSocket(initial_addr.family(), SOCK_STREAM)); + sink.Monitor(server.get()); + EXPECT_NE(0, server->Listen(5)); // Bind required + EXPECT_EQ(0, server->Bind(initial_addr)); + EXPECT_EQ(server->GetLocalAddress().family(), initial_addr.family()); + EXPECT_EQ(0, server->Listen(5)); + EXPECT_EQ(server->GetState(), Socket::CS_CONNECTING); + + // No pending server connections + EXPECT_FALSE(sink.Check(server.get(), SSE_READ)); + EXPECT_TRUE(nullptr == server->Accept(&accept_addr)); + EXPECT_EQ(AF_UNSPEC, accept_addr.family()); + + // Attempt connect to listening socket + EXPECT_EQ(0, client->Connect(server->GetLocalAddress())); + EXPECT_NE(client->GetLocalAddress(), kEmptyAddr); // Implicit Bind + EXPECT_NE(AF_UNSPEC, client->GetLocalAddress().family()); // Implicit Bind + EXPECT_NE(client->GetLocalAddress(), server->GetLocalAddress()); + + // Client is connecting + EXPECT_EQ(client->GetState(), Socket::CS_CONNECTING); + EXPECT_FALSE(sink.Check(client.get(), SSE_OPEN)); + EXPECT_FALSE(sink.Check(client.get(), SSE_CLOSE)); + + ss_.ProcessMessagesUntilIdle(); + + // Client still connecting + EXPECT_EQ(client->GetState(), Socket::CS_CONNECTING); + EXPECT_FALSE(sink.Check(client.get(), SSE_OPEN)); + EXPECT_FALSE(sink.Check(client.get(), SSE_CLOSE)); + + // Server has pending connection + EXPECT_TRUE(sink.Check(server.get(), SSE_READ)); + std::unique_ptr<Socket> accepted = + absl::WrapUnique(server->Accept(&accept_addr)); + EXPECT_TRUE(nullptr != accepted); + EXPECT_NE(accept_addr, kEmptyAddr); + EXPECT_EQ(accepted->GetRemoteAddress(), accept_addr); + + EXPECT_EQ(accepted->GetState(), Socket::CS_CONNECTED); + EXPECT_EQ(accepted->GetLocalAddress(), server->GetLocalAddress()); + EXPECT_EQ(accepted->GetRemoteAddress(), client->GetLocalAddress()); + + ss_.ProcessMessagesUntilIdle(); + + // Client has connected + EXPECT_EQ(client->GetState(), Socket::CS_CONNECTED); + EXPECT_TRUE(sink.Check(client.get(), SSE_OPEN)); + EXPECT_FALSE(sink.Check(client.get(), SSE_CLOSE)); + EXPECT_EQ(client->GetRemoteAddress(), server->GetLocalAddress()); + EXPECT_EQ(client->GetRemoteAddress(), accepted->GetLocalAddress()); + } + + void ConnectToNonListenerTest(const SocketAddress& initial_addr) { + StreamSink sink; + SocketAddress accept_addr; + const SocketAddress nil_addr; + const SocketAddress empty_addr = + EmptySocketAddressWithFamily(initial_addr.family()); + + // Create client + std::unique_ptr<Socket> client = + absl::WrapUnique(ss_.CreateSocket(initial_addr.family(), SOCK_STREAM)); + sink.Monitor(client.get()); + + // Create server + std::unique_ptr<Socket> server = + absl::WrapUnique(ss_.CreateSocket(initial_addr.family(), SOCK_STREAM)); + sink.Monitor(server.get()); + EXPECT_EQ(0, server->Bind(initial_addr)); + EXPECT_EQ(server->GetLocalAddress().family(), initial_addr.family()); + // Attempt connect to non-listening socket + EXPECT_EQ(0, client->Connect(server->GetLocalAddress())); + + ss_.ProcessMessagesUntilIdle(); + + // No pending server connections + EXPECT_FALSE(sink.Check(server.get(), SSE_READ)); + EXPECT_TRUE(nullptr == server->Accept(&accept_addr)); + EXPECT_EQ(accept_addr, nil_addr); + + // Connection failed + EXPECT_EQ(client->GetState(), Socket::CS_CLOSED); + EXPECT_FALSE(sink.Check(client.get(), SSE_OPEN)); + EXPECT_TRUE(sink.Check(client.get(), SSE_ERROR)); + EXPECT_EQ(client->GetRemoteAddress(), nil_addr); + } + + void CloseDuringConnectTest(const SocketAddress& initial_addr) { + StreamSink sink; + SocketAddress accept_addr; + const SocketAddress empty_addr = + EmptySocketAddressWithFamily(initial_addr.family()); + + // Create client and server + std::unique_ptr<Socket> client( + ss_.CreateSocket(initial_addr.family(), SOCK_STREAM)); + sink.Monitor(client.get()); + std::unique_ptr<Socket> server( + ss_.CreateSocket(initial_addr.family(), SOCK_STREAM)); + sink.Monitor(server.get()); + + // Initiate connect + EXPECT_EQ(0, server->Bind(initial_addr)); + EXPECT_EQ(server->GetLocalAddress().family(), initial_addr.family()); + + EXPECT_EQ(0, server->Listen(5)); + EXPECT_EQ(0, client->Connect(server->GetLocalAddress())); + + // Server close before socket enters accept queue + EXPECT_FALSE(sink.Check(server.get(), SSE_READ)); + server->Close(); + + ss_.ProcessMessagesUntilIdle(); + + // Result: connection failed + EXPECT_EQ(client->GetState(), Socket::CS_CLOSED); + EXPECT_TRUE(sink.Check(client.get(), SSE_ERROR)); + + server.reset(ss_.CreateSocket(initial_addr.family(), SOCK_STREAM)); + sink.Monitor(server.get()); + + // Initiate connect + EXPECT_EQ(0, server->Bind(initial_addr)); + EXPECT_EQ(server->GetLocalAddress().family(), initial_addr.family()); + + EXPECT_EQ(0, server->Listen(5)); + EXPECT_EQ(0, client->Connect(server->GetLocalAddress())); + + ss_.ProcessMessagesUntilIdle(); + + // Server close while socket is in accept queue + EXPECT_TRUE(sink.Check(server.get(), SSE_READ)); + server->Close(); + + ss_.ProcessMessagesUntilIdle(); + + // Result: connection failed + EXPECT_EQ(client->GetState(), Socket::CS_CLOSED); + EXPECT_TRUE(sink.Check(client.get(), SSE_ERROR)); + + // New server + server.reset(ss_.CreateSocket(initial_addr.family(), SOCK_STREAM)); + sink.Monitor(server.get()); + + // Initiate connect + EXPECT_EQ(0, server->Bind(initial_addr)); + EXPECT_EQ(server->GetLocalAddress().family(), initial_addr.family()); + + EXPECT_EQ(0, server->Listen(5)); + EXPECT_EQ(0, client->Connect(server->GetLocalAddress())); + + ss_.ProcessMessagesUntilIdle(); + + // Server accepts connection + EXPECT_TRUE(sink.Check(server.get(), SSE_READ)); + std::unique_ptr<Socket> accepted(server->Accept(&accept_addr)); + ASSERT_TRUE(nullptr != accepted.get()); + sink.Monitor(accepted.get()); + + // Client closes before connection complets + EXPECT_EQ(accepted->GetState(), Socket::CS_CONNECTED); + + // Connected message has not been processed yet. + EXPECT_EQ(client->GetState(), Socket::CS_CONNECTING); + client->Close(); + + ss_.ProcessMessagesUntilIdle(); + + // Result: accepted socket closes + EXPECT_EQ(accepted->GetState(), Socket::CS_CLOSED); + EXPECT_TRUE(sink.Check(accepted.get(), SSE_CLOSE)); + EXPECT_FALSE(sink.Check(client.get(), SSE_CLOSE)); + } + + void CloseTest(const SocketAddress& initial_addr) { + StreamSink sink; + const SocketAddress kEmptyAddr; + + // Create clients + std::unique_ptr<Socket> a = + absl::WrapUnique(ss_.CreateSocket(initial_addr.family(), SOCK_STREAM)); + sink.Monitor(a.get()); + a->Bind(initial_addr); + EXPECT_EQ(a->GetLocalAddress().family(), initial_addr.family()); + + std::unique_ptr<Socket> b = + absl::WrapUnique(ss_.CreateSocket(initial_addr.family(), SOCK_STREAM)); + sink.Monitor(b.get()); + b->Bind(initial_addr); + EXPECT_EQ(b->GetLocalAddress().family(), initial_addr.family()); + + EXPECT_EQ(0, a->Connect(b->GetLocalAddress())); + EXPECT_EQ(0, b->Connect(a->GetLocalAddress())); + + ss_.ProcessMessagesUntilIdle(); + + EXPECT_TRUE(sink.Check(a.get(), SSE_OPEN)); + EXPECT_EQ(a->GetState(), Socket::CS_CONNECTED); + EXPECT_EQ(a->GetRemoteAddress(), b->GetLocalAddress()); + + EXPECT_TRUE(sink.Check(b.get(), SSE_OPEN)); + EXPECT_EQ(b->GetState(), Socket::CS_CONNECTED); + EXPECT_EQ(b->GetRemoteAddress(), a->GetLocalAddress()); + + EXPECT_EQ(1, a->Send("a", 1)); + b->Close(); + EXPECT_EQ(1, a->Send("b", 1)); + + ss_.ProcessMessagesUntilIdle(); + + char buffer[10]; + EXPECT_FALSE(sink.Check(b.get(), SSE_READ)); + EXPECT_EQ(-1, b->Recv(buffer, 10, nullptr)); + + EXPECT_TRUE(sink.Check(a.get(), SSE_CLOSE)); + EXPECT_EQ(a->GetState(), Socket::CS_CLOSED); + EXPECT_EQ(a->GetRemoteAddress(), kEmptyAddr); + + // No signal for Closer + EXPECT_FALSE(sink.Check(b.get(), SSE_CLOSE)); + EXPECT_EQ(b->GetState(), Socket::CS_CLOSED); + EXPECT_EQ(b->GetRemoteAddress(), kEmptyAddr); + } + + void TcpSendTest(const SocketAddress& initial_addr) { + StreamSink sink; + const SocketAddress kEmptyAddr; + + // Connect two sockets + std::unique_ptr<Socket> a = + absl::WrapUnique(ss_.CreateSocket(initial_addr.family(), SOCK_STREAM)); + sink.Monitor(a.get()); + a->Bind(initial_addr); + EXPECT_EQ(a->GetLocalAddress().family(), initial_addr.family()); + + std::unique_ptr<Socket> b = + absl::WrapUnique(ss_.CreateSocket(initial_addr.family(), SOCK_STREAM)); + sink.Monitor(b.get()); + b->Bind(initial_addr); + EXPECT_EQ(b->GetLocalAddress().family(), initial_addr.family()); + + EXPECT_EQ(0, a->Connect(b->GetLocalAddress())); + EXPECT_EQ(0, b->Connect(a->GetLocalAddress())); + + ss_.ProcessMessagesUntilIdle(); + + const size_t kBufferSize = 2000; + ss_.set_send_buffer_capacity(kBufferSize); + ss_.set_recv_buffer_capacity(kBufferSize); + + const size_t kDataSize = 5000; + char send_buffer[kDataSize], recv_buffer[kDataSize]; + for (size_t i = 0; i < kDataSize; ++i) + send_buffer[i] = static_cast<char>(i % 256); + memset(recv_buffer, 0, sizeof(recv_buffer)); + size_t send_pos = 0, recv_pos = 0; + + // Can't send more than send buffer in one write + int result = a->Send(send_buffer + send_pos, kDataSize - send_pos); + EXPECT_EQ(static_cast<int>(kBufferSize), result); + send_pos += result; + + ss_.ProcessMessagesUntilIdle(); + EXPECT_FALSE(sink.Check(a.get(), SSE_WRITE)); + EXPECT_TRUE(sink.Check(b.get(), SSE_READ)); + + // Receive buffer is already filled, fill send buffer again + result = a->Send(send_buffer + send_pos, kDataSize - send_pos); + EXPECT_EQ(static_cast<int>(kBufferSize), result); + send_pos += result; + + ss_.ProcessMessagesUntilIdle(); + EXPECT_FALSE(sink.Check(a.get(), SSE_WRITE)); + EXPECT_FALSE(sink.Check(b.get(), SSE_READ)); + + // No more room in send or receive buffer + result = a->Send(send_buffer + send_pos, kDataSize - send_pos); + EXPECT_EQ(-1, result); + EXPECT_TRUE(a->IsBlocking()); + + // Read a subset of the data + result = b->Recv(recv_buffer + recv_pos, 500, nullptr); + EXPECT_EQ(500, result); + recv_pos += result; + + ss_.ProcessMessagesUntilIdle(); + EXPECT_TRUE(sink.Check(a.get(), SSE_WRITE)); + EXPECT_TRUE(sink.Check(b.get(), SSE_READ)); + + // Room for more on the sending side + result = a->Send(send_buffer + send_pos, kDataSize - send_pos); + EXPECT_EQ(500, result); + send_pos += result; + + // Empty the recv buffer + while (true) { + result = b->Recv(recv_buffer + recv_pos, kDataSize - recv_pos, nullptr); + if (result < 0) { + EXPECT_EQ(-1, result); + EXPECT_TRUE(b->IsBlocking()); + break; + } + recv_pos += result; + } + + ss_.ProcessMessagesUntilIdle(); + EXPECT_TRUE(sink.Check(b.get(), SSE_READ)); + + // Continue to empty the recv buffer + while (true) { + result = b->Recv(recv_buffer + recv_pos, kDataSize - recv_pos, nullptr); + if (result < 0) { + EXPECT_EQ(-1, result); + EXPECT_TRUE(b->IsBlocking()); + break; + } + recv_pos += result; + } + + // Send last of the data + result = a->Send(send_buffer + send_pos, kDataSize - send_pos); + EXPECT_EQ(500, result); + send_pos += result; + + ss_.ProcessMessagesUntilIdle(); + EXPECT_TRUE(sink.Check(b.get(), SSE_READ)); + + // Receive the last of the data + while (true) { + result = b->Recv(recv_buffer + recv_pos, kDataSize - recv_pos, nullptr); + if (result < 0) { + EXPECT_EQ(-1, result); + EXPECT_TRUE(b->IsBlocking()); + break; + } + recv_pos += result; + } + + ss_.ProcessMessagesUntilIdle(); + EXPECT_FALSE(sink.Check(b.get(), SSE_READ)); + + // The received data matches the sent data + EXPECT_EQ(kDataSize, send_pos); + EXPECT_EQ(kDataSize, recv_pos); + EXPECT_EQ(0, memcmp(recv_buffer, send_buffer, kDataSize)); + } + + void TcpSendsPacketsInOrderTest(const SocketAddress& initial_addr) { + const SocketAddress kEmptyAddr; + + // Connect two sockets + std::unique_ptr<Socket> a = + absl::WrapUnique(ss_.CreateSocket(initial_addr.family(), SOCK_STREAM)); + std::unique_ptr<Socket> b = + absl::WrapUnique(ss_.CreateSocket(initial_addr.family(), SOCK_STREAM)); + a->Bind(initial_addr); + EXPECT_EQ(a->GetLocalAddress().family(), initial_addr.family()); + + b->Bind(initial_addr); + EXPECT_EQ(b->GetLocalAddress().family(), initial_addr.family()); + + EXPECT_EQ(0, a->Connect(b->GetLocalAddress())); + EXPECT_EQ(0, b->Connect(a->GetLocalAddress())); + ss_.ProcessMessagesUntilIdle(); + + // First, deliver all packets in 0 ms. + char buffer[2] = {0, 0}; + const char cNumPackets = 10; + for (char i = 0; i < cNumPackets; ++i) { + buffer[0] = '0' + i; + EXPECT_EQ(1, a->Send(buffer, 1)); + } + + ss_.ProcessMessagesUntilIdle(); + + for (char i = 0; i < cNumPackets; ++i) { + EXPECT_EQ(1, b->Recv(buffer, sizeof(buffer), nullptr)); + EXPECT_EQ(static_cast<char>('0' + i), buffer[0]); + } + + // Next, deliver packets at random intervals + const uint32_t mean = 50; + const uint32_t stddev = 50; + + ss_.set_delay_mean(mean); + ss_.set_delay_stddev(stddev); + ss_.UpdateDelayDistribution(); + + for (char i = 0; i < cNumPackets; ++i) { + buffer[0] = 'A' + i; + EXPECT_EQ(1, a->Send(buffer, 1)); + } + + ss_.ProcessMessagesUntilIdle(); + + for (char i = 0; i < cNumPackets; ++i) { + EXPECT_EQ(1, b->Recv(buffer, sizeof(buffer), nullptr)); + EXPECT_EQ(static_cast<char>('A' + i), buffer[0]); + } + } + + // It is important that initial_addr's port has to be 0 such that the + // incremental port behavior could ensure the 2 Binds result in different + // address. + void BandwidthTest(const SocketAddress& initial_addr) { + Socket* send_socket = ss_.CreateSocket(initial_addr.family(), SOCK_DGRAM); + Socket* recv_socket = ss_.CreateSocket(initial_addr.family(), SOCK_DGRAM); + ASSERT_EQ(0, send_socket->Bind(initial_addr)); + ASSERT_EQ(0, recv_socket->Bind(initial_addr)); + EXPECT_EQ(send_socket->GetLocalAddress().family(), initial_addr.family()); + EXPECT_EQ(recv_socket->GetLocalAddress().family(), initial_addr.family()); + ASSERT_EQ(0, send_socket->Connect(recv_socket->GetLocalAddress())); + + uint32_t bandwidth = 64 * 1024; + ss_.set_bandwidth(bandwidth); + + Thread* pthMain = Thread::Current(); + Sender sender(pthMain, send_socket, 80 * 1024); + Receiver receiver(pthMain, recv_socket, bandwidth); + + // Allow the sender to run for 5 (simulated) seconds, then be stopped for 5 + // seconds. + SIMULATED_WAIT(false, 5000, fake_clock_); + sender.periodic.Stop(); + SIMULATED_WAIT(false, 5000, fake_clock_); + + // Ensure the observed bandwidth fell within a reasonable margin of error. + EXPECT_TRUE(receiver.count >= 5 * 3 * bandwidth / 4); + EXPECT_TRUE(receiver.count <= 6 * bandwidth); // queue could drain for 1s + + ss_.set_bandwidth(0); + } + + // It is important that initial_addr's port has to be 0 such that the + // incremental port behavior could ensure the 2 Binds result in different + // address. + void DelayTest(const SocketAddress& initial_addr) { + time_t seed = ::time(nullptr); + RTC_LOG(LS_VERBOSE) << "seed = " << seed; + srand(static_cast<unsigned int>(seed)); + + const uint32_t mean = 2000; + const uint32_t stddev = 500; + + ss_.set_delay_mean(mean); + ss_.set_delay_stddev(stddev); + ss_.UpdateDelayDistribution(); + + Socket* send_socket = ss_.CreateSocket(initial_addr.family(), SOCK_DGRAM); + Socket* recv_socket = ss_.CreateSocket(initial_addr.family(), SOCK_DGRAM); + ASSERT_EQ(0, send_socket->Bind(initial_addr)); + ASSERT_EQ(0, recv_socket->Bind(initial_addr)); + EXPECT_EQ(send_socket->GetLocalAddress().family(), initial_addr.family()); + EXPECT_EQ(recv_socket->GetLocalAddress().family(), initial_addr.family()); + ASSERT_EQ(0, send_socket->Connect(recv_socket->GetLocalAddress())); + + Thread* pthMain = Thread::Current(); + // Avg packet size is 2K, so at 200KB/s for 10s, we should see about + // 1000 packets, which is necessary to get a good distribution. + Sender sender(pthMain, send_socket, 100 * 2 * 1024); + Receiver receiver(pthMain, recv_socket, 0); + + // Simulate 10 seconds of packets being sent, then check the observed delay + // distribution. + SIMULATED_WAIT(false, 10000, fake_clock_); + sender.periodic.Stop(); + receiver.periodic.Stop(); + ss_.ProcessMessagesUntilIdle(); + + const double sample_mean = receiver.sum / receiver.samples; + double num = + receiver.samples * receiver.sum_sq - receiver.sum * receiver.sum; + double den = receiver.samples * (receiver.samples - 1); + const double sample_stddev = sqrt(num / den); + RTC_LOG(LS_VERBOSE) << "mean=" << sample_mean + << " stddev=" << sample_stddev; + + EXPECT_LE(500u, receiver.samples); + // We initially used a 0.1 fudge factor, but on the build machine, we + // have seen the value differ by as much as 0.13. + EXPECT_NEAR(mean, sample_mean, 0.15 * mean); + EXPECT_NEAR(stddev, sample_stddev, 0.15 * stddev); + + ss_.set_delay_mean(0); + ss_.set_delay_stddev(0); + ss_.UpdateDelayDistribution(); + } + + // Test cross-family communication between a client bound to client_addr and a + // server bound to server_addr. shouldSucceed indicates if communication is + // expected to work or not. + void CrossFamilyConnectionTest(const SocketAddress& client_addr, + const SocketAddress& server_addr, + bool shouldSucceed) { + StreamSink sink; + SocketAddress accept_address; + const SocketAddress kEmptyAddr; + + // Client gets a IPv4 address + std::unique_ptr<Socket> client = + absl::WrapUnique(ss_.CreateSocket(client_addr.family(), SOCK_STREAM)); + sink.Monitor(client.get()); + EXPECT_EQ(client->GetState(), Socket::CS_CLOSED); + EXPECT_EQ(client->GetLocalAddress(), kEmptyAddr); + client->Bind(client_addr); + + // Server gets a non-mapped non-any IPv6 address. + // IPv4 sockets should not be able to connect to this. + std::unique_ptr<Socket> server = + absl::WrapUnique(ss_.CreateSocket(server_addr.family(), SOCK_STREAM)); + sink.Monitor(server.get()); + server->Bind(server_addr); + server->Listen(5); + + if (shouldSucceed) { + EXPECT_EQ(0, client->Connect(server->GetLocalAddress())); + ss_.ProcessMessagesUntilIdle(); + EXPECT_TRUE(sink.Check(server.get(), SSE_READ)); + std::unique_ptr<Socket> accepted = + absl::WrapUnique(server->Accept(&accept_address)); + EXPECT_TRUE(nullptr != accepted); + EXPECT_NE(kEmptyAddr, accept_address); + ss_.ProcessMessagesUntilIdle(); + EXPECT_TRUE(sink.Check(client.get(), SSE_OPEN)); + EXPECT_EQ(client->GetRemoteAddress(), server->GetLocalAddress()); + } else { + // Check that the connection failed. + EXPECT_EQ(-1, client->Connect(server->GetLocalAddress())); + ss_.ProcessMessagesUntilIdle(); + + EXPECT_FALSE(sink.Check(server.get(), SSE_READ)); + EXPECT_TRUE(nullptr == server->Accept(&accept_address)); + EXPECT_EQ(accept_address, kEmptyAddr); + EXPECT_EQ(client->GetState(), Socket::CS_CLOSED); + EXPECT_FALSE(sink.Check(client.get(), SSE_OPEN)); + EXPECT_EQ(client->GetRemoteAddress(), kEmptyAddr); + } + } + + // Test cross-family datagram sending between a client bound to client_addr + // and a server bound to server_addr. shouldSucceed indicates if sending is + // expected to succeed or not. + void CrossFamilyDatagramTest(const SocketAddress& client_addr, + const SocketAddress& server_addr, + bool shouldSucceed) { + Socket* socket = ss_.CreateSocket(AF_INET, SOCK_DGRAM); + socket->Bind(server_addr); + SocketAddress bound_server_addr = socket->GetLocalAddress(); + auto client1 = std::make_unique<TestClient>( + std::make_unique<AsyncUDPSocket>(socket), &fake_clock_); + + Socket* socket2 = ss_.CreateSocket(AF_INET, SOCK_DGRAM); + socket2->Bind(client_addr); + auto client2 = std::make_unique<TestClient>( + std::make_unique<AsyncUDPSocket>(socket2), &fake_clock_); + SocketAddress client2_addr; + + if (shouldSucceed) { + EXPECT_EQ(3, client2->SendTo("foo", 3, bound_server_addr)); + EXPECT_TRUE(client1->CheckNextPacket("foo", 3, &client2_addr)); + SocketAddress client1_addr; + EXPECT_EQ(6, client1->SendTo("bizbaz", 6, client2_addr)); + EXPECT_TRUE(client2->CheckNextPacket("bizbaz", 6, &client1_addr)); + EXPECT_EQ(client1_addr, bound_server_addr); + } else { + EXPECT_EQ(-1, client2->SendTo("foo", 3, bound_server_addr)); + EXPECT_TRUE(client1->CheckNoPacket()); + } + } + + protected: + rtc::ScopedFakeClock fake_clock_; + VirtualSocketServer ss_; + AutoSocketServerThread thread_; + const SocketAddress kIPv4AnyAddress; + const SocketAddress kIPv6AnyAddress; +}; + +TEST_F(VirtualSocketServerTest, basic_v4) { + SocketAddress ipv4_test_addr(IPAddress(INADDR_ANY), 5000); + BasicTest(ipv4_test_addr); +} + +TEST_F(VirtualSocketServerTest, basic_v6) { + SocketAddress ipv6_test_addr(IPAddress(in6addr_any), 5000); + BasicTest(ipv6_test_addr); +} + +TEST_F(VirtualSocketServerTest, TestDefaultRoute_v4) { + IPAddress ipv4_default_addr(0x01020304); + TestDefaultSourceAddress(ipv4_default_addr); +} + +TEST_F(VirtualSocketServerTest, TestDefaultRoute_v6) { + IPAddress ipv6_default_addr; + EXPECT_TRUE( + IPFromString("2401:fa00:4:1000:be30:5bff:fee5:c3", &ipv6_default_addr)); + TestDefaultSourceAddress(ipv6_default_addr); +} + +TEST_F(VirtualSocketServerTest, connect_v4) { + ConnectTest(kIPv4AnyAddress); +} + +TEST_F(VirtualSocketServerTest, connect_v6) { + ConnectTest(kIPv6AnyAddress); +} + +TEST_F(VirtualSocketServerTest, connect_to_non_listener_v4) { + ConnectToNonListenerTest(kIPv4AnyAddress); +} + +TEST_F(VirtualSocketServerTest, connect_to_non_listener_v6) { + ConnectToNonListenerTest(kIPv6AnyAddress); +} + +TEST_F(VirtualSocketServerTest, close_during_connect_v4) { + CloseDuringConnectTest(kIPv4AnyAddress); +} + +TEST_F(VirtualSocketServerTest, close_during_connect_v6) { + CloseDuringConnectTest(kIPv6AnyAddress); +} + +TEST_F(VirtualSocketServerTest, close_v4) { + CloseTest(kIPv4AnyAddress); +} + +TEST_F(VirtualSocketServerTest, close_v6) { + CloseTest(kIPv6AnyAddress); +} + +TEST_F(VirtualSocketServerTest, tcp_send_v4) { + TcpSendTest(kIPv4AnyAddress); +} + +TEST_F(VirtualSocketServerTest, tcp_send_v6) { + TcpSendTest(kIPv6AnyAddress); +} + +TEST_F(VirtualSocketServerTest, TcpSendsPacketsInOrder_v4) { + TcpSendsPacketsInOrderTest(kIPv4AnyAddress); +} + +TEST_F(VirtualSocketServerTest, TcpSendsPacketsInOrder_v6) { + TcpSendsPacketsInOrderTest(kIPv6AnyAddress); +} + +TEST_F(VirtualSocketServerTest, bandwidth_v4) { + BandwidthTest(kIPv4AnyAddress); +} + +TEST_F(VirtualSocketServerTest, bandwidth_v6) { + BandwidthTest(kIPv6AnyAddress); +} + +TEST_F(VirtualSocketServerTest, delay_v4) { + DelayTest(kIPv4AnyAddress); +} + +TEST_F(VirtualSocketServerTest, delay_v6) { + DelayTest(kIPv6AnyAddress); +} + +// Works, receiving socket sees 127.0.0.2. +TEST_F(VirtualSocketServerTest, CanConnectFromMappedIPv6ToIPv4Any) { + CrossFamilyConnectionTest(SocketAddress("::ffff:127.0.0.2", 0), + SocketAddress("0.0.0.0", 5000), true); +} + +// Fails. +TEST_F(VirtualSocketServerTest, CantConnectFromUnMappedIPv6ToIPv4Any) { + CrossFamilyConnectionTest(SocketAddress("::2", 0), + SocketAddress("0.0.0.0", 5000), false); +} + +// Fails. +TEST_F(VirtualSocketServerTest, CantConnectFromUnMappedIPv6ToMappedIPv6) { + CrossFamilyConnectionTest(SocketAddress("::2", 0), + SocketAddress("::ffff:127.0.0.1", 5000), false); +} + +// Works. receiving socket sees ::ffff:127.0.0.2. +TEST_F(VirtualSocketServerTest, CanConnectFromIPv4ToIPv6Any) { + CrossFamilyConnectionTest(SocketAddress("127.0.0.2", 0), + SocketAddress("::", 5000), true); +} + +// Fails. +TEST_F(VirtualSocketServerTest, CantConnectFromIPv4ToUnMappedIPv6) { + CrossFamilyConnectionTest(SocketAddress("127.0.0.2", 0), + SocketAddress("::1", 5000), false); +} + +// Works. Receiving socket sees ::ffff:127.0.0.1. +TEST_F(VirtualSocketServerTest, CanConnectFromIPv4ToMappedIPv6) { + CrossFamilyConnectionTest(SocketAddress("127.0.0.1", 0), + SocketAddress("::ffff:127.0.0.2", 5000), true); +} + +// Works, receiving socket sees a result from GetNextIP. +TEST_F(VirtualSocketServerTest, CanConnectFromUnboundIPv6ToIPv4Any) { + CrossFamilyConnectionTest(SocketAddress("::", 0), + SocketAddress("0.0.0.0", 5000), true); +} + +// Works, receiving socket sees whatever GetNextIP gave the client. +TEST_F(VirtualSocketServerTest, CanConnectFromUnboundIPv4ToIPv6Any) { + CrossFamilyConnectionTest(SocketAddress("0.0.0.0", 0), + SocketAddress("::", 5000), true); +} + +TEST_F(VirtualSocketServerTest, CanSendDatagramFromUnboundIPv4ToIPv6Any) { + CrossFamilyDatagramTest(SocketAddress("0.0.0.0", 0), + SocketAddress("::", 5000), true); +} + +TEST_F(VirtualSocketServerTest, CanSendDatagramFromMappedIPv6ToIPv4Any) { + CrossFamilyDatagramTest(SocketAddress("::ffff:127.0.0.1", 0), + SocketAddress("0.0.0.0", 5000), true); +} + +TEST_F(VirtualSocketServerTest, CantSendDatagramFromUnMappedIPv6ToIPv4Any) { + CrossFamilyDatagramTest(SocketAddress("::2", 0), + SocketAddress("0.0.0.0", 5000), false); +} + +TEST_F(VirtualSocketServerTest, CantSendDatagramFromUnMappedIPv6ToMappedIPv6) { + CrossFamilyDatagramTest(SocketAddress("::2", 0), + SocketAddress("::ffff:127.0.0.1", 5000), false); +} + +TEST_F(VirtualSocketServerTest, CanSendDatagramFromIPv4ToIPv6Any) { + CrossFamilyDatagramTest(SocketAddress("127.0.0.2", 0), + SocketAddress("::", 5000), true); +} + +TEST_F(VirtualSocketServerTest, CantSendDatagramFromIPv4ToUnMappedIPv6) { + CrossFamilyDatagramTest(SocketAddress("127.0.0.2", 0), + SocketAddress("::1", 5000), false); +} + +TEST_F(VirtualSocketServerTest, CanSendDatagramFromIPv4ToMappedIPv6) { + CrossFamilyDatagramTest(SocketAddress("127.0.0.1", 0), + SocketAddress("::ffff:127.0.0.2", 5000), true); +} + +TEST_F(VirtualSocketServerTest, CanSendDatagramFromUnboundIPv6ToIPv4Any) { + CrossFamilyDatagramTest(SocketAddress("::", 0), + SocketAddress("0.0.0.0", 5000), true); +} + +TEST_F(VirtualSocketServerTest, SetSendingBlockedWithUdpSocket) { + Socket* socket1 = ss_.CreateSocket(kIPv4AnyAddress.family(), SOCK_DGRAM); + std::unique_ptr<Socket> socket2 = + absl::WrapUnique(ss_.CreateSocket(kIPv4AnyAddress.family(), SOCK_DGRAM)); + socket1->Bind(kIPv4AnyAddress); + socket2->Bind(kIPv4AnyAddress); + auto client1 = std::make_unique<TestClient>( + std::make_unique<AsyncUDPSocket>(socket1), &fake_clock_); + + ss_.SetSendingBlocked(true); + EXPECT_EQ(-1, client1->SendTo("foo", 3, socket2->GetLocalAddress())); + EXPECT_TRUE(socket1->IsBlocking()); + EXPECT_EQ(0, client1->ready_to_send_count()); + + ss_.SetSendingBlocked(false); + EXPECT_EQ(1, client1->ready_to_send_count()); + EXPECT_EQ(3, client1->SendTo("foo", 3, socket2->GetLocalAddress())); +} + +TEST_F(VirtualSocketServerTest, SetSendingBlockedWithTcpSocket) { + constexpr size_t kBufferSize = 1024; + ss_.set_send_buffer_capacity(kBufferSize); + ss_.set_recv_buffer_capacity(kBufferSize); + + StreamSink sink; + std::unique_ptr<Socket> socket1 = + absl::WrapUnique(ss_.CreateSocket(kIPv4AnyAddress.family(), SOCK_STREAM)); + std::unique_ptr<Socket> socket2 = + absl::WrapUnique(ss_.CreateSocket(kIPv4AnyAddress.family(), SOCK_STREAM)); + sink.Monitor(socket1.get()); + sink.Monitor(socket2.get()); + socket1->Bind(kIPv4AnyAddress); + socket2->Bind(kIPv4AnyAddress); + + // Connect sockets. + EXPECT_EQ(0, socket1->Connect(socket2->GetLocalAddress())); + EXPECT_EQ(0, socket2->Connect(socket1->GetLocalAddress())); + ss_.ProcessMessagesUntilIdle(); + + char data[kBufferSize] = {}; + + // First Send call will fill the send buffer but not send anything. + ss_.SetSendingBlocked(true); + EXPECT_EQ(static_cast<int>(kBufferSize), socket1->Send(data, kBufferSize)); + ss_.ProcessMessagesUntilIdle(); + EXPECT_FALSE(sink.Check(socket1.get(), SSE_WRITE)); + EXPECT_FALSE(sink.Check(socket2.get(), SSE_READ)); + EXPECT_FALSE(socket1->IsBlocking()); + + // Since the send buffer is full, next Send will result in EWOULDBLOCK. + EXPECT_EQ(-1, socket1->Send(data, kBufferSize)); + EXPECT_FALSE(sink.Check(socket1.get(), SSE_WRITE)); + EXPECT_FALSE(sink.Check(socket2.get(), SSE_READ)); + EXPECT_TRUE(socket1->IsBlocking()); + + // When sending is unblocked, the buffered data should be sent and + // SignalWriteEvent should fire. + ss_.SetSendingBlocked(false); + ss_.ProcessMessagesUntilIdle(); + EXPECT_TRUE(sink.Check(socket1.get(), SSE_WRITE)); + EXPECT_TRUE(sink.Check(socket2.get(), SSE_READ)); +} + +TEST_F(VirtualSocketServerTest, CreatesStandardDistribution) { + const uint32_t kTestMean[] = {10, 100, 333, 1000}; + const double kTestDev[] = {0.25, 0.1, 0.01}; + // TODO(deadbeef): The current code only works for 1000 data points or more. + const uint32_t kTestSamples[] = {/*10, 100,*/ 1000}; + for (size_t midx = 0; midx < arraysize(kTestMean); ++midx) { + for (size_t didx = 0; didx < arraysize(kTestDev); ++didx) { + for (size_t sidx = 0; sidx < arraysize(kTestSamples); ++sidx) { + ASSERT_LT(0u, kTestSamples[sidx]); + const uint32_t kStdDev = + static_cast<uint32_t>(kTestDev[didx] * kTestMean[midx]); + std::unique_ptr<VirtualSocketServer::Function> f = + VirtualSocketServer::CreateDistribution(kTestMean[midx], kStdDev, + kTestSamples[sidx]); + ASSERT_TRUE(nullptr != f.get()); + ASSERT_EQ(kTestSamples[sidx], f->size()); + double sum = 0; + for (uint32_t i = 0; i < f->size(); ++i) { + sum += (*f)[i].second; + } + const double mean = sum / f->size(); + double sum_sq_dev = 0; + for (uint32_t i = 0; i < f->size(); ++i) { + double dev = (*f)[i].second - mean; + sum_sq_dev += dev * dev; + } + const double stddev = sqrt(sum_sq_dev / f->size()); + EXPECT_NEAR(kTestMean[midx], mean, 0.1 * kTestMean[midx]) + << "M=" << kTestMean[midx] << " SD=" << kStdDev + << " N=" << kTestSamples[sidx]; + EXPECT_NEAR(kStdDev, stddev, 0.1 * kStdDev) + << "M=" << kTestMean[midx] << " SD=" << kStdDev + << " N=" << kTestSamples[sidx]; + } + } + } +} + +} // namespace +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/weak_ptr.cc b/third_party/libwebrtc/rtc_base/weak_ptr.cc new file mode 100644 index 0000000000..3bfa71b0b4 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/weak_ptr.cc @@ -0,0 +1,77 @@ +/* + * Copyright 2016 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 "rtc_base/weak_ptr.h" + +// The implementation is borrowed from chromium except that it does not +// implement SupportsWeakPtr. + +namespace rtc { +namespace internal { + +WeakReference::Flag::Flag() : is_valid_(true) {} + +void WeakReference::Flag::Invalidate() { + RTC_DCHECK(checker_.IsCurrent()) + << "WeakPtrs must be invalidated on the same sequence."; + is_valid_ = false; +} + +bool WeakReference::Flag::IsValid() const { + RTC_DCHECK(checker_.IsCurrent()) + << "WeakPtrs must be checked on the same sequence."; + return is_valid_; +} + +WeakReference::Flag::~Flag() {} + +WeakReference::WeakReference() {} + +WeakReference::WeakReference(const Flag* flag) : flag_(flag) {} + +WeakReference::~WeakReference() {} + +WeakReference::WeakReference(WeakReference&& other) = default; + +WeakReference::WeakReference(const WeakReference& other) = default; + +bool WeakReference::is_valid() const { + return flag_.get() && flag_->IsValid(); +} + +WeakReferenceOwner::WeakReferenceOwner() {} + +WeakReferenceOwner::~WeakReferenceOwner() { + Invalidate(); +} + +WeakReference WeakReferenceOwner::GetRef() const { + // If we hold the last reference to the Flag then create a new one. + if (!HasRefs()) + flag_ = new RefCountedObject<WeakReference::Flag>(); + + return WeakReference(flag_.get()); +} + +void WeakReferenceOwner::Invalidate() { + if (flag_.get()) { + flag_->Invalidate(); + flag_ = nullptr; + } +} + +WeakPtrBase::WeakPtrBase() {} + +WeakPtrBase::~WeakPtrBase() {} + +WeakPtrBase::WeakPtrBase(const WeakReference& ref) : ref_(ref) {} + +} // namespace internal +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/weak_ptr.h b/third_party/libwebrtc/rtc_base/weak_ptr.h new file mode 100644 index 0000000000..7e75b5b9be --- /dev/null +++ b/third_party/libwebrtc/rtc_base/weak_ptr.h @@ -0,0 +1,276 @@ +/* + * Copyright 2016 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 RTC_BASE_WEAK_PTR_H_ +#define RTC_BASE_WEAK_PTR_H_ + +#include <memory> +#include <utility> + +#include "api/scoped_refptr.h" +#include "api/sequence_checker.h" +#include "rtc_base/ref_count.h" +#include "rtc_base/ref_counted_object.h" +#include "rtc_base/system/no_unique_address.h" + +// The implementation is borrowed from chromium except that it does not +// implement SupportsWeakPtr. + +// Weak pointers are pointers to an object that do not affect its lifetime, +// and which may be invalidated (i.e. reset to nullptr) by the object, or its +// owner, at any time, most commonly when the object is about to be deleted. + +// Weak pointers are useful when an object needs to be accessed safely by one +// or more objects other than its owner, and those callers can cope with the +// object vanishing and e.g. tasks posted to it being silently dropped. +// Reference-counting such an object would complicate the ownership graph and +// make it harder to reason about the object's lifetime. + +// EXAMPLE: +// +// class Controller { +// public: +// Controller() : weak_factory_(this) {} +// void SpawnWorker() { Worker::StartNew(weak_factory_.GetWeakPtr()); } +// void WorkComplete(const Result& result) { ... } +// private: +// // Member variables should appear before the WeakPtrFactory, to ensure +// // that any WeakPtrs to Controller are invalidated before its members +// // variable's destructors are executed, rendering them invalid. +// WeakPtrFactory<Controller> weak_factory_; +// }; +// +// class Worker { +// public: +// static void StartNew(const WeakPtr<Controller>& controller) { +// Worker* worker = new Worker(controller); +// // Kick off asynchronous processing... +// } +// private: +// Worker(const WeakPtr<Controller>& controller) +// : controller_(controller) {} +// void DidCompleteAsynchronousProcessing(const Result& result) { +// if (controller_) +// controller_->WorkComplete(result); +// } +// WeakPtr<Controller> controller_; +// }; +// +// With this implementation a caller may use SpawnWorker() to dispatch multiple +// Workers and subsequently delete the Controller, without waiting for all +// Workers to have completed. + +// ------------------------- IMPORTANT: Thread-safety ------------------------- + +// Weak pointers may be passed safely between threads, but must always be +// dereferenced and invalidated on the same TaskQueue or thread, otherwise +// checking the pointer would be racey. +// +// To ensure correct use, the first time a WeakPtr issued by a WeakPtrFactory +// is dereferenced, the factory and its WeakPtrs become bound to the calling +// TaskQueue/thread, and cannot be dereferenced or +// invalidated on any other TaskQueue/thread. Bound WeakPtrs can still be handed +// off to other TaskQueues, e.g. to use to post tasks back to object on the +// bound sequence. +// +// Thus, at least one WeakPtr object must exist and have been dereferenced on +// the correct thread to enforce that other WeakPtr objects will enforce they +// are used on the desired thread. + +namespace rtc { + +namespace internal { + +class WeakReference { + public: + // Although Flag is bound to a specific sequence, it may be + // deleted from another via base::WeakPtr::~WeakPtr(). + class Flag : public RefCountInterface { + public: + Flag(); + + void Invalidate(); + bool IsValid() const; + + private: + friend class RefCountedObject<Flag>; + + ~Flag() override; + + RTC_NO_UNIQUE_ADDRESS ::webrtc::SequenceChecker checker_{ + webrtc::SequenceChecker::kDetached}; + bool is_valid_; + }; + + WeakReference(); + explicit WeakReference(const Flag* flag); + ~WeakReference(); + + WeakReference(WeakReference&& other); + WeakReference(const WeakReference& other); + WeakReference& operator=(WeakReference&& other) = default; + WeakReference& operator=(const WeakReference& other) = default; + + bool is_valid() const; + + private: + scoped_refptr<const Flag> flag_; +}; + +class WeakReferenceOwner { + public: + WeakReferenceOwner(); + ~WeakReferenceOwner(); + + WeakReference GetRef() const; + + bool HasRefs() const { return flag_.get() && !flag_->HasOneRef(); } + + void Invalidate(); + + private: + mutable scoped_refptr<RefCountedObject<WeakReference::Flag>> flag_; +}; + +// This class simplifies the implementation of WeakPtr's type conversion +// constructor by avoiding the need for a public accessor for ref_. A +// WeakPtr<T> cannot access the private members of WeakPtr<U>, so this +// base class gives us a way to access ref_ in a protected fashion. +class WeakPtrBase { + public: + WeakPtrBase(); + ~WeakPtrBase(); + + WeakPtrBase(const WeakPtrBase& other) = default; + WeakPtrBase(WeakPtrBase&& other) = default; + WeakPtrBase& operator=(const WeakPtrBase& other) = default; + WeakPtrBase& operator=(WeakPtrBase&& other) = default; + + protected: + explicit WeakPtrBase(const WeakReference& ref); + + WeakReference ref_; +}; + +} // namespace internal + +template <typename T> +class WeakPtrFactory; + +template <typename T> +class WeakPtr : public internal::WeakPtrBase { + public: + WeakPtr() : ptr_(nullptr) {} + + // Allow conversion from U to T provided U "is a" T. Note that this + // is separate from the (implicit) copy and move constructors. + template <typename U> + WeakPtr(const WeakPtr<U>& other) + : internal::WeakPtrBase(other), ptr_(other.ptr_) {} + template <typename U> + WeakPtr(WeakPtr<U>&& other) + : internal::WeakPtrBase(std::move(other)), ptr_(other.ptr_) {} + + T* get() const { return ref_.is_valid() ? ptr_ : nullptr; } + + T& operator*() const { + RTC_DCHECK(get() != nullptr); + return *get(); + } + T* operator->() const { + RTC_DCHECK(get() != nullptr); + return get(); + } + + void reset() { + ref_ = internal::WeakReference(); + ptr_ = nullptr; + } + + // Allow conditionals to test validity, e.g. if (weak_ptr) {...}; + explicit operator bool() const { return get() != nullptr; } + + private: + template <typename U> + friend class WeakPtr; + friend class WeakPtrFactory<T>; + + WeakPtr(const internal::WeakReference& ref, T* ptr) + : internal::WeakPtrBase(ref), ptr_(ptr) {} + + // This pointer is only valid when ref_.is_valid() is true. Otherwise, its + // value is undefined (as opposed to nullptr). + T* ptr_; +}; + +// Allow callers to compare WeakPtrs against nullptr to test validity. +template <class T> +bool operator!=(const WeakPtr<T>& weak_ptr, std::nullptr_t) { + return !(weak_ptr == nullptr); +} +template <class T> +bool operator!=(std::nullptr_t, const WeakPtr<T>& weak_ptr) { + return weak_ptr != nullptr; +} +template <class T> +bool operator==(const WeakPtr<T>& weak_ptr, std::nullptr_t) { + return weak_ptr.get() == nullptr; +} +template <class T> +bool operator==(std::nullptr_t, const WeakPtr<T>& weak_ptr) { + return weak_ptr == nullptr; +} + +// A class may be composed of a WeakPtrFactory and thereby +// control how it exposes weak pointers to itself. This is helpful if you only +// need weak pointers within the implementation of a class. This class is also +// useful when working with primitive types. For example, you could have a +// WeakPtrFactory<bool> that is used to pass around a weak reference to a bool. + +// Note that GetWeakPtr must be called on one and only one TaskQueue or thread +// and the WeakPtr must only be dereferenced and invalidated on that same +// TaskQueue/thread. A WeakPtr instance can be copied and posted to other +// sequences though as long as it is not dereferenced (WeakPtr<T>::get()). +template <class T> +class WeakPtrFactory { + public: + explicit WeakPtrFactory(T* ptr) : ptr_(ptr) {} + + WeakPtrFactory() = delete; + WeakPtrFactory(const WeakPtrFactory&) = delete; + WeakPtrFactory& operator=(const WeakPtrFactory&) = delete; + + ~WeakPtrFactory() { ptr_ = nullptr; } + + WeakPtr<T> GetWeakPtr() { + RTC_DCHECK(ptr_); + return WeakPtr<T>(weak_reference_owner_.GetRef(), ptr_); + } + + // Call this method to invalidate all existing weak pointers. + void InvalidateWeakPtrs() { + RTC_DCHECK(ptr_); + weak_reference_owner_.Invalidate(); + } + + // Call this method to determine if any weak pointers exist. + bool HasWeakPtrs() const { + RTC_DCHECK(ptr_); + return weak_reference_owner_.HasRefs(); + } + + private: + internal::WeakReferenceOwner weak_reference_owner_; + T* ptr_; +}; + +} // namespace rtc + +#endif // RTC_BASE_WEAK_PTR_H_ diff --git a/third_party/libwebrtc/rtc_base/weak_ptr_gn/moz.build b/third_party/libwebrtc/rtc_base/weak_ptr_gn/moz.build new file mode 100644 index 0000000000..a7cf9dd19e --- /dev/null +++ b/third_party/libwebrtc/rtc_base/weak_ptr_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/rtc_base/weak_ptr.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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("weak_ptr_gn") diff --git a/third_party/libwebrtc/rtc_base/weak_ptr_unittest.cc b/third_party/libwebrtc/rtc_base/weak_ptr_unittest.cc new file mode 100644 index 0000000000..9e22312c28 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/weak_ptr_unittest.cc @@ -0,0 +1,236 @@ +/* + * Copyright 2016 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 "rtc_base/weak_ptr.h" + +#include <memory> +#include <string> + +#include "rtc_base/event.h" +#include "rtc_base/task_queue_for_test.h" +#include "test/gtest.h" + +namespace rtc { + +namespace { + +struct Base { + std::string member; +}; +struct Derived : public Base {}; + +struct Target {}; + +struct Arrow { + WeakPtr<Target> target; +}; + +struct TargetWithFactory : public Target { + TargetWithFactory() : factory(this) {} + WeakPtrFactory<Target> factory; +}; + +} // namespace + +TEST(WeakPtrFactoryTest, Basic) { + int data; + WeakPtrFactory<int> factory(&data); + WeakPtr<int> ptr = factory.GetWeakPtr(); + EXPECT_EQ(&data, ptr.get()); +} + +TEST(WeakPtrFactoryTest, Comparison) { + int data; + WeakPtrFactory<int> factory(&data); + WeakPtr<int> ptr = factory.GetWeakPtr(); + WeakPtr<int> ptr2 = ptr; + EXPECT_EQ(ptr.get(), ptr2.get()); +} + +TEST(WeakPtrFactoryTest, Move) { + int data; + WeakPtrFactory<int> factory(&data); + WeakPtr<int> ptr = factory.GetWeakPtr(); + WeakPtr<int> ptr2 = factory.GetWeakPtr(); + WeakPtr<int> ptr3 = std::move(ptr2); + EXPECT_NE(ptr.get(), ptr2.get()); + EXPECT_EQ(ptr.get(), ptr3.get()); +} + +TEST(WeakPtrFactoryTest, OutOfScope) { + WeakPtr<int> ptr; + EXPECT_EQ(nullptr, ptr.get()); + { + int data; + WeakPtrFactory<int> factory(&data); + ptr = factory.GetWeakPtr(); + EXPECT_EQ(&data, ptr.get()); + } + EXPECT_EQ(nullptr, ptr.get()); +} + +TEST(WeakPtrFactoryTest, Multiple) { + WeakPtr<int> a, b; + { + int data; + WeakPtrFactory<int> factory(&data); + a = factory.GetWeakPtr(); + b = factory.GetWeakPtr(); + EXPECT_EQ(&data, a.get()); + EXPECT_EQ(&data, b.get()); + } + EXPECT_EQ(nullptr, a.get()); + EXPECT_EQ(nullptr, b.get()); +} + +TEST(WeakPtrFactoryTest, MultipleStaged) { + WeakPtr<int> a; + { + int data; + WeakPtrFactory<int> factory(&data); + a = factory.GetWeakPtr(); + { WeakPtr<int> b = factory.GetWeakPtr(); } + EXPECT_NE(nullptr, a.get()); + } + EXPECT_EQ(nullptr, a.get()); +} + +TEST(WeakPtrFactoryTest, Dereference) { + Base data; + data.member = "123456"; + WeakPtrFactory<Base> factory(&data); + WeakPtr<Base> ptr = factory.GetWeakPtr(); + EXPECT_EQ(&data, ptr.get()); + EXPECT_EQ(data.member, (*ptr).member); + EXPECT_EQ(data.member, ptr->member); +} + +TEST(WeakPtrFactoryTest, UpCast) { + Derived data; + WeakPtrFactory<Derived> factory(&data); + WeakPtr<Base> ptr = factory.GetWeakPtr(); + ptr = factory.GetWeakPtr(); + EXPECT_EQ(ptr.get(), &data); +} + +TEST(WeakPtrTest, DefaultConstructor) { + WeakPtr<int> ptr; + EXPECT_EQ(nullptr, ptr.get()); +} + +TEST(WeakPtrFactoryTest, BooleanTesting) { + int data; + WeakPtrFactory<int> factory(&data); + + WeakPtr<int> ptr_to_an_instance = factory.GetWeakPtr(); + EXPECT_TRUE(ptr_to_an_instance); + EXPECT_FALSE(!ptr_to_an_instance); + + if (ptr_to_an_instance) { + } else { + ADD_FAILURE() << "Pointer to an instance should result in true."; + } + + if (!ptr_to_an_instance) { // check for operator!(). + ADD_FAILURE() << "Pointer to an instance should result in !x being false."; + } + + WeakPtr<int> null_ptr; + EXPECT_FALSE(null_ptr); + EXPECT_TRUE(!null_ptr); + + if (null_ptr) { + ADD_FAILURE() << "Null pointer should result in false."; + } + + if (!null_ptr) { // check for operator!(). + } else { + ADD_FAILURE() << "Null pointer should result in !x being true."; + } +} + +TEST(WeakPtrFactoryTest, ComparisonToNull) { + int data; + WeakPtrFactory<int> factory(&data); + + WeakPtr<int> ptr_to_an_instance = factory.GetWeakPtr(); + EXPECT_NE(nullptr, ptr_to_an_instance); + EXPECT_NE(ptr_to_an_instance, nullptr); + + WeakPtr<int> null_ptr; + EXPECT_EQ(null_ptr, nullptr); + EXPECT_EQ(nullptr, null_ptr); +} + +TEST(WeakPtrTest, InvalidateWeakPtrs) { + int data; + WeakPtrFactory<int> factory(&data); + WeakPtr<int> ptr = factory.GetWeakPtr(); + EXPECT_EQ(&data, ptr.get()); + EXPECT_TRUE(factory.HasWeakPtrs()); + factory.InvalidateWeakPtrs(); + EXPECT_EQ(nullptr, ptr.get()); + EXPECT_FALSE(factory.HasWeakPtrs()); + + // Test that the factory can create new weak pointers after a + // InvalidateWeakPtrs call, and they remain valid until the next + // InvalidateWeakPtrs call. + WeakPtr<int> ptr2 = factory.GetWeakPtr(); + EXPECT_EQ(&data, ptr2.get()); + EXPECT_TRUE(factory.HasWeakPtrs()); + factory.InvalidateWeakPtrs(); + EXPECT_EQ(nullptr, ptr2.get()); + EXPECT_FALSE(factory.HasWeakPtrs()); +} + +TEST(WeakPtrTest, HasWeakPtrs) { + int data; + WeakPtrFactory<int> factory(&data); + { + WeakPtr<int> ptr = factory.GetWeakPtr(); + EXPECT_TRUE(factory.HasWeakPtrs()); + } + EXPECT_FALSE(factory.HasWeakPtrs()); +} + +template <class T> +std::unique_ptr<T> NewObjectCreatedOnTaskQueue() { + std::unique_ptr<T> obj; + webrtc::TaskQueueForTest queue("NewObjectCreatedOnTaskQueue"); + queue.SendTask([&] { obj = std::make_unique<T>(); }); + return obj; +} + +TEST(WeakPtrTest, ObjectAndWeakPtrOnDifferentThreads) { + // Test that it is OK to create an object with a WeakPtrFactory one thread, + // but use it on another. This tests that we do not trip runtime checks that + // ensure that a WeakPtr is not used by multiple threads. + std::unique_ptr<TargetWithFactory> target( + NewObjectCreatedOnTaskQueue<TargetWithFactory>()); + WeakPtr<Target> weak_ptr = target->factory.GetWeakPtr(); + EXPECT_EQ(target.get(), weak_ptr.get()); +} + +TEST(WeakPtrTest, WeakPtrInitiateAndUseOnDifferentThreads) { + // Test that it is OK to create a WeakPtr on one thread, but use it on + // another. This tests that we do not trip runtime checks that ensure that a + // WeakPtr is not used by multiple threads. + auto target = std::make_unique<TargetWithFactory>(); + // Create weak ptr on main thread + WeakPtr<Target> weak_ptr = target->factory.GetWeakPtr(); + webrtc::TaskQueueForTest queue("queue"); + queue.SendTask([&] { + // Dereference and invalide weak_ptr on another thread. + EXPECT_EQ(weak_ptr.get(), target.get()); + target.reset(); + }); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/win/BUILD.gn b/third_party/libwebrtc/rtc_base/win/BUILD.gn new file mode 100644 index 0000000000..cf8bc21950 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/win/BUILD.gn @@ -0,0 +1,68 @@ +# Copyright (c) 2021 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("create_direct3d_device") { + sources = [ + "create_direct3d_device.cc", + "create_direct3d_device.h", + ] + data_deps = [ "//build/win:runtime_libs" ] +} + +rtc_library("get_activation_factory") { + sources = [ + "get_activation_factory.cc", + "get_activation_factory.h", + ] + data_deps = [ "//build/win:runtime_libs" ] + deps = [ ":hstring" ] +} + +rtc_library("hstring") { + sources = [ + "hstring.cc", + "hstring.h", + ] + data_deps = [ "//build/win:runtime_libs" ] +} + +rtc_library("scoped_com_initializer") { + sources = [ + "scoped_com_initializer.cc", + "scoped_com_initializer.h", + ] + data_deps = [ "//build/win:runtime_libs" ] + deps = [ + "..:checks", + "..:logging", + ] +} + +rtc_library("windows_version") { + sources = [ + "windows_version.cc", + "windows_version.h", + ] + data_deps = [ "//build/win:runtime_libs" ] + deps = [ + "..:checks", + "..:stringutils", + ] +} + +rtc_library("windows_version_unittest") { + testonly = true + sources = [ "windows_version_unittest.cc" ] + deps = [ + ":windows_version", + "..:gunit_helpers", + "..:logging", + ] +} diff --git a/third_party/libwebrtc/rtc_base/win/create_direct3d_device.cc b/third_party/libwebrtc/rtc_base/win/create_direct3d_device.cc new file mode 100644 index 0000000000..35bbec1156 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/win/create_direct3d_device.cc @@ -0,0 +1,58 @@ +/* + * 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 "rtc_base/win/create_direct3d_device.h" + +#include <libloaderapi.h> + +#include <utility> + +namespace { + +FARPROC LoadD3D11Function(const char* function_name) { + static HMODULE const handle = + ::LoadLibraryExW(L"d3d11.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32); + return handle ? ::GetProcAddress(handle, function_name) : nullptr; +} + +decltype(&::CreateDirect3D11DeviceFromDXGIDevice) +GetCreateDirect3D11DeviceFromDXGIDevice() { + static decltype(&::CreateDirect3D11DeviceFromDXGIDevice) const function = + reinterpret_cast<decltype(&::CreateDirect3D11DeviceFromDXGIDevice)>( + LoadD3D11Function("CreateDirect3D11DeviceFromDXGIDevice")); + return function; +} + +} // namespace + +namespace webrtc { + +bool ResolveCoreWinRTDirect3DDelayload() { + return GetCreateDirect3D11DeviceFromDXGIDevice(); +} + +HRESULT CreateDirect3DDeviceFromDXGIDevice( + IDXGIDevice* dxgi_device, + ABI::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice** + out_d3d11_device) { + decltype(&::CreateDirect3D11DeviceFromDXGIDevice) create_d3d11_device_func = + GetCreateDirect3D11DeviceFromDXGIDevice(); + if (!create_d3d11_device_func) + return E_FAIL; + + Microsoft::WRL::ComPtr<IInspectable> inspectableSurface; + HRESULT hr = create_d3d11_device_func(dxgi_device, &inspectableSurface); + if (FAILED(hr)) + return hr; + + return inspectableSurface->QueryInterface(IID_PPV_ARGS(out_d3d11_device)); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/win/create_direct3d_device.h b/third_party/libwebrtc/rtc_base/win/create_direct3d_device.h new file mode 100644 index 0000000000..7c21f8720a --- /dev/null +++ b/third_party/libwebrtc/rtc_base/win/create_direct3d_device.h @@ -0,0 +1,34 @@ +/* + * 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 RTC_BASE_WIN_CREATE_DIRECT3D_DEVICE_H_ +#define RTC_BASE_WIN_CREATE_DIRECT3D_DEVICE_H_ + +#include <windows.graphics.directX.direct3d11.h> +#include <windows.graphics.directX.direct3d11.interop.h> +#include <winerror.h> +#include <wrl/client.h> + +namespace webrtc { + +// Callers must check the return value of ResolveCoreWinRTDirect3DDelayload() +// before using CreateDirect3DDeviceFromDXGIDevice(). +bool ResolveCoreWinRTDirect3DDelayload(); + +// Allows for the creating of Direct3D Devices from a DXGI device on versions +// of Windows greater than Win7. +HRESULT CreateDirect3DDeviceFromDXGIDevice( + IDXGIDevice* dxgi_device, + ABI::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice** + out_d3d11_device); + +} // namespace webrtc + +#endif // RTC_BASE_WIN_CREATE_DIRECT3D_DEVICE_H_ diff --git a/third_party/libwebrtc/rtc_base/win/create_direct3d_device_gn/moz.build b/third_party/libwebrtc/rtc_base/win/create_direct3d_device_gn/moz.build new file mode 100644 index 0000000000..a33d306080 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/win/create_direct3d_device_gn/moz.build @@ -0,0 +1,85 @@ +# 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["CERT_CHAIN_PARA_HAS_EXTRA_FIELDS"] = True +DEFINES["NOMINMAX"] = True +DEFINES["NTDDI_VERSION"] = "0x0A000000" +DEFINES["PSAPI_VERSION"] = "2" +DEFINES["RTC_DAV1D_IN_INTERNAL_DECODER_FACTORY"] = True +DEFINES["RTC_ENABLE_VP9"] = True +DEFINES["RTC_ENABLE_WIN_WGC"] = True +DEFINES["UNICODE"] = True +DEFINES["USE_AURA"] = "1" +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" +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 + +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/rtc_base/win/create_direct3d_device.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" + DEFINES["_HAS_ITERATOR_DEBUGGING"] = "0" + +if CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +Library("create_direct3d_device_gn") diff --git a/third_party/libwebrtc/rtc_base/win/get_activation_factory.cc b/third_party/libwebrtc/rtc_base/win/get_activation_factory.cc new file mode 100644 index 0000000000..b3be9abfa7 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/win/get_activation_factory.cc @@ -0,0 +1,49 @@ +/* + * 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 "rtc_base/win/get_activation_factory.h" + +#include <libloaderapi.h> +#include <roapi.h> + +namespace { + +FARPROC LoadComBaseFunction(const char* function_name) { + static HMODULE const handle = + ::LoadLibraryExW(L"combase.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32); + return handle ? ::GetProcAddress(handle, function_name) : nullptr; +} + +decltype(&::RoGetActivationFactory) GetRoGetActivationFactoryFunction() { + static decltype(&::RoGetActivationFactory) const function = + reinterpret_cast<decltype(&::RoGetActivationFactory)>( + LoadComBaseFunction("RoGetActivationFactory")); + return function; +} + +} // namespace + +namespace webrtc { + +bool ResolveCoreWinRTDelayload() { + return GetRoGetActivationFactoryFunction() && + ResolveCoreWinRTStringDelayload(); +} + +HRESULT RoGetActivationFactoryProxy(HSTRING class_id, + const IID& iid, + void** out_factory) { + auto get_factory_func = GetRoGetActivationFactoryFunction(); + if (!get_factory_func) + return E_FAIL; + return get_factory_func(class_id, iid, out_factory); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/win/get_activation_factory.h b/third_party/libwebrtc/rtc_base/win/get_activation_factory.h new file mode 100644 index 0000000000..08f602f0c4 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/win/get_activation_factory.h @@ -0,0 +1,53 @@ +/* + * 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 RTC_BASE_WIN_GET_ACTIVATION_FACTORY_H_ +#define RTC_BASE_WIN_GET_ACTIVATION_FACTORY_H_ + +#include <winerror.h> + +#include "rtc_base/win/hstring.h" + +namespace webrtc { + +// Provides access to Core WinRT functions which may not be available on +// Windows 7. Loads functions dynamically at runtime to prevent library +// dependencies. + +// Callers must check the return value of ResolveCoreWinRTDelayLoad() before +// using these functions. + +bool ResolveCoreWinRTDelayload(); + +HRESULT RoGetActivationFactoryProxy(HSTRING class_id, + const IID& iid, + void** out_factory); + +// Retrieves an activation factory for the type specified. +template <typename InterfaceType, wchar_t const* runtime_class_id> +HRESULT GetActivationFactory(InterfaceType** factory) { + HSTRING class_id_hstring; + HRESULT hr = CreateHstring(runtime_class_id, wcslen(runtime_class_id), + &class_id_hstring); + if (FAILED(hr)) + return hr; + + hr = RoGetActivationFactoryProxy(class_id_hstring, IID_PPV_ARGS(factory)); + if (FAILED(hr)) { + DeleteHstring(class_id_hstring); + return hr; + } + + return DeleteHstring(class_id_hstring); +} + +} // namespace webrtc + +#endif // RTC_BASE_WIN_GET_ACTIVATION_FACTORY_H_ diff --git a/third_party/libwebrtc/rtc_base/win/get_activation_factory_gn/moz.build b/third_party/libwebrtc/rtc_base/win/get_activation_factory_gn/moz.build new file mode 100644 index 0000000000..387109c968 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/win/get_activation_factory_gn/moz.build @@ -0,0 +1,85 @@ +# 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["CERT_CHAIN_PARA_HAS_EXTRA_FIELDS"] = True +DEFINES["NOMINMAX"] = True +DEFINES["NTDDI_VERSION"] = "0x0A000000" +DEFINES["PSAPI_VERSION"] = "2" +DEFINES["RTC_DAV1D_IN_INTERNAL_DECODER_FACTORY"] = True +DEFINES["RTC_ENABLE_VP9"] = True +DEFINES["RTC_ENABLE_WIN_WGC"] = True +DEFINES["UNICODE"] = True +DEFINES["USE_AURA"] = "1" +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" +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 + +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/rtc_base/win/get_activation_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" + DEFINES["_HAS_ITERATOR_DEBUGGING"] = "0" + +if CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +Library("get_activation_factory_gn") diff --git a/third_party/libwebrtc/rtc_base/win/hstring.cc b/third_party/libwebrtc/rtc_base/win/hstring.cc new file mode 100644 index 0000000000..5a362a97c9 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/win/hstring.cc @@ -0,0 +1,62 @@ +/* + * 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 "rtc_base/win/hstring.h" + +#include <libloaderapi.h> +#include <winstring.h> + +namespace { + +FARPROC LoadComBaseFunction(const char* function_name) { + static HMODULE const handle = + ::LoadLibraryExW(L"combase.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32); + return handle ? ::GetProcAddress(handle, function_name) : nullptr; +} + +decltype(&::WindowsCreateString) GetWindowsCreateString() { + static decltype(&::WindowsCreateString) const function = + reinterpret_cast<decltype(&::WindowsCreateString)>( + LoadComBaseFunction("WindowsCreateString")); + return function; +} + +decltype(&::WindowsDeleteString) GetWindowsDeleteString() { + static decltype(&::WindowsDeleteString) const function = + reinterpret_cast<decltype(&::WindowsDeleteString)>( + LoadComBaseFunction("WindowsDeleteString")); + return function; +} + +} // namespace + +namespace webrtc { + +bool ResolveCoreWinRTStringDelayload() { + return GetWindowsDeleteString() && GetWindowsCreateString(); +} + +HRESULT CreateHstring(const wchar_t* src, uint32_t len, HSTRING* out_hstr) { + decltype(&::WindowsCreateString) create_string_func = + GetWindowsCreateString(); + if (!create_string_func) + return E_FAIL; + return create_string_func(src, len, out_hstr); +} + +HRESULT DeleteHstring(HSTRING hstr) { + decltype(&::WindowsDeleteString) delete_string_func = + GetWindowsDeleteString(); + if (!delete_string_func) + return E_FAIL; + return delete_string_func(hstr); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/win/hstring.h b/third_party/libwebrtc/rtc_base/win/hstring.h new file mode 100644 index 0000000000..8fb119a9e6 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/win/hstring.h @@ -0,0 +1,30 @@ +/* + * 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 RTC_BASE_WIN_HSTRING_H_ +#define RTC_BASE_WIN_HSTRING_H_ + +#include <hstring.h> +#include <stdint.h> +#include <winerror.h> + +namespace webrtc { + +// Callers must check the return value of ResolveCoreWinRTStringDelayLoad() +// before using these functions. +bool ResolveCoreWinRTStringDelayload(); + +HRESULT CreateHstring(const wchar_t* src, uint32_t len, HSTRING* out_hstr); + +HRESULT DeleteHstring(HSTRING hstr); + +} // namespace webrtc + +#endif // RTC_BASE_WIN_HSTRING_H_ diff --git a/third_party/libwebrtc/rtc_base/win/hstring_gn/moz.build b/third_party/libwebrtc/rtc_base/win/hstring_gn/moz.build new file mode 100644 index 0000000000..c69cce6983 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/win/hstring_gn/moz.build @@ -0,0 +1,85 @@ +# 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["CERT_CHAIN_PARA_HAS_EXTRA_FIELDS"] = True +DEFINES["NOMINMAX"] = True +DEFINES["NTDDI_VERSION"] = "0x0A000000" +DEFINES["PSAPI_VERSION"] = "2" +DEFINES["RTC_DAV1D_IN_INTERNAL_DECODER_FACTORY"] = True +DEFINES["RTC_ENABLE_VP9"] = True +DEFINES["RTC_ENABLE_WIN_WGC"] = True +DEFINES["UNICODE"] = True +DEFINES["USE_AURA"] = "1" +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" +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 + +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" +] + +SOURCES += [ + "/third_party/libwebrtc/rtc_base/win/hstring.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" + DEFINES["_HAS_ITERATOR_DEBUGGING"] = "0" + +if CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +Library("hstring_gn") diff --git a/third_party/libwebrtc/rtc_base/win/scoped_com_initializer.cc b/third_party/libwebrtc/rtc_base/win/scoped_com_initializer.cc new file mode 100644 index 0000000000..4b56772ebf --- /dev/null +++ b/third_party/libwebrtc/rtc_base/win/scoped_com_initializer.cc @@ -0,0 +1,57 @@ +/* + * 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 "rtc_base/win/scoped_com_initializer.h" + +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" + +namespace webrtc { + +ScopedCOMInitializer::ScopedCOMInitializer() { + RTC_DLOG(LS_INFO) << "Single-Threaded Apartment (STA) COM thread"; + Initialize(COINIT_APARTMENTTHREADED); +} + +// Constructor for MTA initialization. +ScopedCOMInitializer::ScopedCOMInitializer(SelectMTA mta) { + RTC_DLOG(LS_INFO) << "Multi-Threaded Apartment (MTA) COM thread"; + Initialize(COINIT_MULTITHREADED); +} + +ScopedCOMInitializer::~ScopedCOMInitializer() { + if (Succeeded()) { + CoUninitialize(); + } +} + +void ScopedCOMInitializer::Initialize(COINIT init) { + // Initializes the COM library for use by the calling thread, sets the + // thread's concurrency model, and creates a new apartment for the thread + // if one is required. CoInitializeEx must be called at least once, and is + // usually called only once, for each thread that uses the COM library. + hr_ = CoInitializeEx(NULL, init); + RTC_CHECK_NE(RPC_E_CHANGED_MODE, hr_) + << "Invalid COM thread model change (MTA->STA)"; + // Multiple calls to CoInitializeEx by the same thread are allowed as long + // as they pass the same concurrency flag, but subsequent valid calls + // return S_FALSE. To close the COM library gracefully on a thread, each + // successful call to CoInitializeEx, including any call that returns + // S_FALSE, must be balanced by a corresponding call to CoUninitialize. + if (hr_ == S_OK) { + RTC_DLOG(LS_INFO) + << "The COM library was initialized successfully on this thread"; + } else if (hr_ == S_FALSE) { + RTC_DLOG(LS_WARNING) + << "The COM library is already initialized on this thread"; + } +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/rtc_base/win/scoped_com_initializer.h b/third_party/libwebrtc/rtc_base/win/scoped_com_initializer.h new file mode 100644 index 0000000000..2427097b5b --- /dev/null +++ b/third_party/libwebrtc/rtc_base/win/scoped_com_initializer.h @@ -0,0 +1,56 @@ +/* + * 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 RTC_BASE_WIN_SCOPED_COM_INITIALIZER_H_ +#define RTC_BASE_WIN_SCOPED_COM_INITIALIZER_H_ + +#include <comdef.h> + +namespace webrtc { + +// Initializes COM in the constructor (STA or MTA), and uninitializes COM in the +// destructor. Taken from base::win::ScopedCOMInitializer. +// +// WARNING: This should only be used once per thread, ideally scoped to a +// similar lifetime as the thread itself. You should not be using this in +// random utility functions that make COM calls; instead ensure that these +// functions are running on a COM-supporting thread! +// See https://msdn.microsoft.com/en-us/library/ms809971.aspx for details. +class ScopedCOMInitializer { + public: + // Enum value provided to initialize the thread as an MTA instead of STA. + // There are two types of apartments, Single Threaded Apartments (STAs) + // and Multi Threaded Apartments (MTAs). Within a given process there can + // be multiple STA’s but there is only one MTA. STA is typically used by + // "GUI applications" and MTA by "worker threads" with no UI message loop. + enum SelectMTA { kMTA }; + + // Constructor for STA initialization. + ScopedCOMInitializer(); + + // Constructor for MTA initialization. + explicit ScopedCOMInitializer(SelectMTA mta); + + ~ScopedCOMInitializer(); + + ScopedCOMInitializer(const ScopedCOMInitializer&) = delete; + ScopedCOMInitializer& operator=(const ScopedCOMInitializer&) = delete; + + bool Succeeded() { return SUCCEEDED(hr_); } + + private: + void Initialize(COINIT init); + + HRESULT hr_; +}; + +} // namespace webrtc + +#endif // RTC_BASE_WIN_SCOPED_COM_INITIALIZER_H_ diff --git a/third_party/libwebrtc/rtc_base/win/windows_version.cc b/third_party/libwebrtc/rtc_base/win/windows_version.cc new file mode 100644 index 0000000000..93af1377be --- /dev/null +++ b/third_party/libwebrtc/rtc_base/win/windows_version.cc @@ -0,0 +1,445 @@ +/* + * Copyright (c) 2017 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 "rtc_base/win/windows_version.h" + +#include <windows.h> + +#include <memory> + +#include "rtc_base/checks.h" +#include "rtc_base/string_utils.h" + +#if !defined(__clang__) && _MSC_FULL_VER < 191125507 +#error VS 2017 Update 3.2 or higher is required +#endif + +#if !defined(WINUWP) + +namespace { + +typedef BOOL(WINAPI* GetProductInfoPtr)(DWORD, DWORD, DWORD, DWORD, PDWORD); + +// Mask to pull WOW64 access flags out of REGSAM access. +const REGSAM kWow64AccessMask = KEY_WOW64_32KEY | KEY_WOW64_64KEY; + +// Utility class to read, write and manipulate the Windows Registry. +// Registry vocabulary primer: a "key" is like a folder, in which there +// are "values", which are <name, data> pairs, with an associated data type. +// Based on base::win::RegKey but only implements a small fraction of it. +class RegKey { + public: + RegKey() : key_(nullptr), wow64access_(0) {} + + RegKey(HKEY rootkey, const wchar_t* subkey, REGSAM access) + : key_(nullptr), wow64access_(0) { + if (rootkey) { + if (access & (KEY_SET_VALUE | KEY_CREATE_SUB_KEY | KEY_CREATE_LINK)) + Create(rootkey, subkey, access); + else + Open(rootkey, subkey, access); + } else { + RTC_DCHECK(!subkey); + wow64access_ = access & kWow64AccessMask; + } + } + + ~RegKey() { Close(); } + + LONG Create(HKEY rootkey, const wchar_t* subkey, REGSAM access) { + DWORD disposition_value; + return CreateWithDisposition(rootkey, subkey, &disposition_value, access); + } + + LONG CreateWithDisposition(HKEY rootkey, + const wchar_t* subkey, + DWORD* disposition, + REGSAM access) { + RTC_DCHECK(rootkey && subkey && access && disposition); + HKEY subhkey = NULL; + LONG result = + ::RegCreateKeyExW(rootkey, subkey, 0, NULL, REG_OPTION_NON_VOLATILE, + access, NULL, &subhkey, disposition); + if (result == ERROR_SUCCESS) { + Close(); + key_ = subhkey; + wow64access_ = access & kWow64AccessMask; + } + + return result; + } + + // Opens an existing reg key. + LONG Open(HKEY rootkey, const wchar_t* subkey, REGSAM access) { + RTC_DCHECK(rootkey && subkey && access); + HKEY subhkey = NULL; + + LONG result = ::RegOpenKeyExW(rootkey, subkey, 0, access, &subhkey); + if (result == ERROR_SUCCESS) { + Close(); + key_ = subhkey; + wow64access_ = access & kWow64AccessMask; + } + + return result; + } + + // Closes this reg key. + void Close() { + if (key_) { + ::RegCloseKey(key_); + key_ = nullptr; + } + } + + // Reads a REG_DWORD (uint32_t) into `out_value`. If `name` is null or empty, + // reads the key's default value, if any. + LONG ReadValueDW(const wchar_t* name, DWORD* out_value) const { + RTC_DCHECK(out_value); + DWORD type = REG_DWORD; + DWORD size = sizeof(DWORD); + DWORD local_value = 0; + LONG result = ReadValue(name, &local_value, &size, &type); + if (result == ERROR_SUCCESS) { + if ((type == REG_DWORD || type == REG_BINARY) && size == sizeof(DWORD)) + *out_value = local_value; + else + result = ERROR_CANTREAD; + } + + return result; + } + + // Reads a string into `out_value`. If `name` is null or empty, reads + // the key's default value, if any. + LONG ReadValue(const wchar_t* name, std::wstring* out_value) const { + RTC_DCHECK(out_value); + const size_t kMaxStringLength = 1024; // This is after expansion. + // Use the one of the other forms of ReadValue if 1024 is too small for you. + wchar_t raw_value[kMaxStringLength]; + DWORD type = REG_SZ, size = sizeof(raw_value); + LONG result = ReadValue(name, raw_value, &size, &type); + if (result == ERROR_SUCCESS) { + if (type == REG_SZ) { + *out_value = raw_value; + } else if (type == REG_EXPAND_SZ) { + wchar_t expanded[kMaxStringLength]; + size = + ::ExpandEnvironmentStringsW(raw_value, expanded, kMaxStringLength); + // Success: returns the number of wchar_t's copied + // Fail: buffer too small, returns the size required + // Fail: other, returns 0 + if (size == 0 || size > kMaxStringLength) { + result = ERROR_MORE_DATA; + } else { + *out_value = expanded; + } + } else { + // Not a string. Oops. + result = ERROR_CANTREAD; + } + } + + return result; + } + + LONG ReadValue(const wchar_t* name, + void* data, + DWORD* dsize, + DWORD* dtype) const { + LONG result = RegQueryValueExW(key_, name, 0, dtype, + reinterpret_cast<LPBYTE>(data), dsize); + return result; + } + + private: + HKEY key_; + REGSAM wow64access_; +}; + +} // namespace + +#endif // !defined(WINUWP) + +namespace rtc { +namespace rtc_win { +namespace { + +// Helper to map a major.minor.x.build version (e.g. 6.1) to a Windows release. +Version MajorMinorBuildToVersion(int major, int minor, int build) { + if ((major == 5) && (minor > 0)) { + // Treat XP Pro x64, Home Server, and Server 2003 R2 as Server 2003. + return (minor == 1) ? VERSION_XP : VERSION_SERVER_2003; + } else if (major == 6) { + switch (minor) { + case 0: + // Treat Windows Server 2008 the same as Windows Vista. + return VERSION_VISTA; + case 1: + // Treat Windows Server 2008 R2 the same as Windows 7. + return VERSION_WIN7; + case 2: + // Treat Windows Server 2012 the same as Windows 8. + return VERSION_WIN8; + default: + RTC_DCHECK_EQ(minor, 3); + return VERSION_WIN8_1; + } + } else if (major == 10) { + if (build < 10586) { + return VERSION_WIN10; + } else if (build < 14393) { + return VERSION_WIN10_TH2; + } else if (build < 15063) { + return VERSION_WIN10_RS1; + } else if (build < 16299) { + return VERSION_WIN10_RS2; + } else if (build < 17134) { + return VERSION_WIN10_RS3; + } else if (build < 17763) { + return VERSION_WIN10_RS4; + } else if (build < 18362) { + return VERSION_WIN10_RS5; + } else if (build < 18363) { + return VERSION_WIN10_19H1; + } else if (build < 19041) { + return VERSION_WIN10_19H2; + } else if (build < 19042) { + return VERSION_WIN10_20H1; + } else if (build < 19043) { + return VERSION_WIN10_20H2; + } else if (build < 19044) { + return VERSION_WIN10_21H1; + } else if (build < 20348) { + return VERSION_WIN10_21H2; + } else if (build < 22000) { + return VERSION_SERVER_2022; + } else { + return VERSION_WIN11; + } + } else if (major == 11) { + return VERSION_WIN11; + } else if (major > 6) { + RTC_DCHECK_NOTREACHED(); + return VERSION_WIN_LAST; + } + + return VERSION_PRE_XP; +} + +// Returns the the "UBR" value from the registry. Introduced in Windows 10, +// this undocumented value appears to be similar to a patch number. +// Returns 0 if the value does not exist or it could not be read. +int GetUBR() { +#if defined(WINUWP) + // The registry is not accessible for WinUWP sandboxed store applications. + return 0; +#else + // The values under the CurrentVersion registry hive are mirrored under + // the corresponding Wow6432 hive. + static constexpr wchar_t kRegKeyWindowsNTCurrentVersion[] = + L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"; + + RegKey key; + if (key.Open(HKEY_LOCAL_MACHINE, kRegKeyWindowsNTCurrentVersion, + KEY_QUERY_VALUE) != ERROR_SUCCESS) { + return 0; + } + + DWORD ubr = 0; + key.ReadValueDW(L"UBR", &ubr); + + return static_cast<int>(ubr); +#endif // defined(WINUWP) +} + +} // namespace + +// static +OSInfo* OSInfo::GetInstance() { + // Note: we don't use the Singleton class because it depends on AtExitManager, + // and it's convenient for other modules to use this class without it. This + // pattern is copied from gurl.cc. + static OSInfo* info; + if (!info) { + OSInfo* new_info = new OSInfo(); + if (InterlockedCompareExchangePointer(reinterpret_cast<PVOID*>(&info), + new_info, NULL)) { + delete new_info; + } + } + return info; +} + +OSInfo::OSInfo() + : version_(VERSION_PRE_XP), + architecture_(OTHER_ARCHITECTURE), + wow64_status_(GetWOW64StatusForProcess(GetCurrentProcess())) { + OSVERSIONINFOEXW version_info = {sizeof version_info}; + // Applications not manifested for Windows 8.1 or Windows 10 will return the + // Windows 8 OS version value (6.2). Once an application is manifested for a + // given operating system version, GetVersionEx() will always return the + // version that the application is manifested for in future releases. + // https://docs.microsoft.com/en-us/windows/desktop/SysInfo/targeting-your-application-at-windows-8-1 + // https://www.codeproject.com/Articles/678606/Part-Overcoming-Windows-s-deprecation-of-GetVe +#pragma warning(push) +#pragma warning(disable : 4996) + ::GetVersionExW(reinterpret_cast<OSVERSIONINFOW*>(&version_info)); +#pragma warning(pop) + version_number_.major = version_info.dwMajorVersion; + version_number_.minor = version_info.dwMinorVersion; + version_number_.build = version_info.dwBuildNumber; + version_number_.patch = GetUBR(); + version_ = MajorMinorBuildToVersion( + version_number_.major, version_number_.minor, version_number_.build); + service_pack_.major = version_info.wServicePackMajor; + service_pack_.minor = version_info.wServicePackMinor; + service_pack_str_ = rtc::ToUtf8(version_info.szCSDVersion); + + SYSTEM_INFO system_info = {}; + ::GetNativeSystemInfo(&system_info); + switch (system_info.wProcessorArchitecture) { + case PROCESSOR_ARCHITECTURE_INTEL: + architecture_ = X86_ARCHITECTURE; + break; + case PROCESSOR_ARCHITECTURE_AMD64: + architecture_ = X64_ARCHITECTURE; + break; + case PROCESSOR_ARCHITECTURE_IA64: + architecture_ = IA64_ARCHITECTURE; + break; + } + processors_ = system_info.dwNumberOfProcessors; + allocation_granularity_ = system_info.dwAllocationGranularity; + +#if !defined(WINUWP) + GetProductInfoPtr get_product_info; + DWORD os_type; + + if (version_info.dwMajorVersion == 6 || version_info.dwMajorVersion == 10) { + // Only present on Vista+. + get_product_info = reinterpret_cast<GetProductInfoPtr>(::GetProcAddress( + ::GetModuleHandleW(L"kernel32.dll"), "GetProductInfo")); + + get_product_info(version_info.dwMajorVersion, version_info.dwMinorVersion, + 0, 0, &os_type); + switch (os_type) { + case PRODUCT_CLUSTER_SERVER: + case PRODUCT_DATACENTER_SERVER: + case PRODUCT_DATACENTER_SERVER_CORE: + case PRODUCT_ENTERPRISE_SERVER: + case PRODUCT_ENTERPRISE_SERVER_CORE: + case PRODUCT_ENTERPRISE_SERVER_IA64: + case PRODUCT_SMALLBUSINESS_SERVER: + case PRODUCT_SMALLBUSINESS_SERVER_PREMIUM: + case PRODUCT_STANDARD_SERVER: + case PRODUCT_STANDARD_SERVER_CORE: + case PRODUCT_WEB_SERVER: + version_type_ = SUITE_SERVER; + break; + case PRODUCT_PROFESSIONAL: + case PRODUCT_ULTIMATE: + version_type_ = SUITE_PROFESSIONAL; + break; + case PRODUCT_ENTERPRISE: + case PRODUCT_ENTERPRISE_E: + case PRODUCT_ENTERPRISE_EVALUATION: + case PRODUCT_ENTERPRISE_N: + case PRODUCT_ENTERPRISE_N_EVALUATION: + case PRODUCT_ENTERPRISE_S: + case PRODUCT_ENTERPRISE_S_EVALUATION: + case PRODUCT_ENTERPRISE_S_N: + case PRODUCT_ENTERPRISE_S_N_EVALUATION: + case PRODUCT_BUSINESS: + case PRODUCT_BUSINESS_N: + version_type_ = SUITE_ENTERPRISE; + break; + case PRODUCT_EDUCATION: + case PRODUCT_EDUCATION_N: + version_type_ = SUITE_EDUCATION; + break; + case PRODUCT_HOME_BASIC: + case PRODUCT_HOME_PREMIUM: + case PRODUCT_STARTER: + default: + version_type_ = SUITE_HOME; + break; + } + } else if (version_info.dwMajorVersion == 5 && + version_info.dwMinorVersion == 2) { + if (version_info.wProductType == VER_NT_WORKSTATION && + system_info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) { + version_type_ = SUITE_PROFESSIONAL; + } else if (version_info.wSuiteMask & VER_SUITE_WH_SERVER) { + version_type_ = SUITE_HOME; + } else { + version_type_ = SUITE_SERVER; + } + } else if (version_info.dwMajorVersion == 5 && + version_info.dwMinorVersion == 1) { + if (version_info.wSuiteMask & VER_SUITE_PERSONAL) + version_type_ = SUITE_HOME; + else + version_type_ = SUITE_PROFESSIONAL; + } else { + // Windows is pre XP so we don't care but pick a safe default. + version_type_ = SUITE_HOME; + } +#else + // WinUWP sandboxed store apps do not have a mechanism to determine + // product suite thus the most restricted suite is chosen. + version_type_ = SUITE_HOME; +#endif // !defined(WINUWP) +} + +OSInfo::~OSInfo() {} + +std::string OSInfo::processor_model_name() { +#if defined(WINUWP) + // WinUWP sandboxed store apps do not have the ability to + // probe the name of the current processor. + return "Unknown Processor (UWP)"; +#else + if (processor_model_name_.empty()) { + const wchar_t kProcessorNameString[] = + L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"; + RegKey key(HKEY_LOCAL_MACHINE, kProcessorNameString, KEY_READ); + std::wstring value; + key.ReadValue(L"ProcessorNameString", &value); + processor_model_name_ = rtc::ToUtf8(value); + } + return processor_model_name_; +#endif // defined(WINUWP) +} + +// static +OSInfo::WOW64Status OSInfo::GetWOW64StatusForProcess(HANDLE process_handle) { + BOOL is_wow64; +#if defined(WINUWP) + if (!IsWow64Process(process_handle, &is_wow64)) + return WOW64_UNKNOWN; +#else + typedef BOOL(WINAPI * IsWow64ProcessFunc)(HANDLE, PBOOL); + IsWow64ProcessFunc is_wow64_process = reinterpret_cast<IsWow64ProcessFunc>( + GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "IsWow64Process")); + if (!is_wow64_process) + return WOW64_DISABLED; + if (!(*is_wow64_process)(process_handle, &is_wow64)) + return WOW64_UNKNOWN; +#endif // defined(WINUWP) + return is_wow64 ? WOW64_ENABLED : WOW64_DISABLED; +} + +Version GetVersion() { + return OSInfo::GetInstance()->version(); +} + +} // namespace rtc_win +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/win/windows_version.h b/third_party/libwebrtc/rtc_base/win/windows_version.h new file mode 100644 index 0000000000..8542626afb --- /dev/null +++ b/third_party/libwebrtc/rtc_base/win/windows_version.h @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2017 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 RTC_BASE_WIN_WINDOWS_VERSION_H_ +#define RTC_BASE_WIN_WINDOWS_VERSION_H_ + +#include <stddef.h> + +#include <string> + +typedef void* HANDLE; + +namespace rtc { +namespace rtc_win { + +// The running version of Windows. This is declared outside OSInfo for +// syntactic sugar reasons; see the declaration of GetVersion() below. +// NOTE: Keep these in order so callers can do things like +// "if (rtc_win::GetVersion() >= rtc_win::VERSION_VISTA) ...". +// +// This enum is used in metrics histograms, so they shouldn't be reordered or +// removed. New values can be added before VERSION_WIN_LAST. +enum Version { + VERSION_PRE_XP = 0, // Not supported. + VERSION_XP = 1, + VERSION_SERVER_2003 = 2, // Also includes XP Pro x64 and Server 2003 R2. + VERSION_VISTA = 3, // Also includes Windows Server 2008. + VERSION_WIN7 = 4, // Also includes Windows Server 2008 R2. + VERSION_WIN8 = 5, // Also includes Windows Server 2012. + VERSION_WIN8_1 = 6, // Also includes Windows Server 2012 R2. + VERSION_WIN10 = 7, // Threshold 1: Version 1507, Build 10240. + VERSION_WIN10_TH2 = 8, // Threshold 2: Version 1511, Build 10586. + VERSION_WIN10_RS1 = 9, // Redstone 1: Version 1607, Build 14393. + VERSION_WIN10_RS2 = 10, // Redstone 2: Version 1703, Build 15063. + VERSION_WIN10_RS3 = 11, // Redstone 3: Version 1709, Build 16299. + VERSION_WIN10_RS4 = 12, // Redstone 4: Version 1803, Build 17134. + VERSION_WIN10_RS5 = 13, // Redstone 5: Version 1809, Build 17763. + VERSION_WIN10_19H1 = 14, // 19H1: Version 1903, Build 18362. + VERSION_WIN10_19H2 = 15, // 19H2: Version 1909, Build 18363. + VERSION_WIN10_20H1 = 16, // 20H1: Version 2004, Build 19041. + VERSION_WIN10_20H2 = 17, // 20H2: Build 19042. + VERSION_WIN10_21H1 = 18, // 21H1: Build 19043. + VERSION_WIN10_21H2 = 19, // 21H2: Build 19044. + VERSION_SERVER_2022 = 20, // Server 2022: Build 20348. + VERSION_WIN11 = 21, // Windows 11: Build 22000. + VERSION_WIN_LAST, // Indicates error condition. +}; + +// A rough bucketing of the available types of versions of Windows. This is used +// to distinguish enterprise enabled versions from home versions and potentially +// server versions. Keep these values in the same order, since they are used as +// is for metrics histogram ids. +enum VersionType { + SUITE_HOME = 0, + SUITE_PROFESSIONAL, + SUITE_SERVER, + SUITE_ENTERPRISE, + SUITE_EDUCATION, + SUITE_LAST, +}; + +// A singleton that can be used to query various pieces of information about the +// OS and process state. Note that this doesn't use the base Singleton class, so +// it can be used without an AtExitManager. +class OSInfo { + public: + struct VersionNumber { + int major; + int minor; + int build; + int patch; + }; + + struct ServicePack { + int major; + int minor; + }; + + // The processor architecture this copy of Windows natively uses. For + // example, given an x64-capable processor, we have three possibilities: + // 32-bit Chrome running on 32-bit Windows: X86_ARCHITECTURE + // 32-bit Chrome running on 64-bit Windows via WOW64: X64_ARCHITECTURE + // 64-bit Chrome running on 64-bit Windows: X64_ARCHITECTURE + enum WindowsArchitecture { + X86_ARCHITECTURE, + X64_ARCHITECTURE, + IA64_ARCHITECTURE, + OTHER_ARCHITECTURE, + }; + + // Whether a process is running under WOW64 (the wrapper that allows 32-bit + // processes to run on 64-bit versions of Windows). This will return + // WOW64_DISABLED for both "32-bit Chrome on 32-bit Windows" and "64-bit + // Chrome on 64-bit Windows". WOW64_UNKNOWN means "an error occurred", e.g. + // the process does not have sufficient access rights to determine this. + enum WOW64Status { + WOW64_DISABLED, + WOW64_ENABLED, + WOW64_UNKNOWN, + }; + + OSInfo(const OSInfo&) = delete; + OSInfo& operator=(const OSInfo&) = delete; + + static OSInfo* GetInstance(); + + Version version() const { return version_; } + VersionNumber version_number() const { return version_number_; } + VersionType version_type() const { return version_type_; } + ServicePack service_pack() const { return service_pack_; } + std::string service_pack_str() const { return service_pack_str_; } + WindowsArchitecture architecture() const { return architecture_; } + int processors() const { return processors_; } + size_t allocation_granularity() const { return allocation_granularity_; } + WOW64Status wow64_status() const { return wow64_status_; } + std::string processor_model_name(); + + // Like wow64_status(), but for the supplied handle instead of the current + // process. This doesn't touch member state, so you can bypass the singleton. + static WOW64Status GetWOW64StatusForProcess(HANDLE process_handle); + + private: + OSInfo(); + ~OSInfo(); + + Version version_; + VersionNumber version_number_; + VersionType version_type_; + ServicePack service_pack_; + + // A string, such as "Service Pack 3", that indicates the latest Service Pack + // installed on the system. If no Service Pack has been installed, the string + // is empty. + std::string service_pack_str_; + WindowsArchitecture architecture_; + int processors_; + size_t allocation_granularity_; + WOW64Status wow64_status_; + std::string processor_model_name_; +}; + +// Because this is by far the most commonly-requested value from the above +// singleton, we add a global-scope accessor here as syntactic sugar. +Version GetVersion(); + +} // namespace rtc_win +} // namespace rtc + +#endif // RTC_BASE_WIN_WINDOWS_VERSION_H_ diff --git a/third_party/libwebrtc/rtc_base/win/windows_version_gn/moz.build b/third_party/libwebrtc/rtc_base/win/windows_version_gn/moz.build new file mode 100644 index 0000000000..33b46947a4 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/win/windows_version_gn/moz.build @@ -0,0 +1,85 @@ +# 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["CERT_CHAIN_PARA_HAS_EXTRA_FIELDS"] = True +DEFINES["NOMINMAX"] = True +DEFINES["NTDDI_VERSION"] = "0x0A000000" +DEFINES["PSAPI_VERSION"] = "2" +DEFINES["RTC_DAV1D_IN_INTERNAL_DECODER_FACTORY"] = True +DEFINES["RTC_ENABLE_VP9"] = True +DEFINES["RTC_ENABLE_WIN_WGC"] = True +DEFINES["UNICODE"] = True +DEFINES["USE_AURA"] = "1" +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" +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 + +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/rtc_base/win/windows_version.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" + DEFINES["_HAS_ITERATOR_DEBUGGING"] = "0" + +if CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +Library("windows_version_gn") diff --git a/third_party/libwebrtc/rtc_base/win/windows_version_unittest.cc b/third_party/libwebrtc/rtc_base/win/windows_version_unittest.cc new file mode 100644 index 0000000000..e1cd920157 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/win/windows_version_unittest.cc @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2017 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 "rtc_base/win/windows_version.h" + +#include "rtc_base/gunit.h" +#include "rtc_base/logging.h" + +namespace rtc { +namespace rtc_win { +namespace { + +void MethodSupportedOnWin10AndLater() { + RTC_DLOG(LS_INFO) << "MethodSupportedOnWin10AndLater"; +} + +void MethodNotSupportedOnWin10AndLater() { + RTC_DLOG(LS_INFO) << "MethodNotSupportedOnWin10AndLater"; +} + +// Use global GetVersion() and use it in a way a user would typically use it +// when checking for support of a certain API: +// "if (rtc_win::GetVersion() < VERSION_WIN10) ...". +TEST(WindowsVersion, GetVersionGlobalScopeAccessor) { + if (GetVersion() < VERSION_WIN10) { + MethodNotSupportedOnWin10AndLater(); + } else { + MethodSupportedOnWin10AndLater(); + } +} + +TEST(WindowsVersion, ProcessorModelName) { + std::string name = OSInfo::GetInstance()->processor_model_name(); + EXPECT_FALSE(name.empty()); + RTC_DLOG(LS_INFO) << "processor_model_name: " << name; +} + +} // namespace +} // namespace rtc_win +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/win32.cc b/third_party/libwebrtc/rtc_base/win32.cc new file mode 100644 index 0000000000..9ce0523413 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/win32.cc @@ -0,0 +1,313 @@ +/* + * 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 "rtc_base/win32.h" + +#include <winsock2.h> +#include <ws2tcpip.h> + +#include <algorithm> + +#include "rtc_base/arraysize.h" +#include "rtc_base/byte_order.h" +#include "rtc_base/checks.h" +#include "rtc_base/string_utils.h" + +namespace rtc { + +// Helper function declarations for inet_ntop/inet_pton. +static const char* inet_ntop_v4(const void* src, char* dst, socklen_t size); +static const char* inet_ntop_v6(const void* src, char* dst, socklen_t size); +static int inet_pton_v4(const char* src, void* dst); +static int inet_pton_v6(const char* src, void* dst); + +// Implementation of inet_ntop (create a printable representation of an +// ip address). XP doesn't have its own inet_ntop, and +// WSAAddressToString requires both IPv6 to be installed and for Winsock +// to be initialized. +const char* win32_inet_ntop(int af, + const void* src, + char* dst, + socklen_t size) { + if (!src || !dst) { + return nullptr; + } + switch (af) { + case AF_INET: { + return inet_ntop_v4(src, dst, size); + } + case AF_INET6: { + return inet_ntop_v6(src, dst, size); + } + } + return nullptr; +} + +// As above, but for inet_pton. Implements inet_pton for v4 and v6. +// Note that our inet_ntop will output normal 'dotted' v4 addresses only. +int win32_inet_pton(int af, const char* src, void* dst) { + if (!src || !dst) { + return 0; + } + if (af == AF_INET) { + return inet_pton_v4(src, dst); + } else if (af == AF_INET6) { + return inet_pton_v6(src, dst); + } + return -1; +} + +// Helper function for inet_ntop for IPv4 addresses. +// Outputs "dotted-quad" decimal notation. +const char* inet_ntop_v4(const void* src, char* dst, socklen_t size) { + if (size < INET_ADDRSTRLEN) { + return nullptr; + } + const struct in_addr* as_in_addr = + reinterpret_cast<const struct in_addr*>(src); + snprintf(dst, size, "%d.%d.%d.%d", as_in_addr->S_un.S_un_b.s_b1, + as_in_addr->S_un.S_un_b.s_b2, as_in_addr->S_un.S_un_b.s_b3, + as_in_addr->S_un.S_un_b.s_b4); + return dst; +} + +// Helper function for inet_ntop for IPv6 addresses. +const char* inet_ntop_v6(const void* src, char* dst, socklen_t size) { + if (size < INET6_ADDRSTRLEN) { + return nullptr; + } + const uint16_t* as_shorts = reinterpret_cast<const uint16_t*>(src); + int runpos[8]; + int current = 1; + int max = 0; + int maxpos = -1; + int run_array_size = arraysize(runpos); + // Run over the address marking runs of 0s. + for (int i = 0; i < run_array_size; ++i) { + if (as_shorts[i] == 0) { + runpos[i] = current; + if (current > max) { + maxpos = i; + max = current; + } + ++current; + } else { + runpos[i] = -1; + current = 1; + } + } + + if (max > 0) { + int tmpmax = maxpos; + // Run back through, setting -1 for all but the longest run. + for (int i = run_array_size - 1; i >= 0; i--) { + if (i > tmpmax) { + runpos[i] = -1; + } else if (runpos[i] == -1) { + // We're less than maxpos, we hit a -1, so the 'good' run is done. + // Setting tmpmax -1 means all remaining positions get set to -1. + tmpmax = -1; + } + } + } + + char* cursor = dst; + // Print IPv4 compatible and IPv4 mapped addresses using the IPv4 helper. + // These addresses have an initial run of either eight zero-bytes followed + // by 0xFFFF, or an initial run of ten zero-bytes. + if (runpos[0] == 1 && + (maxpos == 5 || (maxpos == 4 && as_shorts[5] == 0xFFFF))) { + *cursor++ = ':'; + *cursor++ = ':'; + if (maxpos == 4) { + cursor += snprintf(cursor, INET6_ADDRSTRLEN - 2, "ffff:"); + } + const struct in_addr* as_v4 = + reinterpret_cast<const struct in_addr*>(&(as_shorts[6])); + inet_ntop_v4(as_v4, cursor, + static_cast<socklen_t>(INET6_ADDRSTRLEN - (cursor - dst))); + } else { + for (int i = 0; i < run_array_size; ++i) { + if (runpos[i] == -1) { + cursor += snprintf(cursor, INET6_ADDRSTRLEN - (cursor - dst), "%x", + NetworkToHost16(as_shorts[i])); + if (i != 7 && runpos[i + 1] != 1) { + *cursor++ = ':'; + } + } else if (runpos[i] == 1) { + // Entered the run; print the colons and skip the run. + *cursor++ = ':'; + *cursor++ = ':'; + i += (max - 1); + } + } + } + return dst; +} + +// Helper function for inet_pton for IPv4 addresses. +// `src` points to a character string containing an IPv4 network address in +// dotted-decimal format, "ddd.ddd.ddd.ddd", where ddd is a decimal number +// of up to three digits in the range 0 to 255. +// The address is converted and copied to dst, +// which must be sizeof(struct in_addr) (4) bytes (32 bits) long. +int inet_pton_v4(const char* src, void* dst) { + const int kIpv4AddressSize = 4; + int found = 0; + const char* src_pos = src; + unsigned char result[kIpv4AddressSize] = {0}; + + while (*src_pos != '\0') { + // strtol won't treat whitespace characters in the begining as an error, + // so check to ensure this is started with digit before passing to strtol. + if (!isdigit(*src_pos)) { + return 0; + } + char* end_pos; + long value = strtol(src_pos, &end_pos, 10); + if (value < 0 || value > 255 || src_pos == end_pos) { + return 0; + } + ++found; + if (found > kIpv4AddressSize) { + return 0; + } + result[found - 1] = static_cast<unsigned char>(value); + src_pos = end_pos; + if (*src_pos == '.') { + // There's more. + ++src_pos; + } else if (*src_pos != '\0') { + // If it's neither '.' nor '\0' then return fail. + return 0; + } + } + if (found != kIpv4AddressSize) { + return 0; + } + memcpy(dst, result, sizeof(result)); + return 1; +} + +// Helper function for inet_pton for IPv6 addresses. +int inet_pton_v6(const char* src, void* dst) { + // sscanf will pick any other invalid chars up, but it parses 0xnnnn as hex. + // Check for literal x in the input string. + const char* readcursor = src; + char c = *readcursor++; + while (c) { + if (c == 'x') { + return 0; + } + c = *readcursor++; + } + readcursor = src; + + struct in6_addr an_addr; + memset(&an_addr, 0, sizeof(an_addr)); + + uint16_t* addr_cursor = reinterpret_cast<uint16_t*>(&an_addr.s6_addr[0]); + uint16_t* addr_end = reinterpret_cast<uint16_t*>(&an_addr.s6_addr[16]); + bool seencompressed = false; + + // Addresses that start with "::" (i.e., a run of initial zeros) or + // "::ffff:" can potentially be IPv4 mapped or compatibility addresses. + // These have dotted-style IPv4 addresses on the end (e.g. "::192.168.7.1"). + if (*readcursor == ':' && *(readcursor + 1) == ':' && + *(readcursor + 2) != 0) { + // Check for periods, which we'll take as a sign of v4 addresses. + const char* addrstart = readcursor + 2; + if (strchr(addrstart, '.')) { + const char* colon = strchr(addrstart, ':'); + if (colon) { + uint16_t a_short; + int bytesread = 0; + if (sscanf(addrstart, "%hx%n", &a_short, &bytesread) != 1 || + a_short != 0xFFFF || bytesread != 4) { + // Colons + periods means has to be ::ffff:a.b.c.d. But it wasn't. + return 0; + } else { + an_addr.s6_addr[10] = 0xFF; + an_addr.s6_addr[11] = 0xFF; + addrstart = colon + 1; + } + } + struct in_addr v4; + if (inet_pton_v4(addrstart, &v4.s_addr)) { + memcpy(&an_addr.s6_addr[12], &v4, sizeof(v4)); + memcpy(dst, &an_addr, sizeof(an_addr)); + return 1; + } else { + // Invalid v4 address. + return 0; + } + } + } + + // For addresses without a trailing IPv4 component ('normal' IPv6 addresses). + while (*readcursor != 0 && addr_cursor < addr_end) { + if (*readcursor == ':') { + if (*(readcursor + 1) == ':') { + if (seencompressed) { + // Can only have one compressed run of zeroes ("::") per address. + return 0; + } + // Hit a compressed run. Count colons to figure out how much of the + // address is skipped. + readcursor += 2; + const char* coloncounter = readcursor; + int coloncount = 0; + if (*coloncounter == 0) { + // Special case - trailing ::. + addr_cursor = addr_end; + } else { + while (*coloncounter) { + if (*coloncounter == ':') { + ++coloncount; + } + ++coloncounter; + } + // (coloncount + 1) is the number of shorts left in the address. + // If this number is greater than the number of available shorts, the + // address is malformed. + if (coloncount + 1 > addr_end - addr_cursor) { + return 0; + } + addr_cursor = addr_end - (coloncount + 1); + seencompressed = true; + } + } else { + ++readcursor; + } + } else { + uint16_t word; + int bytesread = 0; + if (sscanf(readcursor, "%4hx%n", &word, &bytesread) != 1) { + return 0; + } else { + *addr_cursor = HostToNetwork16(word); + ++addr_cursor; + readcursor += bytesread; + if (*readcursor != ':' && *readcursor != '\0') { + return 0; + } + } + } + } + + if (*readcursor != '\0' || addr_cursor < addr_end) { + // Catches addresses too short or too long. + return 0; + } + memcpy(dst, &an_addr, sizeof(an_addr)); + return 1; +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/win32.h b/third_party/libwebrtc/rtc_base/win32.h new file mode 100644 index 0000000000..6e8d2873aa --- /dev/null +++ b/third_party/libwebrtc/rtc_base/win32.h @@ -0,0 +1,48 @@ +/* + * 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 RTC_BASE_WIN32_H_ +#define RTC_BASE_WIN32_H_ + +#ifndef WEBRTC_WIN +#error "Only #include this header in Windows builds" +#endif + +// Make sure we don't get min/max macros +#ifndef NOMINMAX +#define NOMINMAX +#endif + +#include <winsock2.h> + +// Must be after winsock2.h. +#include <windows.h> + +typedef int socklen_t; + +#ifndef SECURITY_MANDATORY_LABEL_AUTHORITY +// Add defines that we use if we are compiling against older sdks +#define SECURITY_MANDATORY_MEDIUM_RID (0x00002000L) +#define TokenIntegrityLevel static_cast<TOKEN_INFORMATION_CLASS>(0x19) +typedef struct _TOKEN_MANDATORY_LABEL { + SID_AND_ATTRIBUTES Label; +} TOKEN_MANDATORY_LABEL, *PTOKEN_MANDATORY_LABEL; +#endif // SECURITY_MANDATORY_LABEL_AUTHORITY + +#undef SetPort + +namespace rtc { + +const char* win32_inet_ntop(int af, const void* src, char* dst, socklen_t size); +int win32_inet_pton(int af, const char* src, void* dst); + +} // namespace rtc + +#endif // RTC_BASE_WIN32_H_ diff --git a/third_party/libwebrtc/rtc_base/win32_gn/moz.build b/third_party/libwebrtc/rtc_base/win32_gn/moz.build new file mode 100644 index 0000000000..607a23eb5e --- /dev/null +++ b/third_party/libwebrtc/rtc_base/win32_gn/moz.build @@ -0,0 +1,92 @@ +# 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["CERT_CHAIN_PARA_HAS_EXTRA_FIELDS"] = True +DEFINES["NOMINMAX"] = True +DEFINES["NTDDI_VERSION"] = "0x0A000000" +DEFINES["PSAPI_VERSION"] = "2" +DEFINES["RTC_DAV1D_IN_INTERNAL_DECODER_FACTORY"] = True +DEFINES["RTC_ENABLE_VP9"] = True +DEFINES["RTC_ENABLE_WIN_WGC"] = True +DEFINES["UNICODE"] = True +DEFINES["USE_AURA"] = "1" +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" +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_NONSTDC_NO_DEPRECATE"] = 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 + +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" +] + +OS_LIBS += [ + "crypt32", + "iphlpapi", + "secur32" +] + +UNIFIED_SOURCES += [ + "/third_party/libwebrtc/rtc_base/win32.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" + DEFINES["_HAS_ITERATOR_DEBUGGING"] = "0" + +if CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +Library("win32_gn") diff --git a/third_party/libwebrtc/rtc_base/win32_socket_init.h b/third_party/libwebrtc/rtc_base/win32_socket_init.h new file mode 100644 index 0000000000..4a90e142b6 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/win32_socket_init.h @@ -0,0 +1,41 @@ +/* + * Copyright 2009 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 RTC_BASE_WIN32_SOCKET_INIT_H_ +#define RTC_BASE_WIN32_SOCKET_INIT_H_ + +#ifndef WEBRTC_WIN +#error "Only #include this header in Windows builds" +#endif + +#include "rtc_base/win32.h" + +namespace rtc { + +class WinsockInitializer { + public: + WinsockInitializer() { + WSADATA wsaData; + WORD wVersionRequested = MAKEWORD(1, 0); + err_ = WSAStartup(wVersionRequested, &wsaData); + } + ~WinsockInitializer() { + if (!err_) + WSACleanup(); + } + int error() { return err_; } + + private: + int err_; +}; + +} // namespace rtc + +#endif // RTC_BASE_WIN32_SOCKET_INIT_H_ diff --git a/third_party/libwebrtc/rtc_base/win32_unittest.cc b/third_party/libwebrtc/rtc_base/win32_unittest.cc new file mode 100644 index 0000000000..b2955e500a --- /dev/null +++ b/third_party/libwebrtc/rtc_base/win32_unittest.cc @@ -0,0 +1,89 @@ +/* + * Copyright 2010 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 "rtc_base/win32.h" + +#include <string> + +#include "rtc_base/gunit.h" +#include "rtc_base/net_helpers.h" + +#if !defined(WEBRTC_WIN) +#error Only for Windows +#endif + +namespace rtc { + +class Win32Test : public ::testing::Test { + public: + Win32Test() {} +}; + +TEST_F(Win32Test, IPv6AddressCompression) { + IPAddress ipv6; + + // Zero compression should be done on the leftmost 0s when there are + // multiple longest series. + ASSERT_TRUE(IPFromString("2a00:8a00:a000:1190:0000:0001:000:252", &ipv6)); + EXPECT_EQ("2a00:8a00:a000:1190::1:0:252", ipv6.ToString()); + + // Ensure the zero compression could handle multiple octects. + ASSERT_TRUE(IPFromString("0:0:0:0:0:0:0:1", &ipv6)); + EXPECT_EQ("::1", ipv6.ToString()); + + // Make sure multiple 0 octects compressed. + ASSERT_TRUE(IPFromString("fe80:0:0:0:2aa:ff:fe9a:4ca2", &ipv6)); + EXPECT_EQ("fe80::2aa:ff:fe9a:4ca2", ipv6.ToString()); + + // Test zero compression at the end of string. + ASSERT_TRUE(IPFromString("2a00:8a00:a000:1190:0000:0001:000:00", &ipv6)); + EXPECT_EQ("2a00:8a00:a000:1190:0:1::", ipv6.ToString()); + + // Test zero compression at the beginning of string. + ASSERT_TRUE(IPFromString("0:0:000:1190:0000:0001:000:00", &ipv6)); + EXPECT_EQ("::1190:0:1:0:0", ipv6.ToString()); + + // Test zero compression only done once. + ASSERT_TRUE(IPFromString("0:1:000:1190:0000:0001:000:01", &ipv6)); + EXPECT_EQ("::1:0:1190:0:1:0:1", ipv6.ToString()); + + // Make sure noncompressable IPv6 is the same. + ASSERT_TRUE(IPFromString("1234:5678:abcd:1234:5678:abcd:1234:5678", &ipv6)); + EXPECT_EQ("1234:5678:abcd:1234:5678:abcd:1234:5678", ipv6.ToString()); +} + +// Test that invalid IPv6 addresses are recognized and false is returned. +TEST_F(Win32Test, InvalidIPv6AddressParsing) { + IPAddress ipv6; + + // More than 1 run of "::"s. + EXPECT_FALSE(IPFromString("1::2::3", &ipv6)); + + // More than 1 run of "::"s in a longer address. + // See: https://bugs.chromium.org/p/webrtc/issues/detail?id=7592 + EXPECT_FALSE(IPFromString("1::2::3::4::5::6::7::8", &ipv6)); + + // Three ':'s in a row. + EXPECT_FALSE(IPFromString("1:::2", &ipv6)); + + // Non-hex character. + EXPECT_FALSE(IPFromString("test::1", &ipv6)); + + // More than 4 hex digits per group. + EXPECT_FALSE(IPFromString("abcde::1", &ipv6)); + + // More than 8 groups. + EXPECT_FALSE(IPFromString("1:2:3:4:5:6:7:8:9", &ipv6)); + + // Less than 8 groups. + EXPECT_FALSE(IPFromString("1:2:3:4:5:6:7", &ipv6)); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/zero_memory.cc b/third_party/libwebrtc/rtc_base/zero_memory.cc new file mode 100644 index 0000000000..b9c5b380ac --- /dev/null +++ b/third_party/libwebrtc/rtc_base/zero_memory.cc @@ -0,0 +1,38 @@ +/* + * Copyright 2017 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. + */ + +#if defined(WEBRTC_WIN) +#include <windows.h> +#else +#include <string.h> +#endif + +#include "rtc_base/checks.h" +#include "rtc_base/zero_memory.h" + +namespace rtc { + +// Code and comment taken from "OPENSSL_cleanse" of BoringSSL. +void ExplicitZeroMemory(void* ptr, size_t len) { + RTC_DCHECK(ptr || !len); +#if defined(WEBRTC_WIN) + SecureZeroMemory(ptr, len); +#else + memset(ptr, 0, len); +#if !defined(__pnacl__) + /* As best as we can tell, this is sufficient to break any optimisations that + might try to eliminate "superfluous" memsets. If there's an easy way to + detect memset_s, it would be better to use that. */ + __asm__ __volatile__("" : : "r"(ptr) : "memory"); // NOLINT +#endif +#endif // !WEBRTC_WIN +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/zero_memory.h b/third_party/libwebrtc/rtc_base/zero_memory.h new file mode 100644 index 0000000000..b92f52f9b6 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/zero_memory.h @@ -0,0 +1,35 @@ +/* + * Copyright 2017 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 RTC_BASE_ZERO_MEMORY_H_ +#define RTC_BASE_ZERO_MEMORY_H_ + +#include <stddef.h> + +#include <type_traits> + +#include "api/array_view.h" + +namespace rtc { + +// Fill memory with zeros in a way that the compiler doesn't optimize it away +// even if the pointer is not used afterwards. +void ExplicitZeroMemory(void* ptr, size_t len); + +template <typename T, + typename std::enable_if<!std::is_const<T>::value && + std::is_trivial<T>::value>::type* = nullptr> +void ExplicitZeroMemory(rtc::ArrayView<T> a) { + ExplicitZeroMemory(a.data(), a.size()); +} + +} // namespace rtc + +#endif // RTC_BASE_ZERO_MEMORY_H_ diff --git a/third_party/libwebrtc/rtc_base/zero_memory_gn/moz.build b/third_party/libwebrtc/rtc_base/zero_memory_gn/moz.build new file mode 100644 index 0000000000..1029a25252 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/zero_memory_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/rtc_base/zero_memory.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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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_ENABLE_LIBEVENT"] = 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["RTC_ENABLE_WIN_WGC"] = True + 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["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "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["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("zero_memory_gn") diff --git a/third_party/libwebrtc/rtc_base/zero_memory_unittest.cc b/third_party/libwebrtc/rtc_base/zero_memory_unittest.cc new file mode 100644 index 0000000000..74d95f49e9 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/zero_memory_unittest.cc @@ -0,0 +1,53 @@ +/* + * Copyright 2017 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 "rtc_base/zero_memory.h" + +#include <stdint.h> + +#include "api/array_view.h" +#include "test/gtest.h" + +namespace rtc { + +TEST(ZeroMemoryTest, TestZeroMemory) { + static const size_t kBufferSize = 32; + uint8_t buffer[kBufferSize]; + for (size_t i = 0; i < kBufferSize; i++) { + buffer[i] = static_cast<uint8_t>(i + 1); + } + ExplicitZeroMemory(buffer, sizeof(buffer)); + for (size_t i = 0; i < kBufferSize; i++) { + EXPECT_EQ(buffer[i], 0); + } +} + +TEST(ZeroMemoryTest, TestZeroArrayView) { + static const size_t kBufferSize = 32; + uint8_t buffer[kBufferSize]; + for (size_t i = 0; i < kBufferSize; i++) { + buffer[i] = static_cast<uint8_t>(i + 1); + } + ExplicitZeroMemory(rtc::ArrayView<uint8_t>(buffer, sizeof(buffer))); + for (size_t i = 0; i < kBufferSize; i++) { + EXPECT_EQ(buffer[i], 0); + } +} + +// While this test doesn't actually test anything, it can be used to check +// the compiler output to make sure the call to "ExplicitZeroMemory" is not +// optimized away. +TEST(ZeroMemoryTest, TestZeroMemoryUnused) { + static const size_t kBufferSize = 32; + uint8_t buffer[kBufferSize]; + ExplicitZeroMemory(buffer, sizeof(buffer)); +} + +} // namespace rtc |