• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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