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