xref: /aosp_15_r20/external/openscreen/osp/impl/dns_sd_publisher_client.cc (revision 3f982cf4871df8771c9d4abe6e9a6f8d829b2736)
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