1 // Copyright 2015 The Weave 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 "src/privet/publisher.h"
6 
7 #include <map>
8 
9 #include <weave/error.h>
10 #include <weave/provider/dns_service_discovery.h>
11 
12 #include "src/privet/cloud_delegate.h"
13 #include "src/privet/device_delegate.h"
14 #include "src/privet/device_ui_kind.h"
15 #include "src/privet/wifi_bootstrap_manager.h"
16 #include "src/privet/wifi_ssid_generator.h"
17 #include "src/string_utils.h"
18 
19 namespace weave {
20 namespace privet {
21 
22 namespace {
23 
24 // The service type we'll expose via DNS-SD.
25 const char kPrivetServiceType[] = "_privet._tcp";
26 
27 }  // namespace
28 
Publisher(const DeviceDelegate * device,const CloudDelegate * cloud,const WifiDelegate * wifi,provider::DnsServiceDiscovery * dns_sd)29 Publisher::Publisher(const DeviceDelegate* device,
30                      const CloudDelegate* cloud,
31                      const WifiDelegate* wifi,
32                      provider::DnsServiceDiscovery* dns_sd)
33     : dns_sd_{dns_sd}, device_{device}, cloud_{cloud}, wifi_{wifi} {
34   CHECK(device_);
35   CHECK(cloud_);
36   CHECK(dns_sd_);
37   Update();
38 }
39 
~Publisher()40 Publisher::~Publisher() {
41   RemoveService();
42 }
43 
Update()44 void Publisher::Update() {
45   if (device_->GetHttpEnpoint().first == 0)
46     return RemoveService();
47   ExposeService();
48 }
49 
ExposeService()50 void Publisher::ExposeService() {
51   std::string name{cloud_->GetName()};
52   std::string model_id{cloud_->GetModelId()};
53   DCHECK_EQ(model_id.size(), 5U);
54 
55   VLOG(2) << "DNS-SD update requested";
56   const uint16_t port = device_->GetHttpEnpoint().first;
57   DCHECK_NE(port, 0);
58 
59   std::vector<std::string> txt_record{
60       {"txtvers=3"},
61       {"ty=" + name},
62       {"services=" + GetDeviceUiKind(model_id)},
63       {"id=" + cloud_->GetDeviceId()},
64       {"mmid=" + model_id},
65       {"flags=" + WifiSsidGenerator{cloud_, wifi_}.GenerateFlags()},
66   };
67 
68   if (!cloud_->GetCloudId().empty())
69     txt_record.emplace_back("gcd_id=" + cloud_->GetCloudId());
70 
71   if (!cloud_->GetDescription().empty())
72     txt_record.emplace_back("note=" + cloud_->GetDescription());
73 
74   auto new_data = std::make_pair(port, txt_record);
75   if (published_ == new_data)
76     return;
77 
78   VLOG(1) << "Updating service using DNS-SD, port: " << port;
79   published_ = new_data;
80   dns_sd_->PublishService(kPrivetServiceType, port, txt_record);
81 }
82 
RemoveService()83 void Publisher::RemoveService() {
84   if (!published_.first)
85     return;
86   published_ = {};
87   VLOG(1) << "Stopping service publishing";
88   dns_sd_->StopPublishing(kPrivetServiceType);
89 }
90 
91 }  // namespace privet
92 }  // namespace weave
93