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_H_ 6 #define OSP_IMPL_DISCOVERY_MDNS_MDNS_RESPONDER_ADAPTER_H_ 7 8 #include <cstdint> 9 #include <map> 10 #include <string> 11 #include <vector> 12 13 #include "osp/impl/discovery/mdns/domain_name.h" 14 #include "osp/impl/discovery/mdns/mdns_responder_platform.h" 15 #include "platform/api/network_interface.h" 16 #include "platform/api/time.h" 17 #include "platform/api/udp_socket.h" 18 #include "platform/base/error.h" 19 #include "platform/base/ip_address.h" 20 21 namespace openscreen { 22 namespace osp { 23 24 struct QueryEventHeader { 25 enum class Type { 26 kAdded = 0, 27 kAddedNoCache, 28 kRemoved, 29 }; 30 31 QueryEventHeader(); 32 QueryEventHeader(Type response_type, UdpSocket* socket); 33 QueryEventHeader(QueryEventHeader&&) noexcept; 34 ~QueryEventHeader(); 35 QueryEventHeader& operator=(QueryEventHeader&&) noexcept; 36 37 Type response_type; 38 UdpSocket* socket; 39 }; 40 41 struct PtrEvent { 42 PtrEvent(); 43 PtrEvent(QueryEventHeader header, DomainName service_instance); 44 PtrEvent(PtrEvent&&) noexcept; 45 ~PtrEvent(); 46 PtrEvent& operator=(PtrEvent&&) noexcept; 47 48 QueryEventHeader header; 49 DomainName service_instance; 50 }; 51 52 struct SrvEvent { 53 SrvEvent(); 54 SrvEvent(QueryEventHeader header, 55 DomainName service_instance, 56 DomainName domain_name, 57 uint16_t port); 58 SrvEvent(SrvEvent&&) noexcept; 59 ~SrvEvent(); 60 SrvEvent& operator=(SrvEvent&&) noexcept; 61 62 QueryEventHeader header; 63 DomainName service_instance; 64 DomainName domain_name; 65 uint16_t port; 66 }; 67 68 struct TxtEvent { 69 TxtEvent(); 70 TxtEvent(QueryEventHeader header, 71 DomainName service_instance, 72 std::vector<std::string> txt_info); 73 TxtEvent(TxtEvent&&) noexcept; 74 ~TxtEvent(); 75 TxtEvent& operator=(TxtEvent&&) noexcept; 76 77 QueryEventHeader header; 78 DomainName service_instance; 79 80 // NOTE: mDNS does not specify a character encoding for the data in TXT 81 // records. 82 std::vector<std::string> txt_info; 83 }; 84 85 struct AEvent { 86 AEvent(); 87 AEvent(QueryEventHeader header, DomainName domain_name, IPAddress address); 88 AEvent(AEvent&&) noexcept; 89 ~AEvent(); 90 AEvent& operator=(AEvent&&) noexcept; 91 92 QueryEventHeader header; 93 DomainName domain_name; 94 IPAddress address; 95 }; 96 97 struct AaaaEvent { 98 AaaaEvent(); 99 AaaaEvent(QueryEventHeader header, DomainName domain_name, IPAddress address); 100 AaaaEvent(AaaaEvent&&) noexcept; 101 ~AaaaEvent(); 102 AaaaEvent& operator=(AaaaEvent&&) noexcept; 103 104 QueryEventHeader header; 105 DomainName domain_name; 106 IPAddress address; 107 }; 108 109 enum class MdnsResponderErrorCode { 110 kNoError = 0, 111 kUnsupportedError, 112 kDomainOverflowError, 113 kInvalidParameters, 114 kUnknownError, 115 }; 116 117 // This interface wraps all the functionality of mDNSResponder, which includes 118 // both listening and publishing. As a result, some methods are only used by 119 // listeners, some are only used by publishers, and some are used by both. 120 // 121 // Listening for records might look like this: 122 // adapter->Init(); 123 // 124 // // Once for each interface, the meaning of false is described below. 125 // adapter->RegisterInterface(..., false); 126 // 127 // adapter->StartPtrQuery("_openscreen._udp"); 128 // adapter->RunTasks(); 129 // 130 // // When receiving multicast UDP traffic from port 5353. 131 // adapter->OnDataReceived(...); 132 // adapter->RunTasks(); 133 // 134 // // Check |ptrs| for responses after pulling. 135 // auto ptrs = adapter->TakePtrResponses(); 136 // 137 // // Eventually... 138 // adapter->StopPtrQuery("_openscreen._udp"); 139 // 140 // Publishing a service might look like this: 141 // adapter->Init(); 142 // 143 // // Once for each interface, the meaning of true is described below. 144 // adapter->RegisterInterface(..., true); 145 // 146 // adapter->SetHostLabel("deadbeef"); 147 // adapter->RegisterService("living-room", "_openscreen._udp", ...); 148 // adapter->RunTasks(); 149 // 150 // // When receiving multicast UDP traffic from port 5353. 151 // adapter->OnDataReceived(...); 152 // adapter->RunTasks(); 153 // 154 // // Eventually... 155 // adapter->DeregisterService("living-room", "_openscreen", "_udp"); 156 // 157 // Additionally, it's important to understand that mDNSResponder may defer some 158 // tasks (e.g. parsing responses, sending queries, etc.) and those deferred 159 // tasks are only run when RunTasks is called. Therefore, RunTasks should be 160 // called after any sequence of calls to mDNSResponder. It also returns a 161 // timeout value, after which it must be called again (e.g. for maintaining its 162 // cache). 163 class MdnsResponderAdapter : public UdpSocket::Client { 164 public: 165 MdnsResponderAdapter(); 166 virtual ~MdnsResponderAdapter() = 0; 167 168 // Initializes mDNSResponder. This should be called before any queries or 169 // service registrations are made. 170 virtual Error Init() = 0; 171 172 // Stops all open queries and service registrations. If this is not called 173 // before destruction, any registered services will not send their goodbye 174 // messages. 175 virtual void Close() = 0; 176 177 // Called to change the name published by the A and AAAA records for the host 178 // when any service is active (via RegisterService). Returns true if the 179 // label was set successfully, false otherwise (e.g. the label did not meet 180 // DNS name requirements). 181 virtual Error SetHostLabel(const std::string& host_label) = 0; 182 183 // The following methods register and deregister a network interface with 184 // mDNSResponder. |socket| will be used to identify which interface received 185 // the data in OnDataReceived and will be used to send data via the platform 186 // layer. 187 virtual Error RegisterInterface(const InterfaceInfo& interface_info, 188 const IPSubnet& interface_address, 189 UdpSocket* socket) = 0; 190 virtual Error DeregisterInterface(UdpSocket* socket) = 0; 191 192 // Returns the time period after which this method must be called again, if 193 // any. 194 virtual Clock::duration RunTasks() = 0; 195 196 virtual std::vector<PtrEvent> TakePtrResponses() = 0; 197 virtual std::vector<SrvEvent> TakeSrvResponses() = 0; 198 virtual std::vector<TxtEvent> TakeTxtResponses() = 0; 199 virtual std::vector<AEvent> TakeAResponses() = 0; 200 virtual std::vector<AaaaEvent> TakeAaaaResponses() = 0; 201 202 virtual MdnsResponderErrorCode StartPtrQuery( 203 UdpSocket* socket, 204 const DomainName& service_type) = 0; 205 virtual MdnsResponderErrorCode StartSrvQuery( 206 UdpSocket* socket, 207 const DomainName& service_instance) = 0; 208 virtual MdnsResponderErrorCode StartTxtQuery( 209 UdpSocket* socket, 210 const DomainName& service_instance) = 0; 211 virtual MdnsResponderErrorCode StartAQuery(UdpSocket* socket, 212 const DomainName& domain_name) = 0; 213 virtual MdnsResponderErrorCode StartAaaaQuery( 214 UdpSocket* socket, 215 const DomainName& domain_name) = 0; 216 217 virtual MdnsResponderErrorCode StopPtrQuery( 218 UdpSocket* socket, 219 const DomainName& service_type) = 0; 220 virtual MdnsResponderErrorCode StopSrvQuery( 221 UdpSocket* socket, 222 const DomainName& service_instance) = 0; 223 virtual MdnsResponderErrorCode StopTxtQuery( 224 UdpSocket* socket, 225 const DomainName& service_instance) = 0; 226 virtual MdnsResponderErrorCode StopAQuery(UdpSocket* socket, 227 const DomainName& domain_name) = 0; 228 virtual MdnsResponderErrorCode StopAaaaQuery( 229 UdpSocket* socket, 230 const DomainName& domain_name) = 0; 231 232 // The following methods concern advertising a service via mDNS. The 233 // arguments correspond to values needed in the PTR, SRV, and TXT records that 234 // will be published for the service. An A or AAAA record will also be 235 // published with the service for each active interface known to mDNSResponder 236 // via RegisterInterface. 237 virtual MdnsResponderErrorCode RegisterService( 238 const std::string& service_instance, 239 const std::string& service_name, 240 const std::string& service_protocol, 241 const DomainName& target_host, 242 uint16_t target_port, 243 const std::map<std::string, std::string>& txt_data) = 0; 244 virtual MdnsResponderErrorCode DeregisterService( 245 const std::string& service_instance, 246 const std::string& service_name, 247 const std::string& service_protocol) = 0; 248 virtual MdnsResponderErrorCode UpdateTxtData( 249 const std::string& service_instance, 250 const std::string& service_name, 251 const std::string& service_protocol, 252 const std::map<std::string, std::string>& txt_data) = 0; 253 }; 254 255 } // namespace osp 256 } // namespace openscreen 257 258 #endif // OSP_IMPL_DISCOVERY_MDNS_MDNS_RESPONDER_ADAPTER_H_ 259