1 // Copyright 2021 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 "osp/impl/dns_sd_publisher_client.h"
6
7 #include <utility>
8
9 #include "discovery/common/config.h"
10 #include "discovery/dnssd/public/dns_sd_instance.h"
11 #include "discovery/dnssd/public/dns_sd_txt_record.h"
12 #include "discovery/public/dns_sd_service_factory.h"
13 #include "osp/public/service_info.h"
14 #include "platform/base/macros.h"
15 #include "util/osp_logging.h"
16
17 namespace openscreen {
18 namespace osp {
19
20 using State = ServicePublisher::State;
21
22 namespace {
23
24 constexpr char kFriendlyNameTxtKey[] = "fn";
25 constexpr char kDnsSdDomainId[] = "local";
26
ServiceConfigToDnsSdInstance(const ServicePublisher::Config & config)27 discovery::DnsSdInstance ServiceConfigToDnsSdInstance(
28 const ServicePublisher::Config& config) {
29 discovery::DnsSdTxtRecord txt;
30 const bool did_set_everything =
31 txt.SetValue(kFriendlyNameTxtKey, config.friendly_name).ok();
32 OSP_DCHECK(did_set_everything);
33
34 // NOTE: Not totally clear how we should be using config.hostname, which in
35 // principle is already part of config.service_instance_name.
36 return discovery::DnsSdInstance(
37 config.service_instance_name, kOpenScreenServiceName, kDnsSdDomainId,
38 std::move(txt), config.connection_server_port);
39 }
40
41 } // namespace
42
DnsSdPublisherClient(ServicePublisher::Observer * observer,openscreen::TaskRunner * task_runner)43 DnsSdPublisherClient::DnsSdPublisherClient(ServicePublisher::Observer* observer,
44 openscreen::TaskRunner* task_runner)
45 : observer_(observer), task_runner_(task_runner) {
46 OSP_DCHECK(observer_);
47 OSP_DCHECK(task_runner_);
48 }
49
50 DnsSdPublisherClient::~DnsSdPublisherClient() = default;
51
StartPublisher(const ServicePublisher::Config & config)52 void DnsSdPublisherClient::StartPublisher(
53 const ServicePublisher::Config& config) {
54 OSP_LOG_INFO << "StartPublisher with " << config.network_interfaces.size()
55 << " interfaces";
56 StartPublisherInternal(config);
57 Error result = dns_sd_publisher_->Register(config);
58 if (result.ok()) {
59 SetState(State::kRunning);
60 } else {
61 OnFatalError(result);
62 SetState(State::kStopped);
63 }
64 }
65
StartAndSuspendPublisher(const ServicePublisher::Config & config)66 void DnsSdPublisherClient::StartAndSuspendPublisher(
67 const ServicePublisher::Config& config) {
68 StartPublisherInternal(config);
69 SetState(State::kSuspended);
70 }
71
StopPublisher()72 void DnsSdPublisherClient::StopPublisher() {
73 dns_sd_publisher_.reset();
74 SetState(State::kStopped);
75 }
76
SuspendPublisher()77 void DnsSdPublisherClient::SuspendPublisher() {
78 OSP_DCHECK(dns_sd_publisher_);
79 dns_sd_publisher_->DeregisterAll();
80 SetState(State::kSuspended);
81 }
82
ResumePublisher(const ServicePublisher::Config & config)83 void DnsSdPublisherClient::ResumePublisher(
84 const ServicePublisher::Config& config) {
85 OSP_DCHECK(dns_sd_publisher_);
86 dns_sd_publisher_->Register(config);
87 SetState(State::kRunning);
88 }
89
OnFatalError(Error error)90 void DnsSdPublisherClient::OnFatalError(Error error) {
91 observer_->OnError(error);
92 }
93
OnRecoverableError(Error error)94 void DnsSdPublisherClient::OnRecoverableError(Error error) {
95 observer_->OnError(error);
96 }
97
StartPublisherInternal(const ServicePublisher::Config & config)98 void DnsSdPublisherClient::StartPublisherInternal(
99 const ServicePublisher::Config& config) {
100 OSP_DCHECK(!dns_sd_publisher_);
101 if (!dns_sd_service_) {
102 dns_sd_service_ = CreateDnsSdServiceInternal(config);
103 }
104 dns_sd_publisher_ = std::make_unique<OspDnsSdPublisher>(
105 dns_sd_service_.get(), kOpenScreenServiceName,
106 ServiceConfigToDnsSdInstance);
107 }
108
109 SerialDeletePtr<discovery::DnsSdService>
CreateDnsSdServiceInternal(const ServicePublisher::Config & config)110 DnsSdPublisherClient::CreateDnsSdServiceInternal(
111 const ServicePublisher::Config& config) {
112 // NOTE: With the current API, the client cannot customize the behavior of
113 // DNS-SD beyond the interface list.
114 openscreen::discovery::Config dns_sd_config;
115 dns_sd_config.enable_querying = false;
116 dns_sd_config.network_info = config.network_interfaces;
117
118 // NOTE:
119 // It's desirable for the DNS-SD publisher and the DNS-SD listener for OSP to
120 // share the underlying mDNS socket and state, to avoid the agent from
121 // binding 2 sockets per network interface.
122 //
123 // This can be accomplished by having the agent use a shared instance of the
124 // discovery::DnsSdService, e.g. through a ref-counting handle, so that the
125 // OSP publisher and the OSP listener don't have to coordinate through an
126 // additional object.
127 return CreateDnsSdService(task_runner_, this, dns_sd_config);
128 }
129
130 } // namespace osp
131 } // namespace openscreen
132