summaryrefslogtreecommitdiff
path: root/chromium/third_party/openscreen
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2020-11-18 16:35:47 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2020-11-18 15:45:54 +0000
commit32f5a1c56531e4210bc4cf8d8c7825d66e081888 (patch)
treeeeeec6822f4d738d8454525233fd0e2e3a659e6d /chromium/third_party/openscreen
parent99677208ff3b216fdfec551fbe548da5520cd6fb (diff)
downloadqtwebengine-chromium-32f5a1c56531e4210bc4cf8d8c7825d66e081888.tar.gz
BASELINE: Update Chromium to 87.0.4280.67
Change-Id: Ib157360be8c2ffb2c73125751a89f60e049c1d54 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/third_party/openscreen')
-rw-r--r--chromium/third_party/openscreen/src/BUILD.gn78
-rw-r--r--chromium/third_party/openscreen/src/DEPS2
-rwxr-xr-xchromium/third_party/openscreen/src/PRESUBMIT.py4
-rw-r--r--chromium/third_party/openscreen/src/build/config/BUILD.gn9
-rw-r--r--chromium/third_party/openscreen/src/build/config/BUILDCONFIG.gn1
-rw-r--r--chromium/third_party/openscreen/src/build/config/sysroot.gni2
-rwxr-xr-xchromium/third_party/openscreen/src/build/scripts/sysroot_ld_path.py2
-rw-r--r--chromium/third_party/openscreen/src/cast/README.md28
-rw-r--r--chromium/third_party/openscreen/src/cast/common/BUILD.gn29
-rw-r--r--chromium/third_party/openscreen/src/cast/common/certificate/cast_cert_validator_internal.cc76
-rw-r--r--chromium/third_party/openscreen/src/cast/common/certificate/cast_cert_validator_internal.h19
-rw-r--r--chromium/third_party/openscreen/src/cast/common/certificate/cast_cert_validator_unittest.cc11
-rw-r--r--chromium/third_party/openscreen/src/cast/common/certificate/cast_crl_unittest.cc6
-rw-r--r--chromium/third_party/openscreen/src/cast/common/certificate/cast_trust_store.cc16
-rw-r--r--chromium/third_party/openscreen/src/cast/common/certificate/cast_trust_store.h6
-rw-r--r--chromium/third_party/openscreen/src/cast/common/certificate/testing/test_helpers.cc67
-rw-r--r--chromium/third_party/openscreen/src/cast/common/certificate/testing/test_helpers.h7
-rw-r--r--chromium/third_party/openscreen/src/cast/common/channel/cast_message_handler.h1
-rw-r--r--chromium/third_party/openscreen/src/cast/common/channel/cast_socket_message_port.cc103
-rw-r--r--chromium/third_party/openscreen/src/cast/common/channel/cast_socket_message_port.h55
-rw-r--r--chromium/third_party/openscreen/src/cast/common/channel/connection_namespace_handler.cc12
-rw-r--r--chromium/third_party/openscreen/src/cast/common/channel/virtual_connection.h2
-rw-r--r--chromium/third_party/openscreen/src/cast/common/channel/virtual_connection_router.cc61
-rw-r--r--chromium/third_party/openscreen/src/cast/common/channel/virtual_connection_router.h5
-rw-r--r--chromium/third_party/openscreen/src/cast/common/channel/virtual_connection_router_unittest.cc248
-rw-r--r--chromium/third_party/openscreen/src/cast/common/public/cast_socket.h5
-rw-r--r--chromium/third_party/openscreen/src/cast/common/public/message_port.h41
-rw-r--r--chromium/third_party/openscreen/src/cast/receiver/BUILD.gn10
-rw-r--r--chromium/third_party/openscreen/src/cast/receiver/channel/device_auth_namespace_handler.cc6
-rw-r--r--chromium/third_party/openscreen/src/cast/receiver/channel/device_auth_namespace_handler_unittest.cc4
-rw-r--r--chromium/third_party/openscreen/src/cast/receiver/channel/static_credentials.cc (renamed from chromium/third_party/openscreen/src/cast/standalone_receiver/static_credentials.cc)121
-rw-r--r--chromium/third_party/openscreen/src/cast/receiver/channel/static_credentials.h (renamed from chromium/third_party/openscreen/src/cast/standalone_receiver/static_credentials.h)15
-rw-r--r--chromium/third_party/openscreen/src/cast/receiver/channel/testing/device_auth_test_helpers.cc12
-rw-r--r--chromium/third_party/openscreen/src/cast/receiver/channel/testing/device_auth_test_helpers.h19
-rw-r--r--chromium/third_party/openscreen/src/cast/sender/cast_platform_client.cc9
-rw-r--r--chromium/third_party/openscreen/src/cast/sender/channel/cast_auth_util.cc10
-rw-r--r--chromium/third_party/openscreen/src/cast/sender/channel/cast_auth_util_unittest.cc45
-rw-r--r--chromium/third_party/openscreen/src/cast/standalone_receiver/BUILD.gn78
-rw-r--r--chromium/third_party/openscreen/src/cast/standalone_receiver/cast_agent.cc36
-rw-r--r--chromium/third_party/openscreen/src/cast/standalone_receiver/cast_agent.h8
-rw-r--r--chromium/third_party/openscreen/src/cast/standalone_receiver/cast_agent_integration_tests.cc4
-rw-r--r--chromium/third_party/openscreen/src/cast/standalone_receiver/cast_socket_message_port.cc55
-rw-r--r--chromium/third_party/openscreen/src/cast/standalone_receiver/cast_socket_message_port.h43
-rw-r--r--chromium/third_party/openscreen/src/cast/standalone_receiver/main.cc147
-rw-r--r--chromium/third_party/openscreen/src/cast/standalone_receiver/private.derbin1192 -> 0 bytes
-rw-r--r--chromium/third_party/openscreen/src/cast/standalone_receiver/private_key_der.h125
-rw-r--r--chromium/third_party/openscreen/src/cast/standalone_receiver/sdl_audio_player.cc4
-rw-r--r--chromium/third_party/openscreen/src/cast/standalone_receiver/sdl_audio_player.h2
-rw-r--r--chromium/third_party/openscreen/src/cast/standalone_receiver/sdl_player_base.cc1
-rw-r--r--chromium/third_party/openscreen/src/cast/standalone_receiver/sdl_player_base.h1
-rw-r--r--chromium/third_party/openscreen/src/cast/standalone_receiver/sdl_video_player.cc5
-rw-r--r--chromium/third_party/openscreen/src/cast/standalone_receiver/sdl_video_player.h3
-rw-r--r--chromium/third_party/openscreen/src/cast/standalone_receiver/streaming_playback_controller.cc19
-rw-r--r--chromium/third_party/openscreen/src/cast/standalone_sender/BUILD.gn43
-rw-r--r--chromium/third_party/openscreen/src/cast/standalone_sender/constants.h33
-rw-r--r--chromium/third_party/openscreen/src/cast/standalone_sender/looping_file_cast_agent.cc152
-rw-r--r--chromium/third_party/openscreen/src/cast/standalone_sender/looping_file_cast_agent.h119
-rw-r--r--chromium/third_party/openscreen/src/cast/standalone_sender/looping_file_sender.cc189
-rw-r--r--chromium/third_party/openscreen/src/cast/standalone_sender/looping_file_sender.h87
-rw-r--r--chromium/third_party/openscreen/src/cast/standalone_sender/main.cc359
-rw-r--r--chromium/third_party/openscreen/src/cast/standalone_sender/streaming_opus_encoder.cc2
-rw-r--r--chromium/third_party/openscreen/src/cast/streaming/BUILD.gn12
-rw-r--r--chromium/third_party/openscreen/src/cast/streaming/capture_configs.h83
-rw-r--r--chromium/third_party/openscreen/src/cast/streaming/compound_rtcp_builder.cc2
-rw-r--r--chromium/third_party/openscreen/src/cast/streaming/constants.h28
-rw-r--r--chromium/third_party/openscreen/src/cast/streaming/frame_crypto.cc15
-rw-r--r--chromium/third_party/openscreen/src/cast/streaming/frame_crypto.h3
-rw-r--r--chromium/third_party/openscreen/src/cast/streaming/frame_crypto_unittest.cc5
-rw-r--r--chromium/third_party/openscreen/src/cast/streaming/message_fields.cc71
-rw-r--r--chromium/third_party/openscreen/src/cast/streaming/message_fields.h51
-rw-r--r--chromium/third_party/openscreen/src/cast/streaming/message_fields_unittest.cc36
-rw-r--r--chromium/third_party/openscreen/src/cast/streaming/message_port.h38
-rw-r--r--chromium/third_party/openscreen/src/cast/streaming/offer_messages.cc5
-rw-r--r--chromium/third_party/openscreen/src/cast/streaming/packet_receive_stats_tracker_unittest.cc24
-rw-r--r--chromium/third_party/openscreen/src/cast/streaming/receiver.cc3
-rw-r--r--chromium/third_party/openscreen/src/cast/streaming/receiver.h8
-rw-r--r--chromium/third_party/openscreen/src/cast/streaming/receiver_session.cc139
-rw-r--r--chromium/third_party/openscreen/src/cast/streaming/receiver_session.h46
-rw-r--r--chromium/third_party/openscreen/src/cast/streaming/receiver_session_unittest.cc161
-rw-r--r--chromium/third_party/openscreen/src/cast/streaming/rtp_defines.cc8
-rw-r--r--chromium/third_party/openscreen/src/cast/streaming/rtp_defines.h13
-rw-r--r--chromium/third_party/openscreen/src/cast/streaming/rtp_packetizer_unittest.cc4
-rw-r--r--chromium/third_party/openscreen/src/cast/streaming/sender.cc5
-rw-r--r--chromium/third_party/openscreen/src/cast/streaming/sender.h6
-rw-r--r--chromium/third_party/openscreen/src/cast/streaming/sender_session.cc397
-rw-r--r--chromium/third_party/openscreen/src/cast/streaming/sender_session.h179
-rw-r--r--chromium/third_party/openscreen/src/cast/streaming/sender_session_unittest.cc421
-rw-r--r--chromium/third_party/openscreen/src/cast/streaming/testing/simple_message_port.h64
-rw-r--r--chromium/third_party/openscreen/src/cast/test/BUILD.gn13
-rw-r--r--chromium/third_party/openscreen/src/discovery/common/config.h6
-rw-r--r--chromium/third_party/openscreen/src/discovery/dnssd/impl/dns_data_graph.cc3
-rw-r--r--chromium/third_party/openscreen/src/discovery/dnssd/impl/querier_impl.cc3
-rw-r--r--chromium/third_party/openscreen/src/discovery/dnssd/public/dns_sd_instance.cc5
-rw-r--r--chromium/third_party/openscreen/src/discovery/dnssd/public/dns_sd_instance_unittest.cc4
-rw-r--r--chromium/third_party/openscreen/src/discovery/mdns/mdns_querier.cc8
-rw-r--r--chromium/third_party/openscreen/src/discovery/mdns/mdns_querier_unittest.cc26
-rw-r--r--chromium/third_party/openscreen/src/discovery/mdns/mdns_reader.cc22
-rw-r--r--chromium/third_party/openscreen/src/discovery/mdns/mdns_reader.h6
-rw-r--r--chromium/third_party/openscreen/src/discovery/mdns/mdns_reader_fuzztest.cc13
-rw-r--r--chromium/third_party/openscreen/src/discovery/mdns/mdns_reader_unittest.cc22
-rw-r--r--chromium/third_party/openscreen/src/discovery/mdns/mdns_receiver.cc16
-rw-r--r--chromium/third_party/openscreen/src/discovery/mdns/mdns_records.cc31
-rw-r--r--chromium/third_party/openscreen/src/discovery/mdns/mdns_records_unittest.cc77
-rw-r--r--chromium/third_party/openscreen/src/discovery/mdns/mdns_trackers.h3
-rw-r--r--chromium/third_party/openscreen/src/infra/config/global/cr-buildbucket.cfg13
-rw-r--r--chromium/third_party/openscreen/src/infra/config/global/refs.cfg6
-rw-r--r--chromium/third_party/openscreen/src/platform/api/udp_socket.cc2
-rw-r--r--chromium/third_party/openscreen/src/platform/base/error.cc6
-rw-r--r--chromium/third_party/openscreen/src/platform/base/error.h6
-rw-r--r--chromium/third_party/openscreen/src/platform/base/trace_logging_types.h3
-rw-r--r--chromium/third_party/openscreen/src/platform/impl/socket_handle.h2
-rw-r--r--chromium/third_party/openscreen/src/platform/impl/socket_handle_posix.cc2
-rw-r--r--chromium/third_party/openscreen/src/platform/impl/socket_handle_posix.h2
-rw-r--r--chromium/third_party/openscreen/src/platform/impl/task_runner.cc7
-rw-r--r--chromium/third_party/openscreen/src/platform/impl/udp_socket_posix.cc100
-rw-r--r--chromium/third_party/openscreen/src/third_party/abseil/BUILD.gn12
-rw-r--r--chromium/third_party/openscreen/src/third_party/jsoncpp/BUILD.gn22
-rw-r--r--chromium/third_party/openscreen/src/third_party/jsoncpp/generated/version.h22
-rw-r--r--chromium/third_party/openscreen/src/util/BUILD.gn5
-rw-r--r--chromium/third_party/openscreen/src/util/crypto/openssl_util.cc10
-rw-r--r--chromium/third_party/openscreen/src/util/crypto/pem_helpers.cc70
-rw-r--r--chromium/third_party/openscreen/src/util/crypto/pem_helpers.h24
-rw-r--r--chromium/third_party/openscreen/src/util/crypto/random_bytes.cc23
-rw-r--r--chromium/third_party/openscreen/src/util/crypto/random_bytes.h17
-rw-r--r--chromium/third_party/openscreen/src/util/crypto/random_bytes_unittest.cc50
-rw-r--r--chromium/third_party/openscreen/src/util/yet_another_bit_vector_unittest.cc10
126 files changed, 3707 insertions, 1454 deletions
diff --git a/chromium/third_party/openscreen/src/BUILD.gn b/chromium/third_party/openscreen/src/BUILD.gn
index bb698dc7d47..16a82c88a48 100644
--- a/chromium/third_party/openscreen/src/BUILD.gn
+++ b/chromium/third_party/openscreen/src/BUILD.gn
@@ -5,14 +5,6 @@
import("//build_overrides/build.gni")
import("osp/build/config/services.gni")
-declare_args() {
- # Set to true to force building the standalone receiver on Mac. It's currently
- # disabled due to build bot struggles, but works fine on local, recent clang
- # installations.
- # TODO(crbug.com/openscreen/86): Remove when the Mac bots have been upgraded.
- force_build_standalone_receiver = false
-}
-
# All compilable non-test targets in the repository (both executables and
# source_sets).
group("gn_all") {
@@ -28,8 +20,6 @@ group("gn_all") {
"discovery:dnssd",
"discovery:mdns",
"discovery:public",
- "osp",
- "osp/msgs",
"platform",
"third_party/abseil",
"third_party/boringssl",
@@ -40,36 +30,37 @@ group("gn_all") {
"util",
]
- if (use_mdns_responder) {
- deps += [ "osp/impl/discovery/mdns:mdns_demo" ]
- }
-
- if (use_chromium_quic) {
+ # Mac OS X 10.15 is incompatible with the current version of QUIC.
+ if (!is_mac) {
deps += [
- "third_party/chromium_quic",
- "third_party/chromium_quic:quic_demo_server",
- "third_party/chromium_quic:quic_streaming_playback_controller",
+ "osp",
+ "osp/msgs",
]
- }
- if (use_chromium_quic && use_mdns_responder) {
- deps += [ "osp:osp_demo" ]
+ if (use_mdns_responder) {
+ deps += [ "osp/impl/discovery/mdns:mdns_demo" ]
+ }
+
+ if (use_chromium_quic) {
+ deps += [
+ "third_party/chromium_quic",
+ "third_party/chromium_quic:quic_demo_server",
+ "third_party/chromium_quic:quic_streaming_playback_controller",
+ ]
+ }
+
+ if (use_chromium_quic && use_mdns_responder) {
+ deps += [ "osp:osp_demo" ]
+ }
}
if (!build_with_chromium) {
deps += [
+ "cast/standalone_receiver:cast_receiver",
+ "cast/standalone_sender:cast_sender",
"third_party/protobuf:protoc($host_toolchain)",
"third_party/zlib",
]
-
- # TODO(crbug.com/openscreen/86): Build for Mac too once the mac buildbot
- # compiler is upgraded.
- if (!is_mac || force_build_standalone_receiver) {
- deps += [
- "cast/standalone_receiver:cast_receiver",
- "cast/standalone_sender:cast_sender",
- ]
- }
}
}
@@ -81,25 +72,34 @@ source_set("openscreen_unittests_all") {
"cast/sender:unittests",
"cast/streaming:unittests",
"cast/test:unittests",
- "discovery:unittests",
- "osp:unittests",
- "osp/msgs:unittests",
"platform:unittests",
"third_party/abseil",
"util:unittests",
]
if (!build_with_chromium && is_posix) {
- public_deps += [ "cast/test:make_crl_tests($host_toolchain)" ]
+ public_deps += [
+ "cast/test:make_crl_tests($host_toolchain)",
+
+ # TODO(crbug.com/1132604): Discovery unittests fail in Chrome.
+ "discovery:unittests",
+ ]
}
- if (use_mdns_responder) {
+ if (!is_mac) {
public_deps += [
- "osp/impl/discovery/mdns:unittests",
-
- # Currently this target only includes mDNS tests.
- "osp/impl/testing:unittests",
+ "osp:unittests",
+ "osp/msgs:unittests",
]
+
+ if (use_mdns_responder) {
+ public_deps += [
+ "osp/impl/discovery/mdns:unittests",
+
+ # Currently this target only includes mDNS tests.
+ "osp/impl/testing:unittests",
+ ]
+ }
}
}
diff --git a/chromium/third_party/openscreen/src/DEPS b/chromium/third_party/openscreen/src/DEPS
index 9ed742d681d..4834cf41c2b 100644
--- a/chromium/third_party/openscreen/src/DEPS
+++ b/chromium/third_party/openscreen/src/DEPS
@@ -66,7 +66,7 @@ deps = {
'third_party/jsoncpp/src': {
'url': Var('chromium_git') +
'/external/github.com/open-source-parsers/jsoncpp.git' +
- '@' + 'd2e6a971f4544c55b8e3b25cf96db266971b778f', # version 1.9.2
+ '@' + '9059f5cad030ba11d37818847443a53918c327b1', # version 1.9.4
'condition': 'not build_with_chromium',
},
diff --git a/chromium/third_party/openscreen/src/PRESUBMIT.py b/chromium/third_party/openscreen/src/PRESUBMIT.py
index 6aa28248eac..f2426335af2 100755
--- a/chromium/third_party/openscreen/src/PRESUBMIT.py
+++ b/chromium/third_party/openscreen/src/PRESUBMIT.py
@@ -91,7 +91,7 @@ def _CommonChecks(input_api, output_api):
def CheckChangeOnUpload(input_api, output_api):
- input_api.DEFAULT_BLOCK_LIST = _EXCLUDED_PATHS;
+ input_api.DEFAULT_FILES_TO_SKIP = _EXCLUDED_PATHS;
results = []
results.extend(_CommonChecks(input_api, output_api))
results.extend(
@@ -100,7 +100,7 @@ def CheckChangeOnUpload(input_api, output_api):
def CheckChangeOnCommit(input_api, output_api):
- input_api.DEFAULT_BLOCK_LIST = _EXCLUDED_PATHS;
+ input_api.DEFAULT_FILES_TO_SKIP = _EXCLUDED_PATHS;
results = []
results.extend(_CommonChecks(input_api, output_api))
return results
diff --git a/chromium/third_party/openscreen/src/build/config/BUILD.gn b/chromium/third_party/openscreen/src/build/config/BUILD.gn
index a68031e88c5..7309ad8b9c9 100644
--- a/chromium/third_party/openscreen/src/build/config/BUILD.gn
+++ b/chromium/third_party/openscreen/src/build/config/BUILD.gn
@@ -254,3 +254,12 @@ config("sysroot_runtime_libraries") {
}
}
}
+
+config("operating_system_defines") {
+ defines = []
+ if (is_linux) {
+ defines += [ "OS_LINUX" ]
+ } else if (is_mac) {
+ defines += [ "MAC_OSX" ]
+ }
+}
diff --git a/chromium/third_party/openscreen/src/build/config/BUILDCONFIG.gn b/chromium/third_party/openscreen/src/build/config/BUILDCONFIG.gn
index 0fa9693520d..3b1a06a1a0a 100644
--- a/chromium/third_party/openscreen/src/build/config/BUILDCONFIG.gn
+++ b/chromium/third_party/openscreen/src/build/config/BUILDCONFIG.gn
@@ -161,6 +161,7 @@ _shared_binary_target_configs = [
"//build/config:compiler_cpu_abi",
"//build/config:default_optimization",
"//build/config:sysroot_runtime_libraries",
+ "//build/config:operating_system_defines",
]
# Apply that default list to the binary target types.
diff --git a/chromium/third_party/openscreen/src/build/config/sysroot.gni b/chromium/third_party/openscreen/src/build/config/sysroot.gni
index deecdecacf3..339bfd9b0f4 100644
--- a/chromium/third_party/openscreen/src/build/config/sysroot.gni
+++ b/chromium/third_party/openscreen/src/build/config/sysroot.gni
@@ -1,6 +1,6 @@
# Copyright 2019 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file
+# found in the LICENSE file.
# This header file defines the "sysroot" variable which is the absolute path
# of the sysroot. If no sysroot applies, the variable will be an empty string.
diff --git a/chromium/third_party/openscreen/src/build/scripts/sysroot_ld_path.py b/chromium/third_party/openscreen/src/build/scripts/sysroot_ld_path.py
index 8c65861046f..85873812144 100755
--- a/chromium/third_party/openscreen/src/build/scripts/sysroot_ld_path.py
+++ b/chromium/third_party/openscreen/src/build/scripts/sysroot_ld_path.py
@@ -2,7 +2,7 @@
# Copyright 2019 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file
+# found in the LICENSE file.
# Replacement for the deprecated sysroot_ld_path.sh implementation in Chrome.
"""
diff --git a/chromium/third_party/openscreen/src/cast/README.md b/chromium/third_party/openscreen/src/cast/README.md
index 1b890c5b5b6..a501703ba87 100644
--- a/chromium/third_party/openscreen/src/cast/README.md
+++ b/chromium/third_party/openscreen/src/cast/README.md
@@ -3,3 +3,31 @@
libcast is an open source implementation of the Cast procotol supporting Cast
applications and streaming to Cast-compatible devices.
+## Using the standalone implementations
+
+To run the standalone sender and receivers together, first you need to install
+the following dependencies: FFMPEG, LibVPX, LibOpus, LibSDL2, as well as their
+headers (frequently in a seperate -dev package). From here, you need to generate
+a RSA private key and create a self signed certificate with that key.
+
+From there, after building Open Screen the `cast_sender` and `cast_receiver`
+executables should be ready to use:
+```
+ $ /path/to/out/Default/cast_sender -s <certificate> <path/to/video>
+ ...
+ $ /path/to/out/Default/cast_receiver <interface> -p <private_key> -s <certificate>
+```
+
+When running on Mac OS X, also pass the `-x` flag to the cast receiver to
+disable DNS-SD/mDNS, since Open Screen does not currently integrate with
+Bonjour.
+
+When connecting to a receiver that's not running on the loopback interface
+(typically `lo` or `lo0`), pass the `-r <receiver IP endpoint>` flag to the
+`cast_sender` binary.
+
+An archive containing test running scripts, a video, and a generated RSA
+key and certificate is available from google storage. Note that it may require
+modification to work on your specific work environment:
+
+https://storage.googleapis.com/openscreen_standalone/cast_streaming_demo.tar.gz
diff --git a/chromium/third_party/openscreen/src/cast/common/BUILD.gn b/chromium/third_party/openscreen/src/cast/common/BUILD.gn
index 07ac9b710b2..ba1e67fcd16 100644
--- a/chromium/third_party/openscreen/src/cast/common/BUILD.gn
+++ b/chromium/third_party/openscreen/src/cast/common/BUILD.gn
@@ -19,9 +19,7 @@ source_set("certificate") {
"certificate/types.cc",
"certificate/types.h",
]
- public_deps = [
- "../../third_party/boringssl",
- ]
+ public_deps = [ "../../third_party/boringssl" ]
deps = [
"../../platform",
@@ -34,6 +32,8 @@ source_set("certificate") {
source_set("channel") {
sources = [
"channel/cast_socket.cc",
+ "channel/cast_socket_message_port.cc",
+ "channel/cast_socket_message_port.h",
"channel/connection_namespace_handler.cc",
"channel/connection_namespace_handler.h",
"channel/message_framer.cc",
@@ -50,9 +50,7 @@ source_set("channel") {
"public/cast_socket.h",
]
- deps = [
- "certificate/proto:certificate_proto",
- ]
+ deps = [ "certificate/proto:certificate_proto" ]
public_deps = [
"../../platform",
@@ -64,6 +62,7 @@ source_set("channel") {
source_set("public") {
sources = [
+ "public/message_port.h",
"public/service_info.cc",
"public/service_info.h",
]
@@ -81,9 +80,7 @@ if (!build_with_chromium) {
testonly = true
if (!is_mac) {
- sources = [
- "discovery/e2e_test/tests.cc",
- ]
+ sources = [ "discovery/e2e_test/tests.cc" ]
}
deps = [
@@ -112,9 +109,11 @@ source_set("test_helpers") {
":channel",
":public",
"../../platform:test",
+ "../../testing/util",
"../../third_party/abseil",
"../../third_party/boringssl",
"../../third_party/googletest:gmock",
+ "../../third_party/googletest:gtest",
]
deps = [
"../../platform",
@@ -152,18 +151,12 @@ source_set("unittests") {
"channel/proto:channel_proto",
]
- data = [
- "../../test/data/cast/common/certificate/",
- ]
+ data = [ "../../test/data/cast/common/certificate/" ]
}
openscreen_fuzzer_test("message_framer_fuzzer") {
- sources = [
- "channel/message_framer_fuzzer.cc",
- ]
- deps = [
- ":channel",
- ]
+ sources = [ "channel/message_framer_fuzzer.cc" ]
+ deps = [ ":channel" ]
seed_corpus = "channel/message_framer_fuzzer_seeds"
diff --git a/chromium/third_party/openscreen/src/cast/common/certificate/cast_cert_validator_internal.cc b/chromium/third_party/openscreen/src/cast/common/certificate/cast_cert_validator_internal.cc
index 569d22b1379..e4c689f806d 100644
--- a/chromium/third_party/openscreen/src/cast/common/certificate/cast_cert_validator_internal.cc
+++ b/chromium/third_party/openscreen/src/cast/common/certificate/cast_cert_validator_internal.cc
@@ -14,6 +14,7 @@
#include <vector>
#include "cast/common/certificate/types.h"
+#include "util/crypto/pem_helpers.h"
#include "util/osp_logging.h"
namespace openscreen {
@@ -95,7 +96,8 @@ bssl::UniquePtr<ASN1_BIT_STRING> GetKeyUsage(X509* cert) {
Error::Code VerifyCertificateChain(const std::vector<CertPathStep>& path,
uint32_t step_index,
- const DateTime& time) {
+ const DateTime& time,
+ TrustStore::Mode mode) {
// Default max path length is the number of intermediate certificates.
int max_pathlen = path.size() - 2;
@@ -132,33 +134,37 @@ Error::Code VerifyCertificateChain(const std::vector<CertPathStep>& path,
}
}
- // Check that basicConstraints is present, specifies the CA bit, and use
- // pathLenConstraint if present.
- const int basic_constraints_index =
- X509_get_ext_by_NID(issuer, NID_basic_constraints, -1);
- if (basic_constraints_index == -1) {
- return Error::Code::kErrCertsVerifyGeneric;
- }
- X509_EXTENSION* const basic_constraints_extension =
- X509_get_ext(issuer, basic_constraints_index);
- bssl::UniquePtr<BASIC_CONSTRAINTS> basic_constraints{
- reinterpret_cast<BASIC_CONSTRAINTS*>(
- X509V3_EXT_d2i(basic_constraints_extension))};
+ // Certificates issued by a valid CA authority shall have the
+ // basicConstraints property present with the CA bit set. Self-signed
+ // certificates do not have this property present.
+ if (mode == TrustStore::Mode::kStrict) {
+ const int basic_constraints_index =
+ X509_get_ext_by_NID(issuer, NID_basic_constraints, -1);
+ if (basic_constraints_index == -1) {
+ return Error::Code::kErrCertsVerifyGeneric;
+ }
- if (!basic_constraints || !basic_constraints->ca) {
- return Error::Code::kErrCertsVerifyGeneric;
- }
+ X509_EXTENSION* const basic_constraints_extension =
+ X509_get_ext(issuer, basic_constraints_index);
+ bssl::UniquePtr<BASIC_CONSTRAINTS> basic_constraints{
+ reinterpret_cast<BASIC_CONSTRAINTS*>(
+ X509V3_EXT_d2i(basic_constraints_extension))};
- if (basic_constraints->pathlen) {
- if (basic_constraints->pathlen->length != 1) {
+ if (!basic_constraints || !basic_constraints->ca) {
return Error::Code::kErrCertsVerifyGeneric;
- } else {
- const int pathlen = *basic_constraints->pathlen->data;
- if (pathlen < 0) {
+ }
+
+ if (basic_constraints->pathlen) {
+ if (basic_constraints->pathlen->length != 1) {
return Error::Code::kErrCertsVerifyGeneric;
- }
- if (pathlen < max_pathlen) {
- max_pathlen = pathlen;
+ } else {
+ const int pathlen = *basic_constraints->pathlen->data;
+ if (pathlen < 0) {
+ return Error::Code::kErrCertsVerifyGeneric;
+ }
+ if (pathlen < max_pathlen) {
+ max_pathlen = pathlen;
+ }
}
}
}
@@ -355,6 +361,21 @@ bool GetCertValidTimeRange(X509* cert,
return times_valid;
}
+// static
+TrustStore TrustStore::CreateInstanceFromPemFile(absl::string_view file_path,
+ TrustStore::Mode mode) {
+ TrustStore store;
+
+ std::vector<std::string> certs = ReadCertificatesFromPemFile(file_path);
+ for (const auto& der_cert : certs) {
+ const uint8_t* data = (const uint8_t*)der_cert.data();
+ store.certs.emplace_back(d2i_X509(nullptr, &data, der_cert.size()));
+ }
+
+ store.mode = mode;
+ return store;
+}
+
bool VerifySignedData(const EVP_MD* digest,
EVP_PKEY* public_key,
const ConstDataSpan& data,
@@ -374,7 +395,7 @@ Error FindCertificatePath(const std::vector<std::string>& der_certs,
CertificatePathResult* result_path,
TrustStore* trust_store) {
if (der_certs.empty()) {
- return Error::Code::kErrCertsMissing;
+ return Error(Error::Code::kErrCertsMissing, "Missing DER certificates");
}
bssl::UniquePtr<X509>& target_cert = result_path->target_cert;
@@ -500,7 +521,7 @@ Error FindCertificatePath(const std::vector<std::string>& der_certs,
if (last_error == Error::Code::kNone) {
OSP_DVLOG << "FindCertificatePath: Failed after trying all "
"certificate paths, no matches";
- return Error::Code::kErrCertsVerifyGeneric;
+ return Error::Code::kErrCertsVerifyUntrustedCert;
}
return last_error;
} else {
@@ -512,7 +533,8 @@ Error FindCertificatePath(const std::vector<std::string>& der_certs,
}
if (path_cert_in_trust_store) {
- last_error = VerifyCertificateChain(path, path_index, time);
+ last_error =
+ VerifyCertificateChain(path, path_index, time, trust_store->mode);
if (last_error != Error::Code::kNone) {
CertPathStep& last_step = path[path_index++];
trust_store_index = last_step.trust_store_index;
diff --git a/chromium/third_party/openscreen/src/cast/common/certificate/cast_cert_validator_internal.h b/chromium/third_party/openscreen/src/cast/common/certificate/cast_cert_validator_internal.h
index f8424b6d1c0..9264418ef25 100644
--- a/chromium/third_party/openscreen/src/cast/common/certificate/cast_cert_validator_internal.h
+++ b/chromium/third_party/openscreen/src/cast/common/certificate/cast_cert_validator_internal.h
@@ -7,15 +7,32 @@
#include <openssl/x509.h>
+#include <string>
#include <vector>
+#include "absl/strings/string_view.h"
#include "platform/base/error.h"
-
namespace openscreen {
namespace cast {
struct TrustStore {
+ enum class Mode {
+ // In strict mode, only certificates signed by a CA will be accepted as
+ // part of authentication. Note that if a self-signed certificate is placed
+ // in a strict mode TrustStore, it cannot be used for authentication.
+ kStrict,
+
+ // In allow self signed mode, certificates signed by an arbitrary private
+ // key that have been placed in this trust store will be allowed. Note
+ // that certificates must still otherwise be valid.
+ kAllowSelfSigned
+ };
+
+ static TrustStore CreateInstanceFromPemFile(absl::string_view file_path,
+ Mode mode = Mode::kStrict);
+
std::vector<bssl::UniquePtr<X509>> certs;
+ Mode mode = Mode::kStrict;
};
// Adds a trust anchor given a DER-encoded certificate from static
diff --git a/chromium/third_party/openscreen/src/cast/common/certificate/cast_cert_validator_unittest.cc b/chromium/third_party/openscreen/src/cast/common/certificate/cast_cert_validator_unittest.cc
index f7e21d84379..53b6f05f284 100644
--- a/chromium/third_party/openscreen/src/cast/common/certificate/cast_cert_validator_unittest.cc
+++ b/chromium/third_party/openscreen/src/cast/common/certificate/cast_cert_validator_unittest.cc
@@ -12,6 +12,7 @@
#include "gtest/gtest.h"
#include "openssl/pem.h"
#include "platform/test/paths.h"
+#include "util/crypto/pem_helpers.h"
namespace openscreen {
namespace cast {
@@ -51,8 +52,7 @@ void RunTest(Error::Code expected_result,
const DateTime& time,
TrustStoreDependency trust_store_dependency,
const std::string& optional_signed_data_file_name) {
- std::vector<std::string> certs =
- testing::ReadCertificatesFromPemFile(certs_file_name);
+ std::vector<std::string> certs = ReadCertificatesFromPemFile(certs_file_name);
TrustStore* trust_store;
std::unique_ptr<TrustStore> fake_trust_store;
@@ -94,7 +94,10 @@ void RunTest(Error::Code expected_result,
// Test that the context is good.
EXPECT_EQ(expected_common_name, context->GetCommonName());
-#define DATA_SPAN_FROM_LITERAL(s) ConstDataSpan{(uint8_t*)s, sizeof(s) - 1}
+#define DATA_SPAN_FROM_LITERAL(s) \
+ ConstDataSpan{const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(s)), \
+ sizeof(s) - 1}
+
// Test verification of some invalid signatures.
EXPECT_FALSE(context->VerifySignatureOverData(
DATA_SPAN_FROM_LITERAL("bogus signature"),
@@ -233,7 +236,7 @@ TEST(VerifyCastDeviceCertTest, Fugu) {
// This is invalid because it does not chain to a trust anchor.
TEST(VerifyCastDeviceCertTest, Unchained) {
std::string data_path = GetSpecificTestDataPath();
- RunTest(Error::Code::kErrCertsVerifyGeneric, "",
+ RunTest(Error::Code::kErrCertsVerifyUntrustedCert, "",
CastDeviceCertPolicy::kUnrestricted,
data_path + "certificates/unchained.pem", AprilFirst2016(),
TRUST_STORE_BUILTIN, "");
diff --git a/chromium/third_party/openscreen/src/cast/common/certificate/cast_crl_unittest.cc b/chromium/third_party/openscreen/src/cast/common/certificate/cast_crl_unittest.cc
index fe65cce3cfa..c4d3bfc43a8 100644
--- a/chromium/third_party/openscreen/src/cast/common/certificate/cast_crl_unittest.cc
+++ b/chromium/third_party/openscreen/src/cast/common/certificate/cast_crl_unittest.cc
@@ -99,9 +99,11 @@ bool RunTest(const DeviceCertTest& test_case) {
std::unique_ptr<TrustStore> crl_trust_store;
std::unique_ptr<TrustStore> cast_trust_store;
if (test_case.use_test_trust_anchors()) {
- crl_trust_store = testing::CreateTrustStoreFromPemFile(
+ crl_trust_store = std::make_unique<TrustStore>();
+ cast_trust_store = std::make_unique<TrustStore>();
+ *crl_trust_store = TrustStore::CreateInstanceFromPemFile(
GetSpecificTestDataPath() + "certificates/cast_crl_test_root_ca.pem");
- cast_trust_store = testing::CreateTrustStoreFromPemFile(
+ *cast_trust_store = TrustStore::CreateInstanceFromPemFile(
GetSpecificTestDataPath() + "certificates/cast_test_root_ca.pem");
EXPECT_FALSE(crl_trust_store->certs.empty());
diff --git a/chromium/third_party/openscreen/src/cast/common/certificate/cast_trust_store.cc b/chromium/third_party/openscreen/src/cast/common/certificate/cast_trust_store.cc
index 93db49ba034..d8ec513c0f0 100644
--- a/chromium/third_party/openscreen/src/cast/common/certificate/cast_trust_store.cc
+++ b/chromium/third_party/openscreen/src/cast/common/certificate/cast_trust_store.cc
@@ -4,6 +4,9 @@
#include "cast/common/certificate/cast_trust_store.h"
+#include <utility>
+
+#include "util/crypto/pem_helpers.h"
#include "util/osp_logging.h"
namespace openscreen {
@@ -48,6 +51,16 @@ CastTrustStore* CastTrustStore::CreateInstanceForTest(
return store_;
}
+// static
+CastTrustStore* CastTrustStore::CreateInstanceFromPemFile(
+ absl::string_view file_path,
+ TrustStore::Mode mode) {
+ OSP_DCHECK(!store_);
+ store_ = new CastTrustStore();
+ store_->trust_store_ = TrustStore::CreateInstanceFromPemFile(file_path, mode);
+ return store_;
+}
+
CastTrustStore::CastTrustStore() {
trust_store_.certs.emplace_back(MakeTrustAnchor(kCastRootCaDer));
trust_store_.certs.emplace_back(MakeTrustAnchor(kEurekaRootCaDer));
@@ -57,6 +70,9 @@ CastTrustStore::CastTrustStore(const std::vector<uint8_t>& trust_anchor_der) {
trust_store_.certs.emplace_back(MakeTrustAnchor(trust_anchor_der));
}
+CastTrustStore::CastTrustStore(TrustStore trust_store)
+ : trust_store_(std::move(trust_store)) {}
+
CastTrustStore::~CastTrustStore() = default;
// static
diff --git a/chromium/third_party/openscreen/src/cast/common/certificate/cast_trust_store.h b/chromium/third_party/openscreen/src/cast/common/certificate/cast_trust_store.h
index 801d9274a74..7bd7595594d 100644
--- a/chromium/third_party/openscreen/src/cast/common/certificate/cast_trust_store.h
+++ b/chromium/third_party/openscreen/src/cast/common/certificate/cast_trust_store.h
@@ -7,6 +7,7 @@
#include <vector>
+#include "absl/strings/string_view.h"
#include "cast/common/certificate/cast_cert_validator_internal.h"
namespace openscreen {
@@ -20,8 +21,13 @@ class CastTrustStore {
static CastTrustStore* CreateInstanceForTest(
const std::vector<uint8_t>& trust_anchor_der);
+ static CastTrustStore* CreateInstanceFromPemFile(
+ absl::string_view file_path,
+ TrustStore::Mode mode = TrustStore::Mode::kStrict);
+
CastTrustStore();
explicit CastTrustStore(const std::vector<uint8_t>& trust_anchor_der);
+ explicit CastTrustStore(TrustStore trust_store);
CastTrustStore(const CastTrustStore&) = delete;
~CastTrustStore();
CastTrustStore& operator=(const CastTrustStore&) = delete;
diff --git a/chromium/third_party/openscreen/src/cast/common/certificate/testing/test_helpers.cc b/chromium/third_party/openscreen/src/cast/common/certificate/testing/test_helpers.cc
index 113a4bc4e26..09bf26b287f 100644
--- a/chromium/third_party/openscreen/src/cast/common/certificate/testing/test_helpers.cc
+++ b/chromium/third_party/openscreen/src/cast/common/certificate/testing/test_helpers.cc
@@ -17,58 +17,6 @@ namespace openscreen {
namespace cast {
namespace testing {
-std::vector<std::string> ReadCertificatesFromPemFile(
- absl::string_view filename) {
- FILE* fp = fopen(filename.data(), "r");
- if (!fp) {
- return {};
- }
- std::vector<std::string> certs;
- char* name;
- char* header;
- unsigned char* data;
- long length;
- while (PEM_read(fp, &name, &header, &data, &length) == 1) {
- if (absl::StartsWith(name, "CERTIFICATE")) {
- certs.emplace_back((char*)data, length);
- }
- OPENSSL_free(name);
- OPENSSL_free(header);
- OPENSSL_free(data);
- }
- fclose(fp);
- return certs;
-}
-
-bssl::UniquePtr<EVP_PKEY> ReadKeyFromPemFile(absl::string_view filename) {
- FILE* fp = fopen(filename.data(), "r");
- if (!fp) {
- return nullptr;
- }
- bssl::UniquePtr<EVP_PKEY> pkey;
- char* name;
- char* header;
- unsigned char* data;
- long length;
- while (PEM_read(fp, &name, &header, &data, &length) == 1) {
- if (absl::StartsWith(name, "RSA PRIVATE KEY")) {
- OSP_DCHECK(!pkey);
- CBS cbs;
- CBS_init(&cbs, data, length);
- RSA* rsa = RSA_parse_private_key(&cbs);
- if (rsa) {
- pkey.reset(EVP_PKEY_new());
- EVP_PKEY_assign_RSA(pkey.get(), rsa);
- }
- }
- OPENSSL_free(name);
- OPENSSL_free(header);
- OPENSSL_free(data);
- }
- fclose(fp);
- return pkey;
-}
-
SignatureTestData::SignatureTestData()
: message{nullptr, 0}, sha1{nullptr, 0}, sha256{nullptr, 0} {}
@@ -85,7 +33,7 @@ SignatureTestData ReadSignatureTestData(absl::string_view filename) {
char* name;
char* header;
unsigned char* data;
- long length;
+ long length; // NOLINT
while (PEM_read(fp, &name, &header, &data, &length) == 1) {
if (strcmp(name, "MESSAGE") == 0) {
OSP_DCHECK(!result.message.data);
@@ -112,19 +60,6 @@ SignatureTestData ReadSignatureTestData(absl::string_view filename) {
return result;
}
-std::unique_ptr<TrustStore> CreateTrustStoreFromPemFile(
- absl::string_view filename) {
- std::unique_ptr<TrustStore> store = std::make_unique<TrustStore>();
-
- std::vector<std::string> certs =
- testing::ReadCertificatesFromPemFile(filename);
- for (const auto& der_cert : certs) {
- const uint8_t* data = (const uint8_t*)der_cert.data();
- store->certs.emplace_back(d2i_X509(nullptr, &data, der_cert.size()));
- }
- return store;
-}
-
} // namespace testing
} // namespace cast
} // namespace openscreen
diff --git a/chromium/third_party/openscreen/src/cast/common/certificate/testing/test_helpers.h b/chromium/third_party/openscreen/src/cast/common/certificate/testing/test_helpers.h
index c1ff9a25f78..30715971560 100644
--- a/chromium/third_party/openscreen/src/cast/common/certificate/testing/test_helpers.h
+++ b/chromium/third_party/openscreen/src/cast/common/certificate/testing/test_helpers.h
@@ -18,10 +18,6 @@ namespace openscreen {
namespace cast {
namespace testing {
-std::vector<std::string> ReadCertificatesFromPemFile(
- absl::string_view filename);
-bssl::UniquePtr<EVP_PKEY> ReadKeyFromPemFile(absl::string_view filename);
-
class SignatureTestData {
public:
SignatureTestData();
@@ -34,9 +30,6 @@ class SignatureTestData {
SignatureTestData ReadSignatureTestData(absl::string_view filename);
-std::unique_ptr<TrustStore> CreateTrustStoreFromPemFile(
- absl::string_view filename);
-
} // namespace testing
} // namespace cast
} // namespace openscreen
diff --git a/chromium/third_party/openscreen/src/cast/common/channel/cast_message_handler.h b/chromium/third_party/openscreen/src/cast/common/channel/cast_message_handler.h
index cd0d13e690d..e478d156e17 100644
--- a/chromium/third_party/openscreen/src/cast/common/channel/cast_message_handler.h
+++ b/chromium/third_party/openscreen/src/cast/common/channel/cast_message_handler.h
@@ -17,6 +17,7 @@ class CastMessageHandler {
public:
virtual ~CastMessageHandler() = default;
+ // |socket| is null if the source of the message is a local peer.
virtual void OnMessage(VirtualConnectionRouter* router,
CastSocket* socket,
::cast::channel::CastMessage message) = 0;
diff --git a/chromium/third_party/openscreen/src/cast/common/channel/cast_socket_message_port.cc b/chromium/third_party/openscreen/src/cast/common/channel/cast_socket_message_port.cc
new file mode 100644
index 00000000000..b6d65123ae7
--- /dev/null
+++ b/chromium/third_party/openscreen/src/cast/common/channel/cast_socket_message_port.cc
@@ -0,0 +1,103 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cast/common/channel/cast_socket_message_port.h"
+
+#include <utility>
+
+#include "cast/common/channel/message_util.h"
+#include "cast/common/channel/proto/cast_channel.pb.h"
+#include "cast/common/channel/virtual_connection.h"
+#include "cast/common/channel/virtual_connection_manager.h"
+
+namespace openscreen {
+namespace cast {
+
+CastSocketMessagePort::CastSocketMessagePort(VirtualConnectionRouter* router)
+ : router_(router) {}
+
+CastSocketMessagePort::~CastSocketMessagePort() {
+ ResetClient();
+}
+
+// NOTE: we assume here that this message port is already the client for
+// the passed in socket, so leave the socket's client unchanged. However,
+// since sockets should map one to one with receiver sessions, we reset our
+// client. The consumer of this message port should call SetClient with the new
+// message port client after setting the socket.
+void CastSocketMessagePort::SetSocket(WeakPtr<CastSocket> socket) {
+ ResetClient();
+ socket_ = socket;
+}
+
+int CastSocketMessagePort::GetSocketId() {
+ return ToCastSocketId(socket_.get());
+}
+
+void CastSocketMessagePort::SetClient(MessagePort::Client* client,
+ std::string client_sender_id) {
+ ResetClient();
+
+ client_ = client;
+ client_sender_id_ = std::move(client_sender_id);
+ router_->AddHandlerForLocalId(client_sender_id_, this);
+}
+
+void CastSocketMessagePort::ResetClient() {
+ if (!client_) {
+ return;
+ }
+
+ client_ = nullptr;
+ router_->RemoveHandlerForLocalId(client_sender_id_);
+ router_->manager()->RemoveConnectionsByLocalId(
+ client_sender_id_, VirtualConnection::CloseReason::kClosedBySelf);
+ client_sender_id_.clear();
+}
+
+void CastSocketMessagePort::PostMessage(
+ const std::string& destination_sender_id,
+ const std::string& message_namespace,
+ const std::string& message) {
+ if (!client_) {
+ OSP_DLOG_WARN << "Not posting message due to nullptr client_";
+ return;
+ }
+
+ if (!socket_) {
+ client_->OnError(Error::Code::kAlreadyClosed);
+ return;
+ }
+
+ VirtualConnection connection{client_sender_id_, destination_sender_id,
+ socket_->socket_id()};
+ if (!router_->manager()->GetConnectionData(connection)) {
+ router_->manager()->AddConnection(connection,
+ VirtualConnection::AssociatedData{});
+ }
+
+ const Error send_error = router_->Send(
+ std::move(connection), MakeSimpleUTF8Message(message_namespace, message));
+ if (!send_error.ok()) {
+ client_->OnError(std::move(send_error));
+ }
+}
+
+void CastSocketMessagePort::OnMessage(VirtualConnectionRouter* router,
+ CastSocket* socket,
+ ::cast::channel::CastMessage message) {
+ OSP_DCHECK(router == router_);
+ OSP_DCHECK(socket_.get() == socket);
+ OSP_DVLOG << "Received a cast socket message";
+ if (!client_) {
+ OSP_DLOG_WARN << "Dropping message due to nullptr client_";
+ return;
+ }
+
+ client_->OnMessage(message.source_id(), message.namespace_(),
+ message.payload_utf8());
+}
+
+} // namespace cast
+} // namespace openscreen
diff --git a/chromium/third_party/openscreen/src/cast/common/channel/cast_socket_message_port.h b/chromium/third_party/openscreen/src/cast/common/channel/cast_socket_message_port.h
new file mode 100644
index 00000000000..4dbd141c65d
--- /dev/null
+++ b/chromium/third_party/openscreen/src/cast/common/channel/cast_socket_message_port.h
@@ -0,0 +1,55 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CAST_COMMON_CHANNEL_CAST_SOCKET_MESSAGE_PORT_H_
+#define CAST_COMMON_CHANNEL_CAST_SOCKET_MESSAGE_PORT_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "cast/common/channel/cast_message_handler.h"
+#include "cast/common/channel/virtual_connection_router.h"
+#include "cast/common/public/cast_socket.h"
+#include "cast/common/public/message_port.h"
+#include "util/weak_ptr.h"
+
+namespace openscreen {
+namespace cast {
+
+class CastSocketMessagePort : public MessagePort, public CastMessageHandler {
+ public:
+ // The router is expected to outlive this message port.
+ explicit CastSocketMessagePort(VirtualConnectionRouter* router);
+ ~CastSocketMessagePort() override;
+
+ void SetSocket(WeakPtr<CastSocket> socket);
+
+ // Returns current socket identifier, or -1 if not connected.
+ int GetSocketId();
+
+ // MessagePort overrides.
+ void SetClient(MessagePort::Client* client,
+ std::string client_sender_id) override;
+ void ResetClient() override;
+ void PostMessage(const std::string& destination_sender_id,
+ const std::string& message_namespace,
+ const std::string& message) override;
+
+ // CastMessageHandler overrides.
+ void OnMessage(VirtualConnectionRouter* router,
+ CastSocket* socket,
+ ::cast::channel::CastMessage message) override;
+
+ private:
+ VirtualConnectionRouter* const router_;
+ std::string client_sender_id_;
+ MessagePort::Client* client_ = nullptr;
+ WeakPtr<CastSocket> socket_;
+};
+
+} // namespace cast
+} // namespace openscreen
+
+#endif // CAST_COMMON_CHANNEL_CAST_SOCKET_MESSAGE_PORT_H_
diff --git a/chromium/third_party/openscreen/src/cast/common/channel/connection_namespace_handler.cc b/chromium/third_party/openscreen/src/cast/common/channel/connection_namespace_handler.cc
index 396b5d53159..a449dcbddd8 100644
--- a/chromium/third_party/openscreen/src/cast/common/channel/connection_namespace_handler.cc
+++ b/chromium/third_party/openscreen/src/cast/common/channel/connection_namespace_handler.cc
@@ -4,7 +4,9 @@
#include "cast/common/channel/connection_namespace_handler.h"
+#include <string>
#include <type_traits>
+#include <utility>
#include "absl/types/optional.h"
#include "cast/common/channel/message_util.h"
@@ -138,7 +140,7 @@ void ConnectionNamespaceHandler::HandleConnect(VirtualConnectionRouter* router,
VirtualConnection virtual_conn{std::move(message.destination_id()),
std::move(message.source_id()),
- socket->socket_id()};
+ ToCastSocketId(socket)};
if (!vc_policy_->IsConnectionAllowed(virtual_conn)) {
SendClose(router, std::move(virtual_conn));
return;
@@ -187,7 +189,11 @@ void ConnectionNamespaceHandler::HandleConnect(VirtualConnectionRouter* router,
data.max_protocol_version = VirtualConnection::ProtocolVersion::kV2_1_0;
}
- data.ip_fragment = socket->GetSanitizedIpAddress();
+ if (socket) {
+ data.ip_fragment = socket->GetSanitizedIpAddress();
+ } else {
+ data.ip_fragment = {};
+ }
OSP_DVLOG << "Connection opened: " << virtual_conn.local_id << ", "
<< virtual_conn.peer_id << ", " << virtual_conn.socket_id;
@@ -208,7 +214,7 @@ void ConnectionNamespaceHandler::HandleClose(VirtualConnectionRouter* router,
Json::Value parsed_message) {
VirtualConnection virtual_conn{std::move(message.destination_id()),
std::move(message.source_id()),
- socket->socket_id()};
+ ToCastSocketId(socket)};
if (!vc_manager_->GetConnectionData(virtual_conn)) {
return;
}
diff --git a/chromium/third_party/openscreen/src/cast/common/channel/virtual_connection.h b/chromium/third_party/openscreen/src/cast/common/channel/virtual_connection.h
index 04f3ba06ab4..6f8b2cb833a 100644
--- a/chromium/third_party/openscreen/src/cast/common/channel/virtual_connection.h
+++ b/chromium/third_party/openscreen/src/cast/common/channel/virtual_connection.h
@@ -97,6 +97,8 @@ struct VirtualConnection {
// generated and intended to be unique within that device.
// - GUID-style hex string: Random string identifying a particular receiver
// app on the device.
+ //
+ // Additionally, |peer_id| can be an asterisk when broadcast-sending.
std::string local_id;
std::string peer_id;
int socket_id;
diff --git a/chromium/third_party/openscreen/src/cast/common/channel/virtual_connection_router.cc b/chromium/third_party/openscreen/src/cast/common/channel/virtual_connection_router.cc
index 74efcd89e34..140ca138758 100644
--- a/chromium/third_party/openscreen/src/cast/common/channel/virtual_connection_router.cc
+++ b/chromium/third_party/openscreen/src/cast/common/channel/virtual_connection_router.cc
@@ -4,6 +4,8 @@
#include "cast/common/channel/virtual_connection_router.h"
+#include <utility>
+
#include "cast/common/channel/cast_message_handler.h"
#include "cast/common/channel/message_util.h"
#include "cast/common/channel/proto/cast_channel.pb.h"
@@ -55,7 +57,11 @@ void VirtualConnectionRouter::CloseSocket(int id) {
Error VirtualConnectionRouter::Send(VirtualConnection virtual_conn,
CastMessage message) {
- // TODO(btolsch): Check for broadcast message.
+ if (virtual_conn.peer_id == kBroadcastId) {
+ return BroadcastFromLocalPeer(std::move(virtual_conn.local_id),
+ std::move(message));
+ }
+
if (!IsTransportNamespace(message.namespace_()) &&
!vc_manager_->GetConnectionData(virtual_conn)) {
return Error::Code::kNoActiveConnection;
@@ -69,8 +75,33 @@ Error VirtualConnectionRouter::Send(VirtualConnection virtual_conn,
return it->second.socket->Send(message);
}
+Error VirtualConnectionRouter::BroadcastFromLocalPeer(
+ std::string local_id,
+ ::cast::channel::CastMessage message) {
+ message.set_source_id(std::move(local_id));
+ message.set_destination_id(kBroadcastId);
+
+ // Broadcast to local endpoints.
+ for (const auto& entry : endpoints_) {
+ if (entry.first != message.source_id()) {
+ entry.second->OnMessage(this, nullptr, message);
+ }
+ }
+
+ // Broadcast to remote endpoints. If an Error occurs, continue broadcasting,
+ // and later return the first Error that occurred.
+ Error error;
+ for (const auto& entry : sockets_) {
+ auto result = entry.second.socket->Send(message);
+ if (!result.ok() && error.ok()) {
+ error = std::move(result);
+ }
+ }
+ return error;
+}
+
void VirtualConnectionRouter::OnError(CastSocket* socket, Error error) {
- int id = socket->socket_id();
+ const int id = socket->socket_id();
auto it = sockets_.find(id);
if (it != sockets_.end()) {
vc_manager_->RemoveConnectionsBySocketId(id, VirtualConnection::kUnknown);
@@ -83,17 +114,23 @@ void VirtualConnectionRouter::OnError(CastSocket* socket, Error error) {
void VirtualConnectionRouter::OnMessage(CastSocket* socket,
CastMessage message) {
- // TODO(btolsch): Check for broadcast message.
- VirtualConnection virtual_conn{message.destination_id(), message.source_id(),
- socket->socket_id()};
- if (!IsTransportNamespace(message.namespace_()) &&
- !vc_manager_->GetConnectionData(virtual_conn)) {
- return;
- }
+ OSP_DCHECK(socket);
+
const std::string& local_id = message.destination_id();
- auto it = endpoints_.find(local_id);
- if (it != endpoints_.end()) {
- it->second->OnMessage(this, socket, std::move(message));
+ if (local_id == kBroadcastId) {
+ for (const auto& entry : endpoints_) {
+ entry.second->OnMessage(this, socket, message);
+ }
+ } else {
+ if (!IsTransportNamespace(message.namespace_()) &&
+ !vc_manager_->GetConnectionData(VirtualConnection{
+ local_id, message.source_id(), socket->socket_id()})) {
+ return;
+ }
+ auto it = endpoints_.find(local_id);
+ if (it != endpoints_.end()) {
+ it->second->OnMessage(this, socket, std::move(message));
+ }
}
}
diff --git a/chromium/third_party/openscreen/src/cast/common/channel/virtual_connection_router.h b/chromium/third_party/openscreen/src/cast/common/channel/virtual_connection_router.h
index 3f549b1e6aa..1bbf2bc160f 100644
--- a/chromium/third_party/openscreen/src/cast/common/channel/virtual_connection_router.h
+++ b/chromium/third_party/openscreen/src/cast/common/channel/virtual_connection_router.h
@@ -62,11 +62,16 @@ class VirtualConnectionRouter final : public CastSocket::Client {
Error Send(VirtualConnection virtual_conn,
::cast::channel::CastMessage message);
+ Error BroadcastFromLocalPeer(std::string local_id,
+ ::cast::channel::CastMessage message);
+
// CastSocket::Client overrides.
void OnError(CastSocket* socket, Error error) override;
void OnMessage(CastSocket* socket,
::cast::channel::CastMessage message) override;
+ VirtualConnectionManager* manager() { return vc_manager_; }
+
private:
struct SocketWithHandler {
std::unique_ptr<CastSocket> socket;
diff --git a/chromium/third_party/openscreen/src/cast/common/channel/virtual_connection_router_unittest.cc b/chromium/third_party/openscreen/src/cast/common/channel/virtual_connection_router_unittest.cc
index 6b1f0055ac5..b05d10e3a60 100644
--- a/chromium/third_party/openscreen/src/cast/common/channel/virtual_connection_router_unittest.cc
+++ b/chromium/third_party/openscreen/src/cast/common/channel/virtual_connection_router_unittest.cc
@@ -4,6 +4,9 @@
#include "cast/common/channel/virtual_connection_router.h"
+#include <utility>
+
+#include "cast/common/channel/message_util.h"
#include "cast/common/channel/proto/cast_channel.pb.h"
#include "cast/common/channel/testing/fake_cast_socket.h"
#include "cast/common/channel/testing/mock_cast_message_handler.h"
@@ -19,35 +22,43 @@ namespace {
using ::cast::channel::CastMessage;
using ::testing::_;
using ::testing::Invoke;
+using ::testing::SaveArg;
+using ::testing::WithArg;
class VirtualConnectionRouterTest : public ::testing::Test {
public:
void SetUp() override {
- socket_ = fake_cast_socket_pair_.socket.get();
- router_.TakeSocket(&mock_error_handler_,
- std::move(fake_cast_socket_pair_.socket));
+ local_socket_ = fake_cast_socket_pair_.socket.get();
+ local_router_.TakeSocket(&mock_error_handler_,
+ std::move(fake_cast_socket_pair_.socket));
+
+ remote_socket_ = fake_cast_socket_pair_.peer_socket.get();
+ remote_router_.TakeSocket(&mock_error_handler_,
+ std::move(fake_cast_socket_pair_.peer_socket));
}
protected:
- CastSocket& peer_socket() { return *fake_cast_socket_pair_.peer_socket; }
-
FakeCastSocketPair fake_cast_socket_pair_;
- CastSocket* socket_;
+ CastSocket* local_socket_;
+ CastSocket* remote_socket_;
MockSocketErrorHandler mock_error_handler_;
- MockCastMessageHandler mock_message_handler_;
- VirtualConnectionManager manager_;
- VirtualConnectionRouter router_{&manager_};
+ VirtualConnectionManager local_manager_;
+ VirtualConnectionRouter local_router_{&local_manager_};
+
+ VirtualConnectionManager remote_manager_;
+ VirtualConnectionRouter remote_router_{&remote_manager_};
};
} // namespace
TEST_F(VirtualConnectionRouterTest, LocalIdHandler) {
- router_.AddHandlerForLocalId("receiver-1234", &mock_message_handler_);
- manager_.AddConnection(
- VirtualConnection{"receiver-1234", "sender-9873", socket_->socket_id()},
- {});
+ MockCastMessageHandler mock_message_handler;
+ local_router_.AddHandlerForLocalId("receiver-1234", &mock_message_handler);
+ local_manager_.AddConnection(VirtualConnection{"receiver-1234", "sender-9873",
+ local_socket_->socket_id()},
+ {});
CastMessage message;
message.set_protocol_version(
@@ -57,22 +68,25 @@ TEST_F(VirtualConnectionRouterTest, LocalIdHandler) {
message.set_destination_id("receiver-1234");
message.set_payload_type(CastMessage::STRING);
message.set_payload_utf8("cnlybnq");
- EXPECT_CALL(mock_message_handler_, OnMessage(_, socket_, _));
- EXPECT_TRUE(peer_socket().Send(message).ok());
+ EXPECT_CALL(mock_message_handler, OnMessage(_, local_socket_, _));
+ EXPECT_TRUE(remote_socket_->Send(message).ok());
- EXPECT_CALL(mock_message_handler_, OnMessage(_, socket_, _));
- EXPECT_TRUE(peer_socket().Send(message).ok());
+ EXPECT_CALL(mock_message_handler, OnMessage(_, local_socket_, _));
+ EXPECT_TRUE(remote_socket_->Send(message).ok());
message.set_destination_id("receiver-4321");
- EXPECT_CALL(mock_message_handler_, OnMessage(_, _, _)).Times(0);
- EXPECT_TRUE(peer_socket().Send(message).ok());
+ EXPECT_CALL(mock_message_handler, OnMessage(_, _, _)).Times(0);
+ EXPECT_TRUE(remote_socket_->Send(message).ok());
+
+ local_router_.RemoveHandlerForLocalId("receiver-1234");
}
TEST_F(VirtualConnectionRouterTest, RemoveLocalIdHandler) {
- router_.AddHandlerForLocalId("receiver-1234", &mock_message_handler_);
- manager_.AddConnection(
- VirtualConnection{"receiver-1234", "sender-9873", socket_->socket_id()},
- {});
+ MockCastMessageHandler mock_message_handler;
+ local_router_.AddHandlerForLocalId("receiver-1234", &mock_message_handler);
+ local_manager_.AddConnection(VirtualConnection{"receiver-1234", "sender-9873",
+ local_socket_->socket_id()},
+ {});
CastMessage message;
message.set_protocol_version(
@@ -82,18 +96,27 @@ TEST_F(VirtualConnectionRouterTest, RemoveLocalIdHandler) {
message.set_destination_id("receiver-1234");
message.set_payload_type(CastMessage::STRING);
message.set_payload_utf8("cnlybnq");
- EXPECT_CALL(mock_message_handler_, OnMessage(_, socket_, _));
- EXPECT_TRUE(peer_socket().Send(message).ok());
+ EXPECT_CALL(mock_message_handler, OnMessage(_, local_socket_, _));
+ EXPECT_TRUE(remote_socket_->Send(message).ok());
+
+ local_router_.RemoveHandlerForLocalId("receiver-1234");
- router_.RemoveHandlerForLocalId("receiver-1234");
+ EXPECT_CALL(mock_message_handler, OnMessage(_, local_socket_, _)).Times(0);
+ EXPECT_TRUE(remote_socket_->Send(message).ok());
- EXPECT_CALL(mock_message_handler_, OnMessage(_, socket_, _)).Times(0);
- EXPECT_TRUE(peer_socket().Send(message).ok());
+ local_router_.RemoveHandlerForLocalId("receiver-1234");
}
TEST_F(VirtualConnectionRouterTest, SendMessage) {
- manager_.AddConnection(
- VirtualConnection{"receiver-1234", "sender-4321", socket_->socket_id()},
+ local_manager_.AddConnection(VirtualConnection{"receiver-1234", "sender-4321",
+ local_socket_->socket_id()},
+ {});
+
+ MockCastMessageHandler destination;
+ remote_router_.AddHandlerForLocalId("sender-4321", &destination);
+ remote_manager_.AddConnection(
+ VirtualConnection{"sender-4321", "receiver-1234",
+ remote_socket_->socket_id()},
{});
CastMessage message;
@@ -104,30 +127,159 @@ TEST_F(VirtualConnectionRouterTest, SendMessage) {
message.set_destination_id("sender-4321");
message.set_payload_type(CastMessage::STRING);
message.set_payload_utf8("cnlybnq");
- EXPECT_CALL(fake_cast_socket_pair_.mock_peer_client, OnMessage(_, _))
- .WillOnce(Invoke([](CastSocket* socket, CastMessage message) {
- EXPECT_EQ(message.namespace_(), "zrqvn");
- EXPECT_EQ(message.source_id(), "receiver-1234");
- EXPECT_EQ(message.destination_id(), "sender-4321");
- ASSERT_EQ(message.payload_type(),
- ::cast::channel::CastMessage_PayloadType_STRING);
- EXPECT_EQ(message.payload_utf8(), "cnlybnq");
- }));
- router_.Send(
- VirtualConnection{"receiver-1234", "sender-4321", socket_->socket_id()},
- std::move(message));
+ ASSERT_TRUE(message.IsInitialized());
+
+ EXPECT_CALL(destination, OnMessage(&remote_router_, remote_socket_, _))
+ .WillOnce(
+ WithArg<2>(Invoke([&message](CastMessage message_at_destination) {
+ ASSERT_TRUE(message_at_destination.IsInitialized());
+ EXPECT_EQ(message.SerializeAsString(),
+ message_at_destination.SerializeAsString());
+ })));
+ local_router_.Send(VirtualConnection{"receiver-1234", "sender-4321",
+ local_socket_->socket_id()},
+ message);
}
TEST_F(VirtualConnectionRouterTest, CloseSocketRemovesVirtualConnections) {
- manager_.AddConnection(
- VirtualConnection{"receiver-1234", "sender-4321", socket_->socket_id()},
- {});
+ local_manager_.AddConnection(VirtualConnection{"receiver-1234", "sender-4321",
+ local_socket_->socket_id()},
+ {});
+
+ EXPECT_CALL(mock_error_handler_, OnClose(local_socket_)).Times(1);
- int id = socket_->socket_id();
- router_.CloseSocket(id);
- EXPECT_FALSE(manager_.GetConnectionData(
+ int id = local_socket_->socket_id();
+ local_router_.CloseSocket(id);
+ EXPECT_FALSE(local_manager_.GetConnectionData(
VirtualConnection{"receiver-1234", "sender-4321", id}));
}
+// Tests that VirtualConnectionRouter::Send() broadcasts a message from a local
+// source to both: 1) all other local peers; and 2) all remote peers.
+TEST_F(VirtualConnectionRouterTest, BroadcastsFromLocalSource) {
+ // Local peers.
+ MockCastMessageHandler alice, bob;
+ local_router_.AddHandlerForLocalId("alice", &alice);
+ local_router_.AddHandlerForLocalId("bob", &bob);
+
+ // Remote peers.
+ MockCastMessageHandler charlie, dave, eve;
+ remote_router_.AddHandlerForLocalId("charlie", &charlie);
+ remote_router_.AddHandlerForLocalId("dave", &dave);
+ remote_router_.AddHandlerForLocalId("eve", &eve);
+
+ // The local broadcaster, which should never receive her own messages.
+ MockCastMessageHandler wendy;
+ local_router_.AddHandlerForLocalId("wendy", &wendy);
+ EXPECT_CALL(wendy, OnMessage(_, _, _)).Times(0);
+
+ CastMessage message;
+ message.set_protocol_version(
+ ::cast::channel::CastMessage_ProtocolVersion_CASTV2_1_0);
+ message.set_namespace_("zrqvn");
+ message.set_payload_type(CastMessage::STRING);
+ message.set_payload_utf8("cnlybnq");
+
+ CastMessage message_alice_got, message_bob_got, message_charlie_got,
+ message_dave_got, message_eve_got;
+ EXPECT_CALL(alice, OnMessage(&local_router_, nullptr, _))
+ .WillOnce(SaveArg<2>(&message_alice_got))
+ .RetiresOnSaturation();
+ EXPECT_CALL(bob, OnMessage(&local_router_, nullptr, _))
+ .WillOnce(SaveArg<2>(&message_bob_got))
+ .RetiresOnSaturation();
+ EXPECT_CALL(charlie, OnMessage(&remote_router_, remote_socket_, _))
+ .WillOnce(SaveArg<2>(&message_charlie_got))
+ .RetiresOnSaturation();
+ EXPECT_CALL(dave, OnMessage(&remote_router_, remote_socket_, _))
+ .WillOnce(SaveArg<2>(&message_dave_got))
+ .RetiresOnSaturation();
+ EXPECT_CALL(eve, OnMessage(&remote_router_, remote_socket_, _))
+ .WillOnce(SaveArg<2>(&message_eve_got))
+ .RetiresOnSaturation();
+ ASSERT_TRUE(local_router_.BroadcastFromLocalPeer("wendy", message).ok());
+
+ // Confirm message data is correct.
+ message.set_source_id("wendy");
+ message.set_destination_id(kBroadcastId);
+ ASSERT_TRUE(message.IsInitialized());
+ ASSERT_TRUE(message_alice_got.IsInitialized());
+ EXPECT_EQ(message.SerializeAsString(), message_alice_got.SerializeAsString());
+ ASSERT_TRUE(message_bob_got.IsInitialized());
+ EXPECT_EQ(message.SerializeAsString(), message_bob_got.SerializeAsString());
+ ASSERT_TRUE(message_charlie_got.IsInitialized());
+ EXPECT_EQ(message.SerializeAsString(),
+ message_charlie_got.SerializeAsString());
+ ASSERT_TRUE(message_dave_got.IsInitialized());
+ EXPECT_EQ(message.SerializeAsString(), message_dave_got.SerializeAsString());
+ ASSERT_TRUE(message_eve_got.IsInitialized());
+ EXPECT_EQ(message.SerializeAsString(), message_eve_got.SerializeAsString());
+
+ // Remove one local peer and one remote peer, and confirm only the correct
+ // entities receive a broadcast message.
+ local_router_.RemoveHandlerForLocalId("bob");
+ remote_router_.RemoveHandlerForLocalId("charlie");
+ EXPECT_CALL(alice, OnMessage(&local_router_, nullptr, _)).Times(1);
+ EXPECT_CALL(bob, OnMessage(_, _, _)).Times(0);
+ EXPECT_CALL(charlie, OnMessage(_, _, _)).Times(0);
+ EXPECT_CALL(dave, OnMessage(&remote_router_, remote_socket_, _)).Times(1);
+ EXPECT_CALL(eve, OnMessage(&remote_router_, remote_socket_, _)).Times(1);
+ ASSERT_TRUE(local_router_.BroadcastFromLocalPeer("wendy", message).ok());
+}
+
+// Tests that VirtualConnectionRouter::OnMessage() broadcasts a message from a
+// remote source to all local peers.
+TEST_F(VirtualConnectionRouterTest, BroadcastsFromRemoteSource) {
+ // Local peers.
+ MockCastMessageHandler alice, bob, charlie;
+ local_router_.AddHandlerForLocalId("alice", &alice);
+ local_router_.AddHandlerForLocalId("bob", &bob);
+ local_router_.AddHandlerForLocalId("charlie", &charlie);
+
+ // The remote broadcaster, which should never receive her own messages.
+ MockCastMessageHandler wendy;
+ remote_router_.AddHandlerForLocalId("wendy", &wendy);
+ EXPECT_CALL(wendy, OnMessage(_, _, _)).Times(0);
+
+ CastMessage message;
+ message.set_protocol_version(
+ ::cast::channel::CastMessage_ProtocolVersion_CASTV2_1_0);
+ message.set_namespace_("zrqvn");
+ message.set_payload_type(CastMessage::STRING);
+ message.set_payload_utf8("cnlybnq");
+
+ CastMessage message_alice_got, message_bob_got, message_charlie_got;
+ EXPECT_CALL(alice, OnMessage(&local_router_, local_socket_, _))
+ .WillOnce(SaveArg<2>(&message_alice_got))
+ .RetiresOnSaturation();
+ EXPECT_CALL(bob, OnMessage(&local_router_, local_socket_, _))
+ .WillOnce(SaveArg<2>(&message_bob_got))
+ .RetiresOnSaturation();
+ EXPECT_CALL(charlie, OnMessage(&local_router_, local_socket_, _))
+ .WillOnce(SaveArg<2>(&message_charlie_got))
+ .RetiresOnSaturation();
+ ASSERT_TRUE(remote_router_.BroadcastFromLocalPeer("wendy", message).ok());
+
+ // Confirm message data is correct.
+ message.set_source_id("wendy");
+ message.set_destination_id(kBroadcastId);
+ ASSERT_TRUE(message.IsInitialized());
+ ASSERT_TRUE(message_alice_got.IsInitialized());
+ EXPECT_EQ(message.SerializeAsString(), message_alice_got.SerializeAsString());
+ ASSERT_TRUE(message_bob_got.IsInitialized());
+ EXPECT_EQ(message.SerializeAsString(), message_bob_got.SerializeAsString());
+ ASSERT_TRUE(message_charlie_got.IsInitialized());
+ EXPECT_EQ(message.SerializeAsString(),
+ message_charlie_got.SerializeAsString());
+
+ // Remove one local peer, and confirm only the two remaining local peers
+ // receive a broadcast message from the remote source.
+ local_router_.RemoveHandlerForLocalId("bob");
+ EXPECT_CALL(alice, OnMessage(&local_router_, local_socket_, _)).Times(1);
+ EXPECT_CALL(bob, OnMessage(_, _, _)).Times(0);
+ EXPECT_CALL(charlie, OnMessage(&local_router_, local_socket_, _)).Times(1);
+ ASSERT_TRUE(remote_router_.BroadcastFromLocalPeer("wendy", message).ok());
+}
+
} // namespace cast
} // namespace openscreen
diff --git a/chromium/third_party/openscreen/src/cast/common/public/cast_socket.h b/chromium/third_party/openscreen/src/cast/common/public/cast_socket.h
index d7ac683ffb1..2a67b6590fc 100644
--- a/chromium/third_party/openscreen/src/cast/common/public/cast_socket.h
+++ b/chromium/third_party/openscreen/src/cast/common/public/cast_socket.h
@@ -79,6 +79,11 @@ class CastSocket : public TlsConnection::Client {
WeakPtrFactory<CastSocket> weak_factory_{this};
};
+// Returns socket->socket_id() if |socket| is not null, otherwise 0.
+inline int ToCastSocketId(CastSocket* socket) {
+ return socket ? socket->socket_id() : 0;
+}
+
} // namespace cast
} // namespace openscreen
diff --git a/chromium/third_party/openscreen/src/cast/common/public/message_port.h b/chromium/third_party/openscreen/src/cast/common/public/message_port.h
new file mode 100644
index 00000000000..0e62dfe6e90
--- /dev/null
+++ b/chromium/third_party/openscreen/src/cast/common/public/message_port.h
@@ -0,0 +1,41 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CAST_COMMON_PUBLIC_MESSAGE_PORT_H_
+#define CAST_COMMON_PUBLIC_MESSAGE_PORT_H_
+
+#include <string>
+
+#include "platform/base/error.h"
+
+namespace openscreen {
+namespace cast {
+
+// This interface is intended to provide an abstraction for communicating
+// cast messages across a pipe with guaranteed delivery. This is used to
+// decouple the cast streaming receiver and sender sessions from the
+// network implementation.
+class MessagePort {
+ public:
+ class Client {
+ public:
+ virtual void OnMessage(const std::string& source_sender_id,
+ const std::string& message_namespace,
+ const std::string& message) = 0;
+ virtual void OnError(Error error) = 0;
+ };
+
+ virtual ~MessagePort() = default;
+ virtual void SetClient(Client* client, std::string client_sender_id) = 0;
+ virtual void ResetClient() = 0;
+
+ virtual void PostMessage(const std::string& destination_sender_id,
+ const std::string& message_namespace,
+ const std::string& message) = 0;
+};
+
+} // namespace cast
+} // namespace openscreen
+
+#endif // CAST_COMMON_PUBLIC_MESSAGE_PORT_H_
diff --git a/chromium/third_party/openscreen/src/cast/receiver/BUILD.gn b/chromium/third_party/openscreen/src/cast/receiver/BUILD.gn
index 68db5e04015..b9a6573422c 100644
--- a/chromium/third_party/openscreen/src/cast/receiver/BUILD.gn
+++ b/chromium/third_party/openscreen/src/cast/receiver/BUILD.gn
@@ -9,6 +9,8 @@ source_set("channel") {
"channel/message_util.cc",
"channel/message_util.h",
"channel/receiver_socket_factory.cc",
+ "channel/static_credentials.cc",
+ "channel/static_credentials.h",
"public/receiver_socket_factory.h",
]
@@ -46,9 +48,7 @@ source_set("test_helpers") {
source_set("unittests") {
testonly = true
- sources = [
- "channel/device_auth_namespace_handler_unittest.cc",
- ]
+ sources = [ "channel/device_auth_namespace_handler_unittest.cc" ]
deps = [
":channel",
@@ -61,7 +61,5 @@ source_set("unittests") {
"../common/channel/proto:channel_proto",
]
- data = [
- "../../test/data/cast/receiver/channel/",
- ]
+ data = [ "../../test/data/cast/receiver/channel/" ]
}
diff --git a/chromium/third_party/openscreen/src/cast/receiver/channel/device_auth_namespace_handler.cc b/chromium/third_party/openscreen/src/cast/receiver/channel/device_auth_namespace_handler.cc
index 239459a0032..17aca182bfb 100644
--- a/chromium/third_party/openscreen/src/cast/receiver/channel/device_auth_namespace_handler.cc
+++ b/chromium/third_party/openscreen/src/cast/receiver/channel/device_auth_namespace_handler.cc
@@ -6,6 +6,9 @@
#include <openssl/evp.h>
+#include <memory>
+#include <utility>
+
#include "cast/common/certificate/cast_cert_validator.h"
#include "cast/common/channel/message_util.h"
#include "cast/common/channel/proto/cast_channel.pb.h"
@@ -54,6 +57,9 @@ DeviceAuthNamespaceHandler::~DeviceAuthNamespaceHandler() = default;
void DeviceAuthNamespaceHandler::OnMessage(VirtualConnectionRouter* router,
CastSocket* socket,
CastMessage message) {
+ if (!socket) {
+ return; // Don't handle auth messages from local senders. That's nonsense.
+ }
if (message.payload_type() !=
::cast::channel::CastMessage_PayloadType_BINARY) {
return;
diff --git a/chromium/third_party/openscreen/src/cast/receiver/channel/device_auth_namespace_handler_unittest.cc b/chromium/third_party/openscreen/src/cast/receiver/channel/device_auth_namespace_handler_unittest.cc
index 3934b96e4ce..edfc807bafe 100644
--- a/chromium/third_party/openscreen/src/cast/receiver/channel/device_auth_namespace_handler_unittest.cc
+++ b/chromium/third_party/openscreen/src/cast/receiver/channel/device_auth_namespace_handler_unittest.cc
@@ -4,6 +4,9 @@
#include "cast/receiver/channel/device_auth_namespace_handler.h"
+#include <utility>
+
+#include "cast/common/certificate/testing/test_helpers.h"
#include "cast/common/channel/message_util.h"
#include "cast/common/channel/proto/cast_channel.pb.h"
#include "cast/common/channel/testing/fake_cast_socket.h"
@@ -11,6 +14,7 @@
#include "cast/common/channel/virtual_connection_manager.h"
#include "cast/common/channel/virtual_connection_router.h"
#include "cast/common/public/cast_socket.h"
+#include "cast/receiver/channel/static_credentials.h"
#include "cast/receiver/channel/testing/device_auth_test_helpers.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
diff --git a/chromium/third_party/openscreen/src/cast/standalone_receiver/static_credentials.cc b/chromium/third_party/openscreen/src/cast/receiver/channel/static_credentials.cc
index 9980f20caf7..73a5d95fda6 100644
--- a/chromium/third_party/openscreen/src/cast/standalone_receiver/static_credentials.cc
+++ b/chromium/third_party/openscreen/src/cast/receiver/channel/static_credentials.cc
@@ -2,16 +2,17 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "cast/standalone_receiver/static_credentials.h"
+#include "cast/receiver/channel/static_credentials.h"
#include <openssl/mem.h>
+#include <openssl/pem.h>
+#include <cstdio>
#include <memory>
#include <string>
#include <utility>
#include <vector>
-#include "cast/standalone_receiver/private_key_der.h"
#include "platform/base/tls_credentials.h"
#include "util/crypto/certificate_utils.h"
#include "util/osp_logging.h"
@@ -20,46 +21,26 @@ namespace openscreen {
namespace cast {
namespace {
+using FileUniquePtr = std::unique_ptr<FILE, decltype(&fclose)>;
+
constexpr int kThreeDaysInSeconds = 3 * 24 * 60 * 60;
constexpr auto kCertificateDuration = std::chrono::seconds(kThreeDaysInSeconds);
-} // namespace
-
-StaticCredentialsProvider::StaticCredentialsProvider() = default;
-StaticCredentialsProvider::StaticCredentialsProvider(
- DeviceCredentials device_creds,
- std::vector<uint8_t> tls_cert_der)
- : device_creds(std::move(device_creds)),
- tls_cert_der(std::move(tls_cert_der)) {}
-
-StaticCredentialsProvider::StaticCredentialsProvider(
- StaticCredentialsProvider&&) = default;
-StaticCredentialsProvider& StaticCredentialsProvider::operator=(
- StaticCredentialsProvider&&) = default;
-StaticCredentialsProvider::~StaticCredentialsProvider() = default;
-
ErrorOr<GeneratedCredentials> GenerateCredentials(
- absl::string_view device_certificate_id) {
- GeneratedCredentials credentials;
-
- bssl::UniquePtr<EVP_PKEY> root_key = GenerateRsaKeyPair();
+ std::string device_certificate_id,
+ EVP_PKEY* root_key,
+ X509* root_cert) {
+ OSP_CHECK(root_key);
+ OSP_CHECK(root_cert);
bssl::UniquePtr<EVP_PKEY> intermediate_key = GenerateRsaKeyPair();
bssl::UniquePtr<EVP_PKEY> device_key = GenerateRsaKeyPair();
- OSP_CHECK(root_key);
OSP_CHECK(intermediate_key);
OSP_CHECK(device_key);
- ErrorOr<bssl::UniquePtr<X509>> root_cert_or_error =
- CreateSelfSignedX509Certificate("Cast Root CA", kCertificateDuration,
- *root_key, GetWallTimeSinceUnixEpoch(),
- true);
- OSP_CHECK(root_cert_or_error);
- bssl::UniquePtr<X509> root_cert = std::move(root_cert_or_error.value());
-
ErrorOr<bssl::UniquePtr<X509>> intermediate_cert_or_error =
CreateSelfSignedX509Certificate(
"Cast Intermediate", kCertificateDuration, *intermediate_key,
- GetWallTimeSinceUnixEpoch(), true, root_cert.get(), root_key.get());
+ GetWallTimeSinceUnixEpoch(), true, root_cert, root_key);
OSP_CHECK(intermediate_cert_or_error);
bssl::UniquePtr<X509> intermediate_cert =
std::move(intermediate_cert_or_error.value());
@@ -72,7 +53,7 @@ ErrorOr<GeneratedCredentials> GenerateCredentials(
OSP_CHECK(device_cert_or_error);
bssl::UniquePtr<X509> device_cert = std::move(device_cert_or_error.value());
- // NOTE: Device cert chain plumbing + serialization.
+ // Device cert chain plumbing + serialization.
DeviceCredentials device_creds;
device_creds.private_key = std::move(device_key);
@@ -88,12 +69,12 @@ ErrorOr<GeneratedCredentials> GenerateCredentials(
i2d_X509(intermediate_cert.get(), &out);
device_creds.certs.emplace_back(std::move(cert_serial));
- cert_length = i2d_X509(root_cert.get(), nullptr);
+ cert_length = i2d_X509(root_cert, nullptr);
std::vector<uint8_t> trust_anchor_der(cert_length);
out = &trust_anchor_der[0];
- i2d_X509(root_cert.get(), &out);
+ i2d_X509(root_cert, &out);
- // NOTE: TLS key pair + certificate generation.
+ // TLS key pair + certificate generation.
bssl::UniquePtr<EVP_PKEY> tls_key = GenerateRsaKeyPair();
OSP_CHECK_EQ(EVP_PKEY_id(tls_key.get()), EVP_PKEY_RSA);
ErrorOr<bssl::UniquePtr<X509>> tls_cert_or_error =
@@ -102,7 +83,7 @@ ErrorOr<GeneratedCredentials> GenerateCredentials(
OSP_CHECK(tls_cert_or_error);
bssl::UniquePtr<X509> tls_cert = std::move(tls_cert_or_error.value());
- // NOTE: TLS private key serialization.
+ // TLS private key serialization.
RSA* rsa_key = EVP_PKEY_get0_RSA(tls_key.get());
size_t pkey_len = 0;
uint8_t* pkey_bytes = nullptr;
@@ -111,7 +92,7 @@ ErrorOr<GeneratedCredentials> GenerateCredentials(
std::vector<uint8_t> tls_key_serial(pkey_bytes, pkey_bytes + pkey_len);
OPENSSL_free(pkey_bytes);
- // NOTE: TLS public key serialization.
+ // TLS public key serialization.
pkey_len = 0;
pkey_bytes = nullptr;
OSP_CHECK(RSA_public_key_to_bytes(&pkey_bytes, &pkey_len, rsa_key));
@@ -119,7 +100,7 @@ ErrorOr<GeneratedCredentials> GenerateCredentials(
std::vector<uint8_t> tls_pub_serial(pkey_bytes, pkey_bytes + pkey_len);
OPENSSL_free(pkey_bytes);
- // NOTE: TLS cert serialization.
+ // TLS cert serialization.
cert_length = 0;
cert_length = i2d_X509(tls_cert.get(), nullptr);
OSP_CHECK_GT(cert_length, 0);
@@ -127,13 +108,75 @@ ErrorOr<GeneratedCredentials> GenerateCredentials(
out = &tls_cert_serial[0];
i2d_X509(tls_cert.get(), &out);
+ auto provider = std::make_unique<StaticCredentialsProvider>(
+ std::move(device_creds), tls_cert_serial);
return GeneratedCredentials{
- std::make_unique<StaticCredentialsProvider>(std::move(device_creds),
- tls_cert_serial),
+ std::move(provider),
TlsCredentials{std::move(tls_key_serial), std::move(tls_pub_serial),
std::move(tls_cert_serial)},
std::move(trust_anchor_der)};
}
+bssl::UniquePtr<X509> GenerateRootCert(const EVP_PKEY& root_key) {
+ ErrorOr<bssl::UniquePtr<X509>> root_cert_or_error =
+ CreateSelfSignedX509Certificate("Cast Root CA", kCertificateDuration,
+ root_key, GetWallTimeSinceUnixEpoch(),
+ true);
+ OSP_CHECK(root_cert_or_error);
+ return std::move(root_cert_or_error.value());
+}
+} // namespace
+
+StaticCredentialsProvider::StaticCredentialsProvider() = default;
+StaticCredentialsProvider::StaticCredentialsProvider(
+ DeviceCredentials device_creds,
+ std::vector<uint8_t> tls_cert_der)
+ : device_creds(std::move(device_creds)),
+ tls_cert_der(std::move(tls_cert_der)) {}
+
+StaticCredentialsProvider::StaticCredentialsProvider(
+ StaticCredentialsProvider&&) = default;
+StaticCredentialsProvider& StaticCredentialsProvider::operator=(
+ StaticCredentialsProvider&&) = default;
+StaticCredentialsProvider::~StaticCredentialsProvider() = default;
+
+ErrorOr<GeneratedCredentials> GenerateCredentials(
+ const std::string& device_certificate_id) {
+ bssl::UniquePtr<EVP_PKEY> root_key = GenerateRsaKeyPair();
+ OSP_CHECK(root_key);
+
+ bssl::UniquePtr<X509> root_cert = GenerateRootCert(*root_key);
+ OSP_CHECK(root_cert);
+
+ return GenerateCredentials(device_certificate_id, root_key.get(),
+ root_cert.get());
+}
+
+ErrorOr<GeneratedCredentials> GenerateCredentials(
+ const std::string& device_certificate_id,
+ const std::string& private_key_path,
+ const std::string& server_certificate_path) {
+ OSP_CHECK(!private_key_path.empty() && !server_certificate_path.empty());
+
+ FileUniquePtr key_file(fopen(private_key_path.c_str(), "r"), &fclose);
+ if (!key_file) {
+ return Error(Error::Code::kParameterInvalid,
+ "Missing private key file path");
+ }
+ bssl::UniquePtr<EVP_PKEY> root_key(PEM_read_PrivateKey(
+ key_file.get(), nullptr /* x */, nullptr /* cb */, nullptr /* u */));
+
+ FileUniquePtr cert_file(fopen(server_certificate_path.c_str(), "r"), &fclose);
+ if (!cert_file) {
+ return Error(Error::Code::kParameterInvalid,
+ "Missing server certificate file path");
+ }
+ bssl::UniquePtr<X509> root_cert(PEM_read_X509(
+ cert_file.get(), nullptr /* x */, nullptr /* cb */, nullptr /* u */));
+
+ return GenerateCredentials(device_certificate_id, root_key.get(),
+ root_cert.get());
+}
+
} // namespace cast
} // namespace openscreen
diff --git a/chromium/third_party/openscreen/src/cast/standalone_receiver/static_credentials.h b/chromium/third_party/openscreen/src/cast/receiver/channel/static_credentials.h
index 4707f5f40af..97b90cc882c 100644
--- a/chromium/third_party/openscreen/src/cast/standalone_receiver/static_credentials.h
+++ b/chromium/third_party/openscreen/src/cast/receiver/channel/static_credentials.h
@@ -2,13 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CAST_STANDALONE_RECEIVER_STATIC_CREDENTIALS_H_
-#define CAST_STANDALONE_RECEIVER_STATIC_CREDENTIALS_H_
+#ifndef CAST_RECEIVER_CHANNEL_STATIC_CREDENTIALS_H_
+#define CAST_RECEIVER_CHANNEL_STATIC_CREDENTIALS_H_
#include <memory>
+#include <string>
#include <vector>
#include "absl/strings/string_view.h"
+#include "cast/common/certificate/cast_cert_validator_internal.h"
#include "cast/receiver/channel/device_auth_namespace_handler.h"
#include "platform/base/error.h"
#include "platform/base/tls_credentials.h"
@@ -52,9 +54,14 @@ struct GeneratedCredentials {
// stored in private_key_der.h. The certificate is valid for
// kCertificateDuration from when this function is called.
ErrorOr<GeneratedCredentials> GenerateCredentials(
- absl::string_view device_certificate_id);
+ const std::string& device_certificate_id);
+
+ErrorOr<GeneratedCredentials> GenerateCredentials(
+ const std::string& device_certificate_id,
+ const std::string& private_key_path,
+ const std::string& server_certificate_path);
} // namespace cast
} // namespace openscreen
-#endif // CAST_STANDALONE_RECEIVER_STATIC_CREDENTIALS_H_
+#endif // CAST_RECEIVER_CHANNEL_STATIC_CREDENTIALS_H_
diff --git a/chromium/third_party/openscreen/src/cast/receiver/channel/testing/device_auth_test_helpers.cc b/chromium/third_party/openscreen/src/cast/receiver/channel/testing/device_auth_test_helpers.cc
index 51d7ebaa32a..77237dad648 100644
--- a/chromium/third_party/openscreen/src/cast/receiver/channel/testing/device_auth_test_helpers.cc
+++ b/chromium/third_party/openscreen/src/cast/receiver/channel/testing/device_auth_test_helpers.cc
@@ -4,7 +4,12 @@
#include "cast/receiver/channel/testing/device_auth_test_helpers.h"
+#include <string>
+#include <utility>
+
+#include "cast/common/certificate/testing/test_helpers.h"
#include "gtest/gtest.h"
+#include "util/crypto/pem_helpers.h"
namespace openscreen {
namespace cast {
@@ -15,10 +20,9 @@ void InitStaticCredentialsFromFiles(StaticCredentialsProvider* creds,
absl::string_view privkey_filename,
absl::string_view chain_filename,
absl::string_view tls_filename) {
- auto private_key = testing::ReadKeyFromPemFile(privkey_filename);
+ auto private_key = ReadKeyFromPemFile(privkey_filename);
ASSERT_TRUE(private_key);
- std::vector<std::string> certs =
- testing::ReadCertificatesFromPemFile(chain_filename);
+ std::vector<std::string> certs = ReadCertificatesFromPemFile(chain_filename);
ASSERT_GT(certs.size(), 1u);
// Use the root of the chain as the trust store for the test.
@@ -35,7 +39,7 @@ void InitStaticCredentialsFromFiles(StaticCredentialsProvider* creds,
std::move(certs), std::move(private_key), std::string()};
const std::vector<std::string> tls_cert =
- testing::ReadCertificatesFromPemFile(tls_filename);
+ ReadCertificatesFromPemFile(tls_filename);
ASSERT_EQ(tls_cert.size(), 1u);
data = reinterpret_cast<const uint8_t*>(tls_cert[0].data());
if (parsed_cert) {
diff --git a/chromium/third_party/openscreen/src/cast/receiver/channel/testing/device_auth_test_helpers.h b/chromium/third_party/openscreen/src/cast/receiver/channel/testing/device_auth_test_helpers.h
index 65ddccf3b9e..6d9b03ffe81 100644
--- a/chromium/third_party/openscreen/src/cast/receiver/channel/testing/device_auth_test_helpers.h
+++ b/chromium/third_party/openscreen/src/cast/receiver/channel/testing/device_auth_test_helpers.h
@@ -10,29 +10,12 @@
#include <vector>
#include "absl/strings/string_view.h"
-#include "cast/common/certificate/testing/test_helpers.h"
#include "cast/receiver/channel/device_auth_namespace_handler.h"
+#include "cast/receiver/channel/static_credentials.h"
namespace openscreen {
namespace cast {
-class StaticCredentialsProvider final
- : public DeviceAuthNamespaceHandler::CredentialsProvider {
- public:
- StaticCredentialsProvider() = default;
- ~StaticCredentialsProvider() = default;
-
- absl::Span<const uint8_t> GetCurrentTlsCertAsDer() override {
- return absl::Span<uint8_t>(tls_cert_der);
- }
- const DeviceCredentials& GetCurrentDeviceCredentials() override {
- return device_creds;
- }
-
- DeviceCredentials device_creds;
- std::vector<uint8_t> tls_cert_der;
-};
-
void InitStaticCredentialsFromFiles(StaticCredentialsProvider* creds,
bssl::UniquePtr<X509>* parsed_cert,
TrustStore* fake_trust_store,
diff --git a/chromium/third_party/openscreen/src/cast/sender/cast_platform_client.cc b/chromium/third_party/openscreen/src/cast/sender/cast_platform_client.cc
index 4d59c65b2b0..224a58a4515 100644
--- a/chromium/third_party/openscreen/src/cast/sender/cast_platform_client.cc
+++ b/chromium/third_party/openscreen/src/cast/sender/cast_platform_client.cc
@@ -4,7 +4,9 @@
#include "cast/sender/cast_platform_client.h"
+#include <memory>
#include <random>
+#include <utility>
#include "absl/strings/str_cat.h"
#include "cast/common/channel/virtual_connection_manager.h"
@@ -22,6 +24,8 @@ static constexpr std::chrono::seconds kRequestTimeout = std::chrono::seconds(5);
namespace {
+// TODO(miu): This is duplicated in another teammate's WIP CL. De-dupe this by
+// placing the utility in cast/common.
std::string MakeRandomSenderId() {
static auto& rd = *new std::random_device();
static auto& gen = *new std::mt19937(rd());
@@ -149,8 +153,9 @@ void CastPlatformClient::OnMessage(VirtualConnectionRouter* router,
if (request_id) {
auto entry = std::find_if(
socket_id_by_device_id_.begin(), socket_id_by_device_id_.end(),
- [socket](const std::pair<std::string, int>& entry) {
- return entry.second == socket->socket_id();
+ [socket_id =
+ ToCastSocketId(socket)](const std::pair<std::string, int>& entry) {
+ return entry.second == socket_id;
});
if (entry != socket_id_by_device_id_.end()) {
HandleResponse(entry->first, request_id.value(), dict);
diff --git a/chromium/third_party/openscreen/src/cast/sender/channel/cast_auth_util.cc b/chromium/third_party/openscreen/src/cast/sender/channel/cast_auth_util.cc
index 10cbdc45ad1..cb1ced692f8 100644
--- a/chromium/third_party/openscreen/src/cast/sender/channel/cast_auth_util.cc
+++ b/chromium/third_party/openscreen/src/cast/sender/channel/cast_auth_util.cc
@@ -7,6 +7,7 @@
#include <openssl/rand.h>
#include <algorithm>
+#include <memory>
#include "cast/common/certificate/cast_cert_validator.h"
#include "cast/common/certificate/cast_cert_validator_internal.h"
@@ -29,13 +30,13 @@ namespace {
#define PARSE_ERROR_PREFIX "Failed to parse auth message: "
// The maximum number of days a cert can live for.
-const int kMaxSelfSignedCertLifetimeInDays = 4;
+constexpr int kMaxSelfSignedCertLifetimeInDays = 4;
// The size of the nonce challenge in bytes.
-const int kNonceSizeInBytes = 16;
+constexpr int kNonceSizeInBytes = 16;
// The number of hours after which a nonce is regenerated.
-long kNonceExpirationTimeInHours = 24;
+constexpr int kNonceExpirationTimeInHours = 24;
// Extracts an embedded DeviceAuthMessage payload from an auth challenge reply
// message.
@@ -122,6 +123,9 @@ Error MapToOpenscreenError(Error::Code error, bool crl_required) {
case Error::Code::kErrCertsRestrictions:
return Error(Error::Code::kCastV2CertNotSignedByTrustedCa,
"Failed certificate restrictions.");
+ case Error::Code::kErrCertsVerifyUntrustedCert:
+ return Error(Error::Code::kCastV2CertNotSignedByTrustedCa,
+ "Failed with untrusted certificate.");
case Error::Code::kErrCrlInvalid:
// This error is only encountered if |crl_required| is true.
OSP_DCHECK(crl_required);
diff --git a/chromium/third_party/openscreen/src/cast/sender/channel/cast_auth_util_unittest.cc b/chromium/third_party/openscreen/src/cast/sender/channel/cast_auth_util_unittest.cc
index 0365541900c..acdb07a2add 100644
--- a/chromium/third_party/openscreen/src/cast/sender/channel/cast_auth_util_unittest.cc
+++ b/chromium/third_party/openscreen/src/cast/sender/channel/cast_auth_util_unittest.cc
@@ -15,6 +15,7 @@
#include "platform/api/time.h"
#include "platform/test/paths.h"
#include "testing/util/read_file.h"
+#include "util/crypto/pem_helpers.h"
#include "util/osp_logging.h"
namespace openscreen {
@@ -124,7 +125,7 @@ class CastAuthUtilTest : public ::testing::Test {
static AuthResponse CreateAuthResponse(
std::vector<uint8_t>* signed_data,
::cast::channel::HashAlgorithm digest_algorithm) {
- std::vector<std::string> chain = testing::ReadCertificatesFromPemFile(
+ std::vector<std::string> chain = ReadCertificatesFromPemFile(
GetSpecificTestDataPath() + "certificates/chromecast_gen1.pem");
OSP_CHECK(!chain.empty());
@@ -292,7 +293,7 @@ TEST_F(CastAuthUtilTest, VerifySenderNonceMissing) {
}
TEST_F(CastAuthUtilTest, VerifyTLSCertificateSuccess) {
- std::vector<std::string> tls_cert_der = testing::ReadCertificatesFromPemFile(
+ std::vector<std::string> tls_cert_der = ReadCertificatesFromPemFile(
data_path_ + "certificates/test_tls_cert.pem");
std::string& der_cert = tls_cert_der[0];
const uint8_t* data = (const uint8_t*)der_cert.data();
@@ -310,7 +311,7 @@ TEST_F(CastAuthUtilTest, VerifyTLSCertificateSuccess) {
}
TEST_F(CastAuthUtilTest, VerifyTLSCertificateTooEarly) {
- std::vector<std::string> tls_cert_der = testing::ReadCertificatesFromPemFile(
+ std::vector<std::string> tls_cert_der = ReadCertificatesFromPemFile(
data_path_ + "certificates/test_tls_cert.pem");
std::string& der_cert = tls_cert_der[0];
const uint8_t* data = (const uint8_t*)der_cert.data();
@@ -331,7 +332,7 @@ TEST_F(CastAuthUtilTest, VerifyTLSCertificateTooEarly) {
}
TEST_F(CastAuthUtilTest, VerifyTLSCertificateTooLate) {
- std::vector<std::string> tls_cert_der = testing::ReadCertificatesFromPemFile(
+ std::vector<std::string> tls_cert_der = ReadCertificatesFromPemFile(
data_path_ + "certificates/test_tls_cert.pem");
std::string& der_cert = tls_cert_der[0];
const uint8_t* data = (const uint8_t*)der_cert.data();
@@ -392,16 +393,16 @@ ErrorOr<CastDeviceCertPolicy> TestVerifyRevocation(
// Runs a single test case.
bool RunTest(const DeviceCertTest& test_case) {
- std::unique_ptr<TrustStore> crl_trust_store;
- std::unique_ptr<TrustStore> cast_trust_store;
+ TrustStore crl_trust_store;
+ TrustStore cast_trust_store;
if (test_case.use_test_trust_anchors()) {
- crl_trust_store = testing::CreateTrustStoreFromPemFile(
+ crl_trust_store = TrustStore::CreateInstanceFromPemFile(
GetSpecificTestDataPath() + "certificates/cast_crl_test_root_ca.pem");
- cast_trust_store = testing::CreateTrustStoreFromPemFile(
+ cast_trust_store = TrustStore::CreateInstanceFromPemFile(
GetSpecificTestDataPath() + "certificates/cast_test_root_ca.pem");
- EXPECT_FALSE(crl_trust_store->certs.empty());
- EXPECT_FALSE(cast_trust_store->certs.empty());
+ EXPECT_FALSE(crl_trust_store.certs.empty());
+ EXPECT_FALSE(cast_trust_store.certs.empty());
}
std::vector<std::string> certificate_chain;
@@ -421,9 +422,9 @@ bool RunTest(const DeviceCertTest& test_case) {
ErrorOr<CastDeviceCertPolicy> result(CastDeviceCertPolicy::kUnrestricted);
switch (test_case.expected_result()) {
case ::cast::certificate::PATH_VERIFICATION_FAILED:
- result = TestVerifyRevocation(
- certificate_chain, crl_bundle, verification_time, false,
- cast_trust_store.get(), crl_trust_store.get());
+ result =
+ TestVerifyRevocation(certificate_chain, crl_bundle, verification_time,
+ false, &cast_trust_store, &cast_trust_store);
EXPECT_EQ(result.error().code(),
Error::Code::kCastV2CertNotSignedByTrustedCa);
return result.error().code() ==
@@ -431,9 +432,9 @@ bool RunTest(const DeviceCertTest& test_case) {
case ::cast::certificate::CRL_VERIFICATION_FAILED:
// Fall-through intended.
case ::cast::certificate::REVOCATION_CHECK_FAILED_WITHOUT_CRL:
- result = TestVerifyRevocation(
- certificate_chain, crl_bundle, verification_time, true,
- cast_trust_store.get(), crl_trust_store.get());
+ result =
+ TestVerifyRevocation(certificate_chain, crl_bundle, verification_time,
+ true, &cast_trust_store, &cast_trust_store);
EXPECT_EQ(result.error().code(), Error::Code::kErrCrlInvalid);
return result.error().code() == Error::Code::kErrCrlInvalid;
case ::cast::certificate::CRL_EXPIRED_AFTER_INITIAL_VERIFICATION:
@@ -441,15 +442,15 @@ bool RunTest(const DeviceCertTest& test_case) {
// certificate is verified.
return true;
case ::cast::certificate::REVOCATION_CHECK_FAILED:
- result = TestVerifyRevocation(
- certificate_chain, crl_bundle, verification_time, true,
- cast_trust_store.get(), crl_trust_store.get());
+ result =
+ TestVerifyRevocation(certificate_chain, crl_bundle, verification_time,
+ true, &cast_trust_store, &cast_trust_store);
EXPECT_EQ(result.error().code(), Error::Code::kErrCertsRevoked);
return result.error().code() == Error::Code::kErrCertsRevoked;
case ::cast::certificate::SUCCESS:
- result = TestVerifyRevocation(
- certificate_chain, crl_bundle, verification_time, false,
- cast_trust_store.get(), crl_trust_store.get());
+ result =
+ TestVerifyRevocation(certificate_chain, crl_bundle, verification_time,
+ false, &cast_trust_store, &cast_trust_store);
EXPECT_EQ(result.error().code(), Error::Code::kCastV2SignedBlobsMismatch);
return result.error().code() == Error::Code::kCastV2SignedBlobsMismatch;
case ::cast::certificate::UNSPECIFIED:
diff --git a/chromium/third_party/openscreen/src/cast/standalone_receiver/BUILD.gn b/chromium/third_party/openscreen/src/cast/standalone_receiver/BUILD.gn
index 46ab0cad3c7..454c933b2e7 100644
--- a/chromium/third_party/openscreen/src/cast/standalone_receiver/BUILD.gn
+++ b/chromium/third_party/openscreen/src/cast/standalone_receiver/BUILD.gn
@@ -9,33 +9,26 @@ import("//build_overrides/build.gni")
# standalone platform implementation; since this is itself a standalone
# application.
if (!build_with_chromium) {
- source_set("standalone_receiver") {
- sources = [
- "cast_agent.cc",
- "cast_agent.h",
- "cast_socket_message_port.cc",
- "cast_socket_message_port.h",
- "static_credentials.cc",
- "static_credentials.h",
- "streaming_playback_controller.cc",
- "streaming_playback_controller.h",
- ]
+ shared_sources = [
+ "cast_agent.cc",
+ "cast_agent.h",
+ "streaming_playback_controller.cc",
+ "streaming_playback_controller.h",
+ ]
- deps = [
- "../../platform",
- "../../third_party/jsoncpp",
- "../common:public",
- "../common/channel/proto:channel_proto",
- "../receiver:channel",
- "../streaming:receiver",
- ]
+ shared_deps = [
+ "../common:public",
+ "../streaming:receiver",
+ ]
+
+ have_external_libs = have_ffmpeg && have_libsdl2
- defines = []
- include_dirs = []
- lib_dirs = []
- libs = []
- if (have_ffmpeg && have_libsdl2) {
- defines += [ "CAST_STANDALONE_RECEIVER_HAVE_EXTERNAL_LIBS" ]
+ if (have_external_libs) {
+ source_set("standalone_receiver_sdl") {
+ sources = shared_sources
+ deps = shared_deps
+
+ defines = [ "CAST_STANDALONE_RECEIVER_HAVE_EXTERNAL_LIBS" ]
sources += [
"avcodec_glue.h",
"decoder.cc",
@@ -49,23 +42,29 @@ if (!build_with_chromium) {
"sdl_video_player.cc",
"sdl_video_player.h",
]
- include_dirs += ffmpeg_include_dirs + libsdl2_include_dirs
- lib_dirs += ffmpeg_lib_dirs + libsdl2_lib_dirs
- libs += ffmpeg_libs + libsdl2_libs
- } else {
- sources += [
- "dummy_player.cc",
- "dummy_player.h",
- ]
+ include_dirs = ffmpeg_include_dirs + libsdl2_include_dirs
+ lib_dirs = ffmpeg_lib_dirs + libsdl2_lib_dirs
+ libs = ffmpeg_libs + libsdl2_libs
}
}
+ source_set("standalone_receiver_dummy") {
+ sources = shared_sources
+ deps = shared_deps
+
+ sources += [
+ "dummy_player.cc",
+ "dummy_player.h",
+ ]
+ }
+
source_set("e2e_tests") {
testonly = true
+
sources = [ "cast_agent_integration_tests.cc" ]
deps = [
- ":standalone_receiver",
+ ":standalone_receiver_dummy",
"../../third_party/boringssl",
"../../third_party/googletest:gtest",
"../receiver:channel",
@@ -75,9 +74,12 @@ if (!build_with_chromium) {
executable("cast_receiver") {
sources = [ "main.cc" ]
- deps = [
- ":standalone_receiver",
- "../receiver:channel",
- ]
+ deps = [ "../receiver:channel" ]
+
+ if (have_external_libs) {
+ deps += [ ":standalone_receiver_sdl" ]
+ } else {
+ deps += [ ":standalone_receiver_dummy" ]
+ }
}
}
diff --git a/chromium/third_party/openscreen/src/cast/standalone_receiver/cast_agent.cc b/chromium/third_party/openscreen/src/cast/standalone_receiver/cast_agent.cc
index a80827e4fca..791029a3435 100644
--- a/chromium/third_party/openscreen/src/cast/standalone_receiver/cast_agent.cc
+++ b/chromium/third_party/openscreen/src/cast/standalone_receiver/cast_agent.cc
@@ -11,14 +11,15 @@
#include <vector>
#include "absl/strings/str_cat.h"
+#include "cast/common/channel/cast_socket_message_port.h"
#include "cast/common/channel/message_util.h"
-#include "cast/standalone_receiver/cast_socket_message_port.h"
#include "cast/streaming/constants.h"
#include "cast/streaming/offer_messages.h"
#include "platform/base/tls_credentials.h"
#include "platform/base/tls_listen_options.h"
#include "util/json/json_serialization.h"
#include "util/osp_logging.h"
+#include "util/trace_logging.h"
namespace openscreen {
namespace cast {
@@ -31,12 +32,12 @@ const TlsListenOptions kDefaultListenOptions{kDefaultMaxBacklogSize};
CastAgent::CastAgent(
TaskRunner* task_runner,
- InterfaceInfo interface,
+ const InterfaceInfo& interface,
DeviceAuthNamespaceHandler::CredentialsProvider* credentials_provider,
TlsCredentials tls_credentials)
: task_runner_(task_runner),
credentials_provider_(credentials_provider),
- tls_credentials_(tls_credentials) {
+ tls_credentials_(std::move(tls_credentials)) {
const IPAddress address = interface.GetIpAddressV4()
? interface.GetIpAddressV4()
: interface.GetIpAddressV6();
@@ -50,19 +51,21 @@ CastAgent::CastAgent(
CastAgent::~CastAgent() = default;
Error CastAgent::Start() {
+ TRACE_DEFAULT_SCOPED(TraceCategory::kStandaloneReceiver);
OSP_CHECK(!current_session_);
- auth_handler_ = MakeSerialDelete<DeviceAuthNamespaceHandler>(
- task_runner_, credentials_provider_);
- router_ = MakeSerialDelete<VirtualConnectionRouter>(task_runner_,
- &connection_manager_);
- router_->AddHandlerForLocalId(kPlatformReceiverId, auth_handler_.get());
- socket_factory_ = MakeSerialDelete<ReceiverSocketFactory>(task_runner_, this,
- router_.get());
-
task_runner_->PostTask([this] {
wake_lock_ = ScopedWakeLock::Create(task_runner_);
+ auth_handler_ = MakeSerialDelete<DeviceAuthNamespaceHandler>(
+ task_runner_, credentials_provider_);
+ router_ = MakeSerialDelete<VirtualConnectionRouter>(task_runner_,
+ &connection_manager_);
+ message_port_ =
+ MakeSerialDelete<CastSocketMessagePort>(task_runner_, router_.get());
+ router_->AddHandlerForLocalId(kPlatformReceiverId, auth_handler_.get());
+ socket_factory_ = MakeSerialDelete<ReceiverSocketFactory>(
+ task_runner_, this, router_.get());
connection_factory_ = SerialDeletePtr<TlsConnectionFactory>(
task_runner_,
TlsConnectionFactory::CreateFactory(socket_factory_.get(), task_runner_)
@@ -90,18 +93,19 @@ Error CastAgent::Stop() {
void CastAgent::OnConnected(ReceiverSocketFactory* factory,
const IPEndpoint& endpoint,
std::unique_ptr<CastSocket> socket) {
+ TRACE_DEFAULT_SCOPED(TraceCategory::kStandaloneReceiver);
if (current_session_) {
OSP_LOG_WARN << "Already connected, dropping peer at: " << endpoint;
return;
}
OSP_LOG_INFO << "Received connection from peer at: " << endpoint;
- message_port_.SetSocket(socket->GetWeakPtr());
+ message_port_->SetSocket(socket->GetWeakPtr());
router_->TakeSocket(this, std::move(socket));
controller_ =
std::make_unique<StreamingPlaybackController>(task_runner_, this);
current_session_ = std::make_unique<ReceiverSession>(
- controller_.get(), environment_.get(), &message_port_,
+ controller_.get(), environment_.get(), message_port_.get(),
ReceiverSession::Preferences{});
}
@@ -156,10 +160,10 @@ void CastAgent::OnPlaybackError(StreamingPlaybackController* controller,
}
void CastAgent::StopCurrentSession() {
- controller_.reset();
current_session_.reset();
- router_->CloseSocket(message_port_.GetSocketId());
- message_port_.SetSocket(nullptr);
+ controller_.reset();
+ router_->CloseSocket(message_port_->GetSocketId());
+ message_port_->SetSocket(nullptr);
}
} // namespace cast
diff --git a/chromium/third_party/openscreen/src/cast/standalone_receiver/cast_agent.h b/chromium/third_party/openscreen/src/cast/standalone_receiver/cast_agent.h
index 4ed23b5b5bc..db8cf668dc3 100644
--- a/chromium/third_party/openscreen/src/cast/standalone_receiver/cast_agent.h
+++ b/chromium/third_party/openscreen/src/cast/standalone_receiver/cast_agent.h
@@ -10,13 +10,13 @@
#include <memory>
#include <vector>
+#include "cast/common/channel/cast_socket_message_port.h"
#include "cast/common/channel/virtual_connection_manager.h"
#include "cast/common/channel/virtual_connection_router.h"
#include "cast/common/public/cast_socket.h"
#include "cast/receiver/channel/device_auth_namespace_handler.h"
+#include "cast/receiver/channel/static_credentials.h"
#include "cast/receiver/public/receiver_socket_factory.h"
-#include "cast/standalone_receiver/cast_socket_message_port.h"
-#include "cast/standalone_receiver/static_credentials.h"
#include "cast/standalone_receiver/streaming_playback_controller.h"
#include "cast/streaming/environment.h"
#include "cast/streaming/receiver_session.h"
@@ -45,7 +45,7 @@ class CastAgent final : public ReceiverSocketFactory::Client,
public:
CastAgent(
TaskRunner* task_runner,
- InterfaceInfo interface,
+ const InterfaceInfo& interface,
DeviceAuthNamespaceHandler::CredentialsProvider* credentials_provider,
TlsCredentials tls_credentials);
~CastAgent();
@@ -87,7 +87,6 @@ class CastAgent final : public ReceiverSocketFactory::Client,
TaskRunner* const task_runner_;
IPEndpoint receive_endpoint_;
DeviceAuthNamespaceHandler::CredentialsProvider* credentials_provider_;
- CastSocketMessagePort message_port_;
TlsCredentials tls_credentials_;
// Member variables set as part of starting up.
@@ -95,6 +94,7 @@ class CastAgent final : public ReceiverSocketFactory::Client,
SerialDeletePtr<TlsConnectionFactory> connection_factory_;
VirtualConnectionManager connection_manager_;
SerialDeletePtr<VirtualConnectionRouter> router_;
+ SerialDeletePtr<CastSocketMessagePort> message_port_;
SerialDeletePtr<ReceiverSocketFactory> socket_factory_;
SerialDeletePtr<ScopedWakeLock> wake_lock_;
diff --git a/chromium/third_party/openscreen/src/cast/standalone_receiver/cast_agent_integration_tests.cc b/chromium/third_party/openscreen/src/cast/standalone_receiver/cast_agent_integration_tests.cc
index 919711abeb4..94341f437d4 100644
--- a/chromium/third_party/openscreen/src/cast/standalone_receiver/cast_agent_integration_tests.cc
+++ b/chromium/third_party/openscreen/src/cast/standalone_receiver/cast_agent_integration_tests.cc
@@ -6,9 +6,9 @@
#include "cast/common/certificate/testing/test_helpers.h"
#include "cast/common/channel/virtual_connection_manager.h"
#include "cast/common/channel/virtual_connection_router.h"
+#include "cast/receiver/channel/static_credentials.h"
#include "cast/sender/public/sender_socket_factory.h"
#include "cast/standalone_receiver/cast_agent.h"
-#include "cast/standalone_receiver/static_credentials.h"
#include "gtest/gtest.h"
#include "platform/api/serial_delete_ptr.h"
#include "platform/api/time.h"
@@ -120,7 +120,7 @@ class CastAgentIntegrationTest : public ::testing::Test {
SerialDeletePtr<TlsConnectionFactory> sender_tls_factory_;
};
-TEST_F(CastAgentIntegrationTest, StartsListeningProperly) {
+TEST_F(CastAgentIntegrationTest, CanConnect) {
absl::optional<InterfaceInfo> loopback = GetLoopbackInterfaceForTesting();
ASSERT_TRUE(loopback.has_value());
diff --git a/chromium/third_party/openscreen/src/cast/standalone_receiver/cast_socket_message_port.cc b/chromium/third_party/openscreen/src/cast/standalone_receiver/cast_socket_message_port.cc
deleted file mode 100644
index 6f3c55c8ae8..00000000000
--- a/chromium/third_party/openscreen/src/cast/standalone_receiver/cast_socket_message_port.cc
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "cast/standalone_receiver/cast_socket_message_port.h"
-
-#include <utility>
-
-#include "cast/common/channel/proto/cast_channel.pb.h"
-
-namespace openscreen {
-namespace cast {
-
-CastSocketMessagePort::CastSocketMessagePort() = default;
-CastSocketMessagePort::~CastSocketMessagePort() = default;
-
-// NOTE: we assume here that this message port is already the client for
-// the passed in socket, so leave the socket's client unchanged. However,
-// since sockets should map one to one with receiver sessions, we reset our
-// client. The consumer of this message port should call SetClient with the new
-// message port client after setting the socket.
-void CastSocketMessagePort::SetSocket(WeakPtr<CastSocket> socket) {
- client_ = nullptr;
- socket_ = socket;
-}
-
-int CastSocketMessagePort::GetSocketId() {
- return socket_ ? socket_->socket_id() : -1;
-}
-
-void CastSocketMessagePort::SetClient(MessagePort::Client* client) {
- client_ = client;
-}
-
-void CastSocketMessagePort::PostMessage(absl::string_view sender_id,
- absl::string_view message_namespace,
- absl::string_view message) {
- ::cast::channel::CastMessage cast_message;
- cast_message.set_source_id(sender_id.data(), sender_id.size());
- cast_message.set_namespace_(message_namespace.data(),
- message_namespace.size());
- cast_message.set_payload_utf8(message.data(), message.size());
-
- if (!socket_) {
- client_->OnError(Error::Code::kAlreadyClosed);
- return;
- }
- Error error = socket_->Send(cast_message);
- if (!error.ok()) {
- client_->OnError(error);
- }
-}
-
-} // namespace cast
-} // namespace openscreen
diff --git a/chromium/third_party/openscreen/src/cast/standalone_receiver/cast_socket_message_port.h b/chromium/third_party/openscreen/src/cast/standalone_receiver/cast_socket_message_port.h
deleted file mode 100644
index 67d037e96b6..00000000000
--- a/chromium/third_party/openscreen/src/cast/standalone_receiver/cast_socket_message_port.h
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CAST_STANDALONE_RECEIVER_CAST_SOCKET_MESSAGE_PORT_H_
-#define CAST_STANDALONE_RECEIVER_CAST_SOCKET_MESSAGE_PORT_H_
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "cast/common/public/cast_socket.h"
-#include "cast/streaming/receiver_session.h"
-#include "util/weak_ptr.h"
-
-namespace openscreen {
-namespace cast {
-
-class CastSocketMessagePort : public MessagePort {
- public:
- CastSocketMessagePort();
- ~CastSocketMessagePort() override;
-
- void SetSocket(WeakPtr<CastSocket> socket);
-
- // Returns current socket identifier, or -1 if not connected.
- int GetSocketId();
-
- // MessagePort overrides.
- void SetClient(MessagePort::Client* client) override;
- void PostMessage(absl::string_view sender_id,
- absl::string_view message_namespace,
- absl::string_view message) override;
-
- private:
- MessagePort::Client* client_ = nullptr;
- WeakPtr<CastSocket> socket_;
-};
-
-} // namespace cast
-} // namespace openscreen
-
-#endif // CAST_STANDALONE_RECEIVER_CAST_SOCKET_MESSAGE_PORT_H_
diff --git a/chromium/third_party/openscreen/src/cast/standalone_receiver/main.cc b/chromium/third_party/openscreen/src/cast/standalone_receiver/main.cc
index 44a1a0a09bf..803b3414026 100644
--- a/chromium/third_party/openscreen/src/cast/standalone_receiver/main.cc
+++ b/chromium/third_party/openscreen/src/cast/standalone_receiver/main.cc
@@ -10,8 +10,8 @@
#include "absl/strings/str_cat.h"
#include "cast/common/public/service_info.h"
+#include "cast/receiver/channel/static_credentials.h"
#include "cast/standalone_receiver/cast_agent.h"
-#include "cast/standalone_receiver/static_credentials.h"
#include "cast/streaming/ssrc.h"
#include "discovery/common/config.h"
#include "discovery/common/reporting_client.h"
@@ -52,7 +52,10 @@ struct DiscoveryState {
ErrorOr<std::unique_ptr<DiscoveryState>> StartDiscovery(
TaskRunner* task_runner,
- const InterfaceInfo& interface) {
+ const InterfaceInfo& interface,
+ const std::string& friendly_name,
+ const std::string& model_name) {
+ TRACE_DEFAULT_SCOPED(TraceCategory::kStandaloneReceiver);
discovery::Config config;
discovery::Config::NetworkInfo::AddressFamilies supported_address_families =
@@ -80,10 +83,8 @@ ErrorOr<std::unique_ptr<DiscoveryState>> StartDiscovery(
interface.hardware_address.end(),
[](int e) { return e > 0; }));
info.unique_id = HexEncode(interface.hardware_address);
-
- // TODO(jophba): add command line arguments to set these fields.
- info.model_name = "cast_standalone_receiver";
- info.friendly_name = "Cast Standalone Receiver";
+ info.friendly_name = friendly_name;
+ info.model_name = model_name;
state->publisher =
std::make_unique<discovery::DnsSdServicePublisher<ServiceInfo>>(
@@ -96,21 +97,18 @@ ErrorOr<std::unique_ptr<DiscoveryState>> StartDiscovery(
return state;
}
-void StartCastAgent(TaskRunnerImpl* task_runner,
- InterfaceInfo interface,
- GeneratedCredentials* creds) {
- CastAgent agent(task_runner, interface, creds->provider.get(),
- creds->tls_credentials);
- const auto error = agent.Start();
+std::unique_ptr<CastAgent> StartCastAgent(TaskRunnerImpl* task_runner,
+ const InterfaceInfo& interface,
+ GeneratedCredentials* creds) {
+ TRACE_DEFAULT_SCOPED(TraceCategory::kStandaloneReceiver);
+ auto agent = std::make_unique<CastAgent>(
+ task_runner, interface, creds->provider.get(), creds->tls_credentials);
+ const auto error = agent->Start();
if (!error.ok()) {
OSP_LOG_ERROR << "Error occurred while starting agent: " << error;
- return;
+ agent.reset();
}
-
- // Run the event loop until an exit is requested (e.g., the video player GUI
- // window is closed, a SIGINT or SIGTERM is received, or whatever other
- // appropriate user indication that shutdown is requested).
- task_runner->RunUntilSignaled();
+ return agent;
}
void LogUsage(const char* argv0) {
@@ -121,8 +119,18 @@ usage: )" << argv0
options:
interface
Specifies the network interface to bind to. The interface is
- looked up from the system interface registry. This argument is
- mandatory, as it must be known for publishing discovery.
+ looked up from the system interface registry.
+ Mandatory, as it must be known for publishing discovery.
+
+ -p, --private-key=path-to-key: Path to OpenSSL-generated private key to be
+ used for TLS authentication.
+
+ -s, --server-certificate=path-to-cert: Path to PEM file containing a
+ server certificate to be used for TLS authentication.
+
+ -f, --friendly-name: Friendly name to be used for device discovery.
+
+ -m, --model-name: Model name to be used for device discovery.
-t, --tracing: Enable performance tracing logging.
@@ -142,6 +150,15 @@ InterfaceInfo GetInterfaceInfoFromName(const char* name) {
break;
}
}
+
+ if (interface_info.name.empty()) {
+ auto error_or_info = GetLoopbackInterfaceForTesting();
+ if (error_or_info.has_value()) {
+ if (error_or_info.value().name == name) {
+ interface_info = std::move(error_or_info.value());
+ }
+ }
+ }
OSP_CHECK(!interface_info.name.empty()) << "Invalid interface specified.";
return interface_info;
}
@@ -152,29 +169,61 @@ int RunStandaloneReceiver(int argc, char* argv[]) {
// being exposed, consider if it applies to the standalone receiver,
// standalone sender, osp demo, and test_main argument options.
const struct option kArgumentOptions[] = {
+ {"private-key", required_argument, nullptr, 'p'},
+ {"server-certificate", required_argument, nullptr, 's'},
+ {"friendly-name", required_argument, nullptr, 'f'},
+ {"model-name", required_argument, nullptr, 'm'},
{"tracing", no_argument, nullptr, 't'},
{"verbose", no_argument, nullptr, 'v'},
{"help", no_argument, nullptr, 'h'},
+
+ // Discovery is enabled by default, however there are cases where it
+ // needs to be disabled, such as on Mac OS X.
+ {"disable-discovery", no_argument, nullptr, 'x'},
{nullptr, 0, nullptr, 0}};
bool is_verbose = false;
+ bool discovery_enabled = true;
+ std::string private_key_path;
+ std::string server_certificate_path;
+ std::string friendly_name = "Cast Standalone Receiver";
+ std::string model_name = "cast_standalone_receiver";
std::unique_ptr<openscreen::TextTraceLoggingPlatform> trace_logger;
int ch = -1;
- while ((ch = getopt_long(argc, argv, "tvh", kArgumentOptions, nullptr)) !=
- -1) {
+ while ((ch = getopt_long(argc, argv, "p:s:f:m:tvhx", kArgumentOptions,
+ nullptr)) != -1) {
switch (ch) {
+ case 'p':
+ private_key_path = optarg;
+ break;
+ case 's':
+ server_certificate_path = optarg;
+ break;
+ case 'f':
+ friendly_name = optarg;
+ break;
+ case 'm':
+ friendly_name = optarg;
+ break;
case 't':
trace_logger = std::make_unique<openscreen::TextTraceLoggingPlatform>();
break;
case 'v':
is_verbose = true;
break;
+ case 'x':
+ discovery_enabled = false;
+ break;
case 'h':
LogUsage(argv[0]);
return 1;
}
}
- InterfaceInfo interface_info = GetInterfaceInfoFromName(argv[optind]);
+ if (private_key_path.empty() != server_certificate_path.empty()) {
+ OSP_LOG_ERROR << "If a private key or server certificate path is provided, "
+ "both are required.";
+ return 1;
+ }
SetLogLevel(is_verbose ? openscreen::LogLevel::kVerbose
: openscreen::LogLevel::kInfo);
@@ -182,20 +231,50 @@ int RunStandaloneReceiver(int argc, char* argv[]) {
PlatformClientPosix::Create(milliseconds(50), milliseconds(50),
std::unique_ptr<TaskRunnerImpl>(task_runner));
- auto discovery_state = StartDiscovery(task_runner, interface_info);
- OSP_CHECK(discovery_state.is_value()) << "Failed to start discovery.";
+ // Post tasks to kick-off the CastAgent and, if successful, start discovery to
+ // make this standalone receiver visible to senders on the network.
+ std::unique_ptr<DiscoveryState> discovery_state;
+ std::unique_ptr<CastAgent> cast_agent;
+ const char* interface_name = argv[optind];
+ OSP_CHECK(interface_name && strlen(interface_name) > 0)
+ << "No interface name provided.";
+
+ std::string device_id =
+ absl::StrCat("Standalone Receiver on ", interface_name);
+ ErrorOr<GeneratedCredentials> creds = Error::Code::kEVPInitializationError;
+ if (private_key_path.empty()) {
+ creds = GenerateCredentials(device_id);
+ } else {
+ creds = GenerateCredentials(device_id, private_key_path,
+ server_certificate_path);
+ }
+ OSP_CHECK(creds.is_value()) << creds.error();
+ task_runner->PostTask(
+ [&, interface = GetInterfaceInfoFromName(interface_name)] {
+ cast_agent = StartCastAgent(task_runner, interface, &(creds.value()));
+ OSP_CHECK(cast_agent) << "Failed to start CastAgent.";
+
+ if (discovery_enabled) {
+ auto result =
+ StartDiscovery(task_runner, interface, friendly_name, model_name);
+ OSP_CHECK(result.is_value()) << "Failed to start discovery.";
+ discovery_state = std::move(result.value());
+ }
+ });
- auto creds = GenerateCredentials(
- absl::StrCat("Standalone Receiver on ", argv[optind]));
- OSP_CHECK(creds.is_value());
+ // Run the event loop until an exit is requested (e.g., the video player GUI
+ // window is closed, a SIGINT or SIGTERM is received, or whatever other
+ // appropriate user indication that shutdown is requested).
+ task_runner->RunUntilSignaled();
- // Runs until the process is interrupted. Safe to pass |task_runner| as it
- // will not be destroyed by ShutDown() until this exits.
- StartCastAgent(task_runner, interface_info, &(creds.value()));
+ // Shutdown the Cast Agent and discovery-related entities. This may cause one
+ // or more tasks to be posted, and so the TaskRunner is spun to give them a
+ // chance to execute.
+ discovery_state.reset();
+ cast_agent.reset();
+ task_runner->PostTask([task_runner] { task_runner->RequestStopSoon(); });
+ task_runner->RunUntilStopped();
- // The task runner must be deleted after all serial delete pointers, such
- // as the one stored in the discovery state.
- discovery_state.value().reset();
PlatformClientPosix::ShutDown();
return 0;
}
diff --git a/chromium/third_party/openscreen/src/cast/standalone_receiver/private.der b/chromium/third_party/openscreen/src/cast/standalone_receiver/private.der
deleted file mode 100644
index 48aa17b0151..00000000000
--- a/chromium/third_party/openscreen/src/cast/standalone_receiver/private.der
+++ /dev/null
Binary files differ
diff --git a/chromium/third_party/openscreen/src/cast/standalone_receiver/private_key_der.h b/chromium/third_party/openscreen/src/cast/standalone_receiver/private_key_der.h
deleted file mode 100644
index 0d9a328f01c..00000000000
--- a/chromium/third_party/openscreen/src/cast/standalone_receiver/private_key_der.h
+++ /dev/null
@@ -1,125 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CAST_STANDALONE_RECEIVER_PRIVATE_KEY_DER_H_
-#define CAST_STANDALONE_RECEIVER_PRIVATE_KEY_DER_H_
-
-#include <array>
-
-namespace openscreen {
-namespace cast {
-
-// Important note about private keys and security: For example usage purposes,
-// we have checked in a default private key here. However, in a production
-// environment keys should never be checked into source control. This is an
-// example self-signed private key for TLS.
-//
-// Generated using the following command:
-// $ xxd -i <path/to/private_key.der>
-std::array<uint8_t, 1192> kPrivateKeyDer = {
- 0x30, 0x82, 0x04, 0xa4, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01, 0x01, 0x00,
- 0xb8, 0x07, 0xbb, 0x3f, 0xde, 0x47, 0xba, 0xec, 0x7a, 0xc2, 0x6e, 0xe5,
- 0x44, 0x4a, 0xa8, 0x50, 0xd9, 0xef, 0xc1, 0x67, 0xc1, 0x5e, 0x14, 0xc0,
- 0x1a, 0x1f, 0x8e, 0x83, 0xb9, 0xb2, 0x5d, 0x2d, 0x74, 0x12, 0x4b, 0x43,
- 0x3c, 0xa6, 0xfb, 0xc4, 0x6c, 0xb0, 0xab, 0xda, 0xfb, 0xfd, 0x51, 0x18,
- 0xc1, 0xc1, 0x22, 0x05, 0xf5, 0x2b, 0x10, 0xe4, 0x84, 0x1b, 0xa7, 0xdc,
- 0xe6, 0xd0, 0xf5, 0x64, 0xa7, 0xc7, 0x6f, 0x1a, 0x85, 0xf8, 0xc4, 0xfb,
- 0xbf, 0x17, 0x54, 0xaa, 0x11, 0x29, 0xfe, 0xda, 0x33, 0x9e, 0xfa, 0xb1,
- 0x86, 0x9b, 0xf4, 0xcd, 0xf5, 0xe1, 0x3f, 0x7b, 0x3b, 0xad, 0xd9, 0xe2,
- 0xc7, 0x6e, 0x4f, 0x1e, 0xa8, 0x13, 0x22, 0xa2, 0x7a, 0xcf, 0xe1, 0x8a,
- 0x06, 0xf3, 0x28, 0x3a, 0xdc, 0xd3, 0x8c, 0x24, 0xa6, 0xe0, 0xd3, 0x5a,
- 0x23, 0x21, 0x53, 0x02, 0x7d, 0x08, 0x30, 0xcb, 0xf1, 0x21, 0xca, 0x72,
- 0x69, 0x49, 0x6e, 0x0f, 0xbc, 0x03, 0x7e, 0x0e, 0x60, 0x5d, 0x92, 0x08,
- 0x3f, 0x04, 0x76, 0x62, 0x2d, 0x4b, 0xeb, 0x61, 0xaa, 0xe6, 0xcd, 0x2f,
- 0x28, 0x24, 0xb0, 0xe8, 0xa5, 0xfe, 0x89, 0x90, 0xb8, 0xa4, 0x60, 0x6e,
- 0x4c, 0x8c, 0x2f, 0xa3, 0xae, 0x72, 0xf2, 0x42, 0xb9, 0xc9, 0xa2, 0x6f,
- 0x91, 0xbc, 0x75, 0x3b, 0x35, 0xb7, 0xe6, 0x24, 0xcb, 0x80, 0x8a, 0x34,
- 0xfa, 0x9d, 0xf1, 0x7c, 0x88, 0x98, 0x09, 0x7b, 0x50, 0x56, 0xa5, 0x84,
- 0x9c, 0x5f, 0x6c, 0x6e, 0x10, 0xfa, 0x95, 0xb6, 0xbf, 0xe4, 0xb0, 0x55,
- 0x29, 0x3d, 0xe6, 0x3d, 0x14, 0xd7, 0x70, 0x17, 0xd8, 0xd3, 0xaa, 0xaf,
- 0x4f, 0x15, 0x99, 0x63, 0xd0, 0x74, 0xfc, 0xb0, 0x6b, 0x66, 0x28, 0x02,
- 0xd1, 0xbb, 0x01, 0x57, 0x02, 0xfe, 0x52, 0xe2, 0x0b, 0xbd, 0x8c, 0x0a,
- 0x87, 0x8b, 0x60, 0xe9, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x82, 0x01,
- 0x01, 0x00, 0xaa, 0x19, 0x7b, 0x5a, 0x6d, 0x7a, 0x9f, 0xac, 0x35, 0x4b,
- 0xc2, 0x74, 0xe7, 0xca, 0x9a, 0x09, 0x21, 0x68, 0x1a, 0xbc, 0x6c, 0x5f,
- 0x29, 0x8e, 0xe6, 0x96, 0x84, 0x83, 0xfd, 0x00, 0x80, 0x5f, 0xa3, 0x09,
- 0xc5, 0xc7, 0x40, 0x28, 0x98, 0x4d, 0xd6, 0xa8, 0xf6, 0x30, 0x52, 0xfa,
- 0xb2, 0x1a, 0xcf, 0xfc, 0x54, 0x16, 0x6d, 0xa6, 0x80, 0xd6, 0xb7, 0xc5,
- 0x58, 0x43, 0x36, 0x95, 0xae, 0x3c, 0x7b, 0x58, 0x3b, 0xb9, 0xa8, 0x5b,
- 0x68, 0xb7, 0xc8, 0xc9, 0x27, 0xd8, 0x8a, 0x44, 0xe6, 0xeb, 0x89, 0x0b,
- 0x49, 0x6d, 0x0d, 0x9e, 0xd9, 0x88, 0x05, 0xdd, 0x4d, 0x6f, 0xfa, 0x99,
- 0x96, 0xeb, 0xa6, 0xaa, 0xaf, 0x37, 0x06, 0xe3, 0xa8, 0xff, 0xc5, 0xc4,
- 0xa0, 0x13, 0x94, 0x98, 0xec, 0x76, 0x7b, 0xe6, 0x8d, 0x82, 0xd3, 0x3c,
- 0xbc, 0x1e, 0x74, 0x9a, 0x38, 0xbf, 0xf4, 0x11, 0xbe, 0x07, 0x32, 0x2d,
- 0x16, 0x2c, 0xf2, 0x5d, 0x24, 0x38, 0x70, 0xfb, 0x90, 0x8a, 0x38, 0xd6,
- 0x17, 0xe1, 0x66, 0x92, 0x38, 0x06, 0x97, 0xb3, 0x07, 0xfd, 0x77, 0xe2,
- 0xe7, 0x49, 0xae, 0x5a, 0xbc, 0xe5, 0xa8, 0xca, 0xe1, 0x0f, 0xb6, 0x4c,
- 0x05, 0x73, 0x3f, 0x11, 0xd0, 0xf9, 0x1e, 0xba, 0x53, 0x48, 0xf5, 0xaf,
- 0x28, 0x5b, 0xea, 0x12, 0x63, 0xbc, 0x84, 0xa7, 0x5f, 0x2e, 0x1d, 0x3e,
- 0x02, 0x54, 0x58, 0xed, 0x2b, 0x42, 0xf9, 0xc6, 0x0c, 0xd4, 0x24, 0x77,
- 0x1a, 0x2c, 0xbf, 0x75, 0x92, 0xf7, 0xcb, 0xd4, 0x58, 0x2f, 0x88, 0x2d,
- 0xe8, 0x16, 0xca, 0xe5, 0x25, 0xe8, 0x5b, 0xbd, 0x53, 0x26, 0x23, 0xe0,
- 0xa9, 0x35, 0x4d, 0xdb, 0x51, 0x85, 0x63, 0x20, 0xad, 0x61, 0xd2, 0x6d,
- 0xbf, 0x01, 0x7d, 0x04, 0x44, 0x02, 0x96, 0x92, 0x36, 0x19, 0xed, 0xd1,
- 0xd8, 0x16, 0x86, 0x06, 0xd4, 0x81, 0x02, 0x81, 0x81, 0x00, 0xe1, 0xa6,
- 0xca, 0xb3, 0xef, 0xfe, 0x9f, 0xd6, 0xac, 0x58, 0x5c, 0x17, 0x88, 0xaf,
- 0x4d, 0x85, 0x29, 0x50, 0x1f, 0x66, 0x90, 0x9b, 0x81, 0xb6, 0x82, 0x0d,
- 0xc3, 0x5a, 0xa8, 0x8a, 0x2b, 0x7f, 0x58, 0x9b, 0x07, 0xe6, 0x64, 0xf7,
- 0x1c, 0x77, 0x9d, 0x53, 0x97, 0xa0, 0x33, 0x14, 0x6e, 0x77, 0x1e, 0xe3,
- 0x00, 0x0f, 0xb2, 0xb1, 0x69, 0x25, 0x3d, 0x63, 0x3c, 0xe1, 0xbb, 0x41,
- 0x74, 0x97, 0x2d, 0x5e, 0x14, 0x79, 0x93, 0x38, 0x15, 0xbe, 0x52, 0x74,
- 0x64, 0xc0, 0xfd, 0x22, 0x8e, 0xd7, 0xc9, 0xfb, 0x66, 0x55, 0xce, 0x5b,
- 0x6a, 0x6f, 0x00, 0xed, 0x03, 0x7e, 0x4b, 0x9c, 0x4b, 0x8b, 0x3a, 0x50,
- 0x65, 0x0d, 0x70, 0x9b, 0xdb, 0xf7, 0x1f, 0xd7, 0x66, 0x7a, 0xd1, 0x1e,
- 0xa0, 0x8f, 0xe6, 0x03, 0x12, 0x18, 0x52, 0x25, 0x41, 0xa7, 0xb9, 0x8e,
- 0x75, 0x63, 0x11, 0xd2, 0x63, 0xd7, 0x02, 0x81, 0x81, 0x00, 0xd0, 0xc7,
- 0xe9, 0x97, 0x38, 0x33, 0x95, 0xbd, 0x18, 0xa5, 0x0a, 0x68, 0xab, 0xba,
- 0x5e, 0x3e, 0x1f, 0x16, 0x86, 0xc0, 0x50, 0x09, 0xab, 0x52, 0xb7, 0x62,
- 0x4e, 0x34, 0xb1, 0xc1, 0xd3, 0xb5, 0xf4, 0xe0, 0x04, 0x30, 0xa6, 0xdd,
- 0x4a, 0xba, 0x7c, 0x59, 0xed, 0xd7, 0x76, 0xd3, 0x02, 0xe7, 0x05, 0x18,
- 0x00, 0xdb, 0x65, 0xf2, 0x82, 0xe4, 0xfa, 0xbf, 0x9d, 0xad, 0x1a, 0x56,
- 0x7b, 0x5e, 0xef, 0xff, 0x9b, 0xe5, 0x2f, 0x7c, 0xdd, 0x50, 0x53, 0x2b,
- 0x6b, 0xc0, 0xac, 0x7b, 0x21, 0x8d, 0xc3, 0x39, 0xfe, 0xd0, 0x1a, 0xed,
- 0xd1, 0xb6, 0x56, 0xda, 0x9e, 0x87, 0x9a, 0x6a, 0x69, 0x81, 0x29, 0x81,
- 0x75, 0x69, 0xa6, 0x25, 0xc2, 0xf7, 0x5a, 0x94, 0x97, 0x6a, 0x7a, 0xf9,
- 0x6c, 0xbe, 0x43, 0x76, 0x34, 0xba, 0x0c, 0x50, 0x6d, 0x22, 0xe8, 0xa6,
- 0x9c, 0x80, 0x62, 0x87, 0xc9, 0x3f, 0x02, 0x81, 0x80, 0x78, 0xaf, 0x47,
- 0x1c, 0x63, 0x90, 0x30, 0x16, 0x95, 0x88, 0x90, 0x80, 0x79, 0xb7, 0x20,
- 0x63, 0xc6, 0xcb, 0xb6, 0x6f, 0x99, 0x89, 0xc2, 0x1f, 0x45, 0x81, 0x6c,
- 0xe9, 0x10, 0xd9, 0x0d, 0x18, 0x87, 0xe0, 0x2a, 0xa2, 0x7b, 0x7f, 0x7a,
- 0x77, 0x32, 0xea, 0xa1, 0x5e, 0xa9, 0xd3, 0x14, 0x9d, 0x9b, 0x24, 0x57,
- 0x45, 0x0e, 0x12, 0x3a, 0xa5, 0x13, 0x26, 0xff, 0x49, 0xcf, 0x67, 0xdb,
- 0x9e, 0x7b, 0x42, 0x24, 0xfb, 0x3c, 0xd4, 0xb3, 0x34, 0x5e, 0x4f, 0x28,
- 0x0f, 0xdb, 0x92, 0xdf, 0x08, 0xe4, 0x5b, 0x13, 0xc9, 0x72, 0x9b, 0x8b,
- 0xda, 0x20, 0x89, 0xa2, 0xe3, 0xaa, 0x36, 0xc6, 0x64, 0x89, 0x64, 0xb4,
- 0x17, 0x33, 0x11, 0xf8, 0xdc, 0x3b, 0xe8, 0x6d, 0x43, 0xe4, 0x92, 0x57,
- 0xd7, 0x7e, 0x72, 0x47, 0xfc, 0x3f, 0xfa, 0xf3, 0x19, 0x6c, 0x71, 0x97,
- 0xb0, 0xcb, 0xb8, 0x55, 0x73, 0x02, 0x81, 0x81, 0x00, 0x98, 0xf1, 0xfa,
- 0x73, 0x67, 0x1e, 0x93, 0x11, 0x45, 0xde, 0x91, 0xb3, 0x80, 0x2a, 0x35,
- 0x23, 0xf9, 0x0e, 0x3d, 0x84, 0xe0, 0x9d, 0x54, 0xbe, 0x71, 0xcd, 0x38,
- 0x51, 0x6d, 0xee, 0xfa, 0x33, 0x0f, 0xc2, 0x94, 0x0f, 0x38, 0x0e, 0x60,
- 0xd2, 0x20, 0x8a, 0x98, 0xac, 0x01, 0x46, 0x2f, 0x98, 0x21, 0xa9, 0x25,
- 0xe7, 0x93, 0xd5, 0x86, 0x82, 0x4c, 0x16, 0xd7, 0x61, 0x9a, 0x2b, 0xc4,
- 0x91, 0x15, 0xec, 0x00, 0xbe, 0x72, 0x7d, 0x5c, 0x7b, 0x9d, 0x91, 0xef,
- 0x8b, 0xe4, 0x4f, 0x07, 0x93, 0x9c, 0x72, 0xfd, 0xf2, 0x61, 0xe7, 0xda,
- 0x7b, 0x63, 0x41, 0x20, 0x65, 0x62, 0x7f, 0x95, 0xee, 0xa3, 0x03, 0x4d,
- 0x8a, 0x29, 0xc6, 0xfb, 0xfe, 0xcc, 0x82, 0x92, 0x31, 0xd5, 0x08, 0xa7,
- 0xda, 0xf1, 0xfc, 0xc4, 0x3f, 0x8f, 0x09, 0xd4, 0x09, 0x80, 0xb9, 0x9d,
- 0x68, 0x87, 0xc5, 0xc5, 0x6d, 0x02, 0x81, 0x80, 0x1f, 0xd9, 0x20, 0xde,
- 0xba, 0xcd, 0x63, 0x34, 0x4f, 0x9f, 0xbb, 0x05, 0x0a, 0x8d, 0x20, 0xe1,
- 0x66, 0x41, 0x2f, 0xae, 0xc7, 0xfa, 0x5d, 0xfd, 0xb7, 0x2a, 0x0f, 0xa6,
- 0x6d, 0xf3, 0xad, 0x65, 0x54, 0x75, 0x2c, 0x26, 0x1e, 0xac, 0x1f, 0x24,
- 0x4c, 0x83, 0xe3, 0x28, 0x08, 0x60, 0x74, 0xfe, 0xa9, 0x53, 0x36, 0x1e,
- 0xb3, 0x39, 0x9d, 0xe7, 0x49, 0x03, 0x66, 0x61, 0xe8, 0xd4, 0xf4, 0xd8,
- 0x65, 0x57, 0x01, 0xed, 0xaa, 0x7b, 0x6b, 0x04, 0xa2, 0x5f, 0xe1, 0x67,
- 0xe6, 0x06, 0x7c, 0x84, 0x2a, 0x7d, 0x53, 0x03, 0x1c, 0x9c, 0x82, 0x08,
- 0x37, 0x07, 0xaf, 0x77, 0xe0, 0x99, 0x69, 0xce, 0x01, 0x5a, 0x85, 0x4b,
- 0x27, 0xb9, 0xb2, 0x20, 0x8c, 0xa5, 0xb9, 0x42, 0x2f, 0xad, 0x56, 0xdd,
- 0xb9, 0x0d, 0x23, 0x05, 0x53, 0x5a, 0x26, 0x3a, 0xe2, 0x17, 0x58, 0x79,
- 0x96, 0x8c, 0x5a, 0x05};
-
-} // namespace cast
-} // namespace openscreen
-
-#endif // CAST_STANDALONE_RECEIVER_PRIVATE_KEY_DER_H_
diff --git a/chromium/third_party/openscreen/src/cast/standalone_receiver/sdl_audio_player.cc b/chromium/third_party/openscreen/src/cast/standalone_receiver/sdl_audio_player.cc
index 3392b706615..c460a7edb58 100644
--- a/chromium/third_party/openscreen/src/cast/standalone_receiver/sdl_audio_player.cc
+++ b/chromium/third_party/openscreen/src/cast/standalone_receiver/sdl_audio_player.cc
@@ -55,12 +55,12 @@ void InterleaveAudioSamples(const uint8_t* const planes[],
SDLAudioPlayer::SDLAudioPlayer(ClockNowFunctionPtr now_function,
TaskRunner* task_runner,
Receiver* receiver,
- const std::string& codec_name,
+ AudioCodec codec,
std::function<void()> error_callback)
: SDLPlayerBase(now_function,
task_runner,
receiver,
- codec_name,
+ CodecToString(codec),
std::move(error_callback),
kAudioMediaType) {}
diff --git a/chromium/third_party/openscreen/src/cast/standalone_receiver/sdl_audio_player.h b/chromium/third_party/openscreen/src/cast/standalone_receiver/sdl_audio_player.h
index 8788d1f5c05..b21ce2cc5bf 100644
--- a/chromium/third_party/openscreen/src/cast/standalone_receiver/sdl_audio_player.h
+++ b/chromium/third_party/openscreen/src/cast/standalone_receiver/sdl_audio_player.h
@@ -22,7 +22,7 @@ class SDLAudioPlayer final : public SDLPlayerBase {
SDLAudioPlayer(ClockNowFunctionPtr now_function,
TaskRunner* task_runner,
Receiver* receiver,
- const std::string& codec_name,
+ AudioCodec codec,
std::function<void()> error_callback);
~SDLAudioPlayer() final;
diff --git a/chromium/third_party/openscreen/src/cast/standalone_receiver/sdl_player_base.cc b/chromium/third_party/openscreen/src/cast/standalone_receiver/sdl_player_base.cc
index ab2f1327cf1..fdc3c06545e 100644
--- a/chromium/third_party/openscreen/src/cast/standalone_receiver/sdl_player_base.cc
+++ b/chromium/third_party/openscreen/src/cast/standalone_receiver/sdl_player_base.cc
@@ -10,6 +10,7 @@
#include "absl/types/span.h"
#include "cast/standalone_receiver/avcodec_glue.h"
+#include "cast/streaming/constants.h"
#include "cast/streaming/encoded_frame.h"
#include "util/big_endian.h"
#include "util/chrono_helpers.h"
diff --git a/chromium/third_party/openscreen/src/cast/standalone_receiver/sdl_player_base.h b/chromium/third_party/openscreen/src/cast/standalone_receiver/sdl_player_base.h
index 7338edab1b0..4e268e8ade3 100644
--- a/chromium/third_party/openscreen/src/cast/standalone_receiver/sdl_player_base.h
+++ b/chromium/third_party/openscreen/src/cast/standalone_receiver/sdl_player_base.h
@@ -13,6 +13,7 @@
#include "cast/standalone_receiver/decoder.h"
#include "cast/standalone_receiver/sdl_glue.h"
+#include "cast/streaming/message_fields.h"
#include "cast/streaming/receiver.h"
#include "platform/api/task_runner.h"
#include "platform/api/time.h"
diff --git a/chromium/third_party/openscreen/src/cast/standalone_receiver/sdl_video_player.cc b/chromium/third_party/openscreen/src/cast/standalone_receiver/sdl_video_player.cc
index dc540e50a9f..999545de5a4 100644
--- a/chromium/third_party/openscreen/src/cast/standalone_receiver/sdl_video_player.cc
+++ b/chromium/third_party/openscreen/src/cast/standalone_receiver/sdl_video_player.cc
@@ -5,6 +5,7 @@
#include "cast/standalone_receiver/sdl_video_player.h"
#include <sstream>
+#include <utility>
#include "cast/standalone_receiver/avcodec_glue.h"
#include "util/osp_logging.h"
@@ -20,13 +21,13 @@ constexpr char kVideoMediaType[] = "video";
SDLVideoPlayer::SDLVideoPlayer(ClockNowFunctionPtr now_function,
TaskRunner* task_runner,
Receiver* receiver,
- const std::string& codec_name,
+ VideoCodec codec,
SDL_Renderer* renderer,
std::function<void()> error_callback)
: SDLPlayerBase(now_function,
task_runner,
receiver,
- codec_name,
+ CodecToString(codec),
std::move(error_callback),
kVideoMediaType),
renderer_(renderer) {
diff --git a/chromium/third_party/openscreen/src/cast/standalone_receiver/sdl_video_player.h b/chromium/third_party/openscreen/src/cast/standalone_receiver/sdl_video_player.h
index 24b3496ccc0..609c860c3b4 100644
--- a/chromium/third_party/openscreen/src/cast/standalone_receiver/sdl_video_player.h
+++ b/chromium/third_party/openscreen/src/cast/standalone_receiver/sdl_video_player.h
@@ -8,6 +8,7 @@
#include <string>
#include "cast/standalone_receiver/sdl_player_base.h"
+#include "cast/streaming/constants.h"
namespace openscreen {
namespace cast {
@@ -21,7 +22,7 @@ class SDLVideoPlayer final : public SDLPlayerBase {
SDLVideoPlayer(ClockNowFunctionPtr now_function,
TaskRunner* task_runner,
Receiver* receiver,
- const std::string& codec_name,
+ VideoCodec codec_name,
SDL_Renderer* renderer,
std::function<void()> error_callback);
diff --git a/chromium/third_party/openscreen/src/cast/standalone_receiver/streaming_playback_controller.cc b/chromium/third_party/openscreen/src/cast/standalone_receiver/streaming_playback_controller.cc
index e45a281700c..3438c2ed027 100644
--- a/chromium/third_party/openscreen/src/cast/standalone_receiver/streaming_playback_controller.cc
+++ b/chromium/third_party/openscreen/src/cast/standalone_receiver/streaming_playback_controller.cc
@@ -53,8 +53,6 @@ StreamingPlaybackController::StreamingPlaybackController(
}
#endif // defined(CAST_STANDALONE_RECEIVER_HAVE_EXTERNAL_LIBS)
-// TODO(jophba): add async tracing to streaming implementation for exposing
-// how long the OFFER/ANSWER and receiver startup takes.
void StreamingPlaybackController::OnNegotiated(
const ReceiverSession* session,
ReceiverSession::ConfiguredReceivers receivers) {
@@ -62,26 +60,25 @@ void StreamingPlaybackController::OnNegotiated(
#if defined(CAST_STANDALONE_RECEIVER_HAVE_EXTERNAL_LIBS)
if (receivers.audio) {
audio_player_ = std::make_unique<SDLAudioPlayer>(
- &Clock::now, task_runner_, receivers.audio->receiver,
- receivers.audio->selected_stream.stream.codec_name, [this] {
+ &Clock::now, task_runner_, receivers.audio_receiver,
+ receivers.audio_config.codec, [this] {
client_->OnPlaybackError(this, audio_player_->error_status());
});
}
if (receivers.video) {
video_player_ = std::make_unique<SDLVideoPlayer>(
- &Clock::now, task_runner_, receivers.video->receiver,
- receivers.video->selected_stream.stream.codec_name, renderer_.get(),
- [this] {
+ &Clock::now, task_runner_, receivers.video_receiver,
+ receivers.video_config.codec, renderer_.get(), [this] {
client_->OnPlaybackError(this, video_player_->error_status());
});
}
#else
- if (receivers.audio) {
- audio_player_ = std::make_unique<DummyPlayer>(receivers.audio->receiver);
+ if (receivers.audio_receiver) {
+ audio_player_ = std::make_unique<DummyPlayer>(receivers.audio_receiver);
}
- if (receivers.video) {
- video_player_ = std::make_unique<DummyPlayer>(receivers.video->receiver);
+ if (receivers.video_receiver) {
+ video_player_ = std::make_unique<DummyPlayer>(receivers.video_receiver);
}
#endif // defined(CAST_STANDALONE_RECEIVER_HAVE_EXTERNAL_LIBS)
}
diff --git a/chromium/third_party/openscreen/src/cast/standalone_sender/BUILD.gn b/chromium/third_party/openscreen/src/cast/standalone_sender/BUILD.gn
index 85e0f1b047b..c2bd427bc4a 100644
--- a/chromium/third_party/openscreen/src/cast/standalone_sender/BUILD.gn
+++ b/chromium/third_party/openscreen/src/cast/standalone_sender/BUILD.gn
@@ -9,25 +9,40 @@ import("//build_overrides/build.gni")
# standalone platform implementation; since this is itself a standalone
# application.
if (!build_with_chromium) {
- executable("cast_sender") {
- sources = [
- "main.cc",
- ]
+ declare_args() {
+ have_libs = have_ffmpeg && have_libopus && have_libvpx
+ }
+
+ config("standalone_external_libs") {
+ defines = []
+ if (have_libs) {
+ defines += [ "CAST_STANDALONE_SENDER_HAVE_EXTERNAL_LIBS" ]
+ }
+ }
+
+ source_set("standalone_sender") {
deps = [
"../../platform",
+ "../../third_party/jsoncpp",
"../../util",
+ "../common:public",
+ "../common/channel/proto:channel_proto",
+ "../sender:channel",
"../streaming:sender",
]
- defines = []
+ sources = []
include_dirs = []
lib_dirs = []
libs = []
if (have_ffmpeg && have_libopus && have_libvpx) {
- defines += [ "CAST_STANDALONE_SENDER_HAVE_EXTERNAL_LIBS" ]
sources += [
"ffmpeg_glue.cc",
"ffmpeg_glue.h",
+ "looping_file_cast_agent.cc",
+ "looping_file_cast_agent.h",
+ "looping_file_sender.cc",
+ "looping_file_sender.h",
"simulated_capturer.cc",
"simulated_capturer.h",
"streaming_opus_encoder.cc",
@@ -40,5 +55,21 @@ if (!build_with_chromium) {
lib_dirs += ffmpeg_lib_dirs + libopus_lib_dirs + libvpx_lib_dirs
libs += ffmpeg_libs + libopus_libs + libvpx_libs
}
+
+ public_configs = [
+ "../../build:openscreen_include_dirs",
+ ":standalone_external_libs",
+ ]
+ }
+
+ executable("cast_sender") {
+ sources = [ "main.cc" ]
+
+ deps = [
+ ":standalone_sender",
+ "../../third_party/jsoncpp",
+ "../common/channel/proto:channel_proto",
+ "../streaming:common",
+ ]
}
}
diff --git a/chromium/third_party/openscreen/src/cast/standalone_sender/constants.h b/chromium/third_party/openscreen/src/cast/standalone_sender/constants.h
new file mode 100644
index 00000000000..b7534ee53ac
--- /dev/null
+++ b/chromium/third_party/openscreen/src/cast/standalone_sender/constants.h
@@ -0,0 +1,33 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CAST_STANDALONE_SENDER_CONSTANTS_H_
+#define CAST_STANDALONE_SENDER_CONSTANTS_H_
+
+#include "util/chrono_helpers.h"
+
+namespace openscreen {
+namespace cast {
+
+// How often should the congestion control logic re-evaluate the target encode
+// bitrates?
+constexpr milliseconds kCongestionCheckInterval{500};
+
+// Above what available bandwidth should the high-quality audio bitrate be used?
+constexpr int kHighBandwidthThreshold = 5 << 20; // 5 Mbps.
+
+// How often should the file position (media timestamp) be updated on the
+// console?
+constexpr milliseconds kConsoleUpdateInterval{100};
+
+// What is the default maximum bitrate setting?
+constexpr int kDefaultMaxBitrate = 5 << 20; // 5 Mbps.
+
+// What is the minimum amount of bandwidth required?
+constexpr int kMinRequiredBitrate = 384 << 10; // 384 kbps.
+
+} // namespace cast
+} // namespace openscreen
+
+#endif // CAST_STANDALONE_SENDER_CONSTANTS_H_
diff --git a/chromium/third_party/openscreen/src/cast/standalone_sender/looping_file_cast_agent.cc b/chromium/third_party/openscreen/src/cast/standalone_sender/looping_file_cast_agent.cc
new file mode 100644
index 00000000000..a7e99fdb60c
--- /dev/null
+++ b/chromium/third_party/openscreen/src/cast/standalone_sender/looping_file_cast_agent.cc
@@ -0,0 +1,152 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cast/standalone_sender/looping_file_cast_agent.h"
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "cast/standalone_sender/looping_file_sender.h"
+#include "cast/streaming/capture_recommendations.h"
+#include "cast/streaming/constants.h"
+#include "cast/streaming/offer_messages.h"
+#include "util/trace_logging.h"
+
+namespace openscreen {
+namespace cast {
+namespace {
+
+using DeviceMediaPolicy = SenderSocketFactory::DeviceMediaPolicy;
+
+} // namespace
+
+LoopingFileCastAgent::LoopingFileCastAgent(TaskRunner* task_runner)
+ : task_runner_(task_runner) {
+ router_ = MakeSerialDelete<VirtualConnectionRouter>(task_runner_,
+ &connection_manager_);
+ message_port_ =
+ MakeSerialDelete<CastSocketMessagePort>(task_runner_, router_.get());
+ socket_factory_ =
+ MakeSerialDelete<SenderSocketFactory>(task_runner_, this, task_runner_);
+ connection_factory_ = SerialDeletePtr<TlsConnectionFactory>(
+ task_runner_,
+ TlsConnectionFactory::CreateFactory(socket_factory_.get(), task_runner_)
+ .release());
+ socket_factory_->set_factory(connection_factory_.get());
+}
+
+LoopingFileCastAgent::~LoopingFileCastAgent() = default;
+
+void LoopingFileCastAgent::Connect(ConnectionSettings settings) {
+ TRACE_DEFAULT_SCOPED(TraceCategory::kStandaloneSender);
+ connection_settings_ = std::move(settings);
+ const auto policy = connection_settings_->should_include_video
+ ? DeviceMediaPolicy::kIncludesVideo
+ : DeviceMediaPolicy::kAudioOnly;
+
+ task_runner_->PostTask([this, policy] {
+ wake_lock_ = ScopedWakeLock::Create(task_runner_);
+ socket_factory_->Connect(connection_settings_->receiver_endpoint, policy,
+ router_.get());
+ });
+}
+
+void LoopingFileCastAgent::Stop() {
+ task_runner_->PostTask([this] {
+ StopCurrentSession();
+
+ connection_factory_.reset();
+ connection_settings_.reset();
+ socket_factory_.reset();
+ wake_lock_.reset();
+ });
+}
+
+void LoopingFileCastAgent::OnConnected(SenderSocketFactory* factory,
+ const IPEndpoint& endpoint,
+ std::unique_ptr<CastSocket> socket) {
+ TRACE_DEFAULT_SCOPED(TraceCategory::kStandaloneSender);
+ if (current_session_) {
+ OSP_LOG_WARN << "Already connected, dropping peer at: " << endpoint;
+ return;
+ }
+
+ OSP_LOG_INFO << "Received connection from peer at: " << endpoint;
+ message_port_->SetSocket(socket->GetWeakPtr());
+ router_->TakeSocket(this, std::move(socket));
+ CreateAndStartSession();
+}
+
+void LoopingFileCastAgent::OnError(SenderSocketFactory* factory,
+ const IPEndpoint& endpoint,
+ Error error) {
+ OSP_LOG_ERROR << "Cast agent received socket factory error: " << error;
+ StopCurrentSession();
+}
+
+void LoopingFileCastAgent::OnClose(CastSocket* cast_socket) {
+ OSP_VLOG << "Cast agent socket closed.";
+ StopCurrentSession();
+}
+
+void LoopingFileCastAgent::OnError(CastSocket* socket, Error error) {
+ OSP_LOG_ERROR << "Cast agent received socket error: " << error;
+ StopCurrentSession();
+}
+
+void LoopingFileCastAgent::OnNegotiated(
+ const SenderSession* session,
+ SenderSession::ConfiguredSenders senders,
+ capture_recommendations::Recommendations capture_recommendations) {
+ if (senders.audio_sender == nullptr || senders.video_sender == nullptr) {
+ OSP_LOG_ERROR << "Missing either audio or video, so exiting...";
+ return;
+ }
+
+ OSP_VLOG << "Successfully negotiated with sender.";
+
+ file_sender_ = std::make_unique<LoopingFileSender>(
+ task_runner_, connection_settings_->path_to_file.c_str(),
+ connection_settings_->receiver_endpoint, senders,
+ connection_settings_->max_bitrate);
+}
+
+// Currently, we just kill the session if an error is encountered.
+void LoopingFileCastAgent::OnError(const SenderSession* session, Error error) {
+ OSP_LOG_ERROR << "Cast agent received sender session error: " << error;
+ StopCurrentSession();
+}
+
+void LoopingFileCastAgent::CreateAndStartSession() {
+ TRACE_DEFAULT_SCOPED(TraceCategory::kStandaloneSender);
+ environment_ =
+ std::make_unique<Environment>(&Clock::now, task_runner_, IPEndpoint{});
+ current_session_ = std::make_unique<SenderSession>(
+ connection_settings_->receiver_endpoint.address, this, environment_.get(),
+ message_port_.get());
+
+ AudioCaptureConfig audio_config;
+ VideoCaptureConfig video_config;
+ // Use default display resolution of 1080P.
+ video_config.resolutions.emplace_back(DisplayResolution{});
+
+ OSP_VLOG << "Starting session negotiation.";
+ const Error negotiation_error =
+ current_session_->Negotiate({audio_config}, {video_config});
+ if (!negotiation_error.ok()) {
+ OSP_LOG_ERROR << "Failed to negotiate a session: " << negotiation_error;
+ }
+}
+
+void LoopingFileCastAgent::StopCurrentSession() {
+ current_session_.reset();
+ environment_.reset();
+ file_sender_.reset();
+ router_->CloseSocket(message_port_->GetSocketId());
+ message_port_->SetSocket(nullptr);
+}
+
+} // namespace cast
+} // namespace openscreen
diff --git a/chromium/third_party/openscreen/src/cast/standalone_sender/looping_file_cast_agent.h b/chromium/third_party/openscreen/src/cast/standalone_sender/looping_file_cast_agent.h
new file mode 100644
index 00000000000..abe91c96da1
--- /dev/null
+++ b/chromium/third_party/openscreen/src/cast/standalone_sender/looping_file_cast_agent.h
@@ -0,0 +1,119 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CAST_STANDALONE_SENDER_LOOPING_FILE_CAST_AGENT_H_
+#define CAST_STANDALONE_SENDER_LOOPING_FILE_CAST_AGENT_H_
+
+#include <openssl/x509.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "cast/common/channel/cast_socket_message_port.h"
+#include "cast/common/channel/virtual_connection_manager.h"
+#include "cast/common/channel/virtual_connection_router.h"
+#include "cast/common/public/cast_socket.h"
+#include "cast/sender/public/sender_socket_factory.h"
+#include "cast/standalone_sender/looping_file_sender.h"
+#include "cast/streaming/environment.h"
+#include "cast/streaming/sender_session.h"
+#include "platform/api/scoped_wake_lock.h"
+#include "platform/api/serial_delete_ptr.h"
+#include "platform/base/error.h"
+#include "platform/base/interface_info.h"
+#include "platform/impl/task_runner.h"
+
+namespace openscreen {
+namespace cast {
+
+// This class manages sender connections, starting with listening over TLS for
+// connection attempts, constructing SenderSessions when OFFER messages are
+// received, and linking Senders to the output decoder and SDL visualizer.
+class LoopingFileCastAgent final
+ : public SenderSocketFactory::Client,
+ public VirtualConnectionRouter::SocketErrorHandler,
+ public SenderSession::Client {
+ public:
+ explicit LoopingFileCastAgent(TaskRunner* task_runner);
+ ~LoopingFileCastAgent();
+
+ struct ConnectionSettings {
+ // The endpoint of the receiver we wish to connect to. Eventually this
+ // will come from discovery, instead of an endpoint here.
+ IPEndpoint receiver_endpoint;
+
+ // The path to the file that we want to play.
+ std::string path_to_file;
+
+ // The maximum bitrate. Default value means a reasonable default will be
+ // selected.
+ int max_bitrate = 0;
+
+ // Whether the stream should include video, or just be audio only.
+ bool should_include_video = true;
+
+ // Whether we should use the hacky RTP stream IDs for legacy android
+ // receivers, or if we should use the proper values.
+ bool use_android_rtp_hack = true;
+ };
+
+ void Connect(ConnectionSettings settings);
+ void Stop();
+
+ // SenderSocketFactory::Client overrides.
+ void OnConnected(SenderSocketFactory* factory,
+ const IPEndpoint& endpoint,
+ std::unique_ptr<CastSocket> socket) override;
+ void OnError(SenderSocketFactory* factory,
+ const IPEndpoint& endpoint,
+ Error error) override;
+
+ // VirtualConnectionRouter::SocketErrorHandler overrides.
+ void OnClose(CastSocket* cast_socket) override;
+ void OnError(CastSocket* socket, Error error) override;
+
+ // SenderSession::Client overrides.
+ void OnNegotiated(const SenderSession* session,
+ SenderSession::ConfiguredSenders senders,
+ capture_recommendations::Recommendations
+ capture_recommendations) override;
+ void OnError(const SenderSession* session, Error error) override;
+
+ private:
+ // Once we have a connection to the receiver we need to create and start
+ // a sender session. This method results in the OFFER/ANSWER exchange
+ // being completed and a session should be started.
+ void CreateAndStartSession();
+
+ // Helper for stopping the current session. This is useful for when we don't
+ // want to completely stop (e.g. an issue with a specific Sender) but need
+ // to terminate the current connection.
+ void StopCurrentSession();
+
+ // Member variables set as part of construction.
+ VirtualConnectionManager connection_manager_;
+ TaskRunner* const task_runner_;
+ SerialDeletePtr<VirtualConnectionRouter> router_;
+ SerialDeletePtr<CastSocketMessagePort> message_port_;
+ SerialDeletePtr<SenderSocketFactory> socket_factory_;
+ SerialDeletePtr<TlsConnectionFactory> connection_factory_;
+
+ // Member variables set as part of starting up.
+ std::unique_ptr<Environment> environment_;
+ absl::optional<ConnectionSettings> connection_settings_;
+ SerialDeletePtr<ScopedWakeLock> wake_lock_;
+
+ // Member variables set as part of a sender connection.
+ // NOTE: currently we only support a single sender connection and a
+ // single streaming session.
+ std::unique_ptr<SenderSession> current_session_;
+ std::unique_ptr<LoopingFileSender> file_sender_;
+};
+
+} // namespace cast
+} // namespace openscreen
+
+#endif // CAST_STANDALONE_SENDER_LOOPING_FILE_CAST_AGENT_H_
diff --git a/chromium/third_party/openscreen/src/cast/standalone_sender/looping_file_sender.cc b/chromium/third_party/openscreen/src/cast/standalone_sender/looping_file_sender.cc
new file mode 100644
index 00000000000..e4b795b8eb4
--- /dev/null
+++ b/chromium/third_party/openscreen/src/cast/standalone_sender/looping_file_sender.cc
@@ -0,0 +1,189 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cast/standalone_sender/looping_file_sender.h"
+
+#include "util/trace_logging.h"
+
+namespace openscreen {
+namespace cast {
+
+LoopingFileSender::LoopingFileSender(TaskRunner* task_runner,
+ const char* path,
+ const IPEndpoint& remote_endpoint,
+ SenderSession::ConfiguredSenders senders,
+ int max_bitrate)
+ : env_(&Clock::now, task_runner),
+ path_(path),
+ packet_router_(&env_),
+ max_bitrate_(max_bitrate),
+ audio_encoder_(senders.audio_sender->config().channels,
+ StreamingOpusEncoder::kDefaultCastAudioFramesPerSecond,
+ senders.audio_sender),
+ video_encoder_(StreamingVp8Encoder::Parameters{},
+ env_.task_runner(),
+ senders.video_sender),
+ next_task_(env_.now_function(), env_.task_runner()),
+ console_update_task_(env_.now_function(), env_.task_runner()) {
+ env_.set_remote_endpoint(remote_endpoint);
+ // Opus and Vp8 are the default values for the config, and if these are set
+ // to a different value that means we offered a codec that we do not
+ // support, which is a developer error.
+ OSP_CHECK(senders.audio_config.codec == AudioCodec::kOpus);
+ OSP_CHECK(senders.video_config.codec == VideoCodec::kVp8);
+ OSP_LOG_INFO << "Streaming to " << remote_endpoint << "...";
+ OSP_LOG_INFO << "Max allowed media bitrate (audio + video) will be "
+ << max_bitrate_;
+ bandwidth_being_utilized_ = max_bitrate_ / 2;
+ UpdateEncoderBitrates();
+
+ next_task_.Schedule([this] { SendFileAgain(); }, Alarm::kImmediately);
+}
+
+LoopingFileSender::~LoopingFileSender() = default;
+
+void LoopingFileSender::UpdateEncoderBitrates() {
+ if (bandwidth_being_utilized_ >= kHighBandwidthThreshold) {
+ audio_encoder_.UseHighQuality();
+ } else {
+ audio_encoder_.UseStandardQuality();
+ }
+ video_encoder_.SetTargetBitrate(bandwidth_being_utilized_ -
+ audio_encoder_.GetBitrate());
+}
+
+void LoopingFileSender::ControlForNetworkCongestion() {
+ bandwidth_estimate_ = packet_router_.ComputeNetworkBandwidth();
+ if (bandwidth_estimate_ > 0) {
+ // Don't ever try to use *all* of the network bandwidth! However, don't go
+ // below the absolute minimum requirement either.
+ constexpr double kGoodNetworkCitizenFactor = 0.8;
+ const int usable_bandwidth = std::max<int>(
+ kGoodNetworkCitizenFactor * bandwidth_estimate_, kMinRequiredBitrate);
+
+ // See "congestion control" discussion in the class header comments for
+ // BandwidthEstimator.
+ if (usable_bandwidth > bandwidth_being_utilized_) {
+ constexpr double kConservativeIncrease = 1.1;
+ bandwidth_being_utilized_ = std::min<int>(
+ bandwidth_being_utilized_ * kConservativeIncrease, usable_bandwidth);
+ } else {
+ bandwidth_being_utilized_ = usable_bandwidth;
+ }
+
+ // Repsect the user's maximum bitrate setting.
+ bandwidth_being_utilized_ =
+ std::min(bandwidth_being_utilized_, max_bitrate_);
+
+ UpdateEncoderBitrates();
+ } else {
+ // There is no current bandwidth estimate. So, nothing should be adjusted.
+ }
+
+ next_task_.ScheduleFromNow([this] { ControlForNetworkCongestion(); },
+ kCongestionCheckInterval);
+}
+
+void LoopingFileSender::SendFileAgain() {
+ OSP_LOG_INFO << "Sending " << path_ << " (starts in one second)...";
+ TRACE_DEFAULT_SCOPED(TraceCategory::kStandaloneSender);
+
+ OSP_DCHECK_EQ(num_capturers_running_, 0);
+ num_capturers_running_ = 2;
+ capture_start_time_ = latest_frame_time_ = env_.now() + seconds(1);
+ audio_capturer_.emplace(&env_, path_, audio_encoder_.num_channels(),
+ audio_encoder_.sample_rate(), capture_start_time_,
+ this);
+ video_capturer_.emplace(&env_, path_, capture_start_time_, this);
+
+ next_task_.ScheduleFromNow([this] { ControlForNetworkCongestion(); },
+ kCongestionCheckInterval);
+ console_update_task_.Schedule([this] { UpdateStatusOnConsole(); },
+ capture_start_time_);
+}
+
+void LoopingFileSender::OnAudioData(const float* interleaved_samples,
+ int num_samples,
+ Clock::time_point capture_time) {
+ TRACE_DEFAULT_SCOPED(TraceCategory::kStandaloneSender);
+ latest_frame_time_ = std::max(capture_time, latest_frame_time_);
+ audio_encoder_.EncodeAndSend(interleaved_samples, num_samples, capture_time);
+}
+
+void LoopingFileSender::OnVideoFrame(const AVFrame& av_frame,
+ Clock::time_point capture_time) {
+ TRACE_DEFAULT_SCOPED(TraceCategory::kStandaloneSender);
+ latest_frame_time_ = std::max(capture_time, latest_frame_time_);
+ StreamingVp8Encoder::VideoFrame frame{};
+ frame.width = av_frame.width - av_frame.crop_left - av_frame.crop_right;
+ frame.height = av_frame.height - av_frame.crop_top - av_frame.crop_bottom;
+ frame.yuv_planes[0] = av_frame.data[0] + av_frame.crop_left +
+ av_frame.linesize[0] * av_frame.crop_top;
+ frame.yuv_planes[1] = av_frame.data[1] + av_frame.crop_left / 2 +
+ av_frame.linesize[1] * av_frame.crop_top / 2;
+ frame.yuv_planes[2] = av_frame.data[2] + av_frame.crop_left / 2 +
+ av_frame.linesize[2] * av_frame.crop_top / 2;
+ for (int i = 0; i < 3; ++i) {
+ frame.yuv_strides[i] = av_frame.linesize[i];
+ }
+ // TODO(miu): Add performance metrics visual overlay (based on Stats
+ // callback).
+ video_encoder_.EncodeAndSend(frame, capture_time, {});
+}
+
+void LoopingFileSender::UpdateStatusOnConsole() {
+ const Clock::duration elapsed = latest_frame_time_ - capture_start_time_;
+ const auto seconds_part = to_seconds(elapsed);
+ const auto millis_part = to_microseconds(elapsed - seconds_part);
+ // The control codes here attempt to erase the current line the cursor is
+ // on, and then print out the updated status text. If the terminal does not
+ // support simple ANSI escape codes, the following will still work, but
+ // there might sometimes be old status lines not getting erased (i.e., just
+ // partially overwritten).
+ fprintf(stdout,
+ "\r\x1b[2K\rLoopingFileSender: At %01" PRId64
+ ".%03ds in file (est. network bandwidth: %d kbps). \n",
+ static_cast<int64_t>(seconds_part.count()),
+ static_cast<int>(millis_part.count()), bandwidth_estimate_ / 1024);
+ fflush(stdout);
+
+ console_update_task_.ScheduleFromNow([this] { UpdateStatusOnConsole(); },
+ kConsoleUpdateInterval);
+}
+
+void LoopingFileSender::OnEndOfFile(SimulatedCapturer* capturer) {
+ OSP_LOG_INFO << "The " << ToTrackName(capturer)
+ << " capturer has reached the end of the media stream.";
+ --num_capturers_running_;
+ if (num_capturers_running_ == 0) {
+ console_update_task_.Cancel();
+ next_task_.Schedule([this] { SendFileAgain(); }, Alarm::kImmediately);
+ }
+}
+
+void LoopingFileSender::OnError(SimulatedCapturer* capturer,
+ std::string message) {
+ OSP_LOG_ERROR << "The " << ToTrackName(capturer)
+ << " has failed: " << message;
+ --num_capturers_running_;
+ // If both fail, the application just pauses. This accounts for things like
+ // "file not found" errors. However, if only one track fails, then keep
+ // going.
+}
+
+const char* LoopingFileSender::ToTrackName(SimulatedCapturer* capturer) const {
+ const char* which;
+ if (capturer == &*audio_capturer_) {
+ which = "audio";
+ } else if (capturer == &*video_capturer_) {
+ which = "video";
+ } else {
+ OSP_NOTREACHED();
+ which = "";
+ }
+ return which;
+}
+
+} // namespace cast
+} // namespace openscreen
diff --git a/chromium/third_party/openscreen/src/cast/standalone_sender/looping_file_sender.h b/chromium/third_party/openscreen/src/cast/standalone_sender/looping_file_sender.h
new file mode 100644
index 00000000000..782c7fdf958
--- /dev/null
+++ b/chromium/third_party/openscreen/src/cast/standalone_sender/looping_file_sender.h
@@ -0,0 +1,87 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CAST_STANDALONE_SENDER_LOOPING_FILE_SENDER_H_
+#define CAST_STANDALONE_SENDER_LOOPING_FILE_SENDER_H_
+
+#include <algorithm>
+#include <string>
+
+#include "cast/standalone_sender/constants.h"
+#include "cast/standalone_sender/simulated_capturer.h"
+#include "cast/standalone_sender/streaming_opus_encoder.h"
+#include "cast/standalone_sender/streaming_vp8_encoder.h"
+#include "cast/streaming/sender_session.h"
+
+namespace openscreen {
+namespace cast {
+
+// Plays the media file at a given path over and over again, transcoding and
+// streaming its audio/video.
+class LoopingFileSender final : public SimulatedAudioCapturer::Client,
+ public SimulatedVideoCapturer::Client {
+ public:
+ LoopingFileSender(TaskRunner* task_runner,
+ const char* path,
+ const IPEndpoint& remote_endpoint,
+ SenderSession::ConfiguredSenders senders,
+ int max_bitrate);
+
+ ~LoopingFileSender() final;
+
+ private:
+ void UpdateEncoderBitrates();
+ void ControlForNetworkCongestion();
+ void SendFileAgain();
+
+ // SimulatedAudioCapturer overrides.
+ void OnAudioData(const float* interleaved_samples,
+ int num_samples,
+ Clock::time_point capture_time) final;
+
+ // SimulatedVideoCapturer overrides;
+ void OnVideoFrame(const AVFrame& av_frame,
+ Clock::time_point capture_time) final;
+
+ void UpdateStatusOnConsole();
+
+ // SimulatedCapturer overrides.
+ void OnEndOfFile(SimulatedCapturer* capturer) final;
+ void OnError(SimulatedCapturer* capturer, std::string message) final;
+
+ const char* ToTrackName(SimulatedCapturer* capturer) const;
+
+ // Holds the required injected dependencies (clock, task runner) used for Cast
+ // Streaming, and owns the UDP socket over which all communications occur with
+ // the remote's Receivers.
+ Environment env_;
+
+ // The path to the media file to stream over and over.
+ const char* const path_;
+
+ // The packet router allows both the Audio Sender and the Video Sender to
+ // share the same UDP socket.
+ SenderPacketRouter packet_router_;
+
+ const int max_bitrate_; // Passed by the user on the command line.
+ int bandwidth_estimate_ = 0;
+ int bandwidth_being_utilized_;
+
+ StreamingOpusEncoder audio_encoder_;
+ StreamingVp8Encoder video_encoder_;
+
+ int num_capturers_running_ = 0;
+ Clock::time_point capture_start_time_{};
+ Clock::time_point latest_frame_time_{};
+ absl::optional<SimulatedAudioCapturer> audio_capturer_;
+ absl::optional<SimulatedVideoCapturer> video_capturer_;
+
+ Alarm next_task_;
+ Alarm console_update_task_;
+};
+
+} // namespace cast
+} // namespace openscreen
+
+#endif // CAST_STANDALONE_SENDER_LOOPING_FILE_SENDER_H_
diff --git a/chromium/third_party/openscreen/src/cast/standalone_sender/main.cc b/chromium/third_party/openscreen/src/cast/standalone_sender/main.cc
index ef417132eb5..02c2b4ee8c4 100644
--- a/chromium/third_party/openscreen/src/cast/standalone_sender/main.cc
+++ b/chromium/third_party/openscreen/src/cast/standalone_sender/main.cc
@@ -2,6 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "platform/impl/logging.h"
+
+#if defined(CAST_STANDALONE_SENDER_HAVE_EXTERNAL_LIBS)
#include <getopt.h>
#include <chrono>
@@ -12,6 +15,9 @@
#include <iostream>
#include <sstream>
+#include "cast/common/certificate/cast_trust_store.h"
+#include "cast/standalone_sender/constants.h"
+#include "cast/standalone_sender/looping_file_cast_agent.h"
#include "cast/streaming/constants.h"
#include "cast/streaming/environment.h"
#include "cast/streaming/sender.h"
@@ -21,315 +27,18 @@
#include "platform/api/time.h"
#include "platform/base/error.h"
#include "platform/base/ip_address.h"
-#include "platform/impl/logging.h"
#include "platform/impl/platform_client_posix.h"
#include "platform/impl/task_runner.h"
#include "platform/impl/text_trace_logging_platform.h"
#include "util/alarm.h"
#include "util/chrono_helpers.h"
-#if defined(CAST_STANDALONE_SENDER_HAVE_EXTERNAL_LIBS)
-#include "cast/standalone_sender/simulated_capturer.h"
-#include "cast/standalone_sender/streaming_opus_encoder.h"
-#include "cast/standalone_sender/streaming_vp8_encoder.h"
-#endif
-
namespace openscreen {
namespace cast {
namespace {
-////////////////////////////////////////////////////////////////////////////////
-// Sender Configuration
-//
-// The values defined here are constants that correspond to the standalone Cast
-// Receiver app. In a production environment, these should ABSOLUTELY NOT be
-// fixed! Instead a sender↔receiver OFFER/ANSWER exchange should establish them.
-
-// In a production environment, this would start-out at some initial value
-// appropriate to the networking environment, and then be adjusted by the
-// application as: 1) the TYPE of the content changes (interactive, low-latency
-// versus smooth, higher-latency buffered video watching); and 2) the networking
-// environment reliability changes.
-constexpr milliseconds kTargetPlayoutDelay = kDefaultTargetPlayoutDelay;
-
-const SessionConfig kSampleAudioAnswerConfig{
- /* .sender_ssrc = */ 1,
- /* .receiver_ssrc = */ 2,
- /* .rtp_timebase = */ 48000,
- /* .channels = */ 2,
- /* .target_playout_delay */ kTargetPlayoutDelay,
- /* .aes_secret_key = */
- {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
- 0x0c, 0x0d, 0x0e, 0x0f},
- /* .aes_iv_mask = */
- {0xf0, 0xe0, 0xd0, 0xc0, 0xb0, 0xa0, 0x90, 0x80, 0x70, 0x60, 0x50, 0x40,
- 0x30, 0x20, 0x10, 0x00},
-};
-
-const SessionConfig kSampleVideoAnswerConfig{
- /* .sender_ssrc = */ 50001,
- /* .receiver_ssrc = */ 50002,
- /* .rtp_timebase = */ static_cast<int>(kVideoTimebase::den),
- /* .channels = */ 1,
- /* .target_playout_delay */ kTargetPlayoutDelay,
- /* .aes_secret_key = */
- {0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
- 0x1c, 0x1d, 0x1e, 0x1f},
- /* .aes_iv_mask = */
- {0xf1, 0xe1, 0xd1, 0xc1, 0xb1, 0xa1, 0x91, 0x81, 0x71, 0x61, 0x51, 0x41,
- 0x31, 0x21, 0x11, 0x01},
-};
-
-// End of Sender Configuration.
-////////////////////////////////////////////////////////////////////////////////
-
-// What is the minimum amount of bandwidth required?
-constexpr int kMinRequiredBitrate = 384 << 10; // 384 kbps.
-
-// What is the default maximum bitrate setting?
-constexpr int kDefaultMaxBitrate = 5 << 20; // 5 Mbps.
-
-#if defined(CAST_STANDALONE_SENDER_HAVE_EXTERNAL_LIBS)
-
-// Above what available bandwidth should the high-quality audio bitrate be used?
-constexpr int kHighBandwidthThreshold = 5 << 20; // 5 Mbps.
-
-// How often should the file position (media timestamp) be updated on the
-// console?
-constexpr milliseconds kConsoleUpdateInterval{100};
-
-// How often should the congestion control logic re-evaluate the target encode
-// bitrates?
-constexpr milliseconds kCongestionCheckInterval{500};
-
-// Plays the media file at a given path over and over again, transcoding and
-// streaming its audio/video.
-class LoopingFileSender final : public SimulatedAudioCapturer::Client,
- public SimulatedVideoCapturer::Client {
- public:
- LoopingFileSender(TaskRunner* task_runner,
- const char* path,
- const IPEndpoint& remote_endpoint,
- int max_bitrate,
- bool use_android_rtp_hack)
- : env_(&Clock::now, task_runner),
- path_(path),
- packet_router_(&env_),
- max_bitrate_(max_bitrate),
- audio_sender_(&env_,
- &packet_router_,
- kSampleAudioAnswerConfig,
- use_android_rtp_hack
- ? RtpPayloadType::kAudioHackForAndroidTV
- : RtpPayloadType::kAudioOpus),
- video_sender_(&env_,
- &packet_router_,
- kSampleVideoAnswerConfig,
- use_android_rtp_hack
- ? RtpPayloadType::kVideoHackForAndroidTV
- : RtpPayloadType::kVideoVp8),
- audio_encoder_(kSampleAudioAnswerConfig.channels,
- StreamingOpusEncoder::kDefaultCastAudioFramesPerSecond,
- &audio_sender_),
- video_encoder_(StreamingVp8Encoder::Parameters{},
- env_.task_runner(),
- &video_sender_),
- next_task_(env_.now_function(), env_.task_runner()),
- console_update_task_(env_.now_function(), env_.task_runner()) {
- env_.set_remote_endpoint(remote_endpoint);
- OSP_LOG_INFO << "Streaming to " << remote_endpoint << "...";
-
- if (use_android_rtp_hack) {
- OSP_LOG_INFO << "Using RTP payload types for older Android TV receivers.";
- }
-
- OSP_LOG_INFO << "Max allowed media bitrate (audio + video) will be "
- << max_bitrate_;
- bandwidth_being_utilized_ = max_bitrate_ / 2;
- UpdateEncoderBitrates();
-
- next_task_.Schedule([this] { SendFileAgain(); }, Alarm::kImmediately);
- }
-
- ~LoopingFileSender() final = default;
-
- private:
- void UpdateEncoderBitrates() {
- if (bandwidth_being_utilized_ >= kHighBandwidthThreshold) {
- audio_encoder_.UseHighQuality();
- } else {
- audio_encoder_.UseStandardQuality();
- }
- video_encoder_.SetTargetBitrate(bandwidth_being_utilized_ -
- audio_encoder_.GetBitrate());
- }
-
- void ControlForNetworkCongestion() {
- bandwidth_estimate_ = packet_router_.ComputeNetworkBandwidth();
- if (bandwidth_estimate_ > 0) {
- // Don't ever try to use *all* of the network bandwidth! However, don't go
- // below the absolute minimum requirement either.
- constexpr double kGoodNetworkCitizenFactor = 0.8;
- const int usable_bandwidth = std::max<int>(
- kGoodNetworkCitizenFactor * bandwidth_estimate_, kMinRequiredBitrate);
-
- // See "congestion control" discussion in the class header comments for
- // BandwidthEstimator.
- if (usable_bandwidth > bandwidth_being_utilized_) {
- constexpr double kConservativeIncrease = 1.1;
- bandwidth_being_utilized_ =
- std::min<int>(bandwidth_being_utilized_ * kConservativeIncrease,
- usable_bandwidth);
- } else {
- bandwidth_being_utilized_ = usable_bandwidth;
- }
-
- // Repsect the user's maximum bitrate setting.
- bandwidth_being_utilized_ =
- std::min(bandwidth_being_utilized_, max_bitrate_);
-
- UpdateEncoderBitrates();
- } else {
- // There is no current bandwidth estimate. So, nothing should be adjusted.
- }
-
- next_task_.ScheduleFromNow([this] { ControlForNetworkCongestion(); },
- kCongestionCheckInterval);
- }
-
- void SendFileAgain() {
- OSP_LOG_INFO << "Sending " << path_ << " (starts in one second)...";
-
- OSP_DCHECK_EQ(num_capturers_running_, 0);
- num_capturers_running_ = 2;
- capture_start_time_ = latest_frame_time_ = env_.now() + seconds(1);
- audio_capturer_.emplace(&env_, path_, audio_encoder_.num_channels(),
- audio_encoder_.sample_rate(), capture_start_time_,
- this);
- video_capturer_.emplace(&env_, path_, capture_start_time_, this);
-
- next_task_.ScheduleFromNow([this] { ControlForNetworkCongestion(); },
- kCongestionCheckInterval);
- console_update_task_.Schedule([this] { UpdateStatusOnConsole(); },
- capture_start_time_);
- }
-
- void OnAudioData(const float* interleaved_samples,
- int num_samples,
- Clock::time_point capture_time) final {
- latest_frame_time_ = std::max(capture_time, latest_frame_time_);
- audio_encoder_.EncodeAndSend(interleaved_samples, num_samples,
- capture_time);
- }
-
- void OnVideoFrame(const AVFrame& av_frame,
- Clock::time_point capture_time) final {
- latest_frame_time_ = std::max(capture_time, latest_frame_time_);
- StreamingVp8Encoder::VideoFrame frame{};
- frame.width = av_frame.width - av_frame.crop_left - av_frame.crop_right;
- frame.height = av_frame.height - av_frame.crop_top - av_frame.crop_bottom;
- frame.yuv_planes[0] = av_frame.data[0] + av_frame.crop_left +
- av_frame.linesize[0] * av_frame.crop_top;
- frame.yuv_planes[1] = av_frame.data[1] + av_frame.crop_left / 2 +
- av_frame.linesize[1] * av_frame.crop_top / 2;
- frame.yuv_planes[2] = av_frame.data[2] + av_frame.crop_left / 2 +
- av_frame.linesize[2] * av_frame.crop_top / 2;
- for (int i = 0; i < 3; ++i) {
- frame.yuv_strides[i] = av_frame.linesize[i];
- }
- // TODO(miu): Add performance metrics visual overlay (based on Stats
- // callback).
- video_encoder_.EncodeAndSend(frame, capture_time, {});
- }
-
- void UpdateStatusOnConsole() {
- const Clock::duration elapsed = latest_frame_time_ - capture_start_time_;
- const auto seconds_part = to_seconds(elapsed);
- const auto millis_part = to_microseconds(elapsed - seconds_part);
- // The control codes here attempt to erase the current line the cursor is
- // on, and then print out the updated status text. If the terminal does not
- // support simple ANSI escape codes, the following will still work, but
- // there might sometimes be old status lines not getting erased (i.e., just
- // partially overwritten).
- fprintf(stdout,
- "\r\x1b[2K\rAt %01" PRId64
- ".%03ds in file (est. network bandwidth: %d kbps). ",
- static_cast<int64_t>(seconds_part.count()),
- static_cast<int>(millis_part.count()), bandwidth_estimate_ / 1024);
- fflush(stdout);
-
- console_update_task_.ScheduleFromNow([this] { UpdateStatusOnConsole(); },
- kConsoleUpdateInterval);
- }
-
- void OnEndOfFile(SimulatedCapturer* capturer) final {
- OSP_LOG_INFO << "The " << ToTrackName(capturer)
- << " capturer has reached the end of the media stream.";
- --num_capturers_running_;
- if (num_capturers_running_ == 0) {
- console_update_task_.Cancel();
- next_task_.Schedule([this] { SendFileAgain(); }, Alarm::kImmediately);
- }
- }
-
- void OnError(SimulatedCapturer* capturer, std::string message) final {
- OSP_LOG_ERROR << "The " << ToTrackName(capturer)
- << " has failed: " << message;
- --num_capturers_running_;
- // If both fail, the application just pauses. This accounts for things like
- // "file not found" errors. However, if only one track fails, then keep
- // going.
- }
-
- const char* ToTrackName(SimulatedCapturer* capturer) const {
- const char* which;
- if (capturer == &*audio_capturer_) {
- which = "audio";
- } else if (capturer == &*video_capturer_) {
- which = "video";
- } else {
- OSP_NOTREACHED();
- which = "";
- }
- return which;
- }
-
- // Holds the required injected dependencies (clock, task runner) used for Cast
- // Streaming, and owns the UDP socket over which all communications occur with
- // the remote's Receivers.
- Environment env_;
-
- // The path to the media file to stream over and over.
- const char* const path_;
-
- // The packet router allows both the Audio Sender and the Video Sender to
- // share the same UDP socket.
- SenderPacketRouter packet_router_;
-
- const int max_bitrate_; // Passed by the user on the command line.
- int bandwidth_estimate_ = 0;
- int bandwidth_being_utilized_;
-
- Sender audio_sender_;
- Sender video_sender_;
-
- StreamingOpusEncoder audio_encoder_;
- StreamingVp8Encoder video_encoder_;
-
- int num_capturers_running_ = 0;
- Clock::time_point capture_start_time_{};
- Clock::time_point latest_frame_time_{};
- absl::optional<SimulatedAudioCapturer> audio_capturer_;
- absl::optional<SimulatedVideoCapturer> video_capturer_;
-
- Alarm next_task_;
- Alarm console_update_task_;
-};
-
-#endif // defined(CAST_STANDALONE_SENDER_HAVE_EXTERNAL_LIBS)
-
IPEndpoint GetDefaultEndpoint() {
- return IPEndpoint{IPAddress::kV4LoopbackAddress(), kDefaultCastStreamingPort};
+ return IPEndpoint{IPAddress::kV4LoopbackAddress(), kDefaultCastPort};
}
void LogUsage(const char* argv0) {
@@ -349,6 +58,11 @@ void LogUsage(const char* argv0) {
Default if not set: )"
<< kDefaultMaxBitrate << R"(.
+ -s, --server-certificate=path-to-cert
+ Specifies the path to the server certificate used by the receiver.
+ If omitted, only connections to receivers using an official
+ Google-signed cast certificate chain will be permitted.
+
-a, --android-hack:
Use the wrong RTP payload types, for compatibility with older Android
TV receivers.
@@ -369,6 +83,7 @@ int StandaloneSenderMain(int argc, char* argv[]) {
const struct option kArgumentOptions[] = {
{"remote", required_argument, nullptr, 'r'},
{"max-bitrate", required_argument, nullptr, 'm'},
+ {"server-certificate", required_argument, nullptr, 's'},
{"android-hack", no_argument, nullptr, 'a'},
{"tracing", no_argument, nullptr, 't'},
{"verbose", no_argument, nullptr, 'v'},
@@ -377,12 +92,13 @@ int StandaloneSenderMain(int argc, char* argv[]) {
bool is_verbose = false;
IPEndpoint remote_endpoint = GetDefaultEndpoint();
+ std::string server_certificate_path;
[[maybe_unused]] bool use_android_rtp_hack = false;
[[maybe_unused]] int max_bitrate = kDefaultMaxBitrate;
std::unique_ptr<TextTraceLoggingPlatform> trace_logger;
int ch = -1;
- while ((ch = getopt_long(argc, argv, "r:atvh", kArgumentOptions, nullptr)) !=
- -1) {
+ while ((ch = getopt_long(argc, argv, "r:m:s:atvh", kArgumentOptions,
+ nullptr)) != -1) {
switch (ch) {
case 'r': {
const ErrorOr<IPEndpoint> parsed_endpoint = IPEndpoint::Parse(optarg);
@@ -409,6 +125,9 @@ int StandaloneSenderMain(int argc, char* argv[]) {
return 1;
}
break;
+ case 's':
+ server_certificate_path = optarg;
+ break;
case 'a':
use_android_rtp_hack = true;
break;
@@ -437,37 +156,43 @@ int StandaloneSenderMain(int argc, char* argv[]) {
return 1;
}
-#if defined(CAST_STANDALONE_SENDER_HAVE_EXTERNAL_LIBS)
+ if (!server_certificate_path.empty()) {
+ CastTrustStore::CreateInstanceFromPemFile(
+ server_certificate_path, TrustStore::Mode::kAllowSelfSigned);
+ }
auto* const task_runner = new TaskRunnerImpl(&Clock::now);
PlatformClientPosix::Create(Clock::duration{50}, Clock::duration{50},
std::unique_ptr<TaskRunnerImpl>(task_runner));
- {
- LoopingFileSender file_sender(task_runner, path, remote_endpoint,
- max_bitrate, use_android_rtp_hack);
- // Run the event loop until SIGINT (e.g., CTRL-C at the console) or SIGTERM
- // are signaled.
- task_runner->RunUntilSignaled();
- }
+ std::unique_ptr<LoopingFileCastAgent> cast_agent;
+ task_runner->PostTask([&] {
+ cast_agent = std::make_unique<LoopingFileCastAgent>(task_runner);
+ cast_agent->Connect({remote_endpoint, path, max_bitrate,
+ true /* should_include_video */,
+ use_android_rtp_hack});
+ });
- PlatformClientPosix::ShutDown();
-
-#else
-
- OSP_LOG_INFO
- << "It compiled! However, you need to configure the build to point to "
- "external libraries in order to build a useful app.";
-
-#endif // defined(CAST_STANDALONE_SENDER_HAVE_EXTERNAL_LIBS)
+ // Run the event loop until SIGINT (e.g., CTRL-C at the console) or
+ // SIGTERM are signaled.
+ task_runner->RunUntilSignaled();
+ PlatformClientPosix::ShutDown();
return 0;
}
} // namespace
} // namespace cast
} // namespace openscreen
+#endif
int main(int argc, char* argv[]) {
+#if defined(CAST_STANDALONE_SENDER_HAVE_EXTERNAL_LIBS)
return openscreen::cast::StandaloneSenderMain(argc, argv);
+#else
+ OSP_LOG_ERROR
+ << "It compiled! However, you need to configure the build to point to "
+ "external libraries in order to build a useful app.";
+ return 1;
+#endif
}
diff --git a/chromium/third_party/openscreen/src/cast/standalone_sender/streaming_opus_encoder.cc b/chromium/third_party/openscreen/src/cast/standalone_sender/streaming_opus_encoder.cc
index ef9cc577564..b41b2a82934 100644
--- a/chromium/third_party/openscreen/src/cast/standalone_sender/streaming_opus_encoder.cc
+++ b/chromium/third_party/openscreen/src/cast/standalone_sender/streaming_opus_encoder.cc
@@ -9,6 +9,8 @@
#include <algorithm>
#include <chrono>
+#include "util/chrono_helpers.h"
+
namespace openscreen {
namespace cast {
diff --git a/chromium/third_party/openscreen/src/cast/streaming/BUILD.gn b/chromium/third_party/openscreen/src/cast/streaming/BUILD.gn
index e384705be9e..b29ac6505c8 100644
--- a/chromium/third_party/openscreen/src/cast/streaming/BUILD.gn
+++ b/chromium/third_party/openscreen/src/cast/streaming/BUILD.gn
@@ -9,6 +9,7 @@ source_set("common") {
sources = [
"answer_messages.cc",
"answer_messages.h",
+ "capture_configs.h",
"capture_recommendations.cc",
"capture_recommendations.h",
"clock_drift_smoother.cc",
@@ -23,6 +24,8 @@ source_set("common") {
"frame_crypto.h",
"frame_id.cc",
"frame_id.h",
+ "message_fields.cc",
+ "message_fields.h",
"ntp_time.cc",
"ntp_time.h",
"offer_messages.cc",
@@ -48,6 +51,8 @@ source_set("common") {
public_deps = [
"../../third_party/abseil",
"../../third_party/boringssl",
+ "../common:channel",
+ "../common/certificate/proto:certificate_proto",
]
deps = [
@@ -95,9 +100,13 @@ source_set("sender") {
"sender_packet_router.h",
"sender_report_builder.cc",
"sender_report_builder.h",
+ "sender_session.cc",
+ "sender_session.h",
]
public_deps = [ ":common" ]
+
+ deps = [ "../../util" ]
}
source_set("unittests") {
@@ -112,6 +121,7 @@ source_set("unittests") {
"expanded_value_base_unittest.cc",
"frame_collector_unittest.cc",
"frame_crypto_unittest.cc",
+ "message_fields_unittest.cc",
"mock_compound_rtcp_parser_client.h",
"mock_environment.cc",
"mock_environment.h",
@@ -127,8 +137,10 @@ source_set("unittests") {
"rtp_time_unittest.cc",
"sender_packet_router_unittest.cc",
"sender_report_unittest.cc",
+ "sender_session_unittest.cc",
"sender_unittest.cc",
"ssrc_unittest.cc",
+ "testing/simple_message_port.h",
]
deps = [
diff --git a/chromium/third_party/openscreen/src/cast/streaming/capture_configs.h b/chromium/third_party/openscreen/src/cast/streaming/capture_configs.h
new file mode 100644
index 00000000000..fd99c17cba5
--- /dev/null
+++ b/chromium/third_party/openscreen/src/cast/streaming/capture_configs.h
@@ -0,0 +1,83 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CAST_STREAMING_CAPTURE_CONFIGS_H_
+#define CAST_STREAMING_CAPTURE_CONFIGS_H_
+
+#include <string>
+#include <vector>
+
+#include "cast/streaming/constants.h"
+
+namespace openscreen {
+namespace cast {
+
+// A configuration set that can be used by the sender to capture audio, and the
+// receiver to playback audio. Used by Cast Streaming to provide an offer to the
+// receiver.
+struct AudioCaptureConfig {
+ // Audio codec represented by this configuration.
+ AudioCodec codec = AudioCodec::kOpus;
+
+ // Number of channels used by this configuration.
+ int channels = kDefaultAudioChannels;
+
+ // Average bit rate in bits per second used by this configuration. A value
+ // of "zero" suggests that the bitrate should be automatically selected by
+ // the sender.
+ int bit_rate = 0;
+
+ // Sample rate for audio RTP timebase.
+ int sample_rate = kDefaultAudioSampleRate;
+
+ // Target playout delay in milliseconds.
+ std::chrono::milliseconds target_playout_delay = kDefaultTargetPlayoutDelay;
+};
+
+// Display resolution in pixels.
+struct DisplayResolution {
+ // Width in pixels.
+ int width = 1920;
+
+ // Height in pixels.
+ int height = 1080;
+};
+
+// Frame rates are expressed as a rational number, and must be positive.
+struct FrameRate {
+ // For simple cases, the frame rate may be provided by simply setting the
+ // number to the desired value, e.g. 30 or 60FPS. Some common frame rates like
+ // 23.98 FPS (for NTSC compatibility) are represented as fractions, in this
+ // case 24000/1001.
+ int numerator = kDefaultFrameRate;
+ int denominator = 1;
+};
+
+// A configuration set that can be used by the sender to capture video, as
+// well as the receiver to playback video. Used by Cast Streaming to provide an
+// offer to the receiver.
+struct VideoCaptureConfig {
+ // Video codec represented by this configuration.
+ VideoCodec codec = VideoCodec::kVp8;
+
+ // Maximum frame rate in frames per second.
+ FrameRate max_frame_rate;
+
+ // Number specifying the maximum bit rate for this stream. A value of
+ // zero means that the maximum bit rate should be automatically selected by
+ // the sender.
+ int max_bit_rate = 0;
+
+ // Resolutions to be offered to the receiver. At least one resolution
+ // must be provided.
+ std::vector<DisplayResolution> resolutions;
+
+ // Target playout delay in milliseconds.
+ std::chrono::milliseconds target_playout_delay = kDefaultTargetPlayoutDelay;
+};
+
+} // namespace cast
+} // namespace openscreen
+
+#endif // CAST_STREAMING_CAPTURE_CONFIGS_H_
diff --git a/chromium/third_party/openscreen/src/cast/streaming/compound_rtcp_builder.cc b/chromium/third_party/openscreen/src/cast/streaming/compound_rtcp_builder.cc
index fed38a32c87..7a133331f54 100644
--- a/chromium/third_party/openscreen/src/cast/streaming/compound_rtcp_builder.cc
+++ b/chromium/third_party/openscreen/src/cast/streaming/compound_rtcp_builder.cc
@@ -277,7 +277,7 @@ void CompoundRtcpBuilder::AppendCastFeedbackAckFields(
if (!acks_for_next_packet_.empty()) {
OSP_DCHECK(AreElementsSortedAndUnique(acks_for_next_packet_));
const FrameId first_frame_id = checkpoint_frame_id_ + 2;
- for (const FrameId frame_id : acks_for_next_packet_) {
+ for (const FrameId& frame_id : acks_for_next_packet_) {
const int bit_index = frame_id - first_frame_id;
if (bit_index < 0) {
continue;
diff --git a/chromium/third_party/openscreen/src/cast/streaming/constants.h b/chromium/third_party/openscreen/src/cast/streaming/constants.h
index 4a8d526e072..65cb2a1a9b9 100644
--- a/chromium/third_party/openscreen/src/cast/streaming/constants.h
+++ b/chromium/third_party/openscreen/src/cast/streaming/constants.h
@@ -49,7 +49,33 @@ constexpr int kRequiredNetworkPacketSize = 256;
// The spec declares RTP timestamps must always have a timebase of 90000 ticks
// per second for video.
-using kVideoTimebase = std::ratio<1, 90000>;
+constexpr int kRtpVideoTimebase = 90000;
+
+// Minimum resolution is 320x240.
+constexpr int kMinVideoHeight = 240;
+constexpr int kMinVideoWidth = 320;
+
+// The default frame rate for capture options is 30FPS.
+constexpr int kDefaultFrameRate = 30;
+
+// The default audio sample rate is 48kHz, slightly higher than standard
+// consumer audio.
+constexpr int kDefaultAudioSampleRate = 48000;
+
+// The default audio number of channels is set to stereo.
+constexpr int kDefaultAudioChannels = 2;
+
+// TODO(jophba): migrate to discovering a randomly generated streaming
+// sender id. This will require communicating the ID to the sender so that
+// it can send messages appropriately.
+constexpr char kDefaultStreamingReceiverSenderId[] = "receiver-12345";
+
+// Codecs known and understood by cast senders and receivers. Note: receivers
+// are required to implement the following codecs to be Cast V2 compliant: H264,
+// VP8, AAC, Opus. Senders have to implement at least one codec for audio and
+// video to start a session.
+enum class AudioCodec { kAac, kOpus };
+enum class VideoCodec { kH264, kVp8, kHevc, kVp9 };
} // namespace cast
} // namespace openscreen
diff --git a/chromium/third_party/openscreen/src/cast/streaming/frame_crypto.cc b/chromium/third_party/openscreen/src/cast/streaming/frame_crypto.cc
index 4d506d5eb7e..ca39e95015c 100644
--- a/chromium/third_party/openscreen/src/cast/streaming/frame_crypto.cc
+++ b/chromium/third_party/openscreen/src/cast/streaming/frame_crypto.cc
@@ -5,12 +5,14 @@
#include "cast/streaming/frame_crypto.h"
#include <random>
+#include <utility>
#include "openssl/crypto.h"
#include "openssl/err.h"
#include "openssl/rand.h"
#include "util/big_endian.h"
#include "util/crypto/openssl_util.h"
+#include "util/crypto/random_bytes.h"
namespace openscreen {
namespace cast {
@@ -102,18 +104,5 @@ void FrameCrypto::EncryptCommon(FrameId frame_id,
aes_nonce.data(), ecount_buf.data(), &block_offset);
}
-// static
-std::array<uint8_t, 16> FrameCrypto::GenerateRandomBytes() {
- std::array<uint8_t, 16> result;
- const int return_code = RAND_bytes(result.data(), sizeof(result));
- if (return_code != 1) {
- ClearOpenSSLERRStack(CURRENT_LOCATION);
- OSP_LOG_FATAL
- << "Failure when generating random bytes; unsafe to continue.";
- OSP_NOTREACHED();
- }
- return result;
-}
-
} // namespace cast
} // namespace openscreen
diff --git a/chromium/third_party/openscreen/src/cast/streaming/frame_crypto.h b/chromium/third_party/openscreen/src/cast/streaming/frame_crypto.h
index 35ee9787cb1..a86153e3e73 100644
--- a/chromium/third_party/openscreen/src/cast/streaming/frame_crypto.h
+++ b/chromium/third_party/openscreen/src/cast/streaming/frame_crypto.h
@@ -72,9 +72,6 @@ class FrameCrypto {
return encrypted_frame.data.size();
}
- // Returns random bytes from a cryptographically-secure RNG source.
- static std::array<uint8_t, 16> GenerateRandomBytes();
-
private:
// The 244-byte AES_KEY struct, derived from the |aes_key| passed to the ctor,
// and initialized by boringssl's AES_set_encrypt_key() function.
diff --git a/chromium/third_party/openscreen/src/cast/streaming/frame_crypto_unittest.cc b/chromium/third_party/openscreen/src/cast/streaming/frame_crypto_unittest.cc
index 7ac8d5cf2e5..a845ed0333d 100644
--- a/chromium/third_party/openscreen/src/cast/streaming/frame_crypto_unittest.cc
+++ b/chromium/third_party/openscreen/src/cast/streaming/frame_crypto_unittest.cc
@@ -9,6 +9,7 @@
#include <vector>
#include "gtest/gtest.h"
+#include "util/crypto/random_bytes.h"
namespace openscreen {
namespace cast {
@@ -28,8 +29,8 @@ TEST(FrameCryptoTest, EncryptsAndDecryptsFrames) {
frame1.frame_id = frame0.frame_id + 1;
frame1.data = frame0.data;
- const std::array<uint8_t, 16> key = FrameCrypto::GenerateRandomBytes();
- const std::array<uint8_t, 16> iv = FrameCrypto::GenerateRandomBytes();
+ const std::array<uint8_t, 16> key = GenerateRandomBytes16();
+ const std::array<uint8_t, 16> iv = GenerateRandomBytes16();
EXPECT_NE(0, memcmp(key.data(), iv.data(), sizeof(key)));
const FrameCrypto crypto(key, iv);
diff --git a/chromium/third_party/openscreen/src/cast/streaming/message_fields.cc b/chromium/third_party/openscreen/src/cast/streaming/message_fields.cc
new file mode 100644
index 00000000000..d55285194af
--- /dev/null
+++ b/chromium/third_party/openscreen/src/cast/streaming/message_fields.cc
@@ -0,0 +1,71 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cast/streaming/message_fields.h"
+
+#include <array>
+#include <utility>
+
+#include "util/osp_logging.h"
+
+namespace openscreen {
+namespace cast {
+namespace {
+
+constexpr std::array<std::pair<const char*, AudioCodec>, 2> kAudioCodecNames{
+ {{"aac", AudioCodec::kAac}, {"opus", AudioCodec::kOpus}}};
+
+constexpr std::array<std::pair<const char*, VideoCodec>, 4> kVideoCodecNames{
+ {{"h264", VideoCodec::kH264},
+ {"vp8", VideoCodec::kVp8},
+ {"hevc", VideoCodec::kHevc},
+ {"vp9", VideoCodec::kVp9}}};
+
+constexpr char kUnknownCodecError[] = "Codec not accounted for in name array.";
+
+template <typename T, size_t size>
+const char* GetCodecName(
+ const std::array<std::pair<const char*, T>, size>& codecs,
+ T codec) {
+ for (auto pair : codecs) {
+ if (pair.second == codec) {
+ return pair.first;
+ }
+ }
+ OSP_NOTREACHED() << kUnknownCodecError;
+ return {};
+}
+
+template <typename T, size_t size>
+T GetCodec(const std::array<std::pair<const char*, T>, size>& codecs,
+ absl::string_view name) {
+ for (auto pair : codecs) {
+ if (pair.first == name) {
+ return pair.second;
+ }
+ }
+ OSP_NOTREACHED() << kUnknownCodecError;
+ return {};
+}
+
+} // namespace
+
+const char* CodecToString(AudioCodec codec) {
+ return GetCodecName(kAudioCodecNames, codec);
+}
+
+AudioCodec StringToAudioCodec(absl::string_view name) {
+ return GetCodec(kAudioCodecNames, name);
+}
+
+const char* CodecToString(VideoCodec codec) {
+ return GetCodecName(kVideoCodecNames, codec);
+}
+
+VideoCodec StringToVideoCodec(absl::string_view name) {
+ return GetCodec(kVideoCodecNames, name);
+}
+
+} // namespace cast
+} // namespace openscreen
diff --git a/chromium/third_party/openscreen/src/cast/streaming/message_fields.h b/chromium/third_party/openscreen/src/cast/streaming/message_fields.h
new file mode 100644
index 00000000000..ef7b742f5c2
--- /dev/null
+++ b/chromium/third_party/openscreen/src/cast/streaming/message_fields.h
@@ -0,0 +1,51 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CAST_STREAMING_MESSAGE_FIELDS_H_
+#define CAST_STREAMING_MESSAGE_FIELDS_H_
+
+#include <string>
+
+#include "absl/strings/string_view.h"
+#include "cast/streaming/constants.h"
+
+namespace openscreen {
+namespace cast {
+
+/// NOTE: Constants here are all taken from the Cast V2: Mirroring Control
+/// Protocol specification.
+
+// Namespace for OFFER/ANSWER messages.
+constexpr char kCastWebrtcNamespace[] = "urn:x-cast:com.google.cast.webrtc";
+
+// JSON message field values specific to the Sender Session.
+constexpr char kMessageType[] = "type";
+constexpr char kMessageTypeOffer[] = "OFFER";
+constexpr char kMessageTypeAnswer[] = "ANSWER";
+
+// List of OFFER message fields.
+constexpr char kOfferMessageBody[] = "offer";
+constexpr char kKeyType[] = "type";
+constexpr char kSequenceNumber[] = "seqNum";
+
+/// ANSWER message fields.
+constexpr char kAnswerMessageBody[] = "answer";
+constexpr char kResult[] = "result";
+constexpr char kResultOk[] = "ok";
+constexpr char kResultError[] = "error";
+constexpr char kErrorMessageBody[] = "error";
+constexpr char kErrorCode[] = "code";
+constexpr char kErrorDescription[] = "description";
+
+// Conversion methods for codec message fields.
+const char* CodecToString(AudioCodec codec);
+AudioCodec StringToAudioCodec(absl::string_view name);
+
+const char* CodecToString(VideoCodec codec);
+VideoCodec StringToVideoCodec(absl::string_view name);
+
+} // namespace cast
+} // namespace openscreen
+
+#endif // CAST_STREAMING_MESSAGE_FIELDS_H_
diff --git a/chromium/third_party/openscreen/src/cast/streaming/message_fields_unittest.cc b/chromium/third_party/openscreen/src/cast/streaming/message_fields_unittest.cc
new file mode 100644
index 00000000000..f7eedf9c12f
--- /dev/null
+++ b/chromium/third_party/openscreen/src/cast/streaming/message_fields_unittest.cc
@@ -0,0 +1,36 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cast/streaming/message_fields.h"
+
+#include <array>
+#include <cstring>
+#include <vector>
+
+#include "gtest/gtest.h"
+
+namespace openscreen {
+namespace cast {
+namespace {
+
+// NOTE: We don't do an exhaustive check of all values here, to avoid
+// unnecessary duplication, but want to ensure that lookup is working properly.
+TEST(MessageFieldsTest, CanParseEnumToString) {
+ EXPECT_STREQ("aac", CodecToString(AudioCodec::kAac));
+ EXPECT_STREQ("vp8", CodecToString(VideoCodec::kVp8));
+}
+
+TEST(MessageFieldsTest, CanStringToEnum) {
+ EXPECT_EQ(AudioCodec::kOpus, StringToAudioCodec("opus"));
+ EXPECT_EQ(VideoCodec::kHevc, StringToVideoCodec("hevc"));
+}
+
+TEST(MessageFieldsTest, Identity) {
+ EXPECT_STREQ("opus", CodecToString(StringToAudioCodec("opus")));
+ EXPECT_STREQ("vp8", CodecToString(StringToVideoCodec("vp8")));
+}
+
+} // namespace
+} // namespace cast
+} // namespace openscreen
diff --git a/chromium/third_party/openscreen/src/cast/streaming/message_port.h b/chromium/third_party/openscreen/src/cast/streaming/message_port.h
deleted file mode 100644
index f44a808dbf1..00000000000
--- a/chromium/third_party/openscreen/src/cast/streaming/message_port.h
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CAST_STREAMING_MESSAGE_PORT_H_
-#define CAST_STREAMING_MESSAGE_PORT_H_
-
-#include "absl/strings/string_view.h"
-#include "platform/base/error.h"
-
-namespace openscreen {
-namespace cast {
-
-// This interface is intended to provide an abstraction for communicating
-// cast messages across a pipe with guaranteed delivery. This is used to
-// decouple the cast receiver session (and potentially other classes) from any
-// network implementation.
-class MessagePort {
- public:
- class Client {
- public:
- virtual void OnMessage(absl::string_view sender_id,
- absl::string_view message_namespace,
- absl::string_view message) = 0;
- virtual void OnError(Error error) = 0;
- };
-
- virtual ~MessagePort() = default;
- virtual void SetClient(Client* client) = 0;
- virtual void PostMessage(absl::string_view sender_id,
- absl::string_view message_namespace,
- absl::string_view message) = 0;
-};
-
-} // namespace cast
-} // namespace openscreen
-
-#endif // CAST_STREAMING_MESSAGE_PORT_H_
diff --git a/chromium/third_party/openscreen/src/cast/streaming/offer_messages.cc b/chromium/third_party/openscreen/src/cast/streaming/offer_messages.cc
index ff6845a31f7..179037e604e 100644
--- a/chromium/third_party/openscreen/src/cast/streaming/offer_messages.cc
+++ b/chromium/third_party/openscreen/src/cast/streaming/offer_messages.cc
@@ -295,7 +295,7 @@ ErrorOr<Json::Value> Stream::ToJson() const {
root["targetDelay"] = static_cast<int>(target_delay.count());
root["aesKey"] = HexEncode(aes_key);
root["aesIvMask"] = HexEncode(aes_iv_mask);
- root["ReceiverRtcpEventLog"] = receiver_rtcp_event_log;
+ root["receiverRtcpEventLog"] = receiver_rtcp_event_log;
root["receiverRtcpDscp"] = receiver_rtcp_dscp;
root["timeBase"] = "1/" + std::to_string(rtp_timebase);
return root;
@@ -371,6 +371,9 @@ ErrorOr<Json::Value> VideoStream::ToJson() const {
// static
ErrorOr<Offer> Offer::Parse(const Json::Value& root) {
+ if (!root.isObject()) {
+ return json::CreateParseError("null offer");
+ }
CastMode cast_mode = CastMode::Parse(root["castMode"].asString());
const ErrorOr<bool> get_status = json::ParseBool(root, "receiverGetStatus");
diff --git a/chromium/third_party/openscreen/src/cast/streaming/packet_receive_stats_tracker_unittest.cc b/chromium/third_party/openscreen/src/cast/streaming/packet_receive_stats_tracker_unittest.cc
index eb1b45c7118..3d2f21e932b 100644
--- a/chromium/third_party/openscreen/src/cast/streaming/packet_receive_stats_tracker_unittest.cc
+++ b/chromium/third_party/openscreen/src/cast/streaming/packet_receive_stats_tracker_unittest.cc
@@ -15,8 +15,6 @@ namespace openscreen {
namespace cast {
namespace {
-constexpr int kSomeRtpTimebase = static_cast<int>(kVideoTimebase::den);
-
// Returns a RtcpReportBlock with all fields set to known values to see how the
// fields are modified by functions called during the tests.
RtcpReportBlock GetSentinel() {
@@ -66,7 +64,7 @@ RtcpReportBlock GetSentinel() {
} while (false)
TEST(PacketReceiveStatsTrackerTest, DoesNotPopulateReportWithoutData) {
- PacketReceiveStatsTracker tracker(kSomeRtpTimebase);
+ PacketReceiveStatsTracker tracker(kRtpVideoTimebase);
RtcpReportBlock report = GetSentinel();
tracker.PopulateNextReport(&report);
EXPECT_FIELDS_NOT_POPULATED(report);
@@ -78,7 +76,7 @@ TEST(PacketReceiveStatsTrackerTest, PopulatesReportWithOnePacketTracked) {
RtpTimeTicks() + RtpTimeDelta::FromTicks(42);
constexpr auto kArrivalTime = Clock::time_point() + seconds(3600);
- PacketReceiveStatsTracker tracker(kSomeRtpTimebase);
+ PacketReceiveStatsTracker tracker(kRtpVideoTimebase);
tracker.OnReceivedValidRtpPacket(kSequenceNumber, kRtpTimestamp,
kArrivalTime);
@@ -99,14 +97,14 @@ TEST(PacketReceiveStatsTrackerTest, WhenReceivingAllPackets) {
RtpTimeTicks() + RtpTimeDelta::FromTicks(42);
constexpr auto kFirstArrivalTime = Clock::time_point() + seconds(3600);
- PacketReceiveStatsTracker tracker(kSomeRtpTimebase);
+ PacketReceiveStatsTracker tracker(kRtpVideoTimebase);
// Record 10 packets arrived exactly one second apart with media timestamps
// also exactly one second apart.
for (int i = 0; i < 10; ++i) {
tracker.OnReceivedValidRtpPacket(
kFirstSequenceNumber + i,
- kFirstRtpTimestamp + RtpTimeDelta::FromTicks(kSomeRtpTimebase) * i,
+ kFirstRtpTimestamp + RtpTimeDelta::FromTicks(kRtpVideoTimebase) * i,
kFirstArrivalTime + seconds(i));
}
@@ -133,7 +131,7 @@ TEST(PacketReceiveStatsTrackerTest, WhenReceivingAboutHalfThePackets) {
RtpTimeTicks() + RtpTimeDelta::FromTicks(99);
constexpr auto kFirstArrivalTime = Clock::time_point() + seconds(8888);
- PacketReceiveStatsTracker tracker(kSomeRtpTimebase);
+ PacketReceiveStatsTracker tracker(kRtpVideoTimebase);
// Record 10 packet arrivals whose sequence numbers step by 2, which should
// indicate half of the packets didn't arrive.
@@ -143,7 +141,7 @@ TEST(PacketReceiveStatsTrackerTest, WhenReceivingAboutHalfThePackets) {
for (int i = 0; i < 10; ++i) {
tracker.OnReceivedValidRtpPacket(
kFirstSequenceNumber + (i * 2 + 1),
- kFirstRtpTimestamp + RtpTimeDelta::FromTicks(kSomeRtpTimebase) * i,
+ kFirstRtpTimestamp + RtpTimeDelta::FromTicks(kRtpVideoTimebase) * i,
kFirstArrivalTime + seconds(i));
}
@@ -168,13 +166,13 @@ TEST(PacketReceiveStatsTrackerTest, ComputesJitterCorrectly) {
// timestamps are progressing 2 seconds forward. Thus, the jitter calculation
// should gradually converge towards a difference of one second.
constexpr auto kTrueJitter = Clock::to_duration(seconds(1));
- PacketReceiveStatsTracker tracker(kSomeRtpTimebase);
+ PacketReceiveStatsTracker tracker(kRtpVideoTimebase);
Clock::duration last_diff = Clock::duration::max();
for (int i = 0; i < 100; ++i) {
tracker.OnReceivedValidRtpPacket(
kFirstSequenceNumber + i,
kFirstRtpTimestamp +
- RtpTimeDelta::FromTicks(kSomeRtpTimebase) * (i * 2),
+ RtpTimeDelta::FromTicks(kRtpVideoTimebase) * (i * 2),
kFirstArrivalTime + seconds(i));
// Expect that the jitter is becoming closer to the actual value in each
@@ -182,7 +180,7 @@ TEST(PacketReceiveStatsTrackerTest, ComputesJitterCorrectly) {
RtcpReportBlock report;
tracker.PopulateNextReport(&report);
const auto diff = kTrueJitter - report.jitter.ToDuration<Clock::duration>(
- kSomeRtpTimebase);
+ kRtpVideoTimebase);
EXPECT_LT(diff, last_diff);
last_diff = diff;
}
@@ -193,8 +191,8 @@ TEST(PacketReceiveStatsTrackerTest, ComputesJitterCorrectly) {
// to that value.
RtcpReportBlock report;
tracker.PopulateNextReport(&report);
- const auto diff =
- kTrueJitter - report.jitter.ToDuration<Clock::duration>(kSomeRtpTimebase);
+ const auto diff = kTrueJitter - report.jitter.ToDuration<Clock::duration>(
+ kRtpVideoTimebase);
constexpr auto kMaxDiffAtEnd = Clock::to_duration(milliseconds(2));
EXPECT_NEAR(0, diff.count(), kMaxDiffAtEnd.count());
}
diff --git a/chromium/third_party/openscreen/src/cast/streaming/receiver.cc b/chromium/third_party/openscreen/src/cast/streaming/receiver.cc
index d4c86da437c..d62d625147a 100644
--- a/chromium/third_party/openscreen/src/cast/streaming/receiver.cc
+++ b/chromium/third_party/openscreen/src/cast/streaming/receiver.cc
@@ -29,9 +29,10 @@ namespace cast {
Receiver::Receiver(Environment* environment,
ReceiverPacketRouter* packet_router,
- const SessionConfig& config)
+ SessionConfig config)
: now_(environment->now_function()),
packet_router_(packet_router),
+ config_(config),
rtcp_session_(config.sender_ssrc, config.receiver_ssrc, now_()),
rtcp_parser_(&rtcp_session_),
rtcp_builder_(&rtcp_session_),
diff --git a/chromium/third_party/openscreen/src/cast/streaming/receiver.h b/chromium/third_party/openscreen/src/cast/streaming/receiver.h
index b4c53868b03..abdc1852bf0 100644
--- a/chromium/third_party/openscreen/src/cast/streaming/receiver.h
+++ b/chromium/third_party/openscreen/src/cast/streaming/receiver.h
@@ -25,6 +25,7 @@
#include "cast/streaming/rtcp_session.h"
#include "cast/streaming/rtp_packet_parser.h"
#include "cast/streaming/sender_report_parser.h"
+#include "cast/streaming/session_config.h"
#include "cast/streaming/ssrc.h"
#include "platform/api/time.h"
#include "util/alarm.h"
@@ -34,7 +35,6 @@ namespace cast {
struct EncodedFrame;
class ReceiverPacketRouter;
-struct SessionConfig;
// The Cast Streaming Receiver, a peer corresponding to some Cast Streaming
// Sender at the other end of a network link.
@@ -125,11 +125,12 @@ class Receiver {
// is started).
Receiver(Environment* environment,
ReceiverPacketRouter* packet_router,
- const SessionConfig& config);
+ SessionConfig config);
~Receiver();
- Ssrc ssrc() const { return rtcp_session_.receiver_ssrc(); }
+ const SessionConfig& config() const { return config_; }
int rtp_timebase() const { return rtp_timebase_; }
+ Ssrc ssrc() const { return rtcp_session_.receiver_ssrc(); }
// Set the Consumer receiving notifications when new frames are ready for
// consumption. Frames received before this method is called will remain in
@@ -257,6 +258,7 @@ class Receiver {
const ClockNowFunctionPtr now_;
ReceiverPacketRouter* const packet_router_;
+ const SessionConfig config_;
RtcpSession rtcp_session_;
SenderReportParser rtcp_parser_;
CompoundRtcpBuilder rtcp_builder_;
diff --git a/chromium/third_party/openscreen/src/cast/streaming/receiver_session.cc b/chromium/third_party/openscreen/src/cast/streaming/receiver_session.cc
index e692904f1f4..4cabbc853d8 100644
--- a/chromium/third_party/openscreen/src/cast/streaming/receiver_session.cc
+++ b/chromium/third_party/openscreen/src/cast/streaming/receiver_session.cc
@@ -4,14 +4,16 @@
#include "cast/streaming/receiver_session.h"
+#include <algorithm>
#include <chrono>
#include <string>
#include <utility>
#include "absl/strings/match.h"
#include "absl/strings/numbers.h"
+#include "cast/common/public/message_port.h"
#include "cast/streaming/environment.h"
-#include "cast/streaming/message_port.h"
+#include "cast/streaming/message_fields.h"
#include "cast/streaming/offer_messages.h"
#include "cast/streaming/receiver.h"
#include "util/json/json_helpers.h"
@@ -20,63 +22,12 @@
namespace openscreen {
namespace cast {
-/// NOTE: Constants here are all taken from the Cast V2: Mirroring Control
-// JSON message field values specific to the Receiver Session.
-static constexpr char kMessageTypeOffer[] = "OFFER";
-
-// List of OFFER message fields.
-static constexpr char kOfferMessageBody[] = "offer";
-static constexpr char kKeyType[] = "type";
-static constexpr char kSequenceNumber[] = "seqNum";
-
-/// Protocol specification: http://goto.google.com/mirroring-control-protocol
-// TODO(jophba): document the protocol in a public repository.
-static constexpr char kMessageKeyType[] = "type";
-static constexpr char kMessageTypeAnswer[] = "ANSWER";
-
-/// ANSWER message fields.
-static constexpr char kAnswerMessageBody[] = "answer";
-static constexpr char kResult[] = "result";
-static constexpr char kResultOk[] = "ok";
-static constexpr char kResultError[] = "error";
-static constexpr char kErrorMessageBody[] = "error";
-static constexpr char kErrorCode[] = "code";
-static constexpr char kErrorDescription[] = "description";
-
// Using statements for constructor readability.
using Preferences = ReceiverSession::Preferences;
using ConfiguredReceivers = ReceiverSession::ConfiguredReceivers;
namespace {
-std::string CodecToString(ReceiverSession::AudioCodec codec) {
- switch (codec) {
- case ReceiverSession::AudioCodec::kAac:
- return "aac";
- case ReceiverSession::AudioCodec::kOpus:
- return "opus";
- default:
- OSP_NOTREACHED() << "Codec not accounted for in switch statement.";
- return {};
- }
-}
-
-std::string CodecToString(ReceiverSession::VideoCodec codec) {
- switch (codec) {
- case ReceiverSession::VideoCodec::kH264:
- return "h264";
- case ReceiverSession::VideoCodec::kVp8:
- return "vp8";
- case ReceiverSession::VideoCodec::kHevc:
- return "hevc";
- case ReceiverSession::VideoCodec::kVp9:
- return "vp9";
- default:
- OSP_NOTREACHED() << "Codec not accounted for in switch statement.";
- return {};
- }
-}
-
template <typename Stream, typename Codec>
const Stream* SelectStream(const std::vector<Codec>& preferred_codecs,
const std::vector<Stream>& offered_streams) {
@@ -95,7 +46,7 @@ const Stream* SelectStream(const std::vector<Codec>& preferred_codecs,
// Helper method that creates an invalid Answer response.
Json::Value CreateInvalidAnswerMessage(Error error) {
Json::Value message_root;
- message_root[kMessageKeyType] = kMessageTypeAnswer;
+ message_root[kMessageType] = kMessageTypeAnswer;
message_root[kResult] = kResultError;
message_root[kErrorMessageBody][kErrorCode] = static_cast<int>(error.code());
message_root[kErrorMessageBody][kErrorDescription] = error.message();
@@ -107,12 +58,16 @@ Json::Value CreateInvalidAnswerMessage(Error error) {
Json::Value CreateAnswerMessage(const Answer& answer) {
OSP_DCHECK(answer.IsValid());
Json::Value message_root;
- message_root[kMessageKeyType] = kMessageTypeAnswer;
+ message_root[kMessageType] = kMessageTypeAnswer;
message_root[kAnswerMessageBody] = answer.ToJson();
message_root[kResult] = kResultOk;
return message_root;
}
+DisplayResolution ToDisplayResolution(const Resolution& resolution) {
+ return DisplayResolution{resolution.width, resolution.height};
+}
+
} // namespace
ReceiverSession::Client::~Client() = default;
@@ -147,17 +102,17 @@ ReceiverSession::ReceiverSession(Client* const client,
OSP_DCHECK(message_port_);
OSP_DCHECK(environment_);
- message_port_->SetClient(this);
+ message_port_->SetClient(this, kDefaultStreamingReceiverSenderId);
}
ReceiverSession::~ReceiverSession() {
ResetReceivers(Client::kEndOfSession);
- message_port_->SetClient(nullptr);
+ message_port_->ResetClient();
}
-void ReceiverSession::OnMessage(absl::string_view sender_id,
- absl::string_view message_namespace,
- absl::string_view message) {
+void ReceiverSession::OnMessage(const std::string& sender_id,
+ const std::string& message_namespace,
+ const std::string& message) {
ErrorOr<Json::Value> message_json = json::Parse(message);
if (!message_json) {
@@ -167,7 +122,6 @@ void ReceiverSession::OnMessage(absl::string_view sender_id,
}
OSP_DVLOG << "Received a message: " << message;
- // TODO(jophba): add sender connected/disconnected messaging.
int sequence_number;
if (!json::ParseAndValidateInt(message_json.value()[kSequenceNumber],
&sequence_number)) {
@@ -185,12 +139,6 @@ void ReceiverSession::OnMessage(absl::string_view sender_id,
sequence_number};
if (key == kMessageTypeOffer) {
parsed_message.body = std::move(message_json.value()[kOfferMessageBody]);
- if (parsed_message.body.isNull()) {
- client_->OnError(this, Error(Error::Code::kJsonParseError,
- "Received offer missing offer body"));
- OSP_DLOG_WARN << "Invalid message offer body";
- return;
- }
OnOffer(&parsed_message);
}
}
@@ -204,6 +152,9 @@ void ReceiverSession::OnOffer(Message* message) {
if (!offer) {
client_->OnError(this, offer.error());
OSP_DLOG_WARN << "Could not parse offer" << offer.error();
+ message->body = CreateInvalidAnswerMessage(
+ Error(Error::Code::kParseError, "Failed to parse malformed OFFER"));
+ SendMessage(message);
return;
}
@@ -249,16 +200,14 @@ void ReceiverSession::OnOffer(Message* message) {
SendMessage(message);
}
-std::pair<SessionConfig, std::unique_ptr<Receiver>>
-ReceiverSession::ConstructReceiver(const Stream& stream) {
+std::unique_ptr<Receiver> ReceiverSession::ConstructReceiver(
+ const Stream& stream) {
SessionConfig config = {stream.ssrc, stream.ssrc + 1,
stream.rtp_timebase, stream.channels,
stream.target_delay, stream.aes_key,
stream.aes_iv_mask};
- auto receiver =
- std::make_unique<Receiver>(environment_, &packet_router_, config);
-
- return std::make_pair(std::move(config), std::move(receiver));
+ return std::make_unique<Receiver>(environment_, &packet_router_,
+ std::move(config));
}
ConfiguredReceivers ReceiverSession::SpawnReceivers(const AudioStream* audio,
@@ -266,25 +215,45 @@ ConfiguredReceivers ReceiverSession::SpawnReceivers(const AudioStream* audio,
OSP_DCHECK(audio || video);
ResetReceivers(Client::kRenegotiated);
- absl::optional<ConfiguredReceiver<AudioStream>> audio_receiver;
- absl::optional<ConfiguredReceiver<VideoStream>> video_receiver;
-
+ AudioCaptureConfig audio_config;
+ absl::optional<ConfiguredReceiver<AudioStream>> deprecated_audio;
if (audio) {
- auto audio_pair = ConstructReceiver(audio->stream);
- current_audio_receiver_ = std::move(audio_pair.second);
- audio_receiver.emplace(ConfiguredReceiver<AudioStream>{
- current_audio_receiver_.get(), std::move(audio_pair.first), *audio});
+ current_audio_receiver_ = ConstructReceiver(audio->stream);
+ audio_config = AudioCaptureConfig{
+ StringToAudioCodec(audio->stream.codec_name), audio->stream.channels,
+ audio->bit_rate, audio->stream.rtp_timebase,
+ audio->stream.target_delay};
+ deprecated_audio.emplace(ConfiguredReceiver<AudioStream>{
+ current_audio_receiver_.get(), current_audio_receiver_->config(),
+ *audio});
}
+ VideoCaptureConfig video_config;
+ absl::optional<ConfiguredReceiver<VideoStream>> deprecated_video;
if (video) {
- auto video_pair = ConstructReceiver(video->stream);
- current_video_receiver_ = std::move(video_pair.second);
- video_receiver.emplace(ConfiguredReceiver<VideoStream>{
- current_video_receiver_.get(), std::move(video_pair.first), *video});
+ current_video_receiver_ = ConstructReceiver(video->stream);
+ std::vector<DisplayResolution> display_resolutions;
+ std::transform(video->resolutions.begin(), video->resolutions.end(),
+ std::back_inserter(display_resolutions),
+ ToDisplayResolution);
+ video_config =
+ VideoCaptureConfig{StringToVideoCodec(video->stream.codec_name),
+ FrameRate{video->max_frame_rate.numerator,
+ video->max_frame_rate.denominator},
+ video->max_bit_rate, std::move(display_resolutions),
+ video->stream.target_delay};
+ deprecated_video.emplace(ConfiguredReceiver<VideoStream>{
+ current_video_receiver_.get(), current_video_receiver_->config(),
+ *video});
}
- return ConfiguredReceivers{std::move(audio_receiver),
- std::move(video_receiver)};
+ return ConfiguredReceivers{
+ current_audio_receiver_.get(), std::move(audio_config),
+ current_video_receiver_.get(), std::move(video_config),
+
+ // TODO(crbug.com/1132109): Remove deprecated ConfiguredReceiver fields
+ // after downstream migration
+ std::move(deprecated_audio), std::move(deprecated_video)};
}
void ReceiverSession::ResetReceivers(Client::ReceiversDestroyingReason reason) {
diff --git a/chromium/third_party/openscreen/src/cast/streaming/receiver_session.h b/chromium/third_party/openscreen/src/cast/streaming/receiver_session.h
index c9fb691190b..a45add7c014 100644
--- a/chromium/third_party/openscreen/src/cast/streaming/receiver_session.h
+++ b/chromium/third_party/openscreen/src/cast/streaming/receiver_session.h
@@ -10,13 +10,11 @@
#include <utility>
#include <vector>
-// TODO(jophba): remove public abseil dependencies. Will require modifying
-// either Optional or ConfiguredReceivers, as the compiler currently has an
-// error.
#include "absl/strings/string_view.h"
#include "absl/types/optional.h"
+#include "cast/common/public/message_port.h"
#include "cast/streaming/answer_messages.h"
-#include "cast/streaming/message_port.h"
+#include "cast/streaming/capture_configs.h"
#include "cast/streaming/offer_messages.h"
#include "cast/streaming/receiver_packet_router.h"
#include "cast/streaming/session_config.h"
@@ -25,17 +23,14 @@
namespace openscreen {
namespace cast {
-class CastSocket;
class Environment;
class Receiver;
-class VirtualConnectionRouter;
-struct VirtualConnection;
class ReceiverSession final : public MessagePort::Client {
public:
- // A small helper struct that contains all of the information necessary for
- // a configured receiver, including a receiver, its session config, and the
- // stream selected from the OFFER message to instantiate the receiver.
+ // DEPRECATED.
+ // TODO(crbug.com/1132097): Remove deprecated ConfiguredReceiver fields after
+ // downstream migration
template <typename T>
struct ConfiguredReceiver {
Receiver* receiver;
@@ -54,10 +49,19 @@ class ReceiverSession final : public MessagePort::Client {
// ReceiverSession, not the Client, and references to these pointers must be
// cleared before a call to Client::OnReceiversDestroying() returns.
- // If the receiver is audio- or video-only, either of the receivers
- // may be nullptr. However, in the majority of cases they will be populated.
- // TODO(jophba): remove AudioStream, VideoStream from public API.
- // TODO(jophba): remove absl::optional from public API.
+ // If the receiver is audio- or video-only, or we failed to negotiate
+ // an acceptable session configuration with the sender, then either of the
+ // receivers may be nullptr. In this case, the associated config is default
+ // initialized and should be ignored.
+ Receiver* audio_receiver;
+ AudioCaptureConfig audio_config;
+
+ Receiver* video_receiver;
+ VideoCaptureConfig video_config;
+
+ // DEPRECATED
+ // TODO(crbug.com/1132097): Remove deprecated ConfiguredReceiver fields
+ // after downstream migration
absl::optional<ConfiguredReceiver<AudioStream>> audio;
absl::optional<ConfiguredReceiver<VideoStream>> video;
};
@@ -89,11 +93,6 @@ class ReceiverSession final : public MessagePort::Client {
virtual ~Client();
};
- // The embedder has the option of providing a list of prioritized
- // preferences for selecting from the offer.
- enum class AudioCodec { kAac, kOpus };
- enum class VideoCodec { kH264, kVp8, kHevc, kVp9 };
-
// Note: embedders are required to implement the following
// codecs to be Cast V2 compliant: H264, VP8, AAC, Opus.
struct Preferences {
@@ -131,9 +130,9 @@ class ReceiverSession final : public MessagePort::Client {
~ReceiverSession();
// MessagePort::Client overrides
- void OnMessage(absl::string_view sender_id,
- absl::string_view message_namespace,
- absl::string_view message) override;
+ void OnMessage(const std::string& sender_id,
+ const std::string& message_namespace,
+ const std::string& message) override;
void OnError(Error error) override;
private:
@@ -148,8 +147,7 @@ class ReceiverSession final : public MessagePort::Client {
void OnOffer(Message* message);
// Used by SpawnReceivers to generate a receiver for a specific stream.
- std::pair<SessionConfig, std::unique_ptr<Receiver>> ConstructReceiver(
- const Stream& stream);
+ std::unique_ptr<Receiver> ConstructReceiver(const Stream& stream);
// Creates a set of configured receivers from a given pair of audio and
// video streams. NOTE: either audio or video may be null, but not both.
diff --git a/chromium/third_party/openscreen/src/cast/streaming/receiver_session_unittest.cc b/chromium/third_party/openscreen/src/cast/streaming/receiver_session_unittest.cc
index 3e6f794516b..d7fbd7da5f0 100644
--- a/chromium/third_party/openscreen/src/cast/streaming/receiver_session_unittest.cc
+++ b/chromium/third_party/openscreen/src/cast/streaming/receiver_session_unittest.cc
@@ -7,6 +7,8 @@
#include <utility>
#include "cast/streaming/mock_environment.h"
+#include "cast/streaming/receiver.h"
+#include "cast/streaming/testing/simple_message_port.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "platform/base/ip_address.h"
@@ -200,6 +202,20 @@ constexpr char kInvalidJsonOfferMessage[] = R"({
}
})";
+constexpr char kMissingMandatoryFieldOfferMessage[] = R"({
+ "type": "OFFER",
+ "seqNum": 1337
+})";
+
+constexpr char kMissingSeqNumOfferMessage[] = R"({
+ "type": "OFFER",
+ "offer": {
+ "castMode": "mirroring",
+ "receiverGetStatus": true,
+ "supportedStreams": []
+ }
+})";
+
constexpr char kValidJsonInvalidFormatOfferMessage[] = R"({
"type": "OFFER",
"seqNum": 1337,
@@ -230,37 +246,6 @@ constexpr char kInvalidTypeMessage[] = R"({
"seqNum": 1337
})";
-class SimpleMessagePort : public MessagePort {
- public:
- ~SimpleMessagePort() override {}
- void SetClient(MessagePort::Client* client) override { client_ = client; }
-
- void ReceiveMessage(absl::string_view message) {
- ASSERT_NE(client_, nullptr);
- client_->OnMessage("sender-id", "namespace", message);
- }
-
- void ReceiveError(Error error) {
- ASSERT_NE(client_, nullptr);
- client_->OnError(error);
- }
-
- void PostMessage(absl::string_view sender_id,
- absl::string_view message_namespace,
- absl::string_view message) override {
- posted_messages_.emplace_back(std::move(message));
- }
-
- MessagePort::Client* client() const { return client_; }
- const std::vector<std::string> posted_messages() const {
- return posted_messages_;
- }
-
- private:
- MessagePort::Client* client_ = nullptr;
- std::vector<std::string> posted_messages_;
-};
-
class FakeClient : public ReceiverSession::Client {
public:
MOCK_METHOD(void,
@@ -328,31 +313,23 @@ TEST_F(ReceiverSessionTest, CanNegotiateWithDefaultPreferences) {
EXPECT_CALL(client_, OnNegotiated(session_.get(), _))
.WillOnce([](const ReceiverSession* session_,
ReceiverSession::ConfiguredReceivers cr) {
- EXPECT_TRUE(cr.audio);
- EXPECT_EQ(cr.audio.value().receiver_config.sender_ssrc, 19088747u);
- EXPECT_EQ(cr.audio.value().receiver_config.receiver_ssrc, 19088748u);
- EXPECT_EQ(cr.audio.value().receiver_config.channels, 2);
- EXPECT_EQ(cr.audio.value().receiver_config.rtp_timebase, 48000);
+ EXPECT_TRUE(cr.audio_receiver);
+ EXPECT_EQ(cr.audio_receiver->config().sender_ssrc, 19088747u);
+ EXPECT_EQ(cr.audio_receiver->config().receiver_ssrc, 19088748u);
+ EXPECT_EQ(cr.audio_receiver->config().channels, 2);
+ EXPECT_EQ(cr.audio_receiver->config().rtp_timebase, 48000);
// We should have chosen opus
- EXPECT_EQ(cr.audio.value().selected_stream.stream.index, 1337);
- EXPECT_EQ(cr.audio.value().selected_stream.stream.type,
- Stream::Type::kAudioSource);
- EXPECT_EQ(cr.audio.value().selected_stream.stream.codec_name, "opus");
- EXPECT_EQ(cr.audio.value().selected_stream.stream.channels, 2);
-
- EXPECT_TRUE(cr.video);
- EXPECT_EQ(cr.video.value().receiver_config.sender_ssrc, 19088745u);
- EXPECT_EQ(cr.video.value().receiver_config.receiver_ssrc, 19088746u);
- EXPECT_EQ(cr.video.value().receiver_config.channels, 1);
- EXPECT_EQ(cr.video.value().receiver_config.rtp_timebase, 90000);
+ EXPECT_EQ(cr.audio_config.codec, AudioCodec::kOpus);
+
+ EXPECT_TRUE(cr.video_receiver);
+ EXPECT_EQ(cr.video_receiver->config().sender_ssrc, 19088745u);
+ EXPECT_EQ(cr.video_receiver->config().receiver_ssrc, 19088746u);
+ EXPECT_EQ(cr.video_receiver->config().channels, 1);
+ EXPECT_EQ(cr.video_receiver->config().rtp_timebase, 90000);
// We should have chosen vp8
- EXPECT_EQ(cr.video.value().selected_stream.stream.index, 31338);
- EXPECT_EQ(cr.video.value().selected_stream.stream.type,
- Stream::Type::kVideoSource);
- EXPECT_EQ(cr.video.value().selected_stream.stream.codec_name, "vp8");
- EXPECT_EQ(cr.video.value().selected_stream.stream.channels, 1);
+ EXPECT_EQ(cr.video_config.codec, VideoCodec::kVp8);
});
EXPECT_CALL(client_,
OnReceiversDestroying(session_.get(),
@@ -393,25 +370,25 @@ TEST_F(ReceiverSessionTest, CanNegotiateWithDefaultPreferences) {
TEST_F(ReceiverSessionTest, CanNegotiateWithCustomCodecPreferences) {
ReceiverSession session(
&client_, environment_.get(), message_port_.get(),
- ReceiverSession::Preferences{{ReceiverSession::VideoCodec::kVp9},
- {ReceiverSession::AudioCodec::kOpus}});
+ ReceiverSession::Preferences{{VideoCodec::kVp9}, {AudioCodec::kOpus}});
InSequence s;
EXPECT_CALL(client_, OnNegotiated(&session, _))
.WillOnce([](const ReceiverSession* session_,
ReceiverSession::ConfiguredReceivers cr) {
- EXPECT_TRUE(cr.audio);
- EXPECT_EQ(cr.audio.value().receiver_config.sender_ssrc, 19088747u);
- EXPECT_EQ(cr.audio.value().receiver_config.receiver_ssrc, 19088748u);
- EXPECT_EQ(cr.audio.value().receiver_config.channels, 2);
- EXPECT_EQ(cr.audio.value().receiver_config.rtp_timebase, 48000);
-
- EXPECT_TRUE(cr.video);
- // We should have chosen vp9
- EXPECT_EQ(cr.video.value().receiver_config.sender_ssrc, 19088743u);
- EXPECT_EQ(cr.video.value().receiver_config.receiver_ssrc, 19088744u);
- EXPECT_EQ(cr.video.value().receiver_config.channels, 1);
- EXPECT_EQ(cr.video.value().receiver_config.rtp_timebase, 90000);
+ EXPECT_TRUE(cr.audio_receiver);
+ EXPECT_EQ(cr.audio_receiver->config().sender_ssrc, 19088747u);
+ EXPECT_EQ(cr.audio_receiver->config().receiver_ssrc, 19088748u);
+ EXPECT_EQ(cr.audio_receiver->config().channels, 2);
+ EXPECT_EQ(cr.audio_receiver->config().rtp_timebase, 48000);
+ EXPECT_EQ(cr.audio_config.codec, AudioCodec::kOpus);
+
+ EXPECT_TRUE(cr.video_receiver);
+ EXPECT_EQ(cr.video_receiver->config().sender_ssrc, 19088743u);
+ EXPECT_EQ(cr.video_receiver->config().receiver_ssrc, 19088744u);
+ EXPECT_EQ(cr.video_receiver->config().channels, 1);
+ EXPECT_EQ(cr.video_receiver->config().rtp_timebase, 90000);
+ EXPECT_EQ(cr.video_config.codec, VideoCodec::kVp9);
});
EXPECT_CALL(client_, OnReceiversDestroying(
&session, ReceiverSession::Client::kEndOfSession));
@@ -433,12 +410,11 @@ TEST_F(ReceiverSessionTest, CanNegotiateWithCustomConstraints) {
absl::optional<AspectRatio>(AspectRatio{16, 9}),
absl::optional<AspectRatioConstraint>(AspectRatioConstraint::kFixed)});
- ReceiverSession session(
- &client_, environment_.get(), message_port_.get(),
- ReceiverSession::Preferences{{ReceiverSession::VideoCodec::kVp9},
- {ReceiverSession::AudioCodec::kOpus},
- std::move(constraints),
- std::move(display)});
+ ReceiverSession session(&client_, environment_.get(), message_port_.get(),
+ ReceiverSession::Preferences{{VideoCodec::kVp9},
+ {AudioCodec::kOpus},
+ std::move(constraints),
+ std::move(display)});
InSequence s;
EXPECT_CALL(client_, OnNegotiated(&session, _));
@@ -564,27 +540,46 @@ TEST_F(ReceiverSessionTest, HandlesNoValidStreams) {
TEST_F(ReceiverSessionTest, HandlesMalformedOffer) {
// Note that unlike when we simply don't select any streams, when the offer
- // is actually completely invalid we call OnError.
- EXPECT_CALL(client_,
- OnError(session_.get(), Error(Error::Code::kJsonParseError)));
+ // is not valid JSON we actually have no way of knowing it's an offer at all,
+ // so we call OnError and do not reply with an Answer.
+ EXPECT_CALL(client_, OnError(session_.get(), _));
message_port_->ReceiveMessage(kInvalidJsonOfferMessage);
}
+TEST_F(ReceiverSessionTest, HandlesMissingSeqNumInOffer) {
+ // If the OFFER is missing a sequence number it gets rejected before being
+ // parsed as an OFFER, since the sender expects all messages to come back
+ // with a sequence number.
+ message_port_->ReceiveMessage(kMissingSeqNumOfferMessage);
+}
+
+TEST_F(ReceiverSessionTest, HandlesOfferMissingMandatoryFields) {
+ // If the OFFER is missing mandatory fields, we notify the client as well as
+ // reply with an error-case Answer.
+ EXPECT_CALL(client_, OnError(session_.get(), _));
+
+ message_port_->ReceiveMessage(kMissingMandatoryFieldOfferMessage);
+ const auto& messages = message_port_->posted_messages();
+ EXPECT_EQ(1u, messages.size());
+
+ auto message_body = json::Parse(messages[0]);
+ ExpectIsErrorAnswerMessage(message_body);
+}
+
TEST_F(ReceiverSessionTest, HandlesImproperlyFormattedOffer) {
- EXPECT_CALL(client_,
- OnError(session_.get(),
- Error(Error::Code::kJsonParseError,
- "Failed to parse supported streams in offer")));
+ EXPECT_CALL(client_, OnError(session_.get(), _));
message_port_->ReceiveMessage(kValidJsonInvalidFormatOfferMessage);
+ const auto& messages = message_port_->posted_messages();
+ EXPECT_EQ(1u, messages.size());
+
+ auto message_body = json::Parse(messages[0]);
+ ExpectIsErrorAnswerMessage(message_body);
}
TEST_F(ReceiverSessionTest, HandlesNullOffer) {
- EXPECT_CALL(client_, OnError(session_.get(),
- Error(Error::Code::kJsonParseError,
- "Received offer missing offer body")));
-
+ EXPECT_CALL(client_, OnError(session_.get(), _));
message_port_->ReceiveMessage(kNullJsonOfferMessage);
}
diff --git a/chromium/third_party/openscreen/src/cast/streaming/rtp_defines.cc b/chromium/third_party/openscreen/src/cast/streaming/rtp_defines.cc
index 215b9cfcec0..d64773d5c34 100644
--- a/chromium/third_party/openscreen/src/cast/streaming/rtp_defines.cc
+++ b/chromium/third_party/openscreen/src/cast/streaming/rtp_defines.cc
@@ -7,6 +7,14 @@
namespace openscreen {
namespace cast {
+RtpPayloadType GetPayloadType(AudioCodec codec) {
+ return RtpPayloadType::kAudioHackForAndroidTV;
+}
+
+RtpPayloadType GetPayloadType(VideoCodec codec) {
+ return RtpPayloadType::kVideoHackForAndroidTV;
+}
+
bool IsRtpPayloadType(uint8_t raw_byte) {
switch (static_cast<RtpPayloadType>(raw_byte)) {
case RtpPayloadType::kAudioOpus:
diff --git a/chromium/third_party/openscreen/src/cast/streaming/rtp_defines.h b/chromium/third_party/openscreen/src/cast/streaming/rtp_defines.h
index 335c06a04d1..82c91c31a7d 100644
--- a/chromium/third_party/openscreen/src/cast/streaming/rtp_defines.h
+++ b/chromium/third_party/openscreen/src/cast/streaming/rtp_defines.h
@@ -7,6 +7,8 @@
#include <stdint.h>
+#include "cast/streaming/constants.h"
+
namespace openscreen {
namespace cast {
@@ -96,10 +98,21 @@ enum class RtpPayloadType : uint8_t {
// video to be 96; regardless of the codecs actually being used. This is
// definitely out-of-spec, and inconsistent with the audio versus video range
// of values, but must be taken into account for backwards-compatibility.
+ // TODO(crbug.com/1127978): RTP payload types need to represent actual type,
+ // as well as have options for new codecs like VP9.
kAudioHackForAndroidTV = 127,
kVideoHackForAndroidTV = 96,
};
+// NOTE: currently we match the legacy Chrome sender's behavior of always
+// sending the audio and video hacks for AndroidTV, however we should migrate
+// to using proper rtp payload types. New payload types for new codecs, such
+// as VP9, should also be defined.
+// TODO(crbug.com/1127978): RTP payload types need to represent actual type,
+// as well as have options for new codecs like VP9.
+RtpPayloadType GetPayloadType(AudioCodec codec);
+RtpPayloadType GetPayloadType(VideoCodec codec);
+
// Returns true if the |raw_byte| can be type-casted to a RtpPayloadType, and is
// also not RtpPayloadType::kNull. The caller should mask the byte, to select
// the lower 7 bits, if applicable.
diff --git a/chromium/third_party/openscreen/src/cast/streaming/rtp_packetizer_unittest.cc b/chromium/third_party/openscreen/src/cast/streaming/rtp_packetizer_unittest.cc
index 8b4710659d6..1c3cd97a481 100644
--- a/chromium/third_party/openscreen/src/cast/streaming/rtp_packetizer_unittest.cc
+++ b/chromium/third_party/openscreen/src/cast/streaming/rtp_packetizer_unittest.cc
@@ -14,6 +14,7 @@
#include "cast/streaming/ssrc.h"
#include "gtest/gtest.h"
#include "util/chrono_helpers.h"
+#include "util/crypto/random_bytes.h"
namespace openscreen {
namespace cast {
@@ -126,8 +127,7 @@ class RtpPacketizerTest : public testing::Test {
// The RtpPacketizer instance under test, plus some surrounding dependencies
// to generate its input and examine its output.
const Ssrc ssrc_{GenerateSsrc(true)};
- const FrameCrypto crypto_{FrameCrypto::GenerateRandomBytes(),
- FrameCrypto::GenerateRandomBytes()};
+ const FrameCrypto crypto_{GenerateRandomBytes16(), GenerateRandomBytes16()};
RtpPacketizer packetizer_{kPayloadType, ssrc_,
kMaxRtpPacketSizeForIpv4UdpOnEthernet};
RtpPacketParser parser_{ssrc_};
diff --git a/chromium/third_party/openscreen/src/cast/streaming/sender.cc b/chromium/third_party/openscreen/src/cast/streaming/sender.cc
index 3713a199683..dcb2f04b12b 100644
--- a/chromium/third_party/openscreen/src/cast/streaming/sender.cc
+++ b/chromium/third_party/openscreen/src/cast/streaming/sender.cc
@@ -20,9 +20,10 @@ using openscreen::operator<<; // For std::chrono::duration logging.
Sender::Sender(Environment* environment,
SenderPacketRouter* packet_router,
- const SessionConfig& config,
+ SessionConfig config,
RtpPayloadType rtp_payload_type)
- : packet_router_(packet_router),
+ : config_(config),
+ packet_router_(packet_router),
rtcp_session_(config.sender_ssrc,
config.receiver_ssrc,
environment->now()),
diff --git a/chromium/third_party/openscreen/src/cast/streaming/sender.h b/chromium/third_party/openscreen/src/cast/streaming/sender.h
index 33ea5227318..7e82711729b 100644
--- a/chromium/third_party/openscreen/src/cast/streaming/sender.h
+++ b/chromium/third_party/openscreen/src/cast/streaming/sender.h
@@ -21,6 +21,7 @@
#include "cast/streaming/rtp_time.h"
#include "cast/streaming/sender_packet_router.h"
#include "cast/streaming/sender_report_builder.h"
+#include "cast/streaming/session_config.h"
#include "platform/api/time.h"
#include "util/yet_another_bit_vector.h"
@@ -28,7 +29,6 @@ namespace openscreen {
namespace cast {
class Environment;
-struct SessionConfig;
// The Cast Streaming Sender, a peer corresponding to some Cast Streaming
// Receiver at the other end of a network link. See class level comments for
@@ -116,11 +116,12 @@ class Sender final : public SenderPacketRouter::Sender,
// Sender. It is simply passed along to a Receiver in the RTP packet stream.
Sender(Environment* environment,
SenderPacketRouter* packet_router,
- const SessionConfig& config,
+ SessionConfig config,
RtpPayloadType rtp_payload_type);
~Sender() final;
+ const SessionConfig& config() const { return config_; }
Ssrc ssrc() const { return rtcp_session_.sender_ssrc(); }
int rtp_timebase() const { return rtp_timebase_; }
@@ -251,6 +252,7 @@ class Sender final : public SenderPacketRouter::Sender,
pending_frames_.size()];
}
+ const SessionConfig config_;
SenderPacketRouter* const packet_router_;
RtcpSession rtcp_session_;
CompoundRtcpParser rtcp_parser_;
diff --git a/chromium/third_party/openscreen/src/cast/streaming/sender_session.cc b/chromium/third_party/openscreen/src/cast/streaming/sender_session.cc
new file mode 100644
index 00000000000..897e7560aeb
--- /dev/null
+++ b/chromium/third_party/openscreen/src/cast/streaming/sender_session.cc
@@ -0,0 +1,397 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cast/streaming/sender_session.h"
+
+#include <openssl/rand.h>
+#include <stdint.h>
+
+#include <algorithm>
+#include <chrono>
+#include <iterator>
+#include <limits>
+#include <random>
+#include <string>
+#include <utility>
+
+#include "absl/strings/match.h"
+#include "absl/strings/numbers.h"
+#include "cast/common/public/message_port.h"
+#include "cast/streaming/capture_recommendations.h"
+#include "cast/streaming/environment.h"
+#include "cast/streaming/message_fields.h"
+#include "cast/streaming/offer_messages.h"
+#include "cast/streaming/sender.h"
+#include "util/crypto/random_bytes.h"
+#include "util/json/json_helpers.h"
+#include "util/json/json_serialization.h"
+#include "util/osp_logging.h"
+
+namespace openscreen {
+namespace cast {
+
+namespace {
+
+AudioStream CreateStream(int index, const AudioCaptureConfig& config) {
+ return AudioStream{
+ Stream{index,
+ Stream::Type::kAudioSource,
+ config.channels,
+ CodecToString(config.codec),
+ GetPayloadType(config.codec),
+ GenerateSsrc(true /*high_priority*/),
+ config.target_playout_delay,
+ GenerateRandomBytes16(),
+ GenerateRandomBytes16(),
+ false /* receiver_rtcp_event_log */,
+ {} /* receiver_rtcp_dscp */,
+ config.sample_rate},
+ (config.bit_rate >= capture_recommendations::kDefaultAudioMinBitRate)
+ ? config.bit_rate
+ : capture_recommendations::kDefaultAudioMaxBitRate};
+}
+
+Resolution ToResolution(const DisplayResolution& display_resolution) {
+ return Resolution{display_resolution.width, display_resolution.height};
+}
+
+VideoStream CreateStream(int index, const VideoCaptureConfig& config) {
+ std::vector<Resolution> resolutions;
+ std::transform(config.resolutions.begin(), config.resolutions.end(),
+ std::back_inserter(resolutions), ToResolution);
+
+ constexpr int kVideoStreamChannelCount = 1;
+ return VideoStream{
+ Stream{index,
+ Stream::Type::kVideoSource,
+ kVideoStreamChannelCount,
+ CodecToString(config.codec),
+ GetPayloadType(config.codec),
+ GenerateSsrc(false /*high_priority*/),
+ config.target_playout_delay,
+ GenerateRandomBytes16(),
+ GenerateRandomBytes16(),
+ false /* receiver_rtcp_event_log */,
+ {} /* receiver_rtcp_dscp */,
+ kRtpVideoTimebase},
+ SimpleFraction{config.max_frame_rate.numerator,
+ config.max_frame_rate.denominator},
+ (config.max_bit_rate >
+ capture_recommendations::kDefaultVideoBitRateLimits.minimum)
+ ? config.max_bit_rate
+ : capture_recommendations::kDefaultVideoBitRateLimits.maximum,
+ {}, // protection
+ {}, // profile
+ {}, // protection
+ std::move(resolutions),
+ {} /* error_recovery mode, always "castv2" */
+ };
+}
+
+template <typename S, typename C>
+void CreateStreamList(int offset_index,
+ const std::vector<C>& configs,
+ std::vector<S>* out) {
+ out->reserve(configs.size());
+ for (size_t i = 0; i < configs.size(); ++i) {
+ out->emplace_back(CreateStream(i + offset_index, configs[i]));
+ }
+}
+
+Offer CreateOffer(const std::vector<AudioCaptureConfig>& audio_configs,
+ const std::vector<VideoCaptureConfig>& video_configs) {
+ Offer offer{
+ {CastMode::Type::kMirroring},
+ false /* supports_wifi_status_reporting */,
+ {} /* audio_streams */,
+ {} /* video_streams */
+ };
+
+ // NOTE here: IDs will always follow the pattern:
+ // [0.. audio streams... N - 1][N.. video streams.. K]
+ CreateStreamList(0, audio_configs, &offer.audio_streams);
+ CreateStreamList(audio_configs.size(), video_configs, &offer.video_streams);
+
+ return offer;
+}
+
+bool IsValidAudioCaptureConfig(const AudioCaptureConfig& config) {
+ return config.channels >= 1 && config.bit_rate >= 0;
+}
+
+bool IsValidResolution(const DisplayResolution& resolution) {
+ return resolution.width > kMinVideoWidth &&
+ resolution.height > kMinVideoHeight;
+}
+
+bool IsValidVideoCaptureConfig(const VideoCaptureConfig& config) {
+ return config.max_frame_rate.numerator > 0 &&
+ config.max_frame_rate.denominator > 0 &&
+ ((config.max_bit_rate == 0) ||
+ (config.max_bit_rate >=
+ capture_recommendations::kDefaultVideoBitRateLimits.minimum)) &&
+ !config.resolutions.empty() &&
+ std::all_of(config.resolutions.begin(), config.resolutions.end(),
+ IsValidResolution);
+}
+
+bool AreAllValid(const std::vector<AudioCaptureConfig>& audio_configs,
+ const std::vector<VideoCaptureConfig>& video_configs) {
+ return std::all_of(audio_configs.begin(), audio_configs.end(),
+ IsValidAudioCaptureConfig) &&
+ std::all_of(video_configs.begin(), video_configs.end(),
+ IsValidVideoCaptureConfig);
+}
+
+int GenerateSessionId() {
+ static auto& rd = *new std::random_device();
+ static auto& gen = *new std::mt19937(rd());
+ static auto& dist =
+ *new std::uniform_int_distribution<>(1, std::numeric_limits<int>::max());
+
+ return dist(gen);
+}
+} // namespace
+
+SenderSession::Client::~Client() = default;
+
+SenderSession::SenderSession(IPAddress remote_address,
+ Client* const client,
+ Environment* environment,
+ MessagePort* message_port)
+ : session_id_(GenerateSessionId()),
+ remote_address_(remote_address),
+ client_(client),
+ environment_(environment),
+ message_port_(message_port),
+ packet_router_(environment_) {
+ OSP_DCHECK(session_id_ > 0);
+ OSP_DCHECK(client_);
+ OSP_DCHECK(message_port_);
+ OSP_DCHECK(environment_);
+
+ message_port_->SetClient(this, "sender-" + std::to_string(session_id_));
+}
+
+SenderSession::~SenderSession() {
+ message_port_->ResetClient();
+}
+
+Error SenderSession::Negotiate(std::vector<AudioCaptureConfig> audio_configs,
+ std::vector<VideoCaptureConfig> video_configs) {
+ // Negotiating with no streams doesn't make any sense.
+ if (audio_configs.empty() && video_configs.empty()) {
+ return Error(Error::Code::kParameterInvalid,
+ "Need at least one audio or video config to negotiate.");
+ }
+ if (!AreAllValid(audio_configs, video_configs)) {
+ return Error(Error::Code::kParameterInvalid, "Invalid configs provided.");
+ }
+
+ Offer offer = CreateOffer(audio_configs, video_configs);
+ ErrorOr<Json::Value> json_offer = offer.ToJson();
+ if (json_offer.is_error()) {
+ return std::move(json_offer.error());
+ }
+
+ current_negotiation_ = std::unique_ptr<Negotiation>(new Negotiation{
+ std::move(offer), std::move(audio_configs), std::move(video_configs)});
+
+ Json::Value message_body;
+ message_body[kMessageType] = kMessageTypeOffer;
+ message_body[kOfferMessageBody] = std::move(json_offer.value());
+
+ Message message;
+ // Currently we don't have a way to discover the ID of the receiver we
+ // are connected to, since we have to send the first message.
+ // TODO(jophba): migrate to discovered receiver ID when available.
+ message.sender_id = kDefaultStreamingReceiverSenderId;
+ message.message_namespace = kCastWebrtcNamespace;
+ message.body = std::move(message_body);
+ SendMessage(&message);
+ return Error::None();
+}
+
+void SenderSession::OnMessage(const std::string& sender_id,
+ const std::string& message_namespace,
+ const std::string& message) {
+ ErrorOr<Json::Value> message_json = json::Parse(message);
+ if (!message_json) {
+ OSP_DLOG_WARN << "Received an invalid message: " << message
+ << ", dropping.";
+ return;
+ }
+
+ std::string key;
+ if (!json::ParseAndValidateString(message_json.value()[kKeyType], &key)) {
+ OSP_DLOG_WARN << "Received message with invalid message key, dropping.";
+ return;
+ }
+
+ if (receiver_sender_id_.empty()) {
+ receiver_sender_id_ = sender_id;
+ } else if (receiver_sender_id_ != sender_id) {
+ OSP_DLOG_WARN << "Received message from unknown sender ID: " << sender_id
+ << ", dropping.";
+ return;
+ }
+
+ OSP_DVLOG << "Received a message: " << message;
+ if (key == kMessageTypeAnswer) {
+ if (message_namespace != kCastWebrtcNamespace) {
+ OSP_DLOG_INFO << "Received answer from invalid namespace: "
+ << message_namespace;
+ return;
+ }
+ if (!current_negotiation_) {
+ OSP_DLOG_INFO << "Received answer but not currently negotiating.";
+ return;
+ }
+
+ int sequence_number;
+ if (!json::ParseAndValidateInt(message_json.value()[kSequenceNumber],
+ &sequence_number)) {
+ OSP_DLOG_WARN << "Received invalid message sequence number, dropping.";
+ return;
+ }
+
+ if (sequence_number != current_sequence_number_) {
+ OSP_DLOG_WARN << "Received a stale answer message, dropping.";
+ return;
+ } else if (sequence_number > current_sequence_number_) {
+ OSP_DLOG_WARN
+ << "Received an answer with an unexpected sequence number, dropping.";
+ return;
+ }
+
+ const Json::Value body =
+ std::move(message_json.value()[kAnswerMessageBody]);
+ if (body.isObject()) {
+ OnAnswer(body);
+ } else {
+ client_->OnError(
+ this, Error(Error::Code::kJsonParseError, "Failed to parse answer"));
+ OSP_DLOG_WARN
+ << "Received message with invalid answer message body, dropping.";
+ }
+ }
+ current_negotiation_.reset();
+}
+
+void SenderSession::OnError(Error error) {
+ OSP_DLOG_WARN << "SenderSession message port error: " << error;
+}
+
+void SenderSession::OnAnswer(const Json::Value& message_body) {
+ Answer answer;
+ if (!Answer::ParseAndValidate(message_body, &answer)) {
+ client_->OnError(this, Error(Error::Code::kJsonParseError,
+ "Received invalid answer message"));
+ OSP_DLOG_WARN << "Received invalid answer message";
+ return;
+ }
+
+ ConfiguredSenders senders = SpawnSenders(answer);
+
+ // If we didn't select any senders, the negotiation was unsuccessful.
+ if (senders.audio_sender == nullptr && senders.video_sender == nullptr) {
+ return;
+ }
+ client_->OnNegotiated(this, std::move(senders),
+ capture_recommendations::GetRecommendations(answer));
+}
+
+std::unique_ptr<Sender> SenderSession::CreateSender(Ssrc receiver_ssrc,
+ const Stream& stream,
+ RtpPayloadType type) {
+ SessionConfig config{
+ stream.ssrc, receiver_ssrc, stream.rtp_timebase, stream.channels,
+ stream.target_delay, stream.aes_key, stream.aes_iv_mask};
+
+ return std::make_unique<Sender>(environment_, &packet_router_,
+ std::move(config), type);
+}
+
+void SenderSession::SpawnAudioSender(ConfiguredSenders* senders,
+ Ssrc receiver_ssrc,
+ int send_index,
+ int config_index) {
+ const AudioCaptureConfig& config =
+ current_negotiation_->audio_configs[config_index];
+ const RtpPayloadType payload_type = GetPayloadType(config.codec);
+ for (const AudioStream& stream : current_negotiation_->offer.audio_streams) {
+ if (stream.stream.index == send_index) {
+ current_audio_sender_ =
+ CreateSender(receiver_ssrc, stream.stream, payload_type);
+ senders->audio_sender = current_audio_sender_.get();
+ senders->audio_config = config;
+ break;
+ }
+ }
+}
+
+void SenderSession::SpawnVideoSender(ConfiguredSenders* senders,
+ Ssrc receiver_ssrc,
+ int send_index,
+ int config_index) {
+ const VideoCaptureConfig& config =
+ current_negotiation_->video_configs[config_index];
+ const RtpPayloadType payload_type = GetPayloadType(config.codec);
+ for (const VideoStream& stream : current_negotiation_->offer.video_streams) {
+ if (stream.stream.index == send_index) {
+ current_video_sender_ =
+ CreateSender(receiver_ssrc, stream.stream, payload_type);
+ senders->video_sender = current_video_sender_.get();
+ senders->video_config = config;
+ break;
+ }
+ }
+}
+
+SenderSession::ConfiguredSenders SenderSession::SpawnSenders(
+ const Answer& answer) {
+ OSP_DCHECK(current_negotiation_);
+
+ // Although we already have a message port set up with the TLS
+ // address of the receiver, we don't know where to send the seperate UDP
+ // stream until we get the ANSWER message here.
+ environment_->set_remote_endpoint(
+ IPEndpoint{remote_address_, static_cast<uint16_t>(answer.udp_port)});
+
+ ConfiguredSenders senders;
+ for (size_t i = 0; i < answer.send_indexes.size(); ++i) {
+ const Ssrc receiver_ssrc = answer.ssrcs[i];
+ const size_t send_index = static_cast<size_t>(answer.send_indexes[i]);
+
+ const auto audio_size = current_negotiation_->audio_configs.size();
+ const auto video_size = current_negotiation_->video_configs.size();
+ if (send_index < audio_size) {
+ SpawnAudioSender(&senders, receiver_ssrc, send_index, send_index);
+ } else if (send_index < (audio_size + video_size)) {
+ SpawnVideoSender(&senders, receiver_ssrc, send_index,
+ send_index - audio_size);
+ }
+ }
+ return senders;
+}
+
+void SenderSession::SendMessage(Message* message) {
+ message->body[kSequenceNumber] = ++current_sequence_number_;
+
+ auto body_or_error = json::Stringify(message->body);
+ if (body_or_error.is_value()) {
+ OSP_DVLOG << "Sending message: SENDER[" << message->sender_id
+ << "], NAMESPACE[" << message->message_namespace << "], BODY:\n"
+ << body_or_error.value();
+ message_port_->PostMessage(message->sender_id, message->message_namespace,
+ body_or_error.value());
+ } else {
+ OSP_DLOG_WARN << "Sending message failed with error:\n"
+ << body_or_error.error();
+ client_->OnError(this, body_or_error.error());
+ }
+}
+
+} // namespace cast
+} // namespace openscreen
diff --git a/chromium/third_party/openscreen/src/cast/streaming/sender_session.h b/chromium/third_party/openscreen/src/cast/streaming/sender_session.h
new file mode 100644
index 00000000000..a38ac422c21
--- /dev/null
+++ b/chromium/third_party/openscreen/src/cast/streaming/sender_session.h
@@ -0,0 +1,179 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CAST_STREAMING_SENDER_SESSION_H_
+#define CAST_STREAMING_SENDER_SESSION_H_
+
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "cast/common/public/message_port.h"
+#include "cast/streaming/answer_messages.h"
+#include "cast/streaming/capture_configs.h"
+#include "cast/streaming/offer_messages.h"
+#include "cast/streaming/sender.h"
+#include "cast/streaming/sender_packet_router.h"
+#include "cast/streaming/session_config.h"
+#include "json/value.h"
+#include "util/json/json_serialization.h"
+
+namespace openscreen {
+namespace cast {
+
+namespace capture_recommendations {
+struct Recommendations;
+}
+
+class Environment;
+class Sender;
+
+class SenderSession final : public MessagePort::Client {
+ public:
+ // Upon successful negotiation, a set of configured senders is constructed
+ // for handling audio and video. Note that either sender may be null.
+ struct ConfiguredSenders {
+ // In practice, we may have 0, 1, or 2 senders configured, depending
+ // on if the device supports audio and video, and if we were able to
+ // successfully negotiate a sender configuration.
+
+ // If the sender is audio- or video-only, either of the senders
+ // may be nullptr. However, in the majority of cases they will be populated.
+ Sender* audio_sender;
+ AudioCaptureConfig audio_config;
+
+ Sender* video_sender;
+ VideoCaptureConfig video_config;
+ };
+
+ // The embedder should provide a client for handling the negotiation.
+ // When the negotiation is complete, the OnNegotiated callback is called.
+ class Client {
+ public:
+ // Called when a new set of senders has been negotiated. This may be
+ // called multiple times during a session, once for every time Negotiate()
+ // is called on the SenderSession object. The negotation call also includes
+ // capture recommendations that can be used by the sender to provide
+ // an optimal video stream for the receiver.
+ virtual void OnNegotiated(
+ const SenderSession* session,
+ ConfiguredSenders senders,
+ capture_recommendations::Recommendations capture_recommendations) = 0;
+
+ // Called whenever an error occurs. Ends the ongoing session, and the caller
+ // must call Negotiate() again if they wish to re-establish streaming.
+ virtual void OnError(const SenderSession* session, Error error) = 0;
+
+ protected:
+ virtual ~Client();
+ };
+
+ // The SenderSession assumes that the passed in client, environment, and
+ // message port persist for at least the lifetime of the SenderSession. If
+ // one of these classes needs to be reset, a new SenderSession should be
+ // created.
+ SenderSession(IPAddress remote_address,
+ Client* const client,
+ Environment* environment,
+ MessagePort* message_port);
+ SenderSession(const SenderSession&) = delete;
+ SenderSession(SenderSession&&) = delete;
+ SenderSession& operator=(const SenderSession&) = delete;
+ SenderSession& operator=(SenderSession&&) = delete;
+ ~SenderSession();
+
+ // Starts an OFFER/ANSWER exchange with the already configured receiver
+ // over the message port. The caller should assume any configured senders
+ // become invalid when calling this method.
+ Error Negotiate(std::vector<AudioCaptureConfig> audio_configs,
+ std::vector<VideoCaptureConfig> video_configs);
+
+ // MessagePort::Client overrides
+ void OnMessage(const std::string& sender_id,
+ const std::string& message_namespace,
+ const std::string& message) override;
+ void OnError(Error error) override;
+
+ private:
+ struct Message {
+ std::string sender_id;
+ std::string message_namespace;
+ int sequence_number = 0;
+ Json::Value body;
+ };
+
+ // We store the current negotiation, so that when we get an answer from the
+ // receiver we can line up the selected streams with the original
+ // configuration.
+ struct Negotiation {
+ Offer offer;
+
+ std::vector<AudioCaptureConfig> audio_configs;
+ std::vector<VideoCaptureConfig> video_configs;
+ };
+
+ // Specific message type handler methods.
+ void OnAnswer(const Json::Value& message_body);
+
+ // Used by SpawnSenders to generate a sender for a specific stream.
+ std::unique_ptr<Sender> CreateSender(Ssrc receiver_ssrc,
+ const Stream& stream,
+ RtpPayloadType type);
+
+ // Helper methods for spawning specific senders from the Answer message.
+ void SpawnAudioSender(ConfiguredSenders* senders,
+ Ssrc receiver_ssrc,
+ int send_index,
+ int config_index);
+ void SpawnVideoSender(ConfiguredSenders* senders,
+ Ssrc receiver_ssrc,
+ int send_index,
+ int config_index);
+
+ // Spawn a set of configured senders from the currently stored negotiation.
+ ConfiguredSenders SpawnSenders(const Answer& answer);
+
+ // Sends a message over the message port.
+ void SendMessage(Message* message);
+
+ // The cast session ID for this session.
+ const int session_id_;
+
+ // The sender ID of the Receiver for this session.
+ std::string receiver_sender_id_;
+
+ // The remote address of the receiver we are communicating with. Used
+ // for both TLS and UDP traffic.
+ const IPAddress remote_address_;
+
+ // The embedder is expected to provide us a client for notifications about
+ // negotiations and errors, a valid cast environment, and a messaging
+ // port for communicating to the Receiver over TLS.
+ Client* const client_;
+ Environment* const environment_;
+ MessagePort* const message_port_;
+
+ // The packet router used for messaging across all senders.
+ SenderPacketRouter packet_router_;
+
+ // Each negotiation has its own sequence number, and the receiver replies
+ // with the same sequence number that we send. Each message to the receiver
+ // advances our current sequence number.
+ int current_sequence_number_ = 0;
+
+ // The current negotiation. If present, we are expected an ANSWER from
+ // the receiver. If not present, any provided ANSWERS are rejected.
+ std::unique_ptr<Negotiation> current_negotiation_;
+
+ // If the negotiation has succeeded, we store the current audio and video
+ // senders used for this session. Either or both may be nullptr.
+ std::unique_ptr<Sender> current_audio_sender_;
+ std::unique_ptr<Sender> current_video_sender_;
+}; // namespace cast
+
+} // namespace cast
+} // namespace openscreen
+
+#endif // CAST_STREAMING_SENDER_SESSION_H_
diff --git a/chromium/third_party/openscreen/src/cast/streaming/sender_session_unittest.cc b/chromium/third_party/openscreen/src/cast/streaming/sender_session_unittest.cc
new file mode 100644
index 00000000000..7fd428bed0b
--- /dev/null
+++ b/chromium/third_party/openscreen/src/cast/streaming/sender_session_unittest.cc
@@ -0,0 +1,421 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cast/streaming/sender_session.h"
+
+#include <cstdio>
+#include <utility>
+
+#include "cast/streaming/capture_configs.h"
+#include "cast/streaming/capture_recommendations.h"
+#include "cast/streaming/mock_environment.h"
+#include "cast/streaming/testing/simple_message_port.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "platform/base/ip_address.h"
+#include "platform/test/fake_clock.h"
+#include "platform/test/fake_task_runner.h"
+#include "util/chrono_helpers.h"
+
+using ::testing::_;
+using ::testing::InSequence;
+using ::testing::Invoke;
+using ::testing::NiceMock;
+using ::testing::Return;
+using ::testing::StrictMock;
+
+namespace openscreen {
+namespace cast {
+
+namespace {
+constexpr char kMalformedAnswerMessage[] = R"({
+ "type": "ANSWER",
+ "seqNum": 1,
+ "answer": {
+ "castMode": "mirroring",
+ "udpPort": 1234,
+ "sendIndexes": [1, 3],
+ "ssrcs": [1, 2]
+})";
+
+constexpr char kValidJsonInvalidFormatAnswerMessage[] = R"({
+ "type": "ANSWER",
+ "seqNum": 1,
+ "answer-2": {
+ "castMode": "mirroring",
+ "udpPort": 1234,
+ "sendIndexes": [1, 3],
+ "ssrcs": [1, 2]
+ }
+})";
+
+constexpr char kValidJsonInvalidAnswerMessage[] = R"({
+ "type": "ANSWER",
+ "seqNum": 1,
+ "answer": {
+ "castMode": "mirroring",
+ "udpPort": -1234,
+ "sendIndexes": [1, 3],
+ "ssrcs": [1, 2]
+ }
+})";
+
+constexpr char kMissingAnswerMessage[] = R"({
+ "type": "ANSWER",
+ "seqNum": 1
+})";
+
+constexpr char kInvalidSequenceNumberMessage[] = R"({
+ "type": "ANSWER",
+ "seqNum": "not actually a number"
+})";
+
+constexpr char kUnknownTypeMessage[] = R"({
+ "type": "ANSWER_VERSION_2",
+ "seqNum": 1
+})";
+
+constexpr char kInvalidTypeMessage[] = R"({
+ "type": 39,
+ "seqNum": 1
+})";
+
+const AudioCaptureConfig kAudioCaptureConfigInvalidChannels{
+ AudioCodec::kAac, -1 /* channels */, 44000 /* bit_rate */,
+ 96000 /* sample_rate */
+};
+
+const AudioCaptureConfig kAudioCaptureConfigValid{
+ AudioCodec::kOpus, 5 /* channels */, 32000 /* bit_rate */,
+ 44000 /* sample_rate */
+};
+
+const VideoCaptureConfig kVideoCaptureConfigMissingResolutions{
+ VideoCodec::kHevc, FrameRate{60, 1}, 300000 /* max_bit_rate */,
+ std::vector<DisplayResolution>{}};
+
+const VideoCaptureConfig kVideoCaptureConfigInvalid{
+ VideoCodec::kHevc, FrameRate{60, 1}, -300000 /* max_bit_rate */,
+ std::vector<DisplayResolution>{DisplayResolution{1920, 1080},
+ DisplayResolution{1280, 720}}};
+
+const VideoCaptureConfig kVideoCaptureConfigValid{
+ VideoCodec::kHevc, FrameRate{60, 1}, 300000 /* max_bit_rate */,
+ std::vector<DisplayResolution>{DisplayResolution{1280, 720},
+ DisplayResolution{1920, 1080}}};
+
+const VideoCaptureConfig kVideoCaptureConfigValidSimplest{
+ VideoCodec::kHevc, FrameRate{60, 1}, 300000 /* max_bit_rate */,
+ std::vector<DisplayResolution>{DisplayResolution{1920, 1080}}};
+
+class FakeClient : public SenderSession::Client {
+ public:
+ MOCK_METHOD(void,
+ OnNegotiated,
+ (const SenderSession*,
+ SenderSession::ConfiguredSenders,
+ capture_recommendations::Recommendations),
+ (override));
+ MOCK_METHOD(void, OnError, (const SenderSession*, Error error), (override));
+};
+
+} // namespace
+
+class SenderSessionTest : public ::testing::Test {
+ public:
+ SenderSessionTest() : clock_(Clock::time_point{}), task_runner_(&clock_) {}
+
+ std::unique_ptr<MockEnvironment> MakeEnvironment() {
+ auto environment_ = std::make_unique<NiceMock<MockEnvironment>>(
+ &FakeClock::now, &task_runner_);
+ ON_CALL(*environment_, GetBoundLocalEndpoint())
+ .WillByDefault(
+ Return(IPEndpoint{IPAddress::Parse("127.0.0.1").value(), 12345}));
+ return environment_;
+ }
+
+ void SetUp() {
+ message_port_ = std::make_unique<SimpleMessagePort>();
+ environment_ = MakeEnvironment();
+ session_ = std::make_unique<SenderSession>(IPAddress::kV4LoopbackAddress(),
+ &client_, environment_.get(),
+ message_port_.get());
+ }
+
+ protected:
+ StrictMock<FakeClient> client_;
+ FakeClock clock_;
+ std::unique_ptr<MockEnvironment> environment_;
+ std::unique_ptr<SimpleMessagePort> message_port_;
+ std::unique_ptr<SenderSession> session_;
+ FakeTaskRunner task_runner_;
+};
+
+TEST_F(SenderSessionTest, RegistersSelfOnMessagePort) {
+ EXPECT_EQ(message_port_->client(), session_.get());
+}
+
+TEST_F(SenderSessionTest, ComplainsIfNoConfigsToOffer) {
+ const Error error = session_->Negotiate(std::vector<AudioCaptureConfig>{},
+ std::vector<VideoCaptureConfig>{});
+
+ EXPECT_EQ(error,
+ Error(Error::Code::kParameterInvalid,
+ "Need at least one audio or video config to negotiate."));
+}
+
+TEST_F(SenderSessionTest, ComplainsIfInvalidAudioCaptureConfig) {
+ const Error error = session_->Negotiate(
+ std::vector<AudioCaptureConfig>{kAudioCaptureConfigInvalidChannels},
+ std::vector<VideoCaptureConfig>{});
+
+ EXPECT_EQ(error,
+ Error(Error::Code::kParameterInvalid, "Invalid configs provided."));
+}
+
+TEST_F(SenderSessionTest, ComplainsIfInvalidVideoCaptureConfig) {
+ const Error error = session_->Negotiate(
+ std::vector<AudioCaptureConfig>{},
+ std::vector<VideoCaptureConfig>{kVideoCaptureConfigInvalid});
+ EXPECT_EQ(error,
+ Error(Error::Code::kParameterInvalid, "Invalid configs provided."));
+}
+
+TEST_F(SenderSessionTest, ComplainsIfMissingResolutions) {
+ const Error error = session_->Negotiate(
+ std::vector<AudioCaptureConfig>{},
+ std::vector<VideoCaptureConfig>{kVideoCaptureConfigMissingResolutions});
+ EXPECT_EQ(error,
+ Error(Error::Code::kParameterInvalid, "Invalid configs provided."));
+}
+
+TEST_F(SenderSessionTest, SendsOfferWithZeroBitrateOptions) {
+ VideoCaptureConfig video_config = kVideoCaptureConfigValid;
+ video_config.max_bit_rate = 0;
+ AudioCaptureConfig audio_config = kAudioCaptureConfigValid;
+ audio_config.bit_rate = 0;
+
+ const Error error =
+ session_->Negotiate(std::vector<AudioCaptureConfig>{audio_config},
+ std::vector<VideoCaptureConfig>{video_config});
+ EXPECT_TRUE(error.ok());
+
+ const auto& messages = message_port_->posted_messages();
+ ASSERT_EQ(1u, messages.size());
+ auto message_body = json::Parse(messages[0]);
+ ASSERT_TRUE(message_body.is_value());
+ const Json::Value offer = std::move(message_body.value());
+ EXPECT_EQ("OFFER", offer["type"].asString());
+}
+
+TEST_F(SenderSessionTest, SendsOfferWithSimpleVideoOnly) {
+ const Error error = session_->Negotiate(
+ std::vector<AudioCaptureConfig>{},
+ std::vector<VideoCaptureConfig>{kVideoCaptureConfigValid});
+ EXPECT_TRUE(error.ok());
+
+ const auto& messages = message_port_->posted_messages();
+ ASSERT_EQ(1u, messages.size());
+ auto message_body = json::Parse(messages[0]);
+ ASSERT_TRUE(message_body.is_value());
+ const Json::Value offer = std::move(message_body.value());
+ EXPECT_EQ("OFFER", offer["type"].asString());
+}
+
+TEST_F(SenderSessionTest, SendsOfferAudioOnly) {
+ const Error error = session_->Negotiate(
+ std::vector<AudioCaptureConfig>{kAudioCaptureConfigValid},
+ std::vector<VideoCaptureConfig>{});
+ EXPECT_TRUE(error.ok());
+
+ const auto& messages = message_port_->posted_messages();
+ ASSERT_EQ(1u, messages.size());
+ auto message_body = json::Parse(messages[0]);
+ ASSERT_TRUE(message_body.is_value());
+ const Json::Value offer = std::move(message_body.value());
+ EXPECT_EQ("OFFER", offer["type"].asString());
+}
+
+TEST_F(SenderSessionTest, SendsOfferMessage) {
+ session_->Negotiate(
+ std::vector<AudioCaptureConfig>{kAudioCaptureConfigValid},
+ std::vector<VideoCaptureConfig>{kVideoCaptureConfigValid});
+
+ const auto& messages = message_port_->posted_messages();
+ ASSERT_EQ(1u, messages.size());
+
+ auto message_body = json::Parse(messages[0]);
+ ASSERT_TRUE(message_body.is_value());
+ const Json::Value offer = std::move(message_body.value());
+ EXPECT_EQ("OFFER", offer["type"].asString());
+ EXPECT_LT(0, offer["seqNum"].asInt());
+
+ const Json::Value& offer_body = offer["offer"];
+ ASSERT_FALSE(offer_body.isNull());
+ ASSERT_TRUE(offer_body.isObject());
+ EXPECT_EQ("mirroring", offer_body["castMode"].asString());
+ EXPECT_EQ(false, offer_body["receiverGetStatus"].asBool());
+
+ const Json::Value& streams = offer_body["supportedStreams"];
+ EXPECT_TRUE(streams.isArray());
+ EXPECT_EQ(2u, streams.size());
+
+ const Json::Value& audio_stream = streams[0];
+ EXPECT_EQ("opus", audio_stream["codecName"].asString());
+ EXPECT_EQ(0, audio_stream["index"].asInt());
+ EXPECT_EQ(32u, audio_stream["aesKey"].asString().length());
+ EXPECT_EQ(32u, audio_stream["aesIvMask"].asString().length());
+ EXPECT_EQ(5, audio_stream["channels"].asInt());
+ EXPECT_LT(0u, audio_stream["ssrc"].asUInt());
+ EXPECT_EQ(127, audio_stream["rtpPayloadType"].asInt());
+
+ const Json::Value& video_stream = streams[1];
+ EXPECT_EQ("hevc", video_stream["codecName"].asString());
+ EXPECT_EQ(1, video_stream["index"].asInt());
+ EXPECT_EQ(32u, video_stream["aesKey"].asString().length());
+ EXPECT_EQ(32u, video_stream["aesIvMask"].asString().length());
+ EXPECT_EQ(1, video_stream["channels"].asInt());
+ EXPECT_LT(0u, video_stream["ssrc"].asUInt());
+ EXPECT_EQ(96, video_stream["rtpPayloadType"].asInt());
+}
+
+TEST_F(SenderSessionTest, HandlesValidAnswer) {
+ const Error error = session_->Negotiate(
+ std::vector<AudioCaptureConfig>{kAudioCaptureConfigValid},
+ std::vector<VideoCaptureConfig>{kVideoCaptureConfigValid});
+
+ ASSERT_TRUE(error.ok());
+
+ const auto& messages = message_port_->posted_messages();
+ ASSERT_EQ(1u, messages.size());
+ auto message_body = json::Parse(messages[0]);
+ ASSERT_TRUE(message_body.is_value());
+ const Json::Value offer = std::move(message_body.value());
+ EXPECT_EQ("OFFER", offer["type"].asString());
+ EXPECT_LT(0, offer["seqNum"].asInt());
+
+ const Json::Value& offer_body = offer["offer"];
+ ASSERT_FALSE(offer_body.isNull());
+ ASSERT_TRUE(offer_body.isObject());
+ const Json::Value& streams = offer_body["supportedStreams"];
+ EXPECT_TRUE(streams.isArray());
+ EXPECT_EQ(2u, streams.size());
+
+ const Json::Value& audio_stream = streams[0];
+ const int audio_index = audio_stream["index"].asInt();
+ const int audio_ssrc = audio_stream["ssrc"].asUInt();
+
+ const Json::Value& video_stream = streams[1];
+ const int video_index = video_stream["index"].asInt();
+ const int video_ssrc = video_stream["ssrc"].asUInt();
+
+ constexpr size_t kAnswerSize = 512u;
+ char answer[kAnswerSize];
+ snprintf(answer, kAnswerSize, R"({ "type": "ANSWER",
+ "seqNum": %d,
+ "answer": {
+ "castMode": "mirroring",
+ "udpPort": 1234,
+ "sendIndexes": [%d, %d],
+ "ssrcs": [%d, %d]
+ }
+ })",
+ offer["seqNum"].asInt(), audio_index, video_index, audio_ssrc + 1,
+ video_ssrc + 1);
+
+ // We should have responded with an on negotiated call
+ EXPECT_CALL(client_, OnNegotiated(session_.get(), _, _));
+ message_port_->ReceiveMessage(answer);
+}
+
+TEST_F(SenderSessionTest, HandlesInvalidNamespace) {
+ const Error error = session_->Negotiate(
+ std::vector<AudioCaptureConfig>{kAudioCaptureConfigValid},
+ std::vector<VideoCaptureConfig>{kVideoCaptureConfigValid});
+ message_port_->ReceiveMessage(kValidJsonInvalidAnswerMessage,
+ "random-namespace");
+}
+
+TEST_F(SenderSessionTest, HandlesMalformedAnswer) {
+ session_->Negotiate(
+ std::vector<AudioCaptureConfig>{kAudioCaptureConfigValid},
+ std::vector<VideoCaptureConfig>{kVideoCaptureConfigValid});
+
+ // Note that unlike when we simply don't select any streams, when the answer
+ // is actually malformed we have no way of knowing it was an answer at all,
+ // so we just drop it without error.
+ message_port_->ReceiveMessage(kMalformedAnswerMessage);
+}
+
+TEST_F(SenderSessionTest, HandlesImproperlyFormattedAnswer) {
+ session_->Negotiate(
+ std::vector<AudioCaptureConfig>{kAudioCaptureConfigValid},
+ std::vector<VideoCaptureConfig>{kVideoCaptureConfigValid});
+
+ EXPECT_CALL(client_,
+ OnError(session_.get(), Error(Error::Code::kJsonParseError,
+ "Failed to parse answer")));
+ message_port_->ReceiveMessage(kValidJsonInvalidFormatAnswerMessage);
+}
+
+TEST_F(SenderSessionTest, HandlesInvalidAnswer) {
+ const Error error = session_->Negotiate(
+ std::vector<AudioCaptureConfig>{kAudioCaptureConfigValid},
+ std::vector<VideoCaptureConfig>{kVideoCaptureConfigValid});
+
+ EXPECT_CALL(client_, OnError(session_.get(),
+ Error(Error::Code::kJsonParseError,
+ "Received invalid answer message")));
+ message_port_->ReceiveMessage(kValidJsonInvalidAnswerMessage);
+}
+
+TEST_F(SenderSessionTest, HandlesNullAnswer) {
+ const Error error = session_->Negotiate(
+ std::vector<AudioCaptureConfig>{kAudioCaptureConfigValid},
+ std::vector<VideoCaptureConfig>{kVideoCaptureConfigValid});
+
+ EXPECT_TRUE(error.ok());
+ EXPECT_CALL(client_,
+ OnError(session_.get(), Error(Error::Code::kJsonParseError,
+ "Failed to parse answer")));
+ message_port_->ReceiveMessage(kMissingAnswerMessage);
+}
+
+TEST_F(SenderSessionTest, HandlesInvalidSequenceNumber) {
+ const Error error = session_->Negotiate(
+ std::vector<AudioCaptureConfig>{kAudioCaptureConfigValid},
+ std::vector<VideoCaptureConfig>{kVideoCaptureConfigValid});
+
+ // We should just discard messages with an invalid sequence number.
+ message_port_->ReceiveMessage(kInvalidSequenceNumberMessage);
+}
+
+TEST_F(SenderSessionTest, HandlesUnknownTypeMessage) {
+ session_->Negotiate(
+ std::vector<AudioCaptureConfig>{kAudioCaptureConfigValid},
+ std::vector<VideoCaptureConfig>{kVideoCaptureConfigValid});
+
+ // We should just discard messages with an unknown message type.
+ message_port_->ReceiveMessage(kUnknownTypeMessage);
+}
+
+TEST_F(SenderSessionTest, HandlesInvalidTypeMessage) {
+ session_->Negotiate(
+ std::vector<AudioCaptureConfig>{kAudioCaptureConfigValid},
+ std::vector<VideoCaptureConfig>{kVideoCaptureConfigValid});
+
+ // We should just discard messages with an invalid message type.
+ message_port_->ReceiveMessage(kInvalidTypeMessage);
+}
+
+TEST_F(SenderSessionTest, DoesntCrashOnMessagePortError) {
+ session_->Negotiate(
+ std::vector<AudioCaptureConfig>{kAudioCaptureConfigValid},
+ std::vector<VideoCaptureConfig>{kVideoCaptureConfigValid});
+
+ message_port_->ReceiveError(Error(Error::Code::kUnknownError));
+}
+
+} // namespace cast
+} // namespace openscreen
diff --git a/chromium/third_party/openscreen/src/cast/streaming/testing/simple_message_port.h b/chromium/third_party/openscreen/src/cast/streaming/testing/simple_message_port.h
new file mode 100644
index 00000000000..7d91291859d
--- /dev/null
+++ b/chromium/third_party/openscreen/src/cast/streaming/testing/simple_message_port.h
@@ -0,0 +1,64 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CAST_STREAMING_TESTING_SIMPLE_MESSAGE_PORT_H_
+#define CAST_STREAMING_TESTING_SIMPLE_MESSAGE_PORT_H_
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "cast/common/public/message_port.h"
+#include "cast/streaming/message_fields.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace openscreen {
+namespace cast {
+
+class SimpleMessagePort : public MessagePort {
+ public:
+ ~SimpleMessagePort() override {}
+ void SetClient(MessagePort::Client* client,
+ std::string client_sender_id) override {
+ client_ = client;
+ }
+
+ void ResetClient() override { client_ = nullptr; }
+
+ void ReceiveMessage(const std::string& message) {
+ ReceiveMessage(kCastWebrtcNamespace, message);
+ }
+
+ void ReceiveMessage(const std::string& namespace_,
+ const std::string message) {
+ ASSERT_NE(client_, nullptr);
+ client_->OnMessage("sender-1234", namespace_, message);
+ }
+
+ void ReceiveError(Error error) {
+ ASSERT_NE(client_, nullptr);
+ client_->OnError(error);
+ }
+
+ void PostMessage(const std::string& sender_id,
+ const std::string& message_namespace,
+ const std::string& message) override {
+ posted_messages_.emplace_back(message);
+ }
+
+ MessagePort::Client* client() const { return client_; }
+ const std::vector<std::string> posted_messages() const {
+ return posted_messages_;
+ }
+
+ private:
+ MessagePort::Client* client_ = nullptr;
+ std::vector<std::string> posted_messages_;
+};
+
+} // namespace cast
+} // namespace openscreen
+
+#endif // CAST_STREAMING_TESTING_SIMPLE_MESSAGE_PORT_H_
diff --git a/chromium/third_party/openscreen/src/cast/test/BUILD.gn b/chromium/third_party/openscreen/src/cast/test/BUILD.gn
index 67bae8abf6e..71c808c6510 100644
--- a/chromium/third_party/openscreen/src/cast/test/BUILD.gn
+++ b/chromium/third_party/openscreen/src/cast/test/BUILD.gn
@@ -6,9 +6,7 @@ import("//build_overrides/build.gni")
source_set("unittests") {
testonly = true
- sources = [
- "device_auth_test.cc",
- ]
+ sources = [ "device_auth_test.cc" ]
deps = [
"../../platform:test",
@@ -27,9 +25,7 @@ source_set("unittests") {
if (is_posix && !build_with_chromium) {
source_set("e2e_tests") {
testonly = true
- sources = [
- "cast_socket_e2e_test.cc",
- ]
+ sources = [ "cast_socket_e2e_test.cc" ]
deps = [
"../../platform",
@@ -41,16 +37,13 @@ if (is_posix && !build_with_chromium) {
"../common:channel",
"../common:test_helpers",
"../receiver:channel",
- "../receiver:test_helpers",
"../sender:channel",
]
}
executable("make_crl_tests") {
testonly = true
- sources = [
- "make_crl_tests.cc",
- ]
+ sources = [ "make_crl_tests.cc" ]
deps = [
"../../platform:test",
diff --git a/chromium/third_party/openscreen/src/discovery/common/config.h b/chromium/third_party/openscreen/src/discovery/common/config.h
index 7bcdcac75b3..b1ef731ac28 100644
--- a/chromium/third_party/openscreen/src/discovery/common/config.h
+++ b/chromium/third_party/openscreen/src/discovery/common/config.h
@@ -5,6 +5,8 @@
#ifndef DISCOVERY_COMMON_CONFIG_H_
#define DISCOVERY_COMMON_CONFIG_H_
+#include <vector>
+
#include "platform/base/interface_info.h"
namespace openscreen {
@@ -90,6 +92,10 @@ struct Config {
// prevent a malicious or misbehaving mDNS client from causing the memory
// used by mDNS to grow in an unbounded fashion.
int querier_max_records_cached = 1024;
+
+ // Sets the querier to ignore all NSEC negative response records received as
+ // responses to outgoing queries.
+ bool ignore_nsec_responses = false;
};
inline Config::NetworkInfo::AddressFamilies operator&(
diff --git a/chromium/third_party/openscreen/src/discovery/dnssd/impl/dns_data_graph.cc b/chromium/third_party/openscreen/src/discovery/dnssd/impl/dns_data_graph.cc
index 2b46fa7aa3a..036c7985627 100644
--- a/chromium/third_party/openscreen/src/discovery/dnssd/impl/dns_data_graph.cc
+++ b/chromium/third_party/openscreen/src/discovery/dnssd/impl/dns_data_graph.cc
@@ -384,8 +384,7 @@ void DnsDataGraphImpl::StartTracking(const DomainName& domain,
ScopedCallbackHandler creation_handler =
GetScopedCreationHandler(std::move(on_start_tracking));
- auto pair =
- nodes_.emplace(domain, std::make_unique<Node>(std::move(domain), this));
+ auto pair = nodes_.emplace(domain, std::make_unique<Node>(domain, this));
OSP_DCHECK(pair.second);
OSP_DCHECK(nodes_.find(domain) != nodes_.end());
diff --git a/chromium/third_party/openscreen/src/discovery/dnssd/impl/querier_impl.cc b/chromium/third_party/openscreen/src/discovery/dnssd/impl/querier_impl.cc
index 94f54fc91c4..b98feff3dce 100644
--- a/chromium/third_party/openscreen/src/discovery/dnssd/impl/querier_impl.cc
+++ b/chromium/third_party/openscreen/src/discovery/dnssd/impl/querier_impl.cc
@@ -227,8 +227,7 @@ void QuerierImpl::StartQuery(const std::string& service, Callback* callback) {
// Start tracking the new callback
const ServiceKey key(service, kLocalDomain);
- auto it =
- callback_map_.emplace(std::move(key), std::vector<Callback*>{}).first;
+ auto it = callback_map_.emplace(key, std::vector<Callback*>{}).first;
it->second.push_back(callback);
const DomainName domain = key.GetName();
diff --git a/chromium/third_party/openscreen/src/discovery/dnssd/public/dns_sd_instance.cc b/chromium/third_party/openscreen/src/discovery/dnssd/public/dns_sd_instance.cc
index 2c1382b2fb2..6761f7685a8 100644
--- a/chromium/third_party/openscreen/src/discovery/dnssd/public/dns_sd_instance.cc
+++ b/chromium/third_party/openscreen/src/discovery/dnssd/public/dns_sd_instance.cc
@@ -133,8 +133,11 @@ bool IsServiceValid(const std::string& service) {
}
last_char_hyphen = true;
} else if (std::isalpha(service[i])) {
+ last_char_hyphen = false;
seen_letter = true;
- } else if (!std::isdigit(service[i])) {
+ } else if (std::isdigit(service[i])) {
+ last_char_hyphen = false;
+ } else {
return false;
}
}
diff --git a/chromium/third_party/openscreen/src/discovery/dnssd/public/dns_sd_instance_unittest.cc b/chromium/third_party/openscreen/src/discovery/dnssd/public/dns_sd_instance_unittest.cc
index 3479204123d..3395938db77 100644
--- a/chromium/third_party/openscreen/src/discovery/dnssd/public/dns_sd_instance_unittest.cc
+++ b/chromium/third_party/openscreen/src/discovery/dnssd/public/dns_sd_instance_unittest.cc
@@ -114,6 +114,10 @@ TEST(DnsSdInstanceTests, ServiceProtocolNameFormatting) {
EXPECT_FALSE(IsServiceValid("_0a1b--c02d._udp"));
EXPECT_FALSE(IsServiceValid("_0a--1._udp"));
EXPECT_FALSE(IsServiceValid("_a--b._udp"));
+
+ // Multiple, non-adjacent hyphens.
+ EXPECT_TRUE(IsServiceValid("_a-b-c._udp"));
+ EXPECT_TRUE(IsServiceValid("_a-1-c._udp"));
}
TEST(DnsSdInstanceTests, DomainDotPositions) {
diff --git a/chromium/third_party/openscreen/src/discovery/mdns/mdns_querier.cc b/chromium/third_party/openscreen/src/discovery/mdns/mdns_querier.cc
index 2ae7260e1e1..5d961bd45ae 100644
--- a/chromium/third_party/openscreen/src/discovery/mdns/mdns_querier.cc
+++ b/chromium/third_party/openscreen/src/discovery/mdns/mdns_querier.cc
@@ -459,6 +459,11 @@ void MdnsQuerier::ProcessRecord(const MdnsRecord& record) {
return;
}
+ // Ignore NSEC records if the embedder has configured us to do so.
+ if (config_.ignore_nsec_responses && record.dns_type() == DnsType::kNSEC) {
+ return;
+ }
+
// Get the types which the received record is associated with. In most cases
// this will only be the type of the provided record, but in the case of
// NSEC records this will be all records which the record dictates the
@@ -635,8 +640,7 @@ void MdnsQuerier::ProcessCallbacks(const MdnsRecord& record,
void MdnsQuerier::AddQuestion(const MdnsQuestion& question) {
auto tracker = std::make_unique<MdnsQuestionTracker>(
- std::move(question), sender_, task_runner_, now_function_, random_delay_,
- config_);
+ question, sender_, task_runner_, now_function_, random_delay_, config_);
MdnsQuestionTracker* ptr = tracker.get();
questions_.emplace(question.name(), std::move(tracker));
diff --git a/chromium/third_party/openscreen/src/discovery/mdns/mdns_querier_unittest.cc b/chromium/third_party/openscreen/src/discovery/mdns/mdns_querier_unittest.cc
index e6742203b76..afa0cfc6a8b 100644
--- a/chromium/third_party/openscreen/src/discovery/mdns/mdns_querier_unittest.cc
+++ b/chromium/third_party/openscreen/src/discovery/mdns/mdns_querier_unittest.cc
@@ -5,6 +5,7 @@
#include "discovery/mdns/mdns_querier.h"
#include <memory>
+#include <utility>
#include "discovery/common/config.h"
#include "discovery/common/testing/mock_reporting_client.h"
@@ -550,6 +551,31 @@ TEST_F(MdnsQuerierTest, CorrectCallbackCalledWhenNsecRecordReplacesNonNsec) {
EXPECT_TRUE(ContainsRecord(querier.get(), nsec_record_created_, DnsType::kA));
}
+TEST_F(MdnsQuerierTest,
+ NoCallbackCalledWhenNsecRecordWouldReplaceNonNsecButNsecDisabled) {
+ config_.ignore_nsec_responses = true;
+ std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
+
+ // Set up so an A record has been received
+ StrictMock<MockRecordChangedCallback> callback;
+ querier->StartQuery(DomainName{"testing", "local"}, DnsType::kA,
+ DnsClass::kIN, &callback);
+ EXPECT_CALL(callback,
+ OnRecordChanged(record0_created_, RecordChangedEvent::kCreated));
+ auto packet = CreatePacketWithRecord(record0_created_);
+ receiver_.OnRead(&socket_, std::move(packet));
+ testing::Mock::VerifyAndClearExpectations(&callback);
+ ASSERT_TRUE(ContainsRecord(querier.get(), record0_created_, DnsType::kA));
+ EXPECT_FALSE(
+ ContainsRecord(querier.get(), nsec_record_created_, DnsType::kA));
+
+ packet = CreatePacketWithRecord(nsec_record_created_);
+ receiver_.OnRead(&socket_, std::move(packet));
+ EXPECT_TRUE(ContainsRecord(querier.get(), record0_created_, DnsType::kA));
+ EXPECT_FALSE(
+ ContainsRecord(querier.get(), nsec_record_created_, DnsType::kA));
+}
+
TEST_F(MdnsQuerierTest, CorrectCallbackCalledWhenNonNsecRecordReplacesNsec) {
std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
diff --git a/chromium/third_party/openscreen/src/discovery/mdns/mdns_reader.cc b/chromium/third_party/openscreen/src/discovery/mdns/mdns_reader.cc
index c6aa926b6be..bd38e81be23 100644
--- a/chromium/third_party/openscreen/src/discovery/mdns/mdns_reader.cc
+++ b/chromium/third_party/openscreen/src/discovery/mdns/mdns_reader.cc
@@ -322,8 +322,8 @@ bool MdnsReader::Read(MdnsQuestion* out) {
return false;
}
-bool MdnsReader::Read(MdnsMessage* out) {
- OSP_DCHECK(out);
+ErrorOr<MdnsMessage> MdnsReader::Read() {
+ MdnsMessage out;
Cursor cursor(this);
Header header;
std::vector<MdnsQuestion> questions;
@@ -334,26 +334,26 @@ bool MdnsReader::Read(MdnsMessage* out) {
Read(header.answer_count, &answers) &&
Read(header.authority_record_count, &authority_records) &&
Read(header.additional_record_count, &additional_records)) {
- // TODO(yakimakha): Skip messages with non-zero opcode and rcode.
- // One way to do this is to change the method signature to return
- // ErrorOr<MdnsMessage> and return different error codes for failure to read
- // and for messages that were read successfully but are non-conforming.
+ if (!IsValidFlagsSection(header.flags)) {
+ return Error::Code::kMdnsNonConformingFailure;
+ }
+
ErrorOr<MdnsMessage> message = MdnsMessage::TryCreate(
header.id, GetMessageType(header.flags), questions, answers,
authority_records, additional_records);
if (message.is_error()) {
- return false;
+ return std::move(message.error());
}
- *out = std::move(message.value());
+ out = std::move(message.value());
if (IsMessageTruncated(header.flags)) {
- out->set_truncated();
+ out.set_truncated();
}
cursor.Commit();
- return true;
+ return out;
}
- return false;
+ return Error::Code::kMdnsReadFailure;
}
bool MdnsReader::Read(IPAddress::Version version, IPAddress* out) {
diff --git a/chromium/third_party/openscreen/src/discovery/mdns/mdns_reader.h b/chromium/third_party/openscreen/src/discovery/mdns/mdns_reader.h
index bfe7eb04f22..2902e288059 100644
--- a/chromium/third_party/openscreen/src/discovery/mdns/mdns_reader.h
+++ b/chromium/third_party/openscreen/src/discovery/mdns/mdns_reader.h
@@ -5,9 +5,11 @@
#ifndef DISCOVERY_MDNS_MDNS_READER_H_
#define DISCOVERY_MDNS_MDNS_READER_H_
+#include <utility>
#include <vector>
#include "discovery/mdns/mdns_records.h"
+#include "platform/base/error.h"
#include "util/big_endian.h"
namespace openscreen {
@@ -34,14 +36,16 @@ class MdnsReader : public BigEndianReader {
bool Read(PtrRecordRdata* out);
bool Read(TxtRecordRdata* out);
bool Read(NsecRecordRdata* out);
+
// Reads a DNS resource record with its RDATA.
// The correct type of RDATA to be read is determined by the type
// specified in the record.
bool Read(MdnsRecord* out);
bool Read(MdnsQuestion* out);
+
// Reads multiple mDNS questions and records that are a part of
// a mDNS message being read.
- bool Read(MdnsMessage* out);
+ ErrorOr<MdnsMessage> Read();
private:
struct NsecBitMapField {
diff --git a/chromium/third_party/openscreen/src/discovery/mdns/mdns_reader_fuzztest.cc b/chromium/third_party/openscreen/src/discovery/mdns/mdns_reader_fuzztest.cc
index e28ff92de0f..9a97c89b564 100644
--- a/chromium/third_party/openscreen/src/discovery/mdns/mdns_reader_fuzztest.cc
+++ b/chromium/third_party/openscreen/src/discovery/mdns/mdns_reader_fuzztest.cc
@@ -5,10 +5,15 @@
#include "discovery/common/config.h"
#include "discovery/mdns/mdns_reader.h"
+namespace openscreen {
+namespace discovery {
+void Fuzz(const uint8_t* data, size_t size) {
+ MdnsReader reader(Config{}, data, size);
+ reader.Read();
+}
+} // namespace discovery
+} // namespace openscreen
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
- openscreen::discovery::Config config;
- openscreen::discovery::MdnsReader reader(config, data, size);
- openscreen::discovery::MdnsMessage message;
- reader.Read(&message);
+ openscreen::discovery::Fuzz(data, size);
return 0;
}
diff --git a/chromium/third_party/openscreen/src/discovery/mdns/mdns_reader_unittest.cc b/chromium/third_party/openscreen/src/discovery/mdns/mdns_reader_unittest.cc
index 2882c8e2d26..08062e5d9b7 100644
--- a/chromium/third_party/openscreen/src/discovery/mdns/mdns_reader_unittest.cc
+++ b/chromium/third_party/openscreen/src/discovery/mdns/mdns_reader_unittest.cc
@@ -30,6 +30,17 @@ void TestReadEntrySucceeds(const uint8_t* data,
EXPECT_EQ(reader.remaining(), UINT64_C(0));
}
+template <>
+void TestReadEntrySucceeds<MdnsMessage>(const uint8_t* data,
+ size_t size,
+ const MdnsMessage& expected) {
+ MdnsReader reader(Config{}, data, size);
+ const ErrorOr<MdnsMessage> message = reader.Read();
+ EXPECT_TRUE(message.is_value());
+ EXPECT_EQ(message.value(), expected);
+ EXPECT_EQ(reader.remaining(), UINT64_C(0));
+}
+
template <class T>
void TestReadEntryFails(const uint8_t* data, size_t size) {
Config config;
@@ -41,6 +52,17 @@ void TestReadEntryFails(const uint8_t* data, size_t size) {
EXPECT_EQ(reader.offset(), UINT64_C(0));
}
+template <>
+void TestReadEntryFails<MdnsMessage>(const uint8_t* data, size_t size) {
+ Config config;
+ MdnsReader reader(config, data, size);
+ const ErrorOr<MdnsMessage> message = reader.Read();
+ EXPECT_TRUE(message.is_error());
+
+ // There should be no side effects for failing to read an entry. The
+ // underlying pointer should not have changed.
+ EXPECT_EQ(reader.offset(), UINT64_C(0));
+}
} // namespace
TEST(MdnsReaderTest, ReadDomainName) {
diff --git a/chromium/third_party/openscreen/src/discovery/mdns/mdns_receiver.cc b/chromium/third_party/openscreen/src/discovery/mdns/mdns_receiver.cc
index bb8634d2198..09982dd858c 100644
--- a/chromium/third_party/openscreen/src/discovery/mdns/mdns_receiver.cc
+++ b/chromium/third_party/openscreen/src/discovery/mdns/mdns_receiver.cc
@@ -66,15 +66,19 @@ void MdnsReceiver::OnRead(UdpSocket* socket,
TRACE_SCOPED(TraceCategory::kMdns, "MdnsReceiver::OnRead");
MdnsReader reader(config_, packet.data(), packet.size());
- MdnsMessage message;
- if (!reader.Read(&message)) {
- OSP_DVLOG << "mDNS message failed to parse...";
+ const ErrorOr<MdnsMessage> message = reader.Read();
+ if (message.is_error()) {
+ if (message.error().code() == Error::Code::kMdnsNonConformingFailure) {
+ OSP_DVLOG << "mDNS message dropped due to invalid rcode or opcode...";
+ } else {
+ OSP_DVLOG << "mDNS message failed to parse...";
+ }
return;
}
- if (message.type() == MessageType::Response) {
+ if (message.value().type() == MessageType::Response) {
for (ResponseClient* client : response_clients_) {
- client->OnMessageReceived(message);
+ client->OnMessageReceived(message.value());
}
if (response_clients_.empty()) {
OSP_DVLOG
@@ -82,7 +86,7 @@ void MdnsReceiver::OnRead(UdpSocket* socket,
}
} else {
if (query_callback_) {
- query_callback_(message, packet.source());
+ query_callback_(message.value(), packet.source());
} else {
OSP_DVLOG << "mDNS query message dropped. No query client registered...";
}
diff --git a/chromium/third_party/openscreen/src/discovery/mdns/mdns_records.cc b/chromium/third_party/openscreen/src/discovery/mdns/mdns_records.cc
index eadbff9c31c..6eed677bfd4 100644
--- a/chromium/third_party/openscreen/src/discovery/mdns/mdns_records.cc
+++ b/chromium/third_party/openscreen/src/discovery/mdns/mdns_records.cc
@@ -47,27 +47,29 @@ bool IsGreaterThan(const Rdata& lhs, const Rdata& rhs) {
const RDataType& lhs_cast = absl::get<RDataType>(lhs);
const RDataType& rhs_cast = absl::get<RDataType>(rhs);
- size_t lhs_size = lhs_cast.MaxWireSize();
- size_t rhs_size = rhs_cast.MaxWireSize();
- size_t min_size = std::min(lhs_size, rhs_size);
+ // The Extra 2 in length is from the record size that Write() prepends to the
+ // result.
+ const size_t lhs_size = lhs_cast.MaxWireSize() + 2;
+ const size_t rhs_size = rhs_cast.MaxWireSize() + 2;
uint8_t lhs_bytes[lhs_size];
uint8_t rhs_bytes[rhs_size];
MdnsWriter lhs_writer(lhs_bytes, lhs_size);
MdnsWriter rhs_writer(rhs_bytes, rhs_size);
- lhs_writer.Write(lhs_cast);
- rhs_writer.Write(rhs_cast);
- for (size_t i = 0; i < min_size; i++) {
+ const bool lhs_write = lhs_writer.Write(lhs_cast);
+ const bool rhs_write = rhs_writer.Write(rhs_cast);
+ OSP_DCHECK(lhs_write);
+ OSP_DCHECK(rhs_write);
+
+ // Skip the size bits.
+ const size_t min_size = std::min(lhs_writer.offset(), rhs_writer.offset());
+ for (size_t i = 2; i < min_size; i++) {
if (lhs_bytes[i] != rhs_bytes[i]) {
return lhs_bytes[i] > rhs_bytes[i];
}
}
- if (lhs_size == rhs_size) {
- return false;
- }
-
return lhs_size > rhs_size;
}
@@ -619,6 +621,15 @@ bool MdnsRecord::operator>(const MdnsRecord& rhs) const {
// "lexicographically later" is performed by first comparing the record class,
// then the record type, then raw comparison of the binary content of the
// rdata without regard for meaning or structure.
+ // NOTE: Per RFC, the TTL is not included in this comparison.
+ if (name() != rhs.name()) {
+ return name() > rhs.name();
+ }
+
+ if (record_type() != rhs.record_type()) {
+ return record_type() == RecordType::kUnique;
+ }
+
if (dns_class() != rhs.dns_class()) {
return dns_class() > rhs.dns_class();
}
diff --git a/chromium/third_party/openscreen/src/discovery/mdns/mdns_records_unittest.cc b/chromium/third_party/openscreen/src/discovery/mdns/mdns_records_unittest.cc
index 395c9259c5d..f30b8845fd9 100644
--- a/chromium/third_party/openscreen/src/discovery/mdns/mdns_records_unittest.cc
+++ b/chromium/third_party/openscreen/src/discovery/mdns/mdns_records_unittest.cc
@@ -541,38 +541,61 @@ TEST(MdnsRecordTest, Construct) {
}
TEST(MdnsRecordTest, Compare) {
- MdnsRecord record1(DomainName{"hostname", "local"}, DnsType::kPTR,
- DnsClass::kIN, RecordType::kShared, kTtl,
- PtrRecordRdata(DomainName{"testing", "local"}));
- MdnsRecord record2(DomainName{"hostname", "local"}, DnsType::kPTR,
- DnsClass::kIN, RecordType::kShared, kTtl,
- PtrRecordRdata(DomainName{"testing", "local"}));
- MdnsRecord record3(DomainName{"othername", "local"}, DnsType::kPTR,
- DnsClass::kIN, RecordType::kShared, kTtl,
- PtrRecordRdata(DomainName{"testing", "local"}));
- MdnsRecord record4(DomainName{"hostname", "local"}, DnsType::kA,
- DnsClass::kIN, RecordType::kShared, kTtl,
- ARecordRdata(IPAddress{8, 8, 8, 8}));
- MdnsRecord record5(DomainName{"hostname", "local"}, DnsType::kPTR,
- DnsClass::kIN, RecordType::kUnique, kTtl,
- PtrRecordRdata(DomainName{"testing", "local"}));
- MdnsRecord record6(DomainName{"hostname", "local"}, DnsType::kPTR,
- DnsClass::kIN, RecordType::kShared,
- std::chrono::seconds(200),
- PtrRecordRdata(DomainName{"testing", "local"}));
- MdnsRecord record7(DomainName{"hostname", "local"}, DnsType::kPTR,
- DnsClass::kIN, RecordType::kShared, kTtl,
- PtrRecordRdata(DomainName{"device", "local"}));
+ const MdnsRecord record1(DomainName{"hostname", "local"}, DnsType::kPTR,
+ DnsClass::kIN, RecordType::kShared, kTtl,
+ PtrRecordRdata(DomainName{"testing", "local"}));
+ const MdnsRecord record2(DomainName{"hostname", "local"}, DnsType::kPTR,
+ DnsClass::kIN, RecordType::kShared, kTtl,
+ PtrRecordRdata(DomainName{"testing", "local"}));
+ const MdnsRecord record3(DomainName{"othername", "local"}, DnsType::kPTR,
+ DnsClass::kIN, RecordType::kShared, kTtl,
+ PtrRecordRdata(DomainName{"testing", "local"}));
+ const MdnsRecord record4(DomainName{"hostname", "local"}, DnsType::kA,
+ DnsClass::kIN, RecordType::kShared, kTtl,
+ ARecordRdata(IPAddress{8, 8, 8, 8}));
+ const MdnsRecord record5(DomainName{"hostname", "local"}, DnsType::kPTR,
+ DnsClass::kIN, RecordType::kUnique, kTtl,
+ PtrRecordRdata(DomainName{"testing", "local"}));
+ const MdnsRecord record6(DomainName{"hostname", "local"}, DnsType::kPTR,
+ DnsClass::kIN, RecordType::kShared,
+ std::chrono::seconds(200),
+ PtrRecordRdata(DomainName{"testing", "local"}));
+ const MdnsRecord record7(DomainName{"hostname", "local"}, DnsType::kPTR,
+ DnsClass::kIN, RecordType::kShared, kTtl,
+ PtrRecordRdata(DomainName{"device", "local"}));
+ const MdnsRecord record8(
+ DomainName{"testing", "local"}, DnsType::kNSEC, DnsClass::kIN,
+ RecordType::kUnique, std::chrono::seconds(120),
+ NsecRecordRdata(DomainName{"testing", "local"}, DnsType::kA));
+ const MdnsRecord record9(
+ DomainName{"testing", "local"}, DnsType::kNSEC, DnsClass::kIN,
+ RecordType::kUnique, std::chrono::seconds(120),
+ NsecRecordRdata(DomainName{"testing", "local"}, DnsType::kAAAA));
EXPECT_EQ(record1, record2);
- EXPECT_NE(record1, record3);
- EXPECT_NE(record1, record4);
- EXPECT_NE(record1, record5);
+
+ // Account for intentional differences between > / < and = / !=. This is
+ // unfortunate but required difference for > / < per RFC.
EXPECT_NE(record1, record6);
- EXPECT_NE(record1, record7);
+ ASSERT_FALSE(record1 > record6);
+ ASSERT_FALSE(record6 > record1);
+
+ std::vector<const MdnsRecord*> records_sorted{
+ &record4, &record7, &record1, &record5, &record3, &record8, &record9};
+ for (size_t i = 0; i < records_sorted.size(); i++) {
+ for (size_t j = i + 1; j < records_sorted.size(); j++) {
+ EXPECT_NE(*records_sorted[i], *records_sorted[j])
+ << "failure for i=" << i << " , j=" << j;
+ EXPECT_GT(*records_sorted[j], *records_sorted[i])
+ << "failure for i=" << i << " , j=" << j;
+ EXPECT_LT(*records_sorted[i], *records_sorted[j])
+ << "failure for i=" << i << " , j=" << j;
+ }
+ }
EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
- {record1, record2, record3, record4, record5, record6, record7}));
+ {record1, record2, record3, record4, record5, record6, record7, record8,
+ record9}));
}
TEST(MdnsRecordTest, CopyAndMove) {
diff --git a/chromium/third_party/openscreen/src/discovery/mdns/mdns_trackers.h b/chromium/third_party/openscreen/src/discovery/mdns/mdns_trackers.h
index 6cb863a94a1..58e0ccdcabf 100644
--- a/chromium/third_party/openscreen/src/discovery/mdns/mdns_trackers.h
+++ b/chromium/third_party/openscreen/src/discovery/mdns/mdns_trackers.h
@@ -5,6 +5,7 @@
#ifndef DISCOVERY_MDNS_MDNS_TRACKERS_H_
#define DISCOVERY_MDNS_MDNS_TRACKERS_H_
+#include <tuple>
#include <unordered_map>
#include <vector>
@@ -82,7 +83,7 @@ class MdnsTracker {
MdnsSender* const sender_;
TaskRunner* const task_runner_;
const ClockNowFunctionPtr now_function_;
- Alarm send_alarm_; // TODO(yakimakha): Use cancelable task when available
+ Alarm send_alarm_;
MdnsRandom* const random_delay_;
TrackerType tracker_type_;
diff --git a/chromium/third_party/openscreen/src/infra/config/global/cr-buildbucket.cfg b/chromium/third_party/openscreen/src/infra/config/global/cr-buildbucket.cfg
index 2ecf7291081..7a60c48faba 100644
--- a/chromium/third_party/openscreen/src/infra/config/global/cr-buildbucket.cfg
+++ b/chromium/third_party/openscreen/src/infra/config/global/cr-buildbucket.cfg
@@ -91,18 +91,17 @@ builder_mixins {
# NOTE: The OS version here will determine which version of XCode is being
# used. Relevant links; so you and I never have to spend hours finding this
- # stuff all over again to fix things like https://crbug.com/openscreen/86:
+ # stuff all over again to fix things like https://crbug.com/openscreen/86
#
# 1. The recipe code that uses the "osx_sdk" recipe module:
#
- # https://cs.chromium.org/chromium/build/scripts/slave/recipes
- # /openscreen.py?rcl=671f9f1c5f5bef81d0a39973aa8729cc83bb290e&l=74
+ # https://cs.chromium.org/chromium/build/scripts/slave/recipes/openscreen.py?rcl=671f9f1c5f5bef81d0a39973aa8729cc83bb290e&l=74
#
# 2. The XCode version look-up table in the "osx_sdk" recipe module:
#
- # https://cs.chromium.org/chromium/tools/depot_tools/recipes/recipe_modules
- # /osx_sdk/api.py?rcl=fe18a43d590a5eac0d58e7e555b024746ba290ad&l=26
- dimensions: "os:Mac-10.13"
+ # https://cs.chromium.org/chromium/tools/depot_tools/recipes/recipe_modules/osx_sdk/api.py?l=32
+ #
+ dimensions: "os:Mac-10.15"
caches: {
# Cache for mac_toolchain tool and XCode.app used in recipes.
@@ -140,7 +139,7 @@ builder_mixins {
name: "chromium"
recipe: {
name: "chromium"
- properties: "mastername:client.openscreen.chromium"
+ properties: "builder_group:client.openscreen.chromium"
}
}
diff --git a/chromium/third_party/openscreen/src/infra/config/global/refs.cfg b/chromium/third_party/openscreen/src/infra/config/global/refs.cfg
deleted file mode 100644
index b287e225083..00000000000
--- a/chromium/third_party/openscreen/src/infra/config/global/refs.cfg
+++ /dev/null
@@ -1,6 +0,0 @@
-# Refs configuration file. The documentation of the format can be found
-# at https://luci-config.appspot.com/schemas/projects:refs.cfg.
-refs {
- name: "refs/heads/master"
- config_path: "infra/config/branch"
-}
diff --git a/chromium/third_party/openscreen/src/platform/api/udp_socket.cc b/chromium/third_party/openscreen/src/platform/api/udp_socket.cc
index 2da7a73f429..47eba8bdd22 100644
--- a/chromium/third_party/openscreen/src/platform/api/udp_socket.cc
+++ b/chromium/third_party/openscreen/src/platform/api/udp_socket.cc
@@ -1,6 +1,6 @@
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file
+// found in the LICENSE file.
#include "platform/api/udp_socket.h"
diff --git a/chromium/third_party/openscreen/src/platform/base/error.cc b/chromium/third_party/openscreen/src/platform/base/error.cc
index 05a0c070d12..f05c1e79863 100644
--- a/chromium/third_party/openscreen/src/platform/base/error.cc
+++ b/chromium/third_party/openscreen/src/platform/base/error.cc
@@ -110,6 +110,10 @@ std::ostream& operator<<(std::ostream& os, const Error::Code& code) {
return os << "SocketSendFailure";
case Error::Code::kMdnsRegisterFailure:
return os << "MdnsRegisterFailure";
+ case Error::Code::kMdnsReadFailure:
+ return os << "MdnsReadFailure";
+ case Error::Code::kMdnsNonConformingFailure:
+ return os << "kMdnsNonConformingFailure";
case Error::Code::kParseError:
return os << "ParseError";
case Error::Code::kUnknownMessageType:
@@ -154,6 +158,8 @@ std::ostream& operator<<(std::ostream& os, const Error::Code& code) {
return os << "ErrCertsDateInvalid";
case Error::Code::kErrCertsVerifyGeneric:
return os << "ErrCertsVerifyGeneric";
+ case Error::Code::kErrCertsVerifyUntrustedCert:
+ return os << "kErrCertsVerifyUntrustedCert";
case Error::Code::kErrCrlInvalid:
return os << "ErrCrlInvalid";
case Error::Code::kErrCertsRevoked:
diff --git a/chromium/third_party/openscreen/src/platform/base/error.h b/chromium/third_party/openscreen/src/platform/base/error.h
index 55588ac0ebb..919c6575de0 100644
--- a/chromium/third_party/openscreen/src/platform/base/error.h
+++ b/chromium/third_party/openscreen/src/platform/base/error.h
@@ -63,7 +63,10 @@ class Error {
kSocketReadFailure,
kSocketSendFailure,
+ // MDNS errors.
kMdnsRegisterFailure,
+ kMdnsReadFailure,
+ kMdnsNonConformingFailure,
kParseError,
kUnknownMessageType,
@@ -117,6 +120,9 @@ class Error {
// The certificate failed to chain to a trusted root.
kErrCertsVerifyGeneric,
+ // The certificate was not found in the trust store.
+ kErrCertsVerifyUntrustedCert,
+
// The CRL is missing or failed to verify.
kErrCrlInvalid,
diff --git a/chromium/third_party/openscreen/src/platform/base/trace_logging_types.h b/chromium/third_party/openscreen/src/platform/base/trace_logging_types.h
index 64149a7eeb1..257feaff073 100644
--- a/chromium/third_party/openscreen/src/platform/base/trace_logging_types.h
+++ b/chromium/third_party/openscreen/src/platform/base/trace_logging_types.h
@@ -60,7 +60,8 @@ struct TraceCategory {
kSsl = 0x01 << 2,
kPresentation = 0x01 << 3,
kStandaloneReceiver = 0x01 << 4,
- kDiscovery = 0x01 << 5
+ kDiscovery = 0x01 << 5,
+ kStandaloneSender = 0x01 << 6,
};
};
diff --git a/chromium/third_party/openscreen/src/platform/impl/socket_handle.h b/chromium/third_party/openscreen/src/platform/impl/socket_handle.h
index fca8192e941..4e6934c3f6c 100644
--- a/chromium/third_party/openscreen/src/platform/impl/socket_handle.h
+++ b/chromium/third_party/openscreen/src/platform/impl/socket_handle.h
@@ -1,6 +1,6 @@
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file
+// found in the LICENSE file.
#ifndef PLATFORM_IMPL_SOCKET_HANDLE_H_
#define PLATFORM_IMPL_SOCKET_HANDLE_H_
diff --git a/chromium/third_party/openscreen/src/platform/impl/socket_handle_posix.cc b/chromium/third_party/openscreen/src/platform/impl/socket_handle_posix.cc
index dfc9c5bb34c..35e1fd06506 100644
--- a/chromium/third_party/openscreen/src/platform/impl/socket_handle_posix.cc
+++ b/chromium/third_party/openscreen/src/platform/impl/socket_handle_posix.cc
@@ -1,6 +1,6 @@
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file
+// found in the LICENSE file.
#include "platform/impl/socket_handle_posix.h"
diff --git a/chromium/third_party/openscreen/src/platform/impl/socket_handle_posix.h b/chromium/third_party/openscreen/src/platform/impl/socket_handle_posix.h
index 13f977c33d8..f3d8b7a175e 100644
--- a/chromium/third_party/openscreen/src/platform/impl/socket_handle_posix.h
+++ b/chromium/third_party/openscreen/src/platform/impl/socket_handle_posix.h
@@ -1,6 +1,6 @@
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file
+// found in the LICENSE file.
#ifndef PLATFORM_IMPL_SOCKET_HANDLE_POSIX_H_
#define PLATFORM_IMPL_SOCKET_HANDLE_POSIX_H_
diff --git a/chromium/third_party/openscreen/src/platform/impl/task_runner.cc b/chromium/third_party/openscreen/src/platform/impl/task_runner.cc
index d8f941c372d..f306e792130 100644
--- a/chromium/third_party/openscreen/src/platform/impl/task_runner.cc
+++ b/chromium/third_party/openscreen/src/platform/impl/task_runner.cc
@@ -1,6 +1,6 @@
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file
+// found in the LICENSE file.
#include "platform/impl/task_runner.h"
@@ -78,6 +78,7 @@ void TaskRunnerImpl::RunUntilStopped() {
task_runner_thread_id_ = std::this_thread::get_id();
is_running_ = true;
+ OSP_DVLOG << "Running tasks until stopped...";
// Main loop: Run until the |is_running_| flag is set back to false by the
// "quit task" posted by RequestStopSoon(), or the process received a
// termination signal.
@@ -91,6 +92,7 @@ void TaskRunnerImpl::RunUntilStopped() {
}
}
+ OSP_DVLOG << "Finished running, entering flushing phase...";
// Flushing phase: Ensure all immediately-runnable tasks are run before
// returning. Since running some tasks might cause more immediately-runnable
// tasks to be posted, loop until there is no more work.
@@ -103,7 +105,7 @@ void TaskRunnerImpl::RunUntilStopped() {
while (GrabMoreRunnableTasks()) {
RunRunnableTasks();
}
-
+ OSP_DVLOG << "Finished flushing...";
task_runner_thread_id_ = std::thread::id();
}
@@ -118,6 +120,7 @@ void TaskRunnerImpl::RunUntilSignaled() {
std::signal(SIGINT, old_sigint_handler);
std::signal(SIGTERM, old_sigterm_handler);
+ OSP_DVLOG << "Received SIGNIT or SIGTERM, setting state to not running...";
g_signal_state = kNotRunning;
}
diff --git a/chromium/third_party/openscreen/src/platform/impl/udp_socket_posix.cc b/chromium/third_party/openscreen/src/platform/impl/udp_socket_posix.cc
index 5e60dd0d723..393e272743c 100644
--- a/chromium/third_party/openscreen/src/platform/impl/udp_socket_posix.cc
+++ b/chromium/third_party/openscreen/src/platform/impl/udp_socket_posix.cc
@@ -13,6 +13,7 @@
#include <sys/types.h>
#include <unistd.h>
+#include <algorithm>
#include <cstring>
#include <memory>
#include <sstream>
@@ -29,6 +30,11 @@
namespace openscreen {
namespace {
+// 64 KB is the maximum possible UDP datagram size.
+#if !defined(OS_LINUX)
+constexpr int kMaxUdpBufferSize = 64 << 10;
+#endif
+
constexpr bool IsPowerOf2(uint32_t x) {
return (x > 0) && ((x & (x - 1)) == 0);
}
@@ -372,29 +378,53 @@ bool IsPacketInfo<in6_pktinfo>(cmsghdr* cmh) {
}
template <class SockAddrType, class PktInfoType>
-Error ReceiveMessageInternal(int fd, UdpPacket* packet) {
+ErrorOr<UdpPacket> ReceiveMessageInternal(int fd) {
+ int upper_bound_bytes;
+#if defined(OS_LINUX)
+ // This should return the exact size of the next message.
+ upper_bound_bytes = recv(fd, nullptr, 0, MSG_PEEK | MSG_TRUNC);
+ if (upper_bound_bytes == -1) {
+ return ChooseError(errno, Error::Code::kSocketReadFailure);
+ }
+#elif defined(MAC_OSX)
+ // Can't use MSG_TRUNC in recv(). Use the FIONREAD ioctl() to get an
+ // upper-bound.
+ if (ioctl(fd, FIONREAD, &upper_bound_bytes) == -1 || upper_bound_bytes < 0) {
+ return ChooseError(errno, Error::Code::kSocketReadFailure);
+ }
+ upper_bound_bytes = std::min(upper_bound_bytes, kMaxUdpBufferSize);
+#else // Other POSIX platforms (neither MSG_TRUNC nor FIONREAD available).
+ upper_bound_bytes = kMaxUdpBufferSize;
+#endif
+
+ UdpPacket packet(upper_bound_bytes);
+ msghdr msg = {};
SockAddrType sa;
- iovec iov = {packet->data(), packet->size()};
- alignas(alignof(cmsghdr)) uint8_t control_buffer[1024];
- msghdr msg;
msg.msg_name = &sa;
msg.msg_namelen = sizeof(sa);
+ iovec iov = {packet.data(), packet.size()};
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
+
+ // Although we don't do anything with the control buffer, on Linux
+ // it is required for the message to be properly read.
+#if defined(OS_LINUX)
+ alignas(alignof(cmsghdr)) uint8_t control_buffer[1024];
msg.msg_control = control_buffer;
msg.msg_controllen = sizeof(control_buffer);
- msg.msg_flags = 0;
-
- ssize_t bytes_received = recvmsg(fd, &msg, 0);
+#endif
+ const ssize_t bytes_received = recvmsg(fd, &msg, 0);
if (bytes_received == -1) {
+ OSP_DVLOG << "Failed to read from socket.";
return ChooseError(errno, Error::Code::kSocketReadFailure);
}
-
- OSP_DCHECK_EQ(static_cast<size_t>(bytes_received), packet->size());
+ // We may not populate the entire packet.
+ OSP_DCHECK_LE(static_cast<size_t>(bytes_received), packet.size());
+ packet.resize(bytes_received);
IPEndpoint source_endpoint = {.address = GetIPAddressFromSockAddr(sa),
.port = GetPortFromFromSockAddr(sa)};
- packet->set_source(std::move(source_endpoint));
+ packet.set_source(std::move(source_endpoint));
// For multicast sockets, the packet's original destination address may be
// the host address (since we called bind()) but it may also be a
@@ -412,11 +442,11 @@ Error ReceiveMessageInternal(int fd, UdpPacket* packet) {
IPEndpoint destination_endpoint = {
.address = GetIPAddressFromPktInfo(*pktinfo),
.port = GetPortFromFromSockAddr(sa)};
- packet->set_destination(std::move(destination_endpoint));
+ packet.set_destination(std::move(destination_endpoint));
break;
}
}
- return Error::Code::kNone;
+ return std::move(packet);
}
} // namespace
@@ -436,32 +466,15 @@ void UdpSocketPosix::ReceiveMessage() {
return;
}
- ssize_t bytes_available = recv(handle_.fd, nullptr, 0, MSG_PEEK | MSG_TRUNC);
- if (bytes_available == -1) {
- task_runner_->PostTask(
- [weak_this = weak_factory_.GetWeakPtr(),
- error =
- ChooseError(errno, Error::Code::kSocketReadFailure)]() mutable {
- if (auto* self = weak_this.get()) {
- if (auto* client = self->client_) {
- client->OnRead(self, std::move(error));
- }
- }
- });
- return;
- }
- UdpPacket packet(bytes_available);
- packet.set_socket(this);
- Error result = Error::Code::kUnknownError;
+ ErrorOr<UdpPacket> read_result = Error::Code::kUnknownError;
switch (local_endpoint_.address.version()) {
case UdpSocket::Version::kV4: {
- result =
- ReceiveMessageInternal<sockaddr_in, in_pktinfo>(handle_.fd, &packet);
+ read_result = ReceiveMessageInternal<sockaddr_in, in_pktinfo>(handle_.fd);
break;
}
case UdpSocket::Version::kV6: {
- result = ReceiveMessageInternal<sockaddr_in6, in6_pktinfo>(handle_.fd,
- &packet);
+ read_result =
+ ReceiveMessageInternal<sockaddr_in6, in6_pktinfo>(handle_.fd);
break;
}
default: {
@@ -469,21 +482,16 @@ void UdpSocketPosix::ReceiveMessage() {
}
}
- task_runner_->PostTask(
- [weak_this = weak_factory_.GetWeakPtr(),
- read_result = result.ok()
- ? ErrorOr<UdpPacket>(std::move(packet))
- : ErrorOr<UdpPacket>(std::move(result))]() mutable {
- if (auto* self = weak_this.get()) {
- if (auto* client = self->client_) {
- client->OnRead(self, std::move(read_result));
- }
- }
- });
+ task_runner_->PostTask([weak_this = weak_factory_.GetWeakPtr(),
+ read_result = std::move(read_result)]() mutable {
+ if (auto* self = weak_this.get()) {
+ if (auto* client = self->client_) {
+ client->OnRead(self, std::move(read_result));
+ }
+ }
+ });
}
-// TODO(yakimakha): Consider changing the interface to accept UdpPacket as
-// an input parameter.
void UdpSocketPosix::SendMessage(const void* data,
size_t length,
const IPEndpoint& dest) {
diff --git a/chromium/third_party/openscreen/src/third_party/abseil/BUILD.gn b/chromium/third_party/openscreen/src/third_party/abseil/BUILD.gn
index a4ca3d53bcc..e3879cd4386 100644
--- a/chromium/third_party/openscreen/src/third_party/abseil/BUILD.gn
+++ b/chromium/third_party/openscreen/src/third_party/abseil/BUILD.gn
@@ -6,9 +6,7 @@ import("//build_overrides/build.gni")
if (build_with_chromium) {
source_set("abseil") {
- public_deps = [
- "//third_party/abseil-cpp:absl",
- ]
+ public_deps = [ "//third_party/abseil-cpp:absl" ]
}
} else {
config("abseil_config") {
@@ -19,9 +17,16 @@ if (build_with_chromium) {
cflags = [
"-Wno-sign-compare",
"-Wno-extra-semi",
+ "-Wno-range-loop-analysis",
]
+
+ if (is_mac) {
+ cflags += [ "-Wno-range-loop-analysis" ]
+ }
}
+ # NOTE: StrFormat is specifically excluded from the Abseil source set due
+ # to binary size concerns.
source_set("abseil") {
sources = [
"src/absl/base/attributes.h",
@@ -74,7 +79,6 @@ if (build_with_chromium) {
"src/absl/strings/numbers.h",
"src/absl/strings/str_cat.cc",
"src/absl/strings/str_cat.h",
- "src/absl/strings/str_format.h",
"src/absl/strings/str_join.h",
"src/absl/strings/str_replace.cc",
"src/absl/strings/str_replace.h",
diff --git a/chromium/third_party/openscreen/src/third_party/jsoncpp/BUILD.gn b/chromium/third_party/openscreen/src/third_party/jsoncpp/BUILD.gn
index 63df151ca98..bc96a235e0e 100644
--- a/chromium/third_party/openscreen/src/third_party/jsoncpp/BUILD.gn
+++ b/chromium/third_party/openscreen/src/third_party/jsoncpp/BUILD.gn
@@ -6,16 +6,11 @@ import("//build_overrides/build.gni")
if (build_with_chromium) {
source_set("jsoncpp") {
- public_deps = [
- "//third_party/jsoncpp",
- ]
+ public_deps = [ "//third_party/jsoncpp" ]
}
} else {
config("jsoncpp_config") {
- include_dirs = [
- "//third_party/jsoncpp/src/include",
- "//third_party/jsoncpp/generated",
- ]
+ include_dirs = [ "//third_party/jsoncpp/src/include" ]
cflags_cc = [ "-Wno-implicit-fallthrough" ]
@@ -26,22 +21,15 @@ if (build_with_chromium) {
source_set("jsoncpp") {
sources = [
- # Note: the generated/version.h file is a build artifact of JsonCpp's
- # meson/CMake build toolchains. When updating the DEPS, build JsonCpp
- # and copy the generated version.h to this location. You also need to
- # update the include guard to match our PRESUBMIT rule, from
- # JSON_VERSION_H_INCLUDED to THIRD_PARTY_JSONCPP_GENERATED_VERSION_H_
- "generated/version.h",
-
- # All of the other files are from the actual JsonCpp repository.
- "src/include/json/assertions.h",
+ "src/include/json/allocator.h",
"src/include/json/autolink.h",
"src/include/json/config.h",
- "src/include/json/features.h",
"src/include/json/forwards.h",
"src/include/json/json.h",
+ "src/include/json/json_features.h",
"src/include/json/reader.h",
"src/include/json/value.h",
+ "src/include/json/version.h",
"src/include/json/writer.h",
"src/src/lib_json/json_reader.cpp",
"src/src/lib_json/json_tool.h",
diff --git a/chromium/third_party/openscreen/src/third_party/jsoncpp/generated/version.h b/chromium/third_party/openscreen/src/third_party/jsoncpp/generated/version.h
deleted file mode 100644
index 4a79e5539fd..00000000000
--- a/chromium/third_party/openscreen/src/third_party/jsoncpp/generated/version.h
+++ /dev/null
@@ -1,22 +0,0 @@
-// DO NOT EDIT. This file (and "version") is a template used by the build system
-// (either CMake or Meson) to generate a "version.h" header file.
-#ifndef THIRD_PARTY_JSONCPP_GENERATED_VERSION_H_
-#define THIRD_PARTY_JSONCPP_GENERATED_VERSION_H_
-
-#define JSONCPP_VERSION_STRING "1.9.0"
-#define JSONCPP_VERSION_MAJOR 1
-#define JSONCPP_VERSION_MINOR 9
-#define JSONCPP_VERSION_PATCH 0
-#define JSONCPP_VERSION_QUALIFIER
-#define JSONCPP_VERSION_HEXA \
- ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | \
- (JSONCPP_VERSION_PATCH << 8))
-
-#ifdef JSONCPP_USING_SECURE_MEMORY
-#undef JSONCPP_USING_SECURE_MEMORY
-#endif
-#define JSONCPP_USING_SECURE_MEMORY 0
-// If non-zero, the library zeroes any memory that it has allocated before
-// it frees its memory.
-
-#endif // THIRD_PARTY_JSONCPP_GENERATED_VERSION_H_
diff --git a/chromium/third_party/openscreen/src/util/BUILD.gn b/chromium/third_party/openscreen/src/util/BUILD.gn
index 7eaf3d3072b..2fdd24c0b79 100644
--- a/chromium/third_party/openscreen/src/util/BUILD.gn
+++ b/chromium/third_party/openscreen/src/util/BUILD.gn
@@ -30,6 +30,10 @@ source_set("util") {
"crypto/digest_sign.h",
"crypto/openssl_util.cc",
"crypto/openssl_util.h",
+ "crypto/pem_helpers.cc",
+ "crypto/pem_helpers.h",
+ "crypto/random_bytes.cc",
+ "crypto/random_bytes.h",
"crypto/rsa_private_key.cc",
"crypto/rsa_private_key.h",
"crypto/secure_hash.cc",
@@ -83,6 +87,7 @@ source_set("unittests") {
sources = [
"alarm_unittest.cc",
"big_endian_unittest.cc",
+ "crypto/random_bytes_unittest.cc",
"crypto/rsa_private_key_unittest.cc",
"crypto/secure_hash_unittest.cc",
"crypto/sha2_unittest.cc",
diff --git a/chromium/third_party/openscreen/src/util/crypto/openssl_util.cc b/chromium/third_party/openscreen/src/util/crypto/openssl_util.cc
index 580ab3a91cc..505ac71585d 100644
--- a/chromium/third_party/openscreen/src/util/crypto/openssl_util.cc
+++ b/chromium/third_party/openscreen/src/util/crypto/openssl_util.cc
@@ -10,6 +10,7 @@
#include <stddef.h>
#include <stdint.h>
+#include <sstream>
#include <string>
#include <utility>
@@ -68,7 +69,14 @@ Error GetSSLError(const SSL* ssl, int return_code) {
return Error::None();
}
- std::string message = ERR_reason_error_string(ERR_get_error());
+ // Create error message w/ unwind of error stack + original SSL error string.
+ std::stringstream msg;
+ msg << "boringssl error (" << error_code
+ << "): " << SSL_error_description(error_code);
+ while (uint32_t packed_error = ERR_get_error()) {
+ msg << "\nerr stack: " << ERR_reason_error_string(packed_error);
+ }
+ std::string message = msg.str();
switch (error_code) {
case SSL_ERROR_ZERO_RETURN:
return Error(Error::Code::kSocketClosedFailure, std::move(message));
diff --git a/chromium/third_party/openscreen/src/util/crypto/pem_helpers.cc b/chromium/third_party/openscreen/src/util/crypto/pem_helpers.cc
new file mode 100644
index 00000000000..a9dcf1247bc
--- /dev/null
+++ b/chromium/third_party/openscreen/src/util/crypto/pem_helpers.cc
@@ -0,0 +1,70 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "util/crypto/pem_helpers.h"
+
+#include <openssl/bytestring.h>
+#include <openssl/pem.h>
+#include <openssl/rsa.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "absl/strings/match.h"
+#include "util/osp_logging.h"
+
+namespace openscreen {
+
+std::vector<std::string> ReadCertificatesFromPemFile(
+ absl::string_view filename) {
+ FILE* fp = fopen(filename.data(), "r");
+ if (!fp) {
+ return {};
+ }
+ std::vector<std::string> certs;
+ char* name;
+ char* header;
+ unsigned char* data;
+ long length; // NOLINT
+ while (PEM_read(fp, &name, &header, &data, &length) == 1) {
+ if (absl::StartsWith(name, "CERTIFICATE")) {
+ certs.emplace_back(reinterpret_cast<char*>(data), length);
+ }
+ OPENSSL_free(name);
+ OPENSSL_free(header);
+ OPENSSL_free(data);
+ }
+ fclose(fp);
+ return certs;
+}
+
+bssl::UniquePtr<EVP_PKEY> ReadKeyFromPemFile(absl::string_view filename) {
+ FILE* fp = fopen(filename.data(), "r");
+ if (!fp) {
+ return nullptr;
+ }
+ bssl::UniquePtr<EVP_PKEY> pkey;
+ char* name;
+ char* header;
+ unsigned char* data;
+ long length; // NOLINT
+ while (PEM_read(fp, &name, &header, &data, &length) == 1) {
+ if (absl::StartsWith(name, "RSA PRIVATE KEY")) {
+ OSP_DCHECK(!pkey);
+ CBS cbs;
+ CBS_init(&cbs, data, length);
+ RSA* rsa = RSA_parse_private_key(&cbs);
+ if (rsa) {
+ pkey.reset(EVP_PKEY_new());
+ EVP_PKEY_assign_RSA(pkey.get(), rsa);
+ }
+ }
+ OPENSSL_free(name);
+ OPENSSL_free(header);
+ OPENSSL_free(data);
+ }
+ fclose(fp);
+ return pkey;
+}
+
+} // namespace openscreen
diff --git a/chromium/third_party/openscreen/src/util/crypto/pem_helpers.h b/chromium/third_party/openscreen/src/util/crypto/pem_helpers.h
new file mode 100644
index 00000000000..6012b06915b
--- /dev/null
+++ b/chromium/third_party/openscreen/src/util/crypto/pem_helpers.h
@@ -0,0 +1,24 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UTIL_CRYPTO_PEM_HELPERS_H_
+#define UTIL_CRYPTO_PEM_HELPERS_H_
+
+#include <openssl/evp.h>
+
+#include <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+
+namespace openscreen {
+
+std::vector<std::string> ReadCertificatesFromPemFile(
+ absl::string_view filename);
+
+bssl::UniquePtr<EVP_PKEY> ReadKeyFromPemFile(absl::string_view filename);
+
+} // namespace openscreen
+
+#endif // UTIL_CRYPTO_PEM_HELPERS_H_
diff --git a/chromium/third_party/openscreen/src/util/crypto/random_bytes.cc b/chromium/third_party/openscreen/src/util/crypto/random_bytes.cc
new file mode 100644
index 00000000000..6a4c9dcbec6
--- /dev/null
+++ b/chromium/third_party/openscreen/src/util/crypto/random_bytes.cc
@@ -0,0 +1,23 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "util/crypto/random_bytes.h"
+
+#include "openssl/rand.h"
+#include "util/osp_logging.h"
+
+namespace openscreen {
+
+std::array<uint8_t, 16> GenerateRandomBytes16() {
+ std::array<uint8_t, 16> result;
+ GenerateRandomBytes(result.begin(), result.size());
+ return result;
+}
+
+void GenerateRandomBytes(uint8_t* out, int len) {
+ // Working cryptography is mandatory for our library to run.
+ OSP_CHECK(RAND_bytes(out, len) == 1);
+}
+
+} // namespace openscreen
diff --git a/chromium/third_party/openscreen/src/util/crypto/random_bytes.h b/chromium/third_party/openscreen/src/util/crypto/random_bytes.h
new file mode 100644
index 00000000000..3cb2fa8efa6
--- /dev/null
+++ b/chromium/third_party/openscreen/src/util/crypto/random_bytes.h
@@ -0,0 +1,17 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UTIL_CRYPTO_RANDOM_BYTES_H_
+#define UTIL_CRYPTO_RANDOM_BYTES_H_
+
+#include <array>
+
+namespace openscreen {
+
+std::array<uint8_t, 16> GenerateRandomBytes16();
+void GenerateRandomBytes(uint8_t* out, int len);
+
+} // namespace openscreen
+
+#endif // UTIL_CRYPTO_RANDOM_BYTES_H_
diff --git a/chromium/third_party/openscreen/src/util/crypto/random_bytes_unittest.cc b/chromium/third_party/openscreen/src/util/crypto/random_bytes_unittest.cc
new file mode 100644
index 00000000000..8129d604129
--- /dev/null
+++ b/chromium/third_party/openscreen/src/util/crypto/random_bytes_unittest.cc
@@ -0,0 +1,50 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "util/crypto/random_bytes.h"
+
+#include <algorithm>
+#include <utility>
+
+#include "gtest/gtest.h"
+
+namespace openscreen {
+namespace {
+
+struct NonZero {
+ NonZero() = default;
+ bool operator()(int n) const { return n > 0; }
+};
+
+} // namespace
+
+TEST(RandomBytesTest, CanGenerateRandomBytes) {
+ std::array<uint8_t, 4> bytes;
+ GenerateRandomBytes(bytes.begin(), bytes.size());
+
+ NonZero pred;
+ ASSERT_TRUE(std::any_of(bytes.begin(), bytes.end(), pred));
+}
+
+TEST(RandomBytesTest, CanGenerate16RandomBytes) {
+ std::array<uint8_t, 16> bytes = GenerateRandomBytes16();
+
+ NonZero pred;
+ ASSERT_TRUE(std::any_of(bytes.begin(), bytes.end(), pred));
+}
+
+TEST(RandomBytesTest, KeysAreNotIdentical) {
+ constexpr int kNumKeys = 100;
+ constexpr int kKeyLength = 100;
+ std::array<std::array<uint8_t, kKeyLength>, kNumKeys> keys;
+ for (int i = 0; i < kNumKeys; ++i) {
+ GenerateRandomBytes(keys[i].begin(), kKeyLength);
+ }
+
+ std::sort(std::begin(keys), std::end(keys));
+ ASSERT_TRUE(std::adjacent_find(std::begin(keys), std::end(keys)) ==
+ std::end(keys));
+}
+
+} // namespace openscreen
diff --git a/chromium/third_party/openscreen/src/util/yet_another_bit_vector_unittest.cc b/chromium/third_party/openscreen/src/util/yet_another_bit_vector_unittest.cc
index 98951fe0d38..c67e4371103 100644
--- a/chromium/third_party/openscreen/src/util/yet_another_bit_vector_unittest.cc
+++ b/chromium/third_party/openscreen/src/util/yet_another_bit_vector_unittest.cc
@@ -20,12 +20,10 @@ constexpr uint8_t kBitPatterns[] = {0b00000000, 0b11111111, 0b01010101,
// These are used for testing various vector sizes, begins/ends of ranges, etc.
// They will exercise both the "inlined storage" (size <= 64 case) and
// "heap-allocated storage" cases. These are all of the prime numbers less than
-// 200, and also any non-negative multiples of 64 less than 200.
-const int kTestSizes[] = {0, 1, 2, 3, 5, 7, 11, 13, 17, 19, 23,
- 29, 31, 37, 41, 43, 47, 53, 59, 61, 64, 67,
- 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113,
- 127, 128, 131, 137, 139, 149, 151, 157, 163, 167, 173,
- 179, 181, 191, 192, 193, 197, 199};
+// 100, and also any non-negative multiples of 64 less than 192.
+const int kTestSizes[] = {0, 1, 2, 3, 5, 7, 11, 13, 17, 19,
+ 23, 29, 31, 37, 41, 43, 47, 53, 59, 61,
+ 64, 67, 71, 73, 79, 83, 89, 97, 127, 128};
// Returns a subspan of |kTestSizes| that contains all values in the range
// [first,last].