1 // Copyright 2020 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "cast/standalone_receiver/cast_service.h"
6
7 #include <stdint.h>
8
9 #include <array>
10 #include <utility>
11
12 #include "discovery/common/config.h"
13 #include "platform/api/tls_connection_factory.h"
14 #include "platform/base/interface_info.h"
15 #include "platform/base/tls_listen_options.h"
16 #include "util/crypto/random_bytes.h"
17 #include "util/osp_logging.h"
18 #include "util/stringprintf.h"
19
20 namespace openscreen {
21 namespace cast {
22
23 namespace {
24
25 constexpr uint16_t kDefaultCastServicePort = 8010;
26 constexpr int kCastUniqueIdLength = 6;
27
28 constexpr int kDefaultMaxBacklogSize = 64;
29 const TlsListenOptions kDefaultListenOptions{kDefaultMaxBacklogSize};
30
DetermineEndpoint(const InterfaceInfo & interface)31 IPEndpoint DetermineEndpoint(const InterfaceInfo& interface) {
32 const IPAddress address = interface.GetIpAddressV4()
33 ? interface.GetIpAddressV4()
34 : interface.GetIpAddressV6();
35 OSP_CHECK(address);
36 return IPEndpoint{address, kDefaultCastServicePort};
37 }
38
MakeDiscoveryConfig(const InterfaceInfo & interface)39 discovery::Config MakeDiscoveryConfig(const InterfaceInfo& interface) {
40 return discovery::Config{.network_info = {interface}};
41 }
42
43 } // namespace
44
CastService(CastService::Configuration config)45 CastService::CastService(CastService::Configuration config)
46 : local_endpoint_(DetermineEndpoint(config.interface)),
47 credentials_(std::move(config.credentials)),
48 agent_(config.task_runner, credentials_.provider.get()),
49 mirroring_application_(config.task_runner,
50 local_endpoint_.address,
51 &agent_),
52 socket_factory_(&agent_, agent_.cast_socket_client()),
53 connection_factory_(
54 TlsConnectionFactory::CreateFactory(&socket_factory_,
55 config.task_runner)),
56 discovery_service_(config.enable_discovery
57 ? discovery::CreateDnsSdService(
58 config.task_runner,
59 this,
60 MakeDiscoveryConfig(config.interface))
61 : LazyDeletedDiscoveryService()),
62 discovery_publisher_(
63 discovery_service_
64 ? MakeSerialDelete<
65 discovery::DnsSdServicePublisher<ReceiverInfo>>(
66 config.task_runner,
67 discovery_service_.get(),
68 kCastV2ServiceId,
69 ReceiverInfoToDnsSdInstance)
70 : LazyDeletedDiscoveryPublisher()) {
71 connection_factory_->SetListenCredentials(credentials_.tls_credentials);
72 connection_factory_->Listen(local_endpoint_, kDefaultListenOptions);
73
74 if (discovery_publisher_) {
75 ReceiverInfo info;
76 info.port = local_endpoint_.port;
77 if (config.interface.HasHardwareAddress()) {
78 info.unique_id = HexEncode(config.interface.hardware_address.data(),
79 config.interface.hardware_address.size());
80 } else {
81 OSP_LOG_WARN << "Hardware address for interface " << config.interface.name
82 << " is empty. Generating a random unique_id.";
83 std::array<uint8_t, kCastUniqueIdLength> random_bytes;
84 GenerateRandomBytes(random_bytes.data(), kCastUniqueIdLength);
85 info.unique_id = HexEncode(random_bytes.data(), kCastUniqueIdLength);
86 }
87 info.friendly_name = config.friendly_name;
88 info.model_name = config.model_name;
89 info.capabilities = kHasVideoOutput | kHasAudioOutput;
90 const Error error = discovery_publisher_->Register(info);
91 if (!error.ok()) {
92 OnFatalError(std::move(error));
93 }
94 }
95 }
96
~CastService()97 CastService::~CastService() {
98 if (discovery_publisher_) {
99 discovery_publisher_->DeregisterAll();
100 }
101 }
102
OnFatalError(Error error)103 void CastService::OnFatalError(Error error) {
104 OSP_LOG_FATAL << "Encountered fatal discovery error: " << error;
105 }
106
OnRecoverableError(Error error)107 void CastService::OnRecoverableError(Error error) {
108 OSP_LOG_ERROR << "Encountered recoverable discovery error: " << error;
109 }
110
111 } // namespace cast
112 } // namespace openscreen
113