summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/rtc_base
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--third_party/libwebrtc/rtc_base/BUILD.gn2227
-rw-r--r--third_party/libwebrtc/rtc_base/DEPS15
-rw-r--r--third_party/libwebrtc/rtc_base/OWNERS7
-rw-r--r--third_party/libwebrtc/rtc_base/arraysize.h32
-rw-r--r--third_party/libwebrtc/rtc_base/async_dns_resolver.cc204
-rw-r--r--third_party/libwebrtc/rtc_base/async_dns_resolver.h63
-rw-r--r--third_party/libwebrtc/rtc_base/async_dns_resolver_gn/moz.build233
-rw-r--r--third_party/libwebrtc/rtc_base/async_dns_resolver_unittest.cc58
-rw-r--r--third_party/libwebrtc/rtc_base/async_packet_socket.cc49
-rw-r--r--third_party/libwebrtc/rtc_base/async_packet_socket.h191
-rw-r--r--third_party/libwebrtc/rtc_base/async_packet_socket_gn/moz.build205
-rw-r--r--third_party/libwebrtc/rtc_base/async_resolver.cc239
-rw-r--r--third_party/libwebrtc/rtc_base/async_resolver.h80
-rw-r--r--third_party/libwebrtc/rtc_base/async_resolver_interface.cc19
-rw-r--r--third_party/libwebrtc/rtc_base/async_resolver_interface.h55
-rw-r--r--third_party/libwebrtc/rtc_base/async_resolver_interface_gn/moz.build233
-rw-r--r--third_party/libwebrtc/rtc_base/async_socket.cc113
-rw-r--r--third_party/libwebrtc/rtc_base/async_socket.h65
-rw-r--r--third_party/libwebrtc/rtc_base/async_tcp_socket.cc354
-rw-r--r--third_party/libwebrtc/rtc_base/async_tcp_socket.h123
-rw-r--r--third_party/libwebrtc/rtc_base/async_tcp_socket_unittest.cc47
-rw-r--r--third_party/libwebrtc/rtc_base/async_udp_socket.cc147
-rw-r--r--third_party/libwebrtc/rtc_base/async_udp_socket.h78
-rw-r--r--third_party/libwebrtc/rtc_base/async_udp_socket_unittest.cc50
-rw-r--r--third_party/libwebrtc/rtc_base/audio_format_to_string_gn/moz.build232
-rw-r--r--third_party/libwebrtc/rtc_base/base64_unittest.cc1454
-rw-r--r--third_party/libwebrtc/rtc_base/bit_buffer.cc230
-rw-r--r--third_party/libwebrtc/rtc_base/bit_buffer.h100
-rw-r--r--third_party/libwebrtc/rtc_base/bit_buffer_gn/moz.build225
-rw-r--r--third_party/libwebrtc/rtc_base/bit_buffer_unittest.cc256
-rw-r--r--third_party/libwebrtc/rtc_base/bitrate_tracker.cc38
-rw-r--r--third_party/libwebrtc/rtc_base/bitrate_tracker.h64
-rw-r--r--third_party/libwebrtc/rtc_base/bitrate_tracker_gn/moz.build232
-rw-r--r--third_party/libwebrtc/rtc_base/bitrate_tracker_unittest.cc267
-rw-r--r--third_party/libwebrtc/rtc_base/bitstream_reader.cc167
-rw-r--r--third_party/libwebrtc/rtc_base/bitstream_reader.h151
-rw-r--r--third_party/libwebrtc/rtc_base/bitstream_reader_gn/moz.build225
-rw-r--r--third_party/libwebrtc/rtc_base/bitstream_reader_unittest.cc373
-rw-r--r--third_party/libwebrtc/rtc_base/boringssl_certificate.cc412
-rw-r--r--third_party/libwebrtc/rtc_base/boringssl_certificate.h82
-rw-r--r--third_party/libwebrtc/rtc_base/boringssl_identity.cc216
-rw-r--r--third_party/libwebrtc/rtc_base/boringssl_identity.h77
-rw-r--r--third_party/libwebrtc/rtc_base/bounded_inline_vector.h155
-rw-r--r--third_party/libwebrtc/rtc_base/bounded_inline_vector_impl.h225
-rw-r--r--third_party/libwebrtc/rtc_base/bounded_inline_vector_unittest.cc133
-rw-r--r--third_party/libwebrtc/rtc_base/buffer.h452
-rw-r--r--third_party/libwebrtc/rtc_base/buffer_gn/moz.build209
-rw-r--r--third_party/libwebrtc/rtc_base/buffer_queue.cc85
-rw-r--r--third_party/libwebrtc/rtc_base/buffer_queue.h70
-rw-r--r--third_party/libwebrtc/rtc_base/buffer_queue_unittest.cc89
-rw-r--r--third_party/libwebrtc/rtc_base/buffer_unittest.cc548
-rw-r--r--third_party/libwebrtc/rtc_base/byte_buffer.cc160
-rw-r--r--third_party/libwebrtc/rtc_base/byte_buffer.h173
-rw-r--r--third_party/libwebrtc/rtc_base/byte_buffer_gn/moz.build225
-rw-r--r--third_party/libwebrtc/rtc_base/byte_buffer_unittest.cc250
-rw-r--r--third_party/libwebrtc/rtc_base/byte_order.h214
-rw-r--r--third_party/libwebrtc/rtc_base/byte_order_gn/moz.build205
-rw-r--r--third_party/libwebrtc/rtc_base/byte_order_unittest.cc83
-rw-r--r--third_party/libwebrtc/rtc_base/callback_list.cc121
-rw-r--r--third_party/libwebrtc/rtc_base/callback_list.h223
-rw-r--r--third_party/libwebrtc/rtc_base/callback_list_unittest.cc270
-rw-r--r--third_party/libwebrtc/rtc_base/checks.cc240
-rw-r--r--third_party/libwebrtc/rtc_base/checks.h520
-rw-r--r--third_party/libwebrtc/rtc_base/checks_gn/moz.build225
-rw-r--r--third_party/libwebrtc/rtc_base/checks_unittest.cc73
-rw-r--r--third_party/libwebrtc/rtc_base/compile_assert_c.h25
-rw-r--r--third_party/libwebrtc/rtc_base/compile_assert_c_gn/moz.build205
-rw-r--r--third_party/libwebrtc/rtc_base/containers/BUILD.gn56
-rw-r--r--third_party/libwebrtc/rtc_base/containers/flat_containers_internal_gn/moz.build225
-rw-r--r--third_party/libwebrtc/rtc_base/containers/flat_map.h374
-rw-r--r--third_party/libwebrtc/rtc_base/containers/flat_map_gn/moz.build209
-rw-r--r--third_party/libwebrtc/rtc_base/containers/flat_map_unittest.cc455
-rw-r--r--third_party/libwebrtc/rtc_base/containers/flat_set.h178
-rw-r--r--third_party/libwebrtc/rtc_base/containers/flat_set_gn/moz.build209
-rw-r--r--third_party/libwebrtc/rtc_base/containers/flat_set_unittest.cc149
-rw-r--r--third_party/libwebrtc/rtc_base/containers/flat_tree.cc19
-rw-r--r--third_party/libwebrtc/rtc_base/containers/flat_tree.h1099
-rw-r--r--third_party/libwebrtc/rtc_base/containers/flat_tree_unittest.cc1484
-rw-r--r--third_party/libwebrtc/rtc_base/containers/identity.h36
-rw-r--r--third_party/libwebrtc/rtc_base/containers/invoke.h162
-rw-r--r--third_party/libwebrtc/rtc_base/containers/move_only_int.h74
-rw-r--r--third_party/libwebrtc/rtc_base/copy_on_write_buffer.cc127
-rw-r--r--third_party/libwebrtc/rtc_base/copy_on_write_buffer.h316
-rw-r--r--third_party/libwebrtc/rtc_base/copy_on_write_buffer_gn/moz.build225
-rw-r--r--third_party/libwebrtc/rtc_base/copy_on_write_buffer_unittest.cc378
-rw-r--r--third_party/libwebrtc/rtc_base/cpu_time.cc145
-rw-r--r--third_party/libwebrtc/rtc_base/cpu_time.h28
-rw-r--r--third_party/libwebrtc/rtc_base/cpu_time_unittest.cc102
-rw-r--r--third_party/libwebrtc/rtc_base/crc32.cc50
-rw-r--r--third_party/libwebrtc/rtc_base/crc32.h37
-rw-r--r--third_party/libwebrtc/rtc_base/crc32_unittest.cc37
-rw-r--r--third_party/libwebrtc/rtc_base/criticalsection_gn/moz.build225
-rw-r--r--third_party/libwebrtc/rtc_base/crypt_string.cc46
-rw-r--r--third_party/libwebrtc/rtc_base/crypt_string.h70
-rw-r--r--third_party/libwebrtc/rtc_base/data_rate_limiter.cc29
-rw-r--r--third_party/libwebrtc/rtc_base/data_rate_limiter.h58
-rw-r--r--third_party/libwebrtc/rtc_base/data_rate_limiter_unittest.cc60
-rw-r--r--third_party/libwebrtc/rtc_base/deprecated/recursive_critical_section.cc218
-rw-r--r--third_party/libwebrtc/rtc_base/deprecated/recursive_critical_section.h107
-rw-r--r--third_party/libwebrtc/rtc_base/deprecated/recursive_critical_section_unittest.cc288
-rw-r--r--third_party/libwebrtc/rtc_base/divide_round_gn/moz.build209
-rw-r--r--third_party/libwebrtc/rtc_base/dscp.h45
-rw-r--r--third_party/libwebrtc/rtc_base/dscp_gn/moz.build205
-rw-r--r--third_party/libwebrtc/rtc_base/event.cc210
-rw-r--r--third_party/libwebrtc/rtc_base/event.h137
-rw-r--r--third_party/libwebrtc/rtc_base/event_tracer.cc412
-rw-r--r--third_party/libwebrtc/rtc_base/event_tracer.h85
-rw-r--r--third_party/libwebrtc/rtc_base/event_tracer_gn/moz.build232
-rw-r--r--third_party/libwebrtc/rtc_base/event_tracer_unittest.cc75
-rw-r--r--third_party/libwebrtc/rtc_base/event_unittest.cc115
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/BUILD.gn302
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/DEPS8
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/OWNERS13
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/alr_experiment.cc98
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/alr_experiment.h48
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/alr_experiment_gn/moz.build232
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/balanced_degradation_settings.cc487
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/balanced_degradation_settings.h143
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/balanced_degradation_settings_gn/moz.build232
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/balanced_degradation_settings_unittest.cc619
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/bandwidth_quality_scaler_settings.cc43
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/bandwidth_quality_scaler_settings.h35
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/bandwidth_quality_scaler_settings_gn/moz.build232
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/bandwidth_quality_scaler_settings_unittest.cc49
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/cpu_speed_experiment.cc89
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/cpu_speed_experiment.h64
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/cpu_speed_experiment_gn/moz.build232
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/cpu_speed_experiment_unittest.cc106
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/encoder_info_settings.cc236
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/encoder_info_settings.h100
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/encoder_info_settings_gn/moz.build232
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/encoder_info_settings_unittest.cc102
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/field_trial_list.cc59
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/field_trial_list.h226
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/field_trial_list_unittest.cc141
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/field_trial_parser.cc260
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/field_trial_parser.h291
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/field_trial_parser_gn/moz.build235
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/field_trial_parser_unittest.cc187
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/field_trial_units.cc116
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/field_trial_units.h41
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/field_trial_units_unittest.cc87
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/keyframe_interval_settings.cc39
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/keyframe_interval_settings.h39
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/keyframe_interval_settings_experiment_gn/moz.build232
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/keyframe_interval_settings_unittest.cc43
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/min_video_bitrate_experiment.cc116
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/min_video_bitrate_experiment.h28
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/min_video_bitrate_experiment_gn/moz.build232
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/min_video_bitrate_experiment_unittest.cc161
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/normalize_simulcast_size_experiment.cc49
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/normalize_simulcast_size_experiment.h25
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/normalize_simulcast_size_experiment_gn/moz.build232
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/normalize_simulcast_size_experiment_unittest.cc59
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/quality_rampup_experiment.cc82
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/quality_rampup_experiment.h53
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/quality_rampup_experiment_gn/moz.build232
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/quality_rampup_experiment_unittest.cc139
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/quality_scaler_settings.cc96
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/quality_scaler_settings.h44
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/quality_scaler_settings_gn/moz.build232
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/quality_scaler_settings_unittest.cc100
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/quality_scaling_experiment.cc117
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/quality_scaling_experiment.h61
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/quality_scaling_experiment_gn/moz.build232
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/quality_scaling_experiment_unittest.cc186
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/rate_control_settings.cc183
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/rate_control_settings.h93
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/rate_control_settings_gn/moz.build232
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/rate_control_settings_unittest.cc191
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/rtt_mult_experiment.cc39
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/rtt_mult_experiment.h35
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/rtt_mult_experiment_gn/moz.build232
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/rtt_mult_experiment_unittest.cc31
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/stable_target_rate_experiment.cc63
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/stable_target_rate_experiment.h44
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/stable_target_rate_experiment_gn/moz.build232
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/stable_target_rate_experiment_unittest.cc67
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/struct_parameters_parser.cc135
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/struct_parameters_parser.h110
-rw-r--r--third_party/libwebrtc/rtc_base/experiments/struct_parameters_parser_unittest.cc68
-rw-r--r--third_party/libwebrtc/rtc_base/fake_clock.cc62
-rw-r--r--third_party/libwebrtc/rtc_base/fake_clock.h83
-rw-r--r--third_party/libwebrtc/rtc_base/fake_clock_unittest.cc37
-rw-r--r--third_party/libwebrtc/rtc_base/fake_mdns_responder.h71
-rw-r--r--third_party/libwebrtc/rtc_base/fake_network.h139
-rw-r--r--third_party/libwebrtc/rtc_base/fake_ssl_identity.cc121
-rw-r--r--third_party/libwebrtc/rtc_base/fake_ssl_identity.h83
-rw-r--r--third_party/libwebrtc/rtc_base/file_rotating_stream.cc428
-rw-r--r--third_party/libwebrtc/rtc_base/file_rotating_stream.h173
-rw-r--r--third_party/libwebrtc/rtc_base/file_rotating_stream_unittest.cc394
-rw-r--r--third_party/libwebrtc/rtc_base/firewall_socket_server.cc268
-rw-r--r--third_party/libwebrtc/rtc_base/firewall_socket_server.h129
-rw-r--r--third_party/libwebrtc/rtc_base/frequency_tracker.cc35
-rw-r--r--third_party/libwebrtc/rtc_base/frequency_tracker.h56
-rw-r--r--third_party/libwebrtc/rtc_base/frequency_tracker_gn/moz.build232
-rw-r--r--third_party/libwebrtc/rtc_base/frequency_tracker_unittest.cc203
-rw-r--r--third_party/libwebrtc/rtc_base/gtest_prod_gn/moz.build205
-rw-r--r--third_party/libwebrtc/rtc_base/gtest_prod_util.h38
-rw-r--r--third_party/libwebrtc/rtc_base/gunit.cc43
-rw-r--r--third_party/libwebrtc/rtc_base/gunit.h169
-rw-r--r--third_party/libwebrtc/rtc_base/helpers.cc231
-rw-r--r--third_party/libwebrtc/rtc_base/helpers.h92
-rw-r--r--third_party/libwebrtc/rtc_base/helpers_unittest.cc171
-rw-r--r--third_party/libwebrtc/rtc_base/histogram_percentile_counter_gn/moz.build225
-rw-r--r--third_party/libwebrtc/rtc_base/http_common.cc555
-rw-r--r--third_party/libwebrtc/rtc_base/http_common.h53
-rw-r--r--third_party/libwebrtc/rtc_base/ifaddrs_android.cc227
-rw-r--r--third_party/libwebrtc/rtc_base/ifaddrs_android.h38
-rw-r--r--third_party/libwebrtc/rtc_base/ifaddrs_android_gn/moz.build100
-rw-r--r--third_party/libwebrtc/rtc_base/ifaddrs_converter.cc62
-rw-r--r--third_party/libwebrtc/rtc_base/ifaddrs_converter.h45
-rw-r--r--third_party/libwebrtc/rtc_base/ignore_wundef.h33
-rw-r--r--third_party/libwebrtc/rtc_base/ignore_wundef_gn/moz.build205
-rw-r--r--third_party/libwebrtc/rtc_base/internal/default_socket_server.cc33
-rw-r--r--third_party/libwebrtc/rtc_base/internal/default_socket_server.h24
-rw-r--r--third_party/libwebrtc/rtc_base/ip_address.cc578
-rw-r--r--third_party/libwebrtc/rtc_base/ip_address.h206
-rw-r--r--third_party/libwebrtc/rtc_base/ip_address_gn/moz.build232
-rw-r--r--third_party/libwebrtc/rtc_base/ip_address_unittest.cc977
-rw-r--r--third_party/libwebrtc/rtc_base/java/src/org/webrtc/ContextUtils.java45
-rw-r--r--third_party/libwebrtc/rtc_base/java/src/org/webrtc/Loggable.java22
-rw-r--r--third_party/libwebrtc/rtc_base/java/src/org/webrtc/Logging.java201
-rw-r--r--third_party/libwebrtc/rtc_base/java/src/org/webrtc/OWNERS2
-rw-r--r--third_party/libwebrtc/rtc_base/java/src/org/webrtc/Size.java45
-rw-r--r--third_party/libwebrtc/rtc_base/java/src/org/webrtc/ThreadUtils.java212
-rw-r--r--third_party/libwebrtc/rtc_base/log_sinks.cc86
-rw-r--r--third_party/libwebrtc/rtc_base/log_sinks.h80
-rw-r--r--third_party/libwebrtc/rtc_base/logging.cc608
-rw-r--r--third_party/libwebrtc/rtc_base/logging.h780
-rw-r--r--third_party/libwebrtc/rtc_base/logging_gn/moz.build233
-rw-r--r--third_party/libwebrtc/rtc_base/logging_unittest.cc386
-rw-r--r--third_party/libwebrtc/rtc_base/mac_ifaddrs_converter.cc282
-rw-r--r--third_party/libwebrtc/rtc_base/macromagic_gn/moz.build205
-rw-r--r--third_party/libwebrtc/rtc_base/mdns_responder_interface.h51
-rw-r--r--third_party/libwebrtc/rtc_base/memory/BUILD.gn61
-rw-r--r--third_party/libwebrtc/rtc_base/memory/aligned_malloc.cc98
-rw-r--r--third_party/libwebrtc/rtc_base/memory/aligned_malloc.h57
-rw-r--r--third_party/libwebrtc/rtc_base/memory/aligned_malloc_gn/moz.build225
-rw-r--r--third_party/libwebrtc/rtc_base/memory/aligned_malloc_unittest.cc81
-rw-r--r--third_party/libwebrtc/rtc_base/memory/always_valid_pointer.h248
-rw-r--r--third_party/libwebrtc/rtc_base/memory/always_valid_pointer_unittest.cc129
-rw-r--r--third_party/libwebrtc/rtc_base/memory/fifo_buffer.cc197
-rw-r--r--third_party/libwebrtc/rtc_base/memory/fifo_buffer.h118
-rw-r--r--third_party/libwebrtc/rtc_base/memory/fifo_buffer_unittest.cc249
-rw-r--r--third_party/libwebrtc/rtc_base/memory_stream.cc144
-rw-r--r--third_party/libwebrtc/rtc_base/memory_stream.h59
-rw-r--r--third_party/libwebrtc/rtc_base/memory_usage.cc85
-rw-r--r--third_party/libwebrtc/rtc_base/memory_usage.h24
-rw-r--r--third_party/libwebrtc/rtc_base/memory_usage_unittest.cc22
-rw-r--r--third_party/libwebrtc/rtc_base/message_digest.cc183
-rw-r--r--third_party/libwebrtc/rtc_base/message_digest.h133
-rw-r--r--third_party/libwebrtc/rtc_base/message_digest_unittest.cc156
-rw-r--r--third_party/libwebrtc/rtc_base/mod_ops_gn/moz.build209
-rw-r--r--third_party/libwebrtc/rtc_base/moving_max_counter_gn/moz.build209
-rw-r--r--third_party/libwebrtc/rtc_base/nat_server.cc255
-rw-r--r--third_party/libwebrtc/rtc_base/nat_server.h131
-rw-r--r--third_party/libwebrtc/rtc_base/nat_socket_factory.cc515
-rw-r--r--third_party/libwebrtc/rtc_base/nat_socket_factory.h179
-rw-r--r--third_party/libwebrtc/rtc_base/nat_types.cc61
-rw-r--r--third_party/libwebrtc/rtc_base/nat_types.h47
-rw-r--r--third_party/libwebrtc/rtc_base/nat_unittest.cc408
-rw-r--r--third_party/libwebrtc/rtc_base/net_helper.cc33
-rw-r--r--third_party/libwebrtc/rtc_base/net_helper.h35
-rw-r--r--third_party/libwebrtc/rtc_base/net_helpers.cc45
-rw-r--r--third_party/libwebrtc/rtc_base/net_helpers.h34
-rw-r--r--third_party/libwebrtc/rtc_base/net_helpers_gn/moz.build232
-rw-r--r--third_party/libwebrtc/rtc_base/net_test_helpers.cc111
-rw-r--r--third_party/libwebrtc/rtc_base/net_test_helpers.h23
-rw-r--r--third_party/libwebrtc/rtc_base/network.cc1306
-rw-r--r--third_party/libwebrtc/rtc_base/network.h601
-rw-r--r--third_party/libwebrtc/rtc_base/network/BUILD.gn33
-rw-r--r--third_party/libwebrtc/rtc_base/network/received_packet.cc23
-rw-r--r--third_party/libwebrtc/rtc_base/network/received_packet.h47
-rw-r--r--third_party/libwebrtc/rtc_base/network/sent_packet.cc27
-rw-r--r--third_party/libwebrtc/rtc_base/network/sent_packet.h69
-rw-r--r--third_party/libwebrtc/rtc_base/network/sent_packet_gn/moz.build221
-rw-r--r--third_party/libwebrtc/rtc_base/network_constants.cc47
-rw-r--r--third_party/libwebrtc/rtc_base/network_constants.h72
-rw-r--r--third_party/libwebrtc/rtc_base/network_constants_gn/moz.build225
-rw-r--r--third_party/libwebrtc/rtc_base/network_monitor.cc30
-rw-r--r--third_party/libwebrtc/rtc_base/network_monitor.h139
-rw-r--r--third_party/libwebrtc/rtc_base/network_monitor_factory.cc18
-rw-r--r--third_party/libwebrtc/rtc_base/network_monitor_factory.h42
-rw-r--r--third_party/libwebrtc/rtc_base/network_route.cc27
-rw-r--r--third_party/libwebrtc/rtc_base/network_route.h95
-rw-r--r--third_party/libwebrtc/rtc_base/network_route_gn/moz.build225
-rw-r--r--third_party/libwebrtc/rtc_base/network_route_unittest.cc24
-rw-r--r--third_party/libwebrtc/rtc_base/network_unittest.cc1704
-rw-r--r--third_party/libwebrtc/rtc_base/null_socket_server.cc41
-rw-r--r--third_party/libwebrtc/rtc_base/null_socket_server.h37
-rw-r--r--third_party/libwebrtc/rtc_base/null_socket_server_gn/moz.build233
-rw-r--r--third_party/libwebrtc/rtc_base/null_socket_server_unittest.cc44
-rw-r--r--third_party/libwebrtc/rtc_base/numerics/divide_round.h60
-rw-r--r--third_party/libwebrtc/rtc_base/numerics/divide_round_unittest.cc178
-rw-r--r--third_party/libwebrtc/rtc_base/numerics/event_based_exponential_moving_average.cc82
-rw-r--r--third_party/libwebrtc/rtc_base/numerics/event_based_exponential_moving_average.h71
-rw-r--r--third_party/libwebrtc/rtc_base/numerics/event_based_exponential_moving_average_unittest.cc227
-rw-r--r--third_party/libwebrtc/rtc_base/numerics/event_rate_counter.cc49
-rw-r--r--third_party/libwebrtc/rtc_base/numerics/event_rate_counter.h44
-rw-r--r--third_party/libwebrtc/rtc_base/numerics/exp_filter.cc43
-rw-r--r--third_party/libwebrtc/rtc_base/numerics/exp_filter.h48
-rw-r--r--third_party/libwebrtc/rtc_base/numerics/exp_filter_unittest.cc72
-rw-r--r--third_party/libwebrtc/rtc_base/numerics/histogram_percentile_counter.cc79
-rw-r--r--third_party/libwebrtc/rtc_base/numerics/histogram_percentile_counter.h45
-rw-r--r--third_party/libwebrtc/rtc_base/numerics/histogram_percentile_counter_unittest.cc44
-rw-r--r--third_party/libwebrtc/rtc_base/numerics/math_utils.h75
-rw-r--r--third_party/libwebrtc/rtc_base/numerics/mod_ops.h142
-rw-r--r--third_party/libwebrtc/rtc_base/numerics/mod_ops_unittest.cc159
-rw-r--r--third_party/libwebrtc/rtc_base/numerics/moving_average.cc60
-rw-r--r--third_party/libwebrtc/rtc_base/numerics/moving_average.h66
-rw-r--r--third_party/libwebrtc/rtc_base/numerics/moving_average_unittest.cc87
-rw-r--r--third_party/libwebrtc/rtc_base/numerics/moving_max_counter.h118
-rw-r--r--third_party/libwebrtc/rtc_base/numerics/moving_max_counter_unittest.cc58
-rw-r--r--third_party/libwebrtc/rtc_base/numerics/moving_percentile_filter.h103
-rw-r--r--third_party/libwebrtc/rtc_base/numerics/moving_percentile_filter_unittest.cc86
-rw-r--r--third_party/libwebrtc/rtc_base/numerics/percentile_filter.h124
-rw-r--r--third_party/libwebrtc/rtc_base/numerics/percentile_filter_unittest.cc142
-rw-r--r--third_party/libwebrtc/rtc_base/numerics/running_statistics.h171
-rw-r--r--third_party/libwebrtc/rtc_base/numerics/running_statistics_unittest.cc197
-rw-r--r--third_party/libwebrtc/rtc_base/numerics/safe_compare.h176
-rw-r--r--third_party/libwebrtc/rtc_base/numerics/safe_compare_unittest.cc395
-rw-r--r--third_party/libwebrtc/rtc_base/numerics/safe_conversions.h74
-rw-r--r--third_party/libwebrtc/rtc_base/numerics/safe_conversions_impl.h177
-rw-r--r--third_party/libwebrtc/rtc_base/numerics/safe_minmax.h335
-rw-r--r--third_party/libwebrtc/rtc_base/numerics/safe_minmax_unittest.cc345
-rw-r--r--third_party/libwebrtc/rtc_base/numerics/sample_counter.cc118
-rw-r--r--third_party/libwebrtc/rtc_base/numerics/sample_counter.h60
-rw-r--r--third_party/libwebrtc/rtc_base/numerics/sample_counter_unittest.cc84
-rw-r--r--third_party/libwebrtc/rtc_base/numerics/sample_stats.cc152
-rw-r--r--third_party/libwebrtc/rtc_base/numerics/sample_stats.h77
-rw-r--r--third_party/libwebrtc/rtc_base/numerics/sequence_number_unwrapper.h80
-rw-r--r--third_party/libwebrtc/rtc_base/numerics/sequence_number_unwrapper_unittest.cc146
-rw-r--r--third_party/libwebrtc/rtc_base/numerics/sequence_number_util.h85
-rw-r--r--third_party/libwebrtc/rtc_base/numerics/sequence_number_util_unittest.cc215
-rw-r--r--third_party/libwebrtc/rtc_base/one_time_event.h60
-rw-r--r--third_party/libwebrtc/rtc_base/one_time_event_gn/moz.build209
-rw-r--r--third_party/libwebrtc/rtc_base/one_time_event_unittest.cc34
-rw-r--r--third_party/libwebrtc/rtc_base/openssl.h25
-rw-r--r--third_party/libwebrtc/rtc_base/openssl_adapter.cc1126
-rw-r--r--third_party/libwebrtc/rtc_base/openssl_adapter.h245
-rw-r--r--third_party/libwebrtc/rtc_base/openssl_adapter_unittest.cc134
-rw-r--r--third_party/libwebrtc/rtc_base/openssl_certificate.cc290
-rw-r--r--third_party/libwebrtc/rtc_base/openssl_certificate.h79
-rw-r--r--third_party/libwebrtc/rtc_base/openssl_digest.cc118
-rw-r--r--third_party/libwebrtc/rtc_base/openssl_digest.h51
-rw-r--r--third_party/libwebrtc/rtc_base/openssl_identity.cc205
-rw-r--r--third_party/libwebrtc/rtc_base/openssl_identity.h75
-rw-r--r--third_party/libwebrtc/rtc_base/openssl_key_pair.cc194
-rw-r--r--third_party/libwebrtc/rtc_base/openssl_key_pair.h61
-rw-r--r--third_party/libwebrtc/rtc_base/openssl_session_cache.cc54
-rw-r--r--third_party/libwebrtc/rtc_base/openssl_session_cache.h72
-rw-r--r--third_party/libwebrtc/rtc_base/openssl_session_cache_unittest.cc104
-rw-r--r--third_party/libwebrtc/rtc_base/openssl_stream_adapter.cc1305
-rw-r--r--third_party/libwebrtc/rtc_base/openssl_stream_adapter.h264
-rw-r--r--third_party/libwebrtc/rtc_base/openssl_utility.cc274
-rw-r--r--third_party/libwebrtc/rtc_base/openssl_utility.h60
-rw-r--r--third_party/libwebrtc/rtc_base/openssl_utility_unittest.cc308
-rw-r--r--third_party/libwebrtc/rtc_base/operations_chain.cc88
-rw-r--r--third_party/libwebrtc/rtc_base/operations_chain.h203
-rw-r--r--third_party/libwebrtc/rtc_base/operations_chain_unittest.cc502
-rw-r--r--third_party/libwebrtc/rtc_base/physical_socket_server.cc1953
-rw-r--r--third_party/libwebrtc/rtc_base/physical_socket_server.h310
-rw-r--r--third_party/libwebrtc/rtc_base/physical_socket_server_unittest.cc535
-rw-r--r--third_party/libwebrtc/rtc_base/platform_thread.cc222
-rw-r--r--third_party/libwebrtc/rtc_base/platform_thread.h127
-rw-r--r--third_party/libwebrtc/rtc_base/platform_thread_gn/moz.build232
-rw-r--r--third_party/libwebrtc/rtc_base/platform_thread_types.cc128
-rw-r--r--third_party/libwebrtc/rtc_base/platform_thread_types.h62
-rw-r--r--third_party/libwebrtc/rtc_base/platform_thread_types_gn/moz.build225
-rw-r--r--third_party/libwebrtc/rtc_base/platform_thread_unittest.cc109
-rw-r--r--third_party/libwebrtc/rtc_base/protobuf_utils.h30
-rw-r--r--third_party/libwebrtc/rtc_base/protobuf_utils_gn/moz.build205
-rw-r--r--third_party/libwebrtc/rtc_base/proxy_info.cc23
-rw-r--r--third_party/libwebrtc/rtc_base/proxy_info.h39
-rw-r--r--third_party/libwebrtc/rtc_base/proxy_server.cc156
-rw-r--r--third_party/libwebrtc/rtc_base/proxy_server.h110
-rw-r--r--third_party/libwebrtc/rtc_base/proxy_unittest.cc68
-rw-r--r--third_party/libwebrtc/rtc_base/race_checker.cc56
-rw-r--r--third_party/libwebrtc/rtc_base/race_checker.h83
-rw-r--r--third_party/libwebrtc/rtc_base/race_checker_gn/moz.build225
-rw-r--r--third_party/libwebrtc/rtc_base/random.cc87
-rw-r--r--third_party/libwebrtc/rtc_base/random.h96
-rw-r--r--third_party/libwebrtc/rtc_base/random_gn/moz.build225
-rw-r--r--third_party/libwebrtc/rtc_base/random_unittest.cc305
-rw-r--r--third_party/libwebrtc/rtc_base/rate_limiter.cc69
-rw-r--r--third_party/libwebrtc/rtc_base/rate_limiter.h60
-rw-r--r--third_party/libwebrtc/rtc_base/rate_limiter_gn/moz.build236
-rw-r--r--third_party/libwebrtc/rtc_base/rate_limiter_unittest.cc192
-rw-r--r--third_party/libwebrtc/rtc_base/rate_statistics.cc157
-rw-r--r--third_party/libwebrtc/rtc_base/rate_statistics.h105
-rw-r--r--third_party/libwebrtc/rtc_base/rate_statistics_gn/moz.build232
-rw-r--r--third_party/libwebrtc/rtc_base/rate_statistics_unittest.cc318
-rw-r--r--third_party/libwebrtc/rtc_base/rate_tracker.cc158
-rw-r--r--third_party/libwebrtc/rtc_base/rate_tracker.h72
-rw-r--r--third_party/libwebrtc/rtc_base/rate_tracker_gn/moz.build232
-rw-r--r--third_party/libwebrtc/rtc_base/rate_tracker_unittest.cc178
-rw-r--r--third_party/libwebrtc/rtc_base/ref_count.h67
-rw-r--r--third_party/libwebrtc/rtc_base/ref_counted_object.h89
-rw-r--r--third_party/libwebrtc/rtc_base/ref_counted_object_unittest.cc175
-rw-r--r--third_party/libwebrtc/rtc_base/ref_counter.h75
-rw-r--r--third_party/libwebrtc/rtc_base/refcount_gn/moz.build205
-rw-r--r--third_party/libwebrtc/rtc_base/rolling_accumulator.h145
-rw-r--r--third_party/libwebrtc/rtc_base/rolling_accumulator_gn/moz.build209
-rw-r--r--third_party/libwebrtc/rtc_base/rolling_accumulator_unittest.cc150
-rw-r--r--third_party/libwebrtc/rtc_base/rtc_certificate.cc77
-rw-r--r--third_party/libwebrtc/rtc_base/rtc_certificate.h97
-rw-r--r--third_party/libwebrtc/rtc_base/rtc_certificate_generator.cc88
-rw-r--r--third_party/libwebrtc/rtc_base/rtc_certificate_generator.h82
-rw-r--r--third_party/libwebrtc/rtc_base/rtc_certificate_generator_unittest.cc137
-rw-r--r--third_party/libwebrtc/rtc_base/rtc_certificate_unittest.cc140
-rw-r--r--third_party/libwebrtc/rtc_base/rtc_event_gn/moz.build232
-rw-r--r--third_party/libwebrtc/rtc_base/rtc_numerics_gn/moz.build227
-rw-r--r--third_party/libwebrtc/rtc_base/rtc_task_queue_gn/moz.build225
-rw-r--r--third_party/libwebrtc/rtc_base/safe_compare_gn/moz.build205
-rw-r--r--third_party/libwebrtc/rtc_base/safe_conversions_gn/moz.build209
-rw-r--r--third_party/libwebrtc/rtc_base/safe_minmax_gn/moz.build209
-rw-r--r--third_party/libwebrtc/rtc_base/sample_counter_gn/moz.build225
-rw-r--r--third_party/libwebrtc/rtc_base/sanitizer.h144
-rw-r--r--third_party/libwebrtc/rtc_base/sanitizer_gn/moz.build205
-rw-r--r--third_party/libwebrtc/rtc_base/sanitizer_unittest.cc152
-rw-r--r--third_party/libwebrtc/rtc_base/server_socket_adapters.cc186
-rw-r--r--third_party/libwebrtc/rtc_base/server_socket_adapters.h77
-rw-r--r--third_party/libwebrtc/rtc_base/sigslot_tester.h245
-rw-r--r--third_party/libwebrtc/rtc_base/sigslot_tester_unittest.cc86
-rw-r--r--third_party/libwebrtc/rtc_base/sigslot_unittest.cc350
-rwxr-xr-xthird_party/libwebrtc/rtc_base/sigslottester.h.pump102
-rw-r--r--third_party/libwebrtc/rtc_base/socket.cc13
-rw-r--r--third_party/libwebrtc/rtc_base/socket.h147
-rw-r--r--third_party/libwebrtc/rtc_base/socket_adapters.cc665
-rw-r--r--third_party/libwebrtc/rtc_base/socket_adapters.h178
-rw-r--r--third_party/libwebrtc/rtc_base/socket_address.cc354
-rw-r--r--third_party/libwebrtc/rtc_base/socket_address.h209
-rw-r--r--third_party/libwebrtc/rtc_base/socket_address_gn/moz.build233
-rw-r--r--third_party/libwebrtc/rtc_base/socket_address_pair.cc39
-rw-r--r--third_party/libwebrtc/rtc_base/socket_address_pair.h43
-rw-r--r--third_party/libwebrtc/rtc_base/socket_address_unittest.cc366
-rw-r--r--third_party/libwebrtc/rtc_base/socket_factory.h28
-rw-r--r--third_party/libwebrtc/rtc_base/socket_factory_gn/moz.build217
-rw-r--r--third_party/libwebrtc/rtc_base/socket_gn/moz.build233
-rw-r--r--third_party/libwebrtc/rtc_base/socket_server.h67
-rw-r--r--third_party/libwebrtc/rtc_base/socket_server_gn/moz.build217
-rw-r--r--third_party/libwebrtc/rtc_base/socket_stream.cc121
-rw-r--r--third_party/libwebrtc/rtc_base/socket_stream.h62
-rw-r--r--third_party/libwebrtc/rtc_base/socket_unittest.cc1144
-rw-r--r--third_party/libwebrtc/rtc_base/socket_unittest.h108
-rw-r--r--third_party/libwebrtc/rtc_base/ssl_adapter.cc39
-rw-r--r--third_party/libwebrtc/rtc_base/ssl_adapter.h124
-rw-r--r--third_party/libwebrtc/rtc_base/ssl_adapter_unittest.cc610
-rw-r--r--third_party/libwebrtc/rtc_base/ssl_certificate.cc139
-rw-r--r--third_party/libwebrtc/rtc_base/ssl_certificate.h142
-rw-r--r--third_party/libwebrtc/rtc_base/ssl_fingerprint.cc127
-rw-r--r--third_party/libwebrtc/rtc_base/ssl_fingerprint.h77
-rw-r--r--third_party/libwebrtc/rtc_base/ssl_gn/moz.build205
-rw-r--r--third_party/libwebrtc/rtc_base/ssl_identity.cc293
-rw-r--r--third_party/libwebrtc/rtc_base/ssl_identity.h174
-rw-r--r--third_party/libwebrtc/rtc_base/ssl_identity_unittest.cc618
-rw-r--r--third_party/libwebrtc/rtc_base/ssl_roots.h2485
-rw-r--r--third_party/libwebrtc/rtc_base/ssl_stream_adapter.cc146
-rw-r--r--third_party/libwebrtc/rtc_base/ssl_stream_adapter.h281
-rw-r--r--third_party/libwebrtc/rtc_base/ssl_stream_adapter_unittest.cc1853
-rw-r--r--third_party/libwebrtc/rtc_base/stream.cc54
-rw-r--r--third_party/libwebrtc/rtc_base/stream.h128
-rw-r--r--third_party/libwebrtc/rtc_base/string_encode.cc284
-rw-r--r--third_party/libwebrtc/rtc_base/string_encode.h115
-rw-r--r--third_party/libwebrtc/rtc_base/string_encode_unittest.cc335
-rw-r--r--third_party/libwebrtc/rtc_base/string_to_number.cc104
-rw-r--r--third_party/libwebrtc/rtc_base/string_to_number.h105
-rw-r--r--third_party/libwebrtc/rtc_base/string_to_number_unittest.cc138
-rw-r--r--third_party/libwebrtc/rtc_base/string_utils.cc37
-rw-r--r--third_party/libwebrtc/rtc_base/string_utils.h138
-rw-r--r--third_party/libwebrtc/rtc_base/string_utils_unittest.cc59
-rw-r--r--third_party/libwebrtc/rtc_base/strings/audio_format_to_string.cc54
-rw-r--r--third_party/libwebrtc/rtc_base/strings/audio_format_to_string.h24
-rw-r--r--third_party/libwebrtc/rtc_base/strings/json.cc296
-rw-r--r--third_party/libwebrtc/rtc_base/strings/json.h83
-rw-r--r--third_party/libwebrtc/rtc_base/strings/json_unittest.cc283
-rw-r--r--third_party/libwebrtc/rtc_base/strings/string_builder.cc134
-rw-r--r--third_party/libwebrtc/rtc_base/strings/string_builder.h170
-rw-r--r--third_party/libwebrtc/rtc_base/strings/string_builder_unittest.cc202
-rw-r--r--third_party/libwebrtc/rtc_base/strings/string_format.cc41
-rw-r--r--third_party/libwebrtc/rtc_base/strings/string_format.h31
-rw-r--r--third_party/libwebrtc/rtc_base/strings/string_format_unittest.cc52
-rw-r--r--third_party/libwebrtc/rtc_base/stringutils_gn/moz.build229
-rw-r--r--third_party/libwebrtc/rtc_base/strong_alias.h76
-rw-r--r--third_party/libwebrtc/rtc_base/strong_alias_unittest.cc362
-rw-r--r--third_party/libwebrtc/rtc_base/swap_queue.h249
-rw-r--r--third_party/libwebrtc/rtc_base/swap_queue_gn/moz.build209
-rw-r--r--third_party/libwebrtc/rtc_base/swap_queue_unittest.cc223
-rw-r--r--third_party/libwebrtc/rtc_base/synchronization/BUILD.gn105
-rw-r--r--third_party/libwebrtc/rtc_base/synchronization/DEPS11
-rw-r--r--third_party/libwebrtc/rtc_base/synchronization/mutex.h73
-rw-r--r--third_party/libwebrtc/rtc_base/synchronization/mutex_abseil.h43
-rw-r--r--third_party/libwebrtc/rtc_base/synchronization/mutex_benchmark.cc96
-rw-r--r--third_party/libwebrtc/rtc_base/synchronization/mutex_critical_section.h56
-rw-r--r--third_party/libwebrtc/rtc_base/synchronization/mutex_gn/moz.build209
-rw-r--r--third_party/libwebrtc/rtc_base/synchronization/mutex_pthread.h101
-rw-r--r--third_party/libwebrtc/rtc_base/synchronization/mutex_unittest.cc178
-rw-r--r--third_party/libwebrtc/rtc_base/synchronization/sequence_checker_internal.cc86
-rw-r--r--third_party/libwebrtc/rtc_base/synchronization/sequence_checker_internal.h90
-rw-r--r--third_party/libwebrtc/rtc_base/synchronization/sequence_checker_internal_gn/moz.build225
-rw-r--r--third_party/libwebrtc/rtc_base/synchronization/yield.cc36
-rw-r--r--third_party/libwebrtc/rtc_base/synchronization/yield.h20
-rw-r--r--third_party/libwebrtc/rtc_base/synchronization/yield_gn/moz.build221
-rw-r--r--third_party/libwebrtc/rtc_base/synchronization/yield_policy.cc82
-rw-r--r--third_party/libwebrtc/rtc_base/synchronization/yield_policy.h38
-rw-r--r--third_party/libwebrtc/rtc_base/synchronization/yield_policy_gn/moz.build225
-rw-r--r--third_party/libwebrtc/rtc_base/synchronization/yield_policy_unittest.cc68
-rw-r--r--third_party/libwebrtc/rtc_base/system/BUILD.gn111
-rw-r--r--third_party/libwebrtc/rtc_base/system/DEPS5
-rw-r--r--third_party/libwebrtc/rtc_base/system/arch.h100
-rw-r--r--third_party/libwebrtc/rtc_base/system/arch_gn/moz.build205
-rw-r--r--third_party/libwebrtc/rtc_base/system/asm_defines.h72
-rw-r--r--third_party/libwebrtc/rtc_base/system/asm_defines_gn/moz.build81
-rw-r--r--third_party/libwebrtc/rtc_base/system/assume.h73
-rw-r--r--third_party/libwebrtc/rtc_base/system/cocoa_threading.h24
-rw-r--r--third_party/libwebrtc/rtc_base/system/cocoa_threading.mm24
-rw-r--r--third_party/libwebrtc/rtc_base/system/cocoa_threading_gn/moz.build67
-rw-r--r--third_party/libwebrtc/rtc_base/system/file_wrapper.cc135
-rw-r--r--third_party/libwebrtc/rtc_base/system/file_wrapper.h113
-rw-r--r--third_party/libwebrtc/rtc_base/system/file_wrapper_gn/moz.build225
-rw-r--r--third_party/libwebrtc/rtc_base/system/file_wrapper_unittest.cc69
-rw-r--r--third_party/libwebrtc/rtc_base/system/gcd_helpers.h29
-rw-r--r--third_party/libwebrtc/rtc_base/system/gcd_helpers.m22
-rw-r--r--third_party/libwebrtc/rtc_base/system/gcd_helpers_gn/moz.build67
-rw-r--r--third_party/libwebrtc/rtc_base/system/ignore_warnings.h29
-rw-r--r--third_party/libwebrtc/rtc_base/system/ignore_warnings_gn/moz.build205
-rw-r--r--third_party/libwebrtc/rtc_base/system/inline.h31
-rw-r--r--third_party/libwebrtc/rtc_base/system/inline_gn/moz.build205
-rw-r--r--third_party/libwebrtc/rtc_base/system/no_cfi_icall.h33
-rw-r--r--third_party/libwebrtc/rtc_base/system/no_unique_address.h37
-rw-r--r--third_party/libwebrtc/rtc_base/system/no_unique_address_gn/moz.build205
-rw-r--r--third_party/libwebrtc/rtc_base/system/rtc_export.h43
-rw-r--r--third_party/libwebrtc/rtc_base/system/rtc_export_gn/moz.build205
-rw-r--r--third_party/libwebrtc/rtc_base/system/rtc_export_template.h197
-rw-r--r--third_party/libwebrtc/rtc_base/system/unused.h28
-rw-r--r--third_party/libwebrtc/rtc_base/system/unused_gn/moz.build205
-rw-r--r--third_party/libwebrtc/rtc_base/system/warn_current_thread_is_deadlocked.cc23
-rw-r--r--third_party/libwebrtc/rtc_base/system/warn_current_thread_is_deadlocked.h24
-rw-r--r--third_party/libwebrtc/rtc_base/system/warn_current_thread_is_deadlocked_gn/moz.build205
-rw-r--r--third_party/libwebrtc/rtc_base/system_time.cc104
-rw-r--r--third_party/libwebrtc/rtc_base/system_time.h24
-rw-r--r--third_party/libwebrtc/rtc_base/task_queue.cc32
-rw-r--r--third_party/libwebrtc/rtc_base/task_queue.h117
-rw-r--r--third_party/libwebrtc/rtc_base/task_queue_for_test.cc21
-rw-r--r--third_party/libwebrtc/rtc_base/task_queue_for_test.h68
-rw-r--r--third_party/libwebrtc/rtc_base/task_queue_gcd.cc162
-rw-r--r--third_party/libwebrtc/rtc_base/task_queue_gcd.h24
-rw-r--r--third_party/libwebrtc/rtc_base/task_queue_libevent.cc336
-rw-r--r--third_party/libwebrtc/rtc_base/task_queue_libevent.h24
-rw-r--r--third_party/libwebrtc/rtc_base/task_queue_stdlib.cc313
-rw-r--r--third_party/libwebrtc/rtc_base/task_queue_stdlib.h24
-rw-r--r--third_party/libwebrtc/rtc_base/task_queue_stdlib_unittest.cc29
-rw-r--r--third_party/libwebrtc/rtc_base/task_queue_unittest.cc83
-rw-r--r--third_party/libwebrtc/rtc_base/task_queue_win.cc414
-rw-r--r--third_party/libwebrtc/rtc_base/task_queue_win.h24
-rw-r--r--third_party/libwebrtc/rtc_base/task_utils/BUILD.gn47
-rw-r--r--third_party/libwebrtc/rtc_base/task_utils/repeating_task.cc140
-rw-r--r--third_party/libwebrtc/rtc_base/task_utils/repeating_task.h92
-rw-r--r--third_party/libwebrtc/rtc_base/task_utils/repeating_task_gn/moz.build236
-rw-r--r--third_party/libwebrtc/rtc_base/task_utils/repeating_task_unittest.cc439
-rw-r--r--third_party/libwebrtc/rtc_base/test_base64.h2111
-rw-r--r--third_party/libwebrtc/rtc_base/test_certificate_verifier.h34
-rw-r--r--third_party/libwebrtc/rtc_base/test_client.cc180
-rw-r--r--third_party/libwebrtc/rtc_base/test_client.h119
-rw-r--r--third_party/libwebrtc/rtc_base/test_client_unittest.cc108
-rw-r--r--third_party/libwebrtc/rtc_base/test_echo_server.cc32
-rw-r--r--third_party/libwebrtc/rtc_base/test_echo_server.h77
-rw-r--r--third_party/libwebrtc/rtc_base/test_utils.cc20
-rw-r--r--third_party/libwebrtc/rtc_base/test_utils.h99
-rw-r--r--third_party/libwebrtc/rtc_base/third_party/base64/BUILD.gn21
-rw-r--r--third_party/libwebrtc/rtc_base/third_party/base64/LICENSE14
-rw-r--r--third_party/libwebrtc/rtc_base/third_party/base64/README.chromium12
-rw-r--r--third_party/libwebrtc/rtc_base/third_party/base64/base64.cc279
-rw-r--r--third_party/libwebrtc/rtc_base/third_party/base64/base64.h128
-rw-r--r--third_party/libwebrtc/rtc_base/third_party/base64/base64_gn/moz.build225
-rw-r--r--third_party/libwebrtc/rtc_base/third_party/sigslot/BUILD.gn17
-rw-r--r--third_party/libwebrtc/rtc_base/third_party/sigslot/LICENSE7
-rw-r--r--third_party/libwebrtc/rtc_base/third_party/sigslot/README.chromium21
-rw-r--r--third_party/libwebrtc/rtc_base/third_party/sigslot/sigslot.cc22
-rw-r--r--third_party/libwebrtc/rtc_base/third_party/sigslot/sigslot.h649
-rw-r--r--third_party/libwebrtc/rtc_base/third_party/sigslot/sigslot_gn/moz.build221
-rw-r--r--third_party/libwebrtc/rtc_base/thread.cc939
-rw-r--r--third_party/libwebrtc/rtc_base/thread.h571
-rw-r--r--third_party/libwebrtc/rtc_base/thread_annotations.h98
-rw-r--r--third_party/libwebrtc/rtc_base/thread_annotations_unittest.cc131
-rw-r--r--third_party/libwebrtc/rtc_base/thread_unittest.cc852
-rw-r--r--third_party/libwebrtc/rtc_base/threading_gn/moz.build238
-rw-r--r--third_party/libwebrtc/rtc_base/time_utils.cc258
-rw-r--r--third_party/libwebrtc/rtc_base/time_utils.h140
-rw-r--r--third_party/libwebrtc/rtc_base/time_utils_unittest.cc241
-rw-r--r--third_party/libwebrtc/rtc_base/timestamp_aligner.cc143
-rw-r--r--third_party/libwebrtc/rtc_base/timestamp_aligner.h93
-rw-r--r--third_party/libwebrtc/rtc_base/timestamp_aligner_unittest.cc207
-rw-r--r--third_party/libwebrtc/rtc_base/timeutils_gn/moz.build234
-rw-r--r--third_party/libwebrtc/rtc_base/trace_event.h3
-rw-r--r--third_party/libwebrtc/rtc_base/type_traits.h140
-rw-r--r--third_party/libwebrtc/rtc_base/type_traits_gn/moz.build205
-rw-r--r--third_party/libwebrtc/rtc_base/unique_id_generator.cc72
-rw-r--r--third_party/libwebrtc/rtc_base/unique_id_generator.h150
-rw-r--r--third_party/libwebrtc/rtc_base/unique_id_generator_gn/moz.build205
-rw-r--r--third_party/libwebrtc/rtc_base/unique_id_generator_unittest.cc211
-rw-r--r--third_party/libwebrtc/rtc_base/units/BUILD.gn34
-rw-r--r--third_party/libwebrtc/rtc_base/units/OWNERS1
-rw-r--r--third_party/libwebrtc/rtc_base/units/unit_base.h311
-rw-r--r--third_party/libwebrtc/rtc_base/units/unit_base_gn/moz.build209
-rw-r--r--third_party/libwebrtc/rtc_base/units/unit_base_unittest.cc251
-rw-r--r--third_party/libwebrtc/rtc_base/untyped_function.h324
-rw-r--r--third_party/libwebrtc/rtc_base/untyped_function_unittest.cc309
-rw-r--r--third_party/libwebrtc/rtc_base/virtual_socket_server.cc1383
-rw-r--r--third_party/libwebrtc/rtc_base/virtual_socket_server.h482
-rw-r--r--third_party/libwebrtc/rtc_base/virtual_socket_unittest.cc1125
-rw-r--r--third_party/libwebrtc/rtc_base/weak_ptr.cc77
-rw-r--r--third_party/libwebrtc/rtc_base/weak_ptr.h276
-rw-r--r--third_party/libwebrtc/rtc_base/weak_ptr_gn/moz.build225
-rw-r--r--third_party/libwebrtc/rtc_base/weak_ptr_unittest.cc236
-rw-r--r--third_party/libwebrtc/rtc_base/win/BUILD.gn68
-rw-r--r--third_party/libwebrtc/rtc_base/win/create_direct3d_device.cc58
-rw-r--r--third_party/libwebrtc/rtc_base/win/create_direct3d_device.h34
-rw-r--r--third_party/libwebrtc/rtc_base/win/create_direct3d_device_gn/moz.build85
-rw-r--r--third_party/libwebrtc/rtc_base/win/get_activation_factory.cc49
-rw-r--r--third_party/libwebrtc/rtc_base/win/get_activation_factory.h53
-rw-r--r--third_party/libwebrtc/rtc_base/win/get_activation_factory_gn/moz.build85
-rw-r--r--third_party/libwebrtc/rtc_base/win/hstring.cc62
-rw-r--r--third_party/libwebrtc/rtc_base/win/hstring.h30
-rw-r--r--third_party/libwebrtc/rtc_base/win/hstring_gn/moz.build85
-rw-r--r--third_party/libwebrtc/rtc_base/win/scoped_com_initializer.cc57
-rw-r--r--third_party/libwebrtc/rtc_base/win/scoped_com_initializer.h56
-rw-r--r--third_party/libwebrtc/rtc_base/win/windows_version.cc445
-rw-r--r--third_party/libwebrtc/rtc_base/win/windows_version.h156
-rw-r--r--third_party/libwebrtc/rtc_base/win/windows_version_gn/moz.build85
-rw-r--r--third_party/libwebrtc/rtc_base/win/windows_version_unittest.cc47
-rw-r--r--third_party/libwebrtc/rtc_base/win32.cc313
-rw-r--r--third_party/libwebrtc/rtc_base/win32.h48
-rw-r--r--third_party/libwebrtc/rtc_base/win32_gn/moz.build92
-rw-r--r--third_party/libwebrtc/rtc_base/win32_socket_init.h41
-rw-r--r--third_party/libwebrtc/rtc_base/win32_unittest.cc89
-rw-r--r--third_party/libwebrtc/rtc_base/zero_memory.cc38
-rw-r--r--third_party/libwebrtc/rtc_base/zero_memory.h35
-rw-r--r--third_party/libwebrtc/rtc_base/zero_memory_gn/moz.build225
-rw-r--r--third_party/libwebrtc/rtc_base/zero_memory_unittest.cc53
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, &timestamp);
+
+ 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, &params, 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(), &copy);
+
+ 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(), &copy);
+
+ 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&section=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, &not_after, &not_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(&not_after), CBS_len(&not_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, &param) == 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, &current_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, &current_dscp));
+ ASSERT_NE(-1, socket->SetOption(Socket::OPT_DSCP, desired_dscp));
+ ASSERT_NE(-1, socket->GetOption(Socket::OPT_DSCP, &current_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