1 // Copyright 2018 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 #ifndef OSP_IMPL_DISCOVERY_MDNS_MDNS_RESPONDER_ADAPTER_IMPL_H_
6 #define OSP_IMPL_DISCOVERY_MDNS_MDNS_RESPONDER_ADAPTER_IMPL_H_
7 
8 #include <map>
9 #include <memory>
10 #include <string>
11 #include <vector>
12 
13 #include "osp/impl/discovery/mdns/mdns_responder_adapter.h"
14 #include "platform/api/udp_socket.h"
15 #include "platform/base/error.h"
16 #include "third_party/mDNSResponder/src/mDNSCore/mDNSEmbeddedAPI.h"
17 
18 namespace openscreen {
19 namespace osp {
20 
21 class MdnsResponderAdapterImpl final : public MdnsResponderAdapter {
22  public:
23   static constexpr int kRrCacheSize = 500;
24 
25   MdnsResponderAdapterImpl();
26   ~MdnsResponderAdapterImpl() override;
27 
28   Error Init() override;
29   void Close() override;
30 
31   Error SetHostLabel(const std::string& host_label) override;
32 
33   Error RegisterInterface(const InterfaceInfo& interface_info,
34                           const IPSubnet& interface_address,
35                           UdpSocket* socket) override;
36   Error DeregisterInterface(UdpSocket* socket) override;
37 
38   void OnRead(UdpSocket* socket, ErrorOr<UdpPacket> packet) override;
39   void OnSendError(UdpSocket* socket, Error error) override;
40   void OnError(UdpSocket* socket, Error error) override;
41   void OnBound(UdpSocket* socket) override;
42 
43   Clock::duration RunTasks() override;
44 
45   std::vector<PtrEvent> TakePtrResponses() override;
46   std::vector<SrvEvent> TakeSrvResponses() override;
47   std::vector<TxtEvent> TakeTxtResponses() override;
48   std::vector<AEvent> TakeAResponses() override;
49   std::vector<AaaaEvent> TakeAaaaResponses() override;
50 
51   MdnsResponderErrorCode StartPtrQuery(UdpSocket* socket,
52                                        const DomainName& service_type) override;
53   MdnsResponderErrorCode StartSrvQuery(
54       UdpSocket* socket,
55       const DomainName& service_instance) override;
56   MdnsResponderErrorCode StartTxtQuery(
57       UdpSocket* socket,
58       const DomainName& service_instance) override;
59   MdnsResponderErrorCode StartAQuery(UdpSocket* socket,
60                                      const DomainName& domain_name) override;
61   MdnsResponderErrorCode StartAaaaQuery(UdpSocket* socket,
62                                         const DomainName& domain_name) override;
63   MdnsResponderErrorCode StopPtrQuery(UdpSocket* socket,
64                                       const DomainName& service_type) override;
65   MdnsResponderErrorCode StopSrvQuery(
66       UdpSocket* socket,
67       const DomainName& service_instance) override;
68   MdnsResponderErrorCode StopTxtQuery(
69       UdpSocket* socket,
70       const DomainName& service_instance) override;
71   MdnsResponderErrorCode StopAQuery(UdpSocket* socket,
72                                     const DomainName& domain_name) override;
73   MdnsResponderErrorCode StopAaaaQuery(UdpSocket* socket,
74                                        const DomainName& domain_name) override;
75 
76   MdnsResponderErrorCode RegisterService(
77       const std::string& service_instance,
78       const std::string& service_name,
79       const std::string& service_protocol,
80       const DomainName& target_host,
81       uint16_t target_port,
82       const std::map<std::string, std::string>& txt_data) override;
83   MdnsResponderErrorCode DeregisterService(
84       const std::string& service_instance,
85       const std::string& service_name,
86       const std::string& service_protocol) override;
87   MdnsResponderErrorCode UpdateTxtData(
88       const std::string& service_instance,
89       const std::string& service_name,
90       const std::string& service_protocol,
91       const std::map<std::string, std::string>& txt_data) override;
92 
93  private:
94   struct Questions {
95     std::map<DomainName, DNSQuestion, DomainNameComparator> a;
96     std::map<DomainName, DNSQuestion, DomainNameComparator> aaaa;
97     std::map<DomainName, DNSQuestion, DomainNameComparator> ptr;
98     std::map<DomainName, DNSQuestion, DomainNameComparator> srv;
99     std::map<DomainName, DNSQuestion, DomainNameComparator> txt;
100   };
101 
102   static void AQueryCallback(mDNS* m,
103                              DNSQuestion* question,
104                              const ResourceRecord* answer,
105                              QC_result added);
106   static void AaaaQueryCallback(mDNS* m,
107                                 DNSQuestion* question,
108                                 const ResourceRecord* answer,
109                                 QC_result added);
110   static void PtrQueryCallback(mDNS* m,
111                                DNSQuestion* question,
112                                const ResourceRecord* answer,
113                                QC_result added);
114   static void SrvQueryCallback(mDNS* m,
115                                DNSQuestion* question,
116                                const ResourceRecord* answer,
117                                QC_result added);
118   static void TxtQueryCallback(mDNS* m,
119                                DNSQuestion* question,
120                                const ResourceRecord* answer,
121                                QC_result added);
122   static void ServiceCallback(mDNS* m,
123                               ServiceRecordSet* service_record,
124                               mStatus result);
125 
126   void AdvertiseInterfaces();
127   void DeadvertiseInterfaces();
128   void RemoveQuestionsIfEmpty(UdpSocket* socket);
129 
130   CacheEntity rr_cache_[kRrCacheSize];
131 
132   //  The main context structure for mDNSResponder.
133   mDNS mdns_;
134 
135   // Our own storage that is placed inside |mdns_|.  The intent in C is to allow
136   // us access to our own state during callbacks.  Here we just use it to group
137   // platform sockets.
138   mDNS_PlatformSupport platform_storage_;
139 
140   std::map<UdpSocket*, Questions> socket_to_questions_;
141 
142   std::map<UdpSocket*, NetworkInterfaceInfo> responder_interface_info_;
143 
144   std::vector<AEvent> a_responses_;
145   std::vector<AaaaEvent> aaaa_responses_;
146   std::vector<PtrEvent> ptr_responses_;
147   std::vector<SrvEvent> srv_responses_;
148   std::vector<TxtEvent> txt_responses_;
149 
150   // A list of services we are advertising.  ServiceRecordSet is an
151   // mDNSResponder structure which holds all the resource record data
152   // (PTR/SRV/TXT/A and misc.) that is necessary to advertise a service.
153   std::vector<std::unique_ptr<ServiceRecordSet>> service_records_;
154 };
155 
156 }  // namespace osp
157 }  // namespace openscreen
158 
159 #endif  // OSP_IMPL_DISCOVERY_MDNS_MDNS_RESPONDER_ADAPTER_IMPL_H_
160