1 /* 2 * Copyright (c) 2017, The OpenThread Authors. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 3. Neither the name of the copyright holder nor the 13 * names of its contributors may be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /** 30 * @file 31 * This file includes definitions for mDNS publisher. 32 */ 33 34 #ifndef OTBR_AGENT_MDNS_HPP_ 35 #define OTBR_AGENT_MDNS_HPP_ 36 37 #include <functional> 38 #include <map> 39 #include <memory> 40 #include <string> 41 #include <vector> 42 43 #include <sys/select.h> 44 45 #include "common/callback.hpp" 46 #include "common/code_utils.hpp" 47 #include "common/time.hpp" 48 #include "common/types.hpp" 49 50 namespace otbr { 51 52 namespace Mdns { 53 54 /** 55 * @addtogroup border-router-mdns 56 * 57 * @brief 58 * This module includes definition for mDNS publisher. 59 * 60 * @{ 61 */ 62 63 /** 64 * This interface defines the functionality of mDNS publisher. 65 * 66 */ 67 class Publisher : private NonCopyable 68 { 69 public: 70 /** 71 * This structure represents a name/value pair of the TXT record. 72 * 73 */ 74 struct TxtEntry 75 { 76 std::string mName; ///< The name of the TXT entry. 77 std::vector<uint8_t> mValue; ///< The value of the TXT entry. 78 TxtEntryotbr::Mdns::Publisher::TxtEntry79 TxtEntry(const char *aName, const char *aValue) 80 : TxtEntry(aName, reinterpret_cast<const uint8_t *>(aValue), strlen(aValue)) 81 { 82 } 83 TxtEntryotbr::Mdns::Publisher::TxtEntry84 TxtEntry(const char *aName, const uint8_t *aValue, size_t aValueLength) 85 : TxtEntry(aName, strlen(aName), aValue, aValueLength) 86 { 87 } 88 TxtEntryotbr::Mdns::Publisher::TxtEntry89 TxtEntry(const char *aName, size_t aNameLength, const uint8_t *aValue, size_t aValueLength) 90 : mName(aName, aNameLength) 91 , mValue(aValue, aValue + aValueLength) 92 { 93 } 94 operator ==otbr::Mdns::Publisher::TxtEntry95 bool operator==(const TxtEntry &aOther) const { return mName == aOther.mName && mValue == aOther.mValue; } 96 }; 97 98 typedef std::vector<TxtEntry> TxtList; 99 typedef std::vector<std::string> SubTypeList; 100 101 /** 102 * This structure represents information of a discovered service instance. 103 * 104 */ 105 struct DiscoveredInstanceInfo 106 { 107 bool mRemoved = false; ///< The Service Instance is removed. 108 uint32_t mNetifIndex = 0; ///< Network interface. 109 std::string mName; ///< Instance name. 110 std::string mHostName; ///< Full host name. 111 std::vector<Ip6Address> mAddresses; ///< IPv6 addresses. 112 uint16_t mPort = 0; ///< Port. 113 uint16_t mPriority = 0; ///< Service priority. 114 uint16_t mWeight = 0; ///< Service weight. 115 std::vector<uint8_t> mTxtData; ///< TXT RDATA bytes. 116 uint32_t mTtl = 0; ///< Service TTL. 117 }; 118 119 /** 120 * This structure represents information of a discovered host. 121 * 122 */ 123 struct DiscoveredHostInfo 124 { 125 std::string mHostName; ///< Full host name. 126 std::vector<Ip6Address> mAddresses; ///< IP6 addresses. 127 uint32_t mTtl = 0; ///< Host TTL. 128 }; 129 130 /** 131 * This function is called to notify a discovered service instance. 132 * 133 */ 134 using DiscoveredServiceInstanceCallback = 135 std::function<void(const std::string &aType, const DiscoveredInstanceInfo &aInstanceInfo)>; 136 137 /** 138 * This function is called to notify a discovered host. 139 * 140 */ 141 using DiscoveredHostCallback = 142 std::function<void(const std::string &aHostName, const DiscoveredHostInfo &aHostInfo)>; 143 144 /** 145 * mDNS state values. 146 * 147 */ 148 enum class State 149 { 150 kIdle, ///< Unable to publish service. 151 kReady, ///< Ready to publish service. 152 }; 153 154 /** The callback for receiving mDNS publisher state changes. */ 155 using StateCallback = std::function<void(State aNewState)>; 156 157 /** The callback for receiving the result of a operation. */ 158 using ResultCallback = OnceCallback<void(otbrError aError)>; 159 160 /** 161 * This method starts the mDNS publisher. 162 * 163 * @retval OTBR_ERROR_NONE Successfully started mDNS publisher; 164 * @retval OTBR_ERROR_MDNS Failed to start mDNS publisher. 165 * 166 */ 167 virtual otbrError Start(void) = 0; 168 169 /** 170 * This method stops the mDNS publisher. 171 * 172 */ 173 virtual void Stop(void) = 0; 174 175 /** 176 * This method checks if publisher has been started. 177 * 178 * @retval true Already started. 179 * @retval false Not started. 180 * 181 */ 182 virtual bool IsStarted(void) const = 0; 183 184 /** 185 * This method publishes or updates a service. 186 * 187 * @param[in] aHostName The name of the host which this service resides on. If an empty string is 188 * provided, this service resides on local host and it is the implementation 189 * to provide specific host name. Otherwise, the caller MUST publish the host 190 * with method PublishHost. 191 * @param[in] aName The name of this service. 192 * @param[in] aType The type of this service. 193 * @param[in] aSubTypeList A list of service subtypes. 194 * @param[in] aPort The port number of this service. 195 * @param[in] aTxtList A list of TXT name/value pairs. 196 * @param[in] aCallback The callback for receiving the publishing result. `OTBR_ERROR_NONE` will be 197 * returned if the operation is successful and all other values indicate a 198 * failure. Specifically, `OTBR_ERROR_DUPLICATED` indicates that the name has 199 * already been published and the caller can re-publish with a new name if an 200 * alternative name is available/acceptable. 201 * 202 */ 203 void PublishService(const std::string &aHostName, 204 const std::string &aName, 205 const std::string &aType, 206 const SubTypeList &aSubTypeList, 207 uint16_t aPort, 208 const TxtList & aTxtList, 209 ResultCallback && aCallback); 210 211 /** 212 * This method un-publishes a service. 213 * 214 * @param[in] aName The name of this service. 215 * @param[in] aType The type of this service. 216 * @param[in] aCallback The callback for receiving the publishing result. 217 * 218 */ 219 virtual void UnpublishService(const std::string &aName, const std::string &aType, ResultCallback &&aCallback) = 0; 220 221 /** 222 * This method publishes or updates a host. 223 * 224 * Publishing a host is advertising an AAAA RR for the host name. This method should be called 225 * before a service with non-empty host name is published. 226 * 227 * @param[in] aName The name of the host. 228 * @param[in] aAddress The address of the host. 229 * @param[in] aCallback The callback for receiving the publishing result.`OTBR_ERROR_NONE` will be 230 * returned if the operation is successful and all other values indicate a 231 * failure. Specifically, `OTBR_ERROR_DUPLICATED` indicates that the name has 232 * already been published and the caller can re-publish with a new name if an 233 * alternative name is available/acceptable. 234 * 235 */ 236 void PublishHost(const std::string &aName, const std::vector<uint8_t> &aAddress, ResultCallback &&aCallback); 237 238 /** 239 * This method un-publishes a host. 240 * 241 * @param[in] aName A host name. 242 * @param[in] aCallback The callback for receiving the publishing result. 243 * 244 */ 245 virtual void UnpublishHost(const std::string &aName, ResultCallback &&aCallback) = 0; 246 247 /** 248 * This method subscribes a given service or service instance. 249 * 250 * If @p aInstanceName is not empty, this method subscribes the service instance. Otherwise, this method subscribes 251 * the service. mDNS implementations should use the `DiscoveredServiceInstanceCallback` function to notify 252 * discovered service instances. 253 * 254 * @note Discovery Proxy implementation guarantees no duplicate subscriptions for the same service or service 255 * instance. 256 * 257 * @param[in] aType The service type. 258 * @param[in] aInstanceName The service instance to subscribe, or empty to subscribe the service. 259 * 260 */ 261 virtual void SubscribeService(const std::string &aType, const std::string &aInstanceName) = 0; 262 263 /** 264 * This method unsubscribes a given service or service instance. 265 * 266 * If @p aInstanceName is not empty, this method unsubscribes the service instance. Otherwise, this method 267 * unsubscribes the service. 268 * 269 * @note Discovery Proxy implementation guarantees no redundant unsubscription for a service or service instance. 270 * 271 * @param[in] aType The service type. 272 * @param[in] aInstanceName The service instance to unsubscribe, or empty to unsubscribe the service. 273 * 274 */ 275 virtual void UnsubscribeService(const std::string &aType, const std::string &aInstanceName) = 0; 276 277 /** 278 * This method subscribes a given host. 279 * 280 * mDNS implementations should use the `DiscoveredHostCallback` function to notify discovered hosts. 281 * 282 * @note Discovery Proxy implementation guarantees no duplicate subscriptions for the same host. 283 * 284 * @param[in] aHostName The host name (without domain). 285 * 286 */ 287 virtual void SubscribeHost(const std::string &aHostName) = 0; 288 289 /** 290 * This method unsubscribes a given host. 291 * 292 * @note Discovery Proxy implementation guarantees no redundant unsubscription for a host. 293 * 294 * @param[in] aHostName The host name (without domain). 295 * 296 */ 297 virtual void UnsubscribeHost(const std::string &aHostName) = 0; 298 299 /** 300 * This method sets the callbacks for subscriptions. 301 * 302 * @param[in] aInstanceCallback The callback function to receive discovered service instances. 303 * @param[in] aHostCallback The callback function to receive discovered hosts. 304 * 305 * @returns The Subscriber ID for the callbacks. 306 * 307 */ 308 uint64_t AddSubscriptionCallbacks(DiscoveredServiceInstanceCallback aInstanceCallback, 309 DiscoveredHostCallback aHostCallback); 310 311 /** 312 * This method cancels callbacks for subscriptions. 313 * 314 * @param[in] aSubscriberId The Subscriber ID previously returned by `AddSubscriptionCallbacks`. 315 * 316 */ 317 void RemoveSubscriptionCallbacks(uint64_t aSubscriberId); 318 319 /** 320 * This method returns the mDNS statistics information of the publisher. 321 * 322 * @returns The MdnsTelemetryInfo of the publisher. 323 * 324 */ GetMdnsTelemetryInfo() const325 const MdnsTelemetryInfo &GetMdnsTelemetryInfo() const { return mTelemetryInfo; } 326 327 virtual ~Publisher(void) = default; 328 329 /** 330 * This function creates a mDNS publisher. 331 * 332 * @param[in] aCallback The callback for receiving mDNS publisher state changes. 333 * 334 * @returns A pointer to the newly created mDNS publisher. 335 * 336 */ 337 static Publisher *Create(StateCallback aCallback); 338 339 /** 340 * This function destroys the mDNS publisher. 341 * 342 * @param[in] aPublisher A pointer to the publisher. 343 * 344 */ 345 static void Destroy(Publisher *aPublisher); 346 347 /** 348 * This function writes the TXT entry list to a TXT data buffer. The TXT entries 349 * will be sorted by their keys. 350 * 351 * The output data is in standard DNS-SD TXT data format. 352 * See RFC 6763 for details: https://tools.ietf.org/html/rfc6763#section-6. 353 * 354 * @param[in] aTxtList A TXT entry list. 355 * @param[out] aTxtData A TXT data buffer. 356 * 357 * @retval OTBR_ERROR_NONE Successfully write the TXT entry list. 358 * @retval OTBR_ERROR_INVALID_ARGS The @p aTxtList includes invalid TXT entry. 359 * 360 * @sa DecodeTxtData 361 * 362 */ 363 static otbrError EncodeTxtData(const TxtList &aTxtList, std::vector<uint8_t> &aTxtData); 364 365 /** 366 * This function decodes a TXT entry list from a TXT data buffer. 367 * 368 * The input data should be in standard DNS-SD TXT data format. 369 * See RFC 6763 for details: https://tools.ietf.org/html/rfc6763#section-6. 370 * 371 * @param[out] aTxtList A TXT entry list. 372 * @param[in] aTxtData A pointer to TXT data. 373 * @param[in] aTxtLength The TXT data length. 374 * 375 * @retval OTBR_ERROR_NONE Successfully decoded the TXT data. 376 * @retval OTBR_ERROR_INVALID_ARGS The @p aTxtdata has invalid TXT format. 377 * 378 * @sa EncodeTxtData 379 * 380 */ 381 static otbrError DecodeTxtData(TxtList &aTxtList, const uint8_t *aTxtData, uint16_t aTxtLength); 382 383 protected: 384 static constexpr uint8_t kMaxTextEntrySize = 255; 385 386 class Registration 387 { 388 public: 389 ResultCallback mCallback; 390 Publisher * mPublisher; 391 Registration(ResultCallback && aCallback,Publisher * aPublisher)392 Registration(ResultCallback &&aCallback, Publisher *aPublisher) 393 : mCallback(std::move(aCallback)) 394 , mPublisher(aPublisher) 395 { 396 } 397 virtual ~Registration(void); 398 399 // Tells whether the service registration has been completed (typically by calling 400 // `ServiceRegistration::Complete`). IsCompleted() const401 bool IsCompleted() const { return mCallback.IsNull(); } 402 403 protected: 404 // Completes the service registration with given result/error. TriggerCompleteCallback(otbrError aError)405 void TriggerCompleteCallback(otbrError aError) 406 { 407 if (!IsCompleted()) 408 { 409 std::move(mCallback)(aError); 410 } 411 } 412 }; 413 414 class ServiceRegistration : public Registration 415 { 416 public: 417 std::string mHostName; 418 std::string mName; 419 std::string mType; 420 SubTypeList mSubTypeList; 421 uint16_t mPort; 422 TxtList mTxtList; 423 ServiceRegistration(std::string aHostName,std::string aName,std::string aType,SubTypeList aSubTypeList,uint16_t aPort,TxtList aTxtList,ResultCallback && aCallback,Publisher * aPublisher)424 ServiceRegistration(std::string aHostName, 425 std::string aName, 426 std::string aType, 427 SubTypeList aSubTypeList, 428 uint16_t aPort, 429 TxtList aTxtList, 430 ResultCallback &&aCallback, 431 Publisher * aPublisher) 432 : Registration(std::move(aCallback), aPublisher) 433 , mHostName(std::move(aHostName)) 434 , mName(std::move(aName)) 435 , mType(std::move(aType)) 436 , mSubTypeList(SortSubTypeList(std::move(aSubTypeList))) 437 , mPort(aPort) 438 , mTxtList(SortTxtList(std::move(aTxtList))) 439 { 440 } ~ServiceRegistration(void)441 ~ServiceRegistration(void) override { OnComplete(OTBR_ERROR_ABORTED); } 442 443 void Complete(otbrError aError); 444 445 void OnComplete(otbrError aError); 446 447 // Tells whether this `ServiceRegistration` object is outdated comparing to the given parameters. 448 bool IsOutdated(const std::string &aHostName, 449 const std::string &aName, 450 const std::string &aType, 451 const SubTypeList &aSubTypeList, 452 uint16_t aPort, 453 const TxtList & aTxtList) const; 454 }; 455 456 class HostRegistration : public Registration 457 { 458 public: 459 std::string mName; 460 std::vector<uint8_t> mAddress; 461 HostRegistration(std::string aName,std::vector<uint8_t> aAddress,ResultCallback && aCallback,Publisher * aPublisher)462 HostRegistration(std::string aName, 463 std::vector<uint8_t> aAddress, 464 ResultCallback && aCallback, 465 Publisher * aPublisher) 466 : Registration(std::move(aCallback), aPublisher) 467 , mName(std::move(aName)) 468 , mAddress(std::move(aAddress)) 469 { 470 } 471 ~HostRegistration(void)472 ~HostRegistration(void) { OnComplete(OTBR_ERROR_ABORTED); } 473 474 void Complete(otbrError aError); 475 476 void OnComplete(otbrError); 477 478 // Tells whether this `HostRegistration` object is outdated comparing to the given parameters. 479 bool IsOutdated(const std::string &aName, const std::vector<uint8_t> &aAddress) const; 480 }; 481 482 using ServiceRegistrationPtr = std::unique_ptr<ServiceRegistration>; 483 using ServiceRegistrationMap = std::map<std::string, ServiceRegistrationPtr>; 484 using HostRegistrationPtr = std::unique_ptr<HostRegistration>; 485 using HostRegistrationMap = std::map<std::string, HostRegistrationPtr>; 486 487 static SubTypeList SortSubTypeList(SubTypeList aSubTypeList); 488 static TxtList SortTxtList(TxtList aTxtList); 489 static std::string MakeFullServiceName(const std::string &aName, const std::string &aType); 490 static std::string MakeFullHostName(const std::string &aName); 491 492 virtual void PublishServiceImpl(const std::string &aHostName, 493 const std::string &aName, 494 const std::string &aType, 495 const SubTypeList &aSubTypeList, 496 uint16_t aPort, 497 const TxtList & aTxtList, 498 ResultCallback && aCallback) = 0; 499 virtual void PublishHostImpl(const std::string & aName, 500 const std::vector<uint8_t> &aAddress, 501 ResultCallback && aCallback) = 0; 502 virtual void OnServiceResolveFailedImpl(const std::string &aType, 503 const std::string &aInstanceName, 504 int32_t aErrorCode) = 0; 505 virtual void OnHostResolveFailedImpl(const std::string &aHostName, int32_t aErrorCode) = 0; 506 507 virtual otbrError DnsErrorToOtbrError(int32_t aError) = 0; 508 509 void AddServiceRegistration(ServiceRegistrationPtr &&aServiceReg); 510 void RemoveServiceRegistration(const std::string &aName, const std::string &aType, otbrError aError); 511 ServiceRegistration *FindServiceRegistration(const std::string &aName, const std::string &aType); 512 void OnServiceResolved(const std::string &aType, const DiscoveredInstanceInfo &aInstanceInfo); 513 void OnServiceResolveFailed(const std::string &aType, const std::string &aInstanceName, int32_t aErrorCode); 514 void OnServiceRemoved(uint32_t aNetifIndex, const std::string &aType, const std::string &aInstanceName); 515 void OnHostResolved(const std::string &aHostName, const DiscoveredHostInfo &aHostInfo); 516 void OnHostResolveFailed(const std::string &aHostName, int32_t aErrorCode); 517 518 // Handles the cases that there is already a registration for the same service. 519 // If the returned callback is completed, current registration should be considered 520 // success and no further action should be performed. 521 ResultCallback HandleDuplicateServiceRegistration(const std::string &aHostName, 522 const std::string &aName, 523 const std::string &aType, 524 const SubTypeList &aSubTypeList, 525 uint16_t aPort, 526 const TxtList & aTxtList, 527 ResultCallback && aCallback); 528 529 ResultCallback HandleDuplicateHostRegistration(const std::string & aName, 530 const std::vector<uint8_t> &aAddress, 531 ResultCallback && aCallback); 532 533 void AddHostRegistration(HostRegistrationPtr &&aHostReg); 534 void RemoveHostRegistration(const std::string &aName, otbrError aError); 535 HostRegistration *FindHostRegistration(const std::string &aName); 536 537 static void UpdateMdnsResponseCounters(otbr::MdnsResponseCounters &aCounters, otbrError aError); 538 static void UpdateEmaLatency(uint32_t &aEmaLatency, uint32_t aLatency, otbrError aError); 539 540 void UpdateServiceRegistrationEmaLatency(const std::string &aInstanceName, 541 const std::string &aType, 542 otbrError aError); 543 void UpdateHostRegistrationEmaLatency(const std::string &aHostName, otbrError aError); 544 void UpdateServiceInstanceResolutionEmaLatency(const std::string &aInstanceName, 545 const std::string &aType, 546 otbrError aError); 547 void UpdateHostResolutionEmaLatency(const std::string &aHostName, otbrError aError); 548 549 ServiceRegistrationMap mServiceRegistrations; 550 HostRegistrationMap mHostRegistrations; 551 552 uint64_t mNextSubscriberId = 1; 553 554 std::map<uint64_t, std::pair<DiscoveredServiceInstanceCallback, DiscoveredHostCallback>> mDiscoveredCallbacks; 555 // {instance name, service type} -> the timepoint to begin service registration 556 std::map<std::pair<std::string, std::string>, Timepoint> mServiceRegistrationBeginTime; 557 // host name -> the timepoint to begin host registration 558 std::map<std::string, Timepoint> mHostRegistrationBeginTime; 559 // {instance name, service type} -> the timepoint to begin service resolution 560 std::map<std::pair<std::string, std::string>, Timepoint> mServiceInstanceResolutionBeginTime; 561 // host name -> the timepoint to begin host resolution 562 std::map<std::string, Timepoint> mHostResolutionBeginTime; 563 564 otbr::MdnsTelemetryInfo mTelemetryInfo{}; 565 }; 566 567 /** 568 * @} 569 */ 570 571 } // namespace Mdns 572 573 } // namespace otbr 574 575 #endif // OTBR_AGENT_MDNS_HPP_ 576