• 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 definition for mDNS publisher based on avahi.
32  */
33 
34 #ifndef OTBR_AGENT_MDNS_AVAHI_HPP_
35 #define OTBR_AGENT_MDNS_AVAHI_HPP_
36 
37 #include "openthread-br/config.h"
38 
39 #include <memory>
40 #include <set>
41 #include <vector>
42 
43 #include <avahi-client/client.h>
44 #include <avahi-client/lookup.h>
45 #include <avahi-client/publish.h>
46 #include <avahi-common/domain.h>
47 #include <avahi-common/watch.h>
48 
49 #include "mdns.hpp"
50 #include "common/code_utils.hpp"
51 #include "common/mainloop.hpp"
52 #include "common/time.hpp"
53 
54 /**
55  * @addtogroup border-router-mdns
56  *
57  * @brief
58  *   This module includes definition for avahi-based mDNS publisher.
59  *
60  * @{
61  */
62 
63 namespace otbr {
64 
65 namespace Mdns {
66 
67 class AvahiPoller;
68 
69 /**
70  * This class implements mDNS publisher with avahi.
71  *
72  */
73 class PublisherAvahi : public Publisher
74 {
75 public:
76     PublisherAvahi(StateCallback aStateCallback);
77     ~PublisherAvahi(void) override;
78 
79     void      UnpublishService(const std::string &aName, const std::string &aType, ResultCallback &&aCallback) override;
80     void      UnpublishHost(const std::string &aName, ResultCallback &&aCallback) override;
81     void      UnpublishKey(const std::string &aName, ResultCallback &&aCallback) override;
82     void      SubscribeService(const std::string &aType, const std::string &aInstanceName) override;
83     void      UnsubscribeService(const std::string &aType, const std::string &aInstanceName) override;
84     void      SubscribeHost(const std::string &aHostName) override;
85     void      UnsubscribeHost(const std::string &aHostName) override;
86     otbrError Start(void) override;
87     bool      IsStarted(void) const override;
88     void      Stop(void) override;
89 
90 protected:
91     otbrError PublishServiceImpl(const std::string &aHostName,
92                                  const std::string &aName,
93                                  const std::string &aType,
94                                  const SubTypeList &aSubTypeList,
95                                  uint16_t           aPort,
96                                  const TxtData     &aTxtData,
97                                  ResultCallback   &&aCallback) override;
98     otbrError PublishHostImpl(const std::string &aName,
99                               const AddressList &aAddresses,
100                               ResultCallback   &&aCallback) override;
101     otbrError PublishKeyImpl(const std::string &aName, const KeyData &aKeyData, ResultCallback &&aCallback) override;
102     void      OnServiceResolveFailedImpl(const std::string &aType,
103                                          const std::string &aInstanceName,
104                                          int32_t            aErrorCode) override;
105     void      OnHostResolveFailedImpl(const std::string &aHostName, int32_t aErrorCode) override;
106     otbrError DnsErrorToOtbrError(int32_t aErrorCode) override;
107 
108 private:
109     static constexpr size_t   kMaxSizeOfTxtRecord = 1024;
110     static constexpr uint32_t kDefaultTtl         = 10; // In seconds.
111     static constexpr uint16_t kDnsKeyRecordType   = 25;
112 
113     class AvahiServiceRegistration : public ServiceRegistration
114     {
115     public:
AvahiServiceRegistration(const std::string & aHostName,const std::string & aName,const std::string & aType,const SubTypeList & aSubTypeList,uint16_t aPort,const TxtData & aTxtData,ResultCallback && aCallback,AvahiEntryGroup * aEntryGroup,PublisherAvahi * aPublisher)116         AvahiServiceRegistration(const std::string &aHostName,
117                                  const std::string &aName,
118                                  const std::string &aType,
119                                  const SubTypeList &aSubTypeList,
120                                  uint16_t           aPort,
121                                  const TxtData     &aTxtData,
122                                  ResultCallback   &&aCallback,
123                                  AvahiEntryGroup   *aEntryGroup,
124                                  PublisherAvahi    *aPublisher)
125             : ServiceRegistration(aHostName,
126                                   aName,
127                                   aType,
128                                   aSubTypeList,
129                                   aPort,
130                                   aTxtData,
131                                   std::move(aCallback),
132                                   aPublisher)
133             , mEntryGroup(aEntryGroup)
134         {
135         }
136 
137         ~AvahiServiceRegistration(void) override;
GetEntryGroup(void) const138         const AvahiEntryGroup *GetEntryGroup(void) const { return mEntryGroup; }
139 
140     private:
141         AvahiEntryGroup *mEntryGroup;
142     };
143 
144     class AvahiHostRegistration : public HostRegistration
145     {
146     public:
AvahiHostRegistration(const std::string & aName,const AddressList & aAddresses,ResultCallback && aCallback,AvahiEntryGroup * aEntryGroup,PublisherAvahi * aPublisher)147         AvahiHostRegistration(const std::string &aName,
148                               const AddressList &aAddresses,
149                               ResultCallback   &&aCallback,
150                               AvahiEntryGroup   *aEntryGroup,
151                               PublisherAvahi    *aPublisher)
152             : HostRegistration(aName, aAddresses, std::move(aCallback), aPublisher)
153             , mEntryGroup(aEntryGroup)
154         {
155         }
156 
157         ~AvahiHostRegistration(void) override;
GetEntryGroup(void) const158         const AvahiEntryGroup *GetEntryGroup(void) const { return mEntryGroup; }
159 
160     private:
161         AvahiEntryGroup *mEntryGroup;
162     };
163 
164     class AvahiKeyRegistration : public KeyRegistration
165     {
166     public:
AvahiKeyRegistration(const std::string & aName,const KeyData & aKeyData,ResultCallback && aCallback,AvahiEntryGroup * aEntryGroup,PublisherAvahi * aPublisher)167         AvahiKeyRegistration(const std::string &aName,
168                              const KeyData     &aKeyData,
169                              ResultCallback   &&aCallback,
170                              AvahiEntryGroup   *aEntryGroup,
171                              PublisherAvahi    *aPublisher)
172             : KeyRegistration(aName, aKeyData, std::move(aCallback), aPublisher)
173             , mEntryGroup(aEntryGroup)
174         {
175         }
176 
177         ~AvahiKeyRegistration(void) override;
GetEntryGroup(void) const178         const AvahiEntryGroup *GetEntryGroup(void) const { return mEntryGroup; }
179 
180     private:
181         AvahiEntryGroup *mEntryGroup;
182     };
183 
184     struct Subscription : private ::NonCopyable
185     {
186         PublisherAvahi *mPublisherAvahi;
187 
Subscriptionotbr::Mdns::PublisherAvahi::Subscription188         explicit Subscription(PublisherAvahi &aPublisherAvahi)
189             : mPublisherAvahi(&aPublisherAvahi)
190         {
191         }
192     };
193 
194     struct HostSubscription : public Subscription
195     {
HostSubscriptionotbr::Mdns::PublisherAvahi::HostSubscription196         explicit HostSubscription(PublisherAvahi &aAvahiPublisher, std::string aHostName)
197             : Subscription(aAvahiPublisher)
198             , mHostName(std::move(aHostName))
199             , mRecordBrowser(nullptr)
200         {
201         }
202 
~HostSubscriptionotbr::Mdns::PublisherAvahi::HostSubscription203         ~HostSubscription() { Release(); }
204 
205         void        Release(void);
206         void        Resolve(void);
207         static void HandleResolveResult(AvahiRecordBrowser    *aRecordBrowser,
208                                         AvahiIfIndex           aInterfaceIndex,
209                                         AvahiProtocol          aProtocol,
210                                         AvahiBrowserEvent      aEvent,
211                                         const char            *aName,
212                                         uint16_t               aClazz,
213                                         uint16_t               aType,
214                                         const void            *aRdata,
215                                         size_t                 aSize,
216                                         AvahiLookupResultFlags aFlags,
217                                         void                  *aContext);
218 
219         void HandleResolveResult(AvahiRecordBrowser    *aRecordBrowser,
220                                  AvahiIfIndex           aInterfaceIndex,
221                                  AvahiProtocol          aProtocol,
222                                  AvahiBrowserEvent      aEvent,
223                                  const char            *aName,
224                                  uint16_t               aClazz,
225                                  uint16_t               aType,
226                                  const void            *aRdata,
227                                  size_t                 aSize,
228                                  AvahiLookupResultFlags aFlags);
229 
230         std::string         mHostName;
231         DiscoveredHostInfo  mHostInfo;
232         AvahiRecordBrowser *mRecordBrowser;
233     };
234 
235     struct ServiceResolver
236     {
~ServiceResolverotbr::Mdns::PublisherAvahi::ServiceResolver237         ~ServiceResolver()
238         {
239             if (mServiceResolver)
240             {
241                 avahi_service_resolver_free(mServiceResolver);
242             }
243             if (mRecordBrowser)
244             {
245                 avahi_record_browser_free(mRecordBrowser);
246             }
247         }
248 
249         static void HandleResolveServiceResult(AvahiServiceResolver  *aServiceResolver,
250                                                AvahiIfIndex           aInterfaceIndex,
251                                                AvahiProtocol          Protocol,
252                                                AvahiResolverEvent     aEvent,
253                                                const char            *aName,
254                                                const char            *aType,
255                                                const char            *aDomain,
256                                                const char            *aHostName,
257                                                const AvahiAddress    *aAddress,
258                                                uint16_t               aPort,
259                                                AvahiStringList       *aTxt,
260                                                AvahiLookupResultFlags aFlags,
261                                                void                  *aContext);
262 
263         void HandleResolveServiceResult(AvahiServiceResolver  *aServiceResolver,
264                                         AvahiIfIndex           aInterfaceIndex,
265                                         AvahiProtocol          Protocol,
266                                         AvahiResolverEvent     aEvent,
267                                         const char            *aName,
268                                         const char            *aType,
269                                         const char            *aDomain,
270                                         const char            *aHostName,
271                                         const AvahiAddress    *aAddress,
272                                         uint16_t               aPort,
273                                         AvahiStringList       *aTxt,
274                                         AvahiLookupResultFlags aFlags);
275 
276         static void HandleResolveHostResult(AvahiRecordBrowser    *aRecordBrowser,
277                                             AvahiIfIndex           aInterfaceIndex,
278                                             AvahiProtocol          aProtocol,
279                                             AvahiBrowserEvent      aEvent,
280                                             const char            *aName,
281                                             uint16_t               aClazz,
282                                             uint16_t               aType,
283                                             const void            *aRdata,
284                                             size_t                 aSize,
285                                             AvahiLookupResultFlags aFlags,
286                                             void                  *aContext);
287 
288         void HandleResolveHostResult(AvahiRecordBrowser    *aRecordBrowser,
289                                      AvahiIfIndex           aInterfaceIndex,
290                                      AvahiProtocol          aProtocol,
291                                      AvahiBrowserEvent      aEvent,
292                                      const char            *aName,
293                                      uint16_t               aClazz,
294                                      uint16_t               aType,
295                                      const void            *aRdata,
296                                      size_t                 aSize,
297                                      AvahiLookupResultFlags aFlags);
298 
299         std::string            mType;
300         PublisherAvahi        *mPublisherAvahi;
301         AvahiServiceResolver  *mServiceResolver = nullptr;
302         AvahiRecordBrowser    *mRecordBrowser   = nullptr;
303         DiscoveredInstanceInfo mInstanceInfo;
304     };
305     struct ServiceSubscription : public Subscription
306     {
ServiceSubscriptionotbr::Mdns::PublisherAvahi::ServiceSubscription307         explicit ServiceSubscription(PublisherAvahi &aPublisherAvahi, std::string aType, std::string aInstanceName)
308             : Subscription(aPublisherAvahi)
309             , mType(std::move(aType))
310             , mInstanceName(std::move(aInstanceName))
311             , mServiceBrowser(nullptr)
312         {
313         }
314 
~ServiceSubscriptionotbr::Mdns::PublisherAvahi::ServiceSubscription315         ~ServiceSubscription() { Release(); }
316 
317         void Release(void);
318         void Browse(void);
319         void Resolve(uint32_t           aInterfaceIndex,
320                      AvahiProtocol      aProtocol,
321                      const std::string &aInstanceName,
322                      const std::string &aType);
323         void AddServiceResolver(const std::string &aInstanceName, ServiceResolver *aServiceResolver);
324         void RemoveServiceResolver(const std::string &aInstanceName);
325 
326         static void HandleBrowseResult(AvahiServiceBrowser   *aServiceBrowser,
327                                        AvahiIfIndex           aInterfaceIndex,
328                                        AvahiProtocol          aProtocol,
329                                        AvahiBrowserEvent      aEvent,
330                                        const char            *aName,
331                                        const char            *aType,
332                                        const char            *aDomain,
333                                        AvahiLookupResultFlags aFlags,
334                                        void                  *aContext);
335 
336         void HandleBrowseResult(AvahiServiceBrowser   *aServiceBrowser,
337                                 AvahiIfIndex           aInterfaceIndex,
338                                 AvahiProtocol          aProtocol,
339                                 AvahiBrowserEvent      aEvent,
340                                 const char            *aName,
341                                 const char            *aType,
342                                 const char            *aDomain,
343                                 AvahiLookupResultFlags aFlags);
344 
345         std::string          mType;
346         std::string          mInstanceName;
347         AvahiServiceBrowser *mServiceBrowser;
348 
349         using ServiceResolversMap = std::map<std::string, std::set<ServiceResolver *>>;
350         ServiceResolversMap mServiceResolvers;
351     };
352 
353     typedef std::vector<std::unique_ptr<ServiceSubscription>> ServiceSubscriptionList;
354     typedef std::vector<std::unique_ptr<HostSubscription>>    HostSubscriptionList;
355 
356     static void HandleClientState(AvahiClient *aClient, AvahiClientState aState, void *aContext);
357     void        HandleClientState(AvahiClient *aClient, AvahiClientState aState);
358 
359     AvahiEntryGroup *CreateGroup(AvahiClient *aClient);
360     static void      ReleaseGroup(AvahiEntryGroup *aGroup);
361 
362     static void HandleGroupState(AvahiEntryGroup *aGroup, AvahiEntryGroupState aState, void *aContext);
363     void        HandleGroupState(AvahiEntryGroup *aGroup, AvahiEntryGroupState aState);
364     void        CallHostOrServiceCallback(AvahiEntryGroup *aGroup, otbrError aError);
365 
366     static otbrError TxtDataToAvahiStringList(const TxtData    &aTxtData,
367                                               AvahiStringList  *aBuffer,
368                                               size_t            aBufferSize,
369                                               AvahiStringList *&aHead);
370 
371     ServiceRegistration *FindServiceRegistration(const AvahiEntryGroup *aEntryGroup);
372     HostRegistration    *FindHostRegistration(const AvahiEntryGroup *aEntryGroup);
373     KeyRegistration     *FindKeyRegistration(const AvahiEntryGroup *aEntryGroup);
374 
375     AvahiClient                 *mClient;
376     std::unique_ptr<AvahiPoller> mPoller;
377     State                        mState;
378     StateCallback                mStateCallback;
379 
380     ServiceSubscriptionList mSubscribedServices;
381     HostSubscriptionList    mSubscribedHosts;
382 };
383 
384 } // namespace Mdns
385 
386 } // namespace otbr
387 
388 /**
389  * @}
390  */
391 #endif // OTBR_AGENT_MDNS_AVAHI_HPP_
392