xref: /aosp_15_r20/external/ot-br-posix/src/mdns/mdns_avahi.cpp (revision 4a64e381480ef79f0532b2421e44e6ee336b8e0d)
1*4a64e381SAndroid Build Coastguard Worker /*
2*4a64e381SAndroid Build Coastguard Worker  *    Copyright (c) 2017, The OpenThread Authors.
3*4a64e381SAndroid Build Coastguard Worker  *    All rights reserved.
4*4a64e381SAndroid Build Coastguard Worker  *
5*4a64e381SAndroid Build Coastguard Worker  *    Redistribution and use in source and binary forms, with or without
6*4a64e381SAndroid Build Coastguard Worker  *    modification, are permitted provided that the following conditions are met:
7*4a64e381SAndroid Build Coastguard Worker  *    1. Redistributions of source code must retain the above copyright
8*4a64e381SAndroid Build Coastguard Worker  *       notice, this list of conditions and the following disclaimer.
9*4a64e381SAndroid Build Coastguard Worker  *    2. Redistributions in binary form must reproduce the above copyright
10*4a64e381SAndroid Build Coastguard Worker  *       notice, this list of conditions and the following disclaimer in the
11*4a64e381SAndroid Build Coastguard Worker  *       documentation and/or other materials provided with the distribution.
12*4a64e381SAndroid Build Coastguard Worker  *    3. Neither the name of the copyright holder nor the
13*4a64e381SAndroid Build Coastguard Worker  *       names of its contributors may be used to endorse or promote products
14*4a64e381SAndroid Build Coastguard Worker  *       derived from this software without specific prior written permission.
15*4a64e381SAndroid Build Coastguard Worker  *
16*4a64e381SAndroid Build Coastguard Worker  *    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17*4a64e381SAndroid Build Coastguard Worker  *    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18*4a64e381SAndroid Build Coastguard Worker  *    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19*4a64e381SAndroid Build Coastguard Worker  *    ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20*4a64e381SAndroid Build Coastguard Worker  *    LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21*4a64e381SAndroid Build Coastguard Worker  *    CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22*4a64e381SAndroid Build Coastguard Worker  *    SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23*4a64e381SAndroid Build Coastguard Worker  *    INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24*4a64e381SAndroid Build Coastguard Worker  *    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25*4a64e381SAndroid Build Coastguard Worker  *    ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26*4a64e381SAndroid Build Coastguard Worker  *    POSSIBILITY OF SUCH DAMAGE.
27*4a64e381SAndroid Build Coastguard Worker  */
28*4a64e381SAndroid Build Coastguard Worker 
29*4a64e381SAndroid Build Coastguard Worker /**
30*4a64e381SAndroid Build Coastguard Worker  * @file
31*4a64e381SAndroid Build Coastguard Worker  *   This file implements mDNS publisher based on avahi.
32*4a64e381SAndroid Build Coastguard Worker  */
33*4a64e381SAndroid Build Coastguard Worker 
34*4a64e381SAndroid Build Coastguard Worker #define OTBR_LOG_TAG "MDNS"
35*4a64e381SAndroid Build Coastguard Worker 
36*4a64e381SAndroid Build Coastguard Worker #include "mdns/mdns_avahi.hpp"
37*4a64e381SAndroid Build Coastguard Worker 
38*4a64e381SAndroid Build Coastguard Worker #include <algorithm>
39*4a64e381SAndroid Build Coastguard Worker 
40*4a64e381SAndroid Build Coastguard Worker #include <avahi-client/client.h>
41*4a64e381SAndroid Build Coastguard Worker #include <avahi-common/alternative.h>
42*4a64e381SAndroid Build Coastguard Worker #include <avahi-common/error.h>
43*4a64e381SAndroid Build Coastguard Worker #include <avahi-common/malloc.h>
44*4a64e381SAndroid Build Coastguard Worker #include <avahi-common/timeval.h>
45*4a64e381SAndroid Build Coastguard Worker #include <errno.h>
46*4a64e381SAndroid Build Coastguard Worker #include <inttypes.h>
47*4a64e381SAndroid Build Coastguard Worker #include <stdio.h>
48*4a64e381SAndroid Build Coastguard Worker #include <stdlib.h>
49*4a64e381SAndroid Build Coastguard Worker #include <string.h>
50*4a64e381SAndroid Build Coastguard Worker #include <sys/socket.h>
51*4a64e381SAndroid Build Coastguard Worker 
52*4a64e381SAndroid Build Coastguard Worker #include "common/code_utils.hpp"
53*4a64e381SAndroid Build Coastguard Worker #include "common/logging.hpp"
54*4a64e381SAndroid Build Coastguard Worker #include "common/time.hpp"
55*4a64e381SAndroid Build Coastguard Worker 
56*4a64e381SAndroid Build Coastguard Worker namespace otbr {
57*4a64e381SAndroid Build Coastguard Worker namespace Mdns {
58*4a64e381SAndroid Build Coastguard Worker 
59*4a64e381SAndroid Build Coastguard Worker class AvahiPoller;
60*4a64e381SAndroid Build Coastguard Worker 
61*4a64e381SAndroid Build Coastguard Worker } // namespace Mdns
62*4a64e381SAndroid Build Coastguard Worker } // namespace otbr
63*4a64e381SAndroid Build Coastguard Worker 
64*4a64e381SAndroid Build Coastguard Worker struct AvahiWatch
65*4a64e381SAndroid Build Coastguard Worker {
66*4a64e381SAndroid Build Coastguard Worker     typedef otbr::Mdns::AvahiPoller AvahiPoller;
67*4a64e381SAndroid Build Coastguard Worker 
68*4a64e381SAndroid Build Coastguard Worker     int                mFd;           ///< The file descriptor to watch.
69*4a64e381SAndroid Build Coastguard Worker     AvahiWatchEvent    mEvents;       ///< The interested events.
70*4a64e381SAndroid Build Coastguard Worker     int                mHappened;     ///< The events happened.
71*4a64e381SAndroid Build Coastguard Worker     AvahiWatchCallback mCallback;     ///< The function to be called to report events happened on `mFd`.
72*4a64e381SAndroid Build Coastguard Worker     void              *mContext;      ///< A pointer to application-specific context to use with `mCallback`.
73*4a64e381SAndroid Build Coastguard Worker     bool               mShouldReport; ///< Whether or not we need to report events (invoking callback).
74*4a64e381SAndroid Build Coastguard Worker     AvahiPoller       &mPoller;       ///< The poller owning this watch.
75*4a64e381SAndroid Build Coastguard Worker 
76*4a64e381SAndroid Build Coastguard Worker     /**
77*4a64e381SAndroid Build Coastguard Worker      * The constructor to initialize an Avahi watch.
78*4a64e381SAndroid Build Coastguard Worker      *
79*4a64e381SAndroid Build Coastguard Worker      * @param[in] aFd        The file descriptor to watch.
80*4a64e381SAndroid Build Coastguard Worker      * @param[in] aEvents    The events to watch.
81*4a64e381SAndroid Build Coastguard Worker      * @param[in] aCallback  The function to be called when events happened on this file descriptor.
82*4a64e381SAndroid Build Coastguard Worker      * @param[in] aContext   A pointer to application-specific context.
83*4a64e381SAndroid Build Coastguard Worker      * @param[in] aPoller    The AvahiPoller this watcher belongs to.
84*4a64e381SAndroid Build Coastguard Worker      */
AvahiWatchAvahiWatch85*4a64e381SAndroid Build Coastguard Worker     AvahiWatch(int aFd, AvahiWatchEvent aEvents, AvahiWatchCallback aCallback, void *aContext, AvahiPoller &aPoller)
86*4a64e381SAndroid Build Coastguard Worker         : mFd(aFd)
87*4a64e381SAndroid Build Coastguard Worker         , mEvents(aEvents)
88*4a64e381SAndroid Build Coastguard Worker         , mCallback(aCallback)
89*4a64e381SAndroid Build Coastguard Worker         , mContext(aContext)
90*4a64e381SAndroid Build Coastguard Worker         , mShouldReport(false)
91*4a64e381SAndroid Build Coastguard Worker         , mPoller(aPoller)
92*4a64e381SAndroid Build Coastguard Worker     {
93*4a64e381SAndroid Build Coastguard Worker     }
94*4a64e381SAndroid Build Coastguard Worker };
95*4a64e381SAndroid Build Coastguard Worker 
96*4a64e381SAndroid Build Coastguard Worker /**
97*4a64e381SAndroid Build Coastguard Worker  * This structure implements the AvahiTimeout.
98*4a64e381SAndroid Build Coastguard Worker  */
99*4a64e381SAndroid Build Coastguard Worker struct AvahiTimeout
100*4a64e381SAndroid Build Coastguard Worker {
101*4a64e381SAndroid Build Coastguard Worker     typedef otbr::Mdns::AvahiPoller AvahiPoller;
102*4a64e381SAndroid Build Coastguard Worker 
103*4a64e381SAndroid Build Coastguard Worker     otbr::Timepoint      mTimeout;      ///< Absolute time when this timer timeout.
104*4a64e381SAndroid Build Coastguard Worker     AvahiTimeoutCallback mCallback;     ///< The function to be called when timeout.
105*4a64e381SAndroid Build Coastguard Worker     void                *mContext;      ///< The pointer to application-specific context.
106*4a64e381SAndroid Build Coastguard Worker     bool                 mShouldReport; ///< Whether or not timeout occurred and need to reported (invoking callback).
107*4a64e381SAndroid Build Coastguard Worker     AvahiPoller         &mPoller;       ///< The poller created this timer.
108*4a64e381SAndroid Build Coastguard Worker 
109*4a64e381SAndroid Build Coastguard Worker     /**
110*4a64e381SAndroid Build Coastguard Worker      * The constructor to initialize an AvahiTimeout.
111*4a64e381SAndroid Build Coastguard Worker      *
112*4a64e381SAndroid Build Coastguard Worker      * @param[in] aTimeout   A pointer to the time after which the callback should be called.
113*4a64e381SAndroid Build Coastguard Worker      * @param[in] aCallback  The function to be called after timeout.
114*4a64e381SAndroid Build Coastguard Worker      * @param[in] aContext   A pointer to application-specific context.
115*4a64e381SAndroid Build Coastguard Worker      * @param[in] aPoller    The AvahiPoller this timeout belongs to.
116*4a64e381SAndroid Build Coastguard Worker      */
AvahiTimeoutAvahiTimeout117*4a64e381SAndroid Build Coastguard Worker     AvahiTimeout(const struct timeval *aTimeout, AvahiTimeoutCallback aCallback, void *aContext, AvahiPoller &aPoller)
118*4a64e381SAndroid Build Coastguard Worker         : mCallback(aCallback)
119*4a64e381SAndroid Build Coastguard Worker         , mContext(aContext)
120*4a64e381SAndroid Build Coastguard Worker         , mShouldReport(false)
121*4a64e381SAndroid Build Coastguard Worker         , mPoller(aPoller)
122*4a64e381SAndroid Build Coastguard Worker     {
123*4a64e381SAndroid Build Coastguard Worker         if (aTimeout)
124*4a64e381SAndroid Build Coastguard Worker         {
125*4a64e381SAndroid Build Coastguard Worker             mTimeout = otbr::Clock::now() + otbr::FromTimeval<otbr::Microseconds>(*aTimeout);
126*4a64e381SAndroid Build Coastguard Worker         }
127*4a64e381SAndroid Build Coastguard Worker         else
128*4a64e381SAndroid Build Coastguard Worker         {
129*4a64e381SAndroid Build Coastguard Worker             mTimeout = otbr::Timepoint::min();
130*4a64e381SAndroid Build Coastguard Worker         }
131*4a64e381SAndroid Build Coastguard Worker     }
132*4a64e381SAndroid Build Coastguard Worker };
133*4a64e381SAndroid Build Coastguard Worker 
134*4a64e381SAndroid Build Coastguard Worker namespace otbr {
135*4a64e381SAndroid Build Coastguard Worker 
136*4a64e381SAndroid Build Coastguard Worker namespace Mdns {
137*4a64e381SAndroid Build Coastguard Worker 
DnsErrorToOtbrError(int aAvahiError)138*4a64e381SAndroid Build Coastguard Worker static otbrError DnsErrorToOtbrError(int aAvahiError)
139*4a64e381SAndroid Build Coastguard Worker {
140*4a64e381SAndroid Build Coastguard Worker     otbrError error;
141*4a64e381SAndroid Build Coastguard Worker 
142*4a64e381SAndroid Build Coastguard Worker     switch (aAvahiError)
143*4a64e381SAndroid Build Coastguard Worker     {
144*4a64e381SAndroid Build Coastguard Worker     case AVAHI_OK:
145*4a64e381SAndroid Build Coastguard Worker     case AVAHI_ERR_INVALID_ADDRESS:
146*4a64e381SAndroid Build Coastguard Worker         error = OTBR_ERROR_NONE;
147*4a64e381SAndroid Build Coastguard Worker         break;
148*4a64e381SAndroid Build Coastguard Worker 
149*4a64e381SAndroid Build Coastguard Worker     case AVAHI_ERR_NOT_FOUND:
150*4a64e381SAndroid Build Coastguard Worker         error = OTBR_ERROR_NOT_FOUND;
151*4a64e381SAndroid Build Coastguard Worker         break;
152*4a64e381SAndroid Build Coastguard Worker 
153*4a64e381SAndroid Build Coastguard Worker     case AVAHI_ERR_INVALID_ARGUMENT:
154*4a64e381SAndroid Build Coastguard Worker         error = OTBR_ERROR_INVALID_ARGS;
155*4a64e381SAndroid Build Coastguard Worker         break;
156*4a64e381SAndroid Build Coastguard Worker 
157*4a64e381SAndroid Build Coastguard Worker     case AVAHI_ERR_COLLISION:
158*4a64e381SAndroid Build Coastguard Worker         error = OTBR_ERROR_DUPLICATED;
159*4a64e381SAndroid Build Coastguard Worker         break;
160*4a64e381SAndroid Build Coastguard Worker 
161*4a64e381SAndroid Build Coastguard Worker     case AVAHI_ERR_DNS_NOTIMP:
162*4a64e381SAndroid Build Coastguard Worker     case AVAHI_ERR_NOT_SUPPORTED:
163*4a64e381SAndroid Build Coastguard Worker         error = OTBR_ERROR_NOT_IMPLEMENTED;
164*4a64e381SAndroid Build Coastguard Worker         break;
165*4a64e381SAndroid Build Coastguard Worker 
166*4a64e381SAndroid Build Coastguard Worker     default:
167*4a64e381SAndroid Build Coastguard Worker         error = OTBR_ERROR_MDNS;
168*4a64e381SAndroid Build Coastguard Worker         break;
169*4a64e381SAndroid Build Coastguard Worker     }
170*4a64e381SAndroid Build Coastguard Worker 
171*4a64e381SAndroid Build Coastguard Worker     return error;
172*4a64e381SAndroid Build Coastguard Worker }
173*4a64e381SAndroid Build Coastguard Worker 
174*4a64e381SAndroid Build Coastguard Worker class AvahiPoller : public MainloopProcessor
175*4a64e381SAndroid Build Coastguard Worker {
176*4a64e381SAndroid Build Coastguard Worker public:
177*4a64e381SAndroid Build Coastguard Worker     AvahiPoller(void);
178*4a64e381SAndroid Build Coastguard Worker 
179*4a64e381SAndroid Build Coastguard Worker     // Implementation of MainloopProcessor.
180*4a64e381SAndroid Build Coastguard Worker 
181*4a64e381SAndroid Build Coastguard Worker     void Update(MainloopContext &aMainloop) override;
182*4a64e381SAndroid Build Coastguard Worker     void Process(const MainloopContext &aMainloop) override;
183*4a64e381SAndroid Build Coastguard Worker 
GetAvahiPoll(void) const184*4a64e381SAndroid Build Coastguard Worker     const AvahiPoll *GetAvahiPoll(void) const { return &mAvahiPoll; }
185*4a64e381SAndroid Build Coastguard Worker 
186*4a64e381SAndroid Build Coastguard Worker private:
187*4a64e381SAndroid Build Coastguard Worker     typedef std::vector<AvahiWatch *>   Watches;
188*4a64e381SAndroid Build Coastguard Worker     typedef std::vector<AvahiTimeout *> Timers;
189*4a64e381SAndroid Build Coastguard Worker 
190*4a64e381SAndroid Build Coastguard Worker     static AvahiWatch     *WatchNew(const struct AvahiPoll *aPoll,
191*4a64e381SAndroid Build Coastguard Worker                                     int                     aFd,
192*4a64e381SAndroid Build Coastguard Worker                                     AvahiWatchEvent         aEvent,
193*4a64e381SAndroid Build Coastguard Worker                                     AvahiWatchCallback      aCallback,
194*4a64e381SAndroid Build Coastguard Worker                                     void                   *aContext);
195*4a64e381SAndroid Build Coastguard Worker     AvahiWatch            *WatchNew(int aFd, AvahiWatchEvent aEvent, AvahiWatchCallback aCallback, void *aContext);
196*4a64e381SAndroid Build Coastguard Worker     static void            WatchUpdate(AvahiWatch *aWatch, AvahiWatchEvent aEvent);
197*4a64e381SAndroid Build Coastguard Worker     static AvahiWatchEvent WatchGetEvents(AvahiWatch *aWatch);
198*4a64e381SAndroid Build Coastguard Worker     static void            WatchFree(AvahiWatch *aWatch);
199*4a64e381SAndroid Build Coastguard Worker     void                   WatchFree(AvahiWatch &aWatch);
200*4a64e381SAndroid Build Coastguard Worker     static AvahiTimeout   *TimeoutNew(const AvahiPoll      *aPoll,
201*4a64e381SAndroid Build Coastguard Worker                                       const struct timeval *aTimeout,
202*4a64e381SAndroid Build Coastguard Worker                                       AvahiTimeoutCallback  aCallback,
203*4a64e381SAndroid Build Coastguard Worker                                       void                 *aContext);
204*4a64e381SAndroid Build Coastguard Worker     AvahiTimeout          *TimeoutNew(const struct timeval *aTimeout, AvahiTimeoutCallback aCallback, void *aContext);
205*4a64e381SAndroid Build Coastguard Worker     static void            TimeoutUpdate(AvahiTimeout *aTimer, const struct timeval *aTimeout);
206*4a64e381SAndroid Build Coastguard Worker     static void            TimeoutFree(AvahiTimeout *aTimer);
207*4a64e381SAndroid Build Coastguard Worker     void                   TimeoutFree(AvahiTimeout &aTimer);
208*4a64e381SAndroid Build Coastguard Worker 
209*4a64e381SAndroid Build Coastguard Worker     Watches   mWatches;
210*4a64e381SAndroid Build Coastguard Worker     Timers    mTimers;
211*4a64e381SAndroid Build Coastguard Worker     AvahiPoll mAvahiPoll;
212*4a64e381SAndroid Build Coastguard Worker };
213*4a64e381SAndroid Build Coastguard Worker 
AvahiPoller(void)214*4a64e381SAndroid Build Coastguard Worker AvahiPoller::AvahiPoller(void)
215*4a64e381SAndroid Build Coastguard Worker {
216*4a64e381SAndroid Build Coastguard Worker     mAvahiPoll.userdata         = this;
217*4a64e381SAndroid Build Coastguard Worker     mAvahiPoll.watch_new        = WatchNew;
218*4a64e381SAndroid Build Coastguard Worker     mAvahiPoll.watch_update     = WatchUpdate;
219*4a64e381SAndroid Build Coastguard Worker     mAvahiPoll.watch_get_events = WatchGetEvents;
220*4a64e381SAndroid Build Coastguard Worker     mAvahiPoll.watch_free       = WatchFree;
221*4a64e381SAndroid Build Coastguard Worker 
222*4a64e381SAndroid Build Coastguard Worker     mAvahiPoll.timeout_new    = TimeoutNew;
223*4a64e381SAndroid Build Coastguard Worker     mAvahiPoll.timeout_update = TimeoutUpdate;
224*4a64e381SAndroid Build Coastguard Worker     mAvahiPoll.timeout_free   = TimeoutFree;
225*4a64e381SAndroid Build Coastguard Worker }
226*4a64e381SAndroid Build Coastguard Worker 
WatchNew(const struct AvahiPoll * aPoll,int aFd,AvahiWatchEvent aEvent,AvahiWatchCallback aCallback,void * aContext)227*4a64e381SAndroid Build Coastguard Worker AvahiWatch *AvahiPoller::WatchNew(const struct AvahiPoll *aPoll,
228*4a64e381SAndroid Build Coastguard Worker                                   int                     aFd,
229*4a64e381SAndroid Build Coastguard Worker                                   AvahiWatchEvent         aEvent,
230*4a64e381SAndroid Build Coastguard Worker                                   AvahiWatchCallback      aCallback,
231*4a64e381SAndroid Build Coastguard Worker                                   void                   *aContext)
232*4a64e381SAndroid Build Coastguard Worker {
233*4a64e381SAndroid Build Coastguard Worker     return reinterpret_cast<AvahiPoller *>(aPoll->userdata)->WatchNew(aFd, aEvent, aCallback, aContext);
234*4a64e381SAndroid Build Coastguard Worker }
235*4a64e381SAndroid Build Coastguard Worker 
WatchNew(int aFd,AvahiWatchEvent aEvent,AvahiWatchCallback aCallback,void * aContext)236*4a64e381SAndroid Build Coastguard Worker AvahiWatch *AvahiPoller::WatchNew(int aFd, AvahiWatchEvent aEvent, AvahiWatchCallback aCallback, void *aContext)
237*4a64e381SAndroid Build Coastguard Worker {
238*4a64e381SAndroid Build Coastguard Worker     assert(aEvent && aCallback && aFd >= 0);
239*4a64e381SAndroid Build Coastguard Worker 
240*4a64e381SAndroid Build Coastguard Worker     mWatches.push_back(new AvahiWatch(aFd, aEvent, aCallback, aContext, *this));
241*4a64e381SAndroid Build Coastguard Worker 
242*4a64e381SAndroid Build Coastguard Worker     return mWatches.back();
243*4a64e381SAndroid Build Coastguard Worker }
244*4a64e381SAndroid Build Coastguard Worker 
WatchUpdate(AvahiWatch * aWatch,AvahiWatchEvent aEvent)245*4a64e381SAndroid Build Coastguard Worker void AvahiPoller::WatchUpdate(AvahiWatch *aWatch, AvahiWatchEvent aEvent)
246*4a64e381SAndroid Build Coastguard Worker {
247*4a64e381SAndroid Build Coastguard Worker     aWatch->mEvents = aEvent;
248*4a64e381SAndroid Build Coastguard Worker }
249*4a64e381SAndroid Build Coastguard Worker 
WatchGetEvents(AvahiWatch * aWatch)250*4a64e381SAndroid Build Coastguard Worker AvahiWatchEvent AvahiPoller::WatchGetEvents(AvahiWatch *aWatch)
251*4a64e381SAndroid Build Coastguard Worker {
252*4a64e381SAndroid Build Coastguard Worker     return static_cast<AvahiWatchEvent>(aWatch->mHappened);
253*4a64e381SAndroid Build Coastguard Worker }
254*4a64e381SAndroid Build Coastguard Worker 
WatchFree(AvahiWatch * aWatch)255*4a64e381SAndroid Build Coastguard Worker void AvahiPoller::WatchFree(AvahiWatch *aWatch)
256*4a64e381SAndroid Build Coastguard Worker {
257*4a64e381SAndroid Build Coastguard Worker     aWatch->mPoller.WatchFree(*aWatch);
258*4a64e381SAndroid Build Coastguard Worker }
259*4a64e381SAndroid Build Coastguard Worker 
WatchFree(AvahiWatch & aWatch)260*4a64e381SAndroid Build Coastguard Worker void AvahiPoller::WatchFree(AvahiWatch &aWatch)
261*4a64e381SAndroid Build Coastguard Worker {
262*4a64e381SAndroid Build Coastguard Worker     for (Watches::iterator it = mWatches.begin(); it != mWatches.end(); ++it)
263*4a64e381SAndroid Build Coastguard Worker     {
264*4a64e381SAndroid Build Coastguard Worker         if (*it == &aWatch)
265*4a64e381SAndroid Build Coastguard Worker         {
266*4a64e381SAndroid Build Coastguard Worker             mWatches.erase(it);
267*4a64e381SAndroid Build Coastguard Worker             delete &aWatch;
268*4a64e381SAndroid Build Coastguard Worker             break;
269*4a64e381SAndroid Build Coastguard Worker         }
270*4a64e381SAndroid Build Coastguard Worker     }
271*4a64e381SAndroid Build Coastguard Worker }
272*4a64e381SAndroid Build Coastguard Worker 
TimeoutNew(const AvahiPoll * aPoll,const struct timeval * aTimeout,AvahiTimeoutCallback aCallback,void * aContext)273*4a64e381SAndroid Build Coastguard Worker AvahiTimeout *AvahiPoller::TimeoutNew(const AvahiPoll      *aPoll,
274*4a64e381SAndroid Build Coastguard Worker                                       const struct timeval *aTimeout,
275*4a64e381SAndroid Build Coastguard Worker                                       AvahiTimeoutCallback  aCallback,
276*4a64e381SAndroid Build Coastguard Worker                                       void                 *aContext)
277*4a64e381SAndroid Build Coastguard Worker {
278*4a64e381SAndroid Build Coastguard Worker     assert(aPoll && aCallback);
279*4a64e381SAndroid Build Coastguard Worker     return static_cast<AvahiPoller *>(aPoll->userdata)->TimeoutNew(aTimeout, aCallback, aContext);
280*4a64e381SAndroid Build Coastguard Worker }
281*4a64e381SAndroid Build Coastguard Worker 
TimeoutNew(const struct timeval * aTimeout,AvahiTimeoutCallback aCallback,void * aContext)282*4a64e381SAndroid Build Coastguard Worker AvahiTimeout *AvahiPoller::TimeoutNew(const struct timeval *aTimeout, AvahiTimeoutCallback aCallback, void *aContext)
283*4a64e381SAndroid Build Coastguard Worker {
284*4a64e381SAndroid Build Coastguard Worker     mTimers.push_back(new AvahiTimeout(aTimeout, aCallback, aContext, *this));
285*4a64e381SAndroid Build Coastguard Worker     return mTimers.back();
286*4a64e381SAndroid Build Coastguard Worker }
287*4a64e381SAndroid Build Coastguard Worker 
TimeoutUpdate(AvahiTimeout * aTimer,const struct timeval * aTimeout)288*4a64e381SAndroid Build Coastguard Worker void AvahiPoller::TimeoutUpdate(AvahiTimeout *aTimer, const struct timeval *aTimeout)
289*4a64e381SAndroid Build Coastguard Worker {
290*4a64e381SAndroid Build Coastguard Worker     if (aTimeout == nullptr)
291*4a64e381SAndroid Build Coastguard Worker     {
292*4a64e381SAndroid Build Coastguard Worker         aTimer->mTimeout = Timepoint::min();
293*4a64e381SAndroid Build Coastguard Worker     }
294*4a64e381SAndroid Build Coastguard Worker     else
295*4a64e381SAndroid Build Coastguard Worker     {
296*4a64e381SAndroid Build Coastguard Worker         aTimer->mTimeout = Clock::now() + FromTimeval<Microseconds>(*aTimeout);
297*4a64e381SAndroid Build Coastguard Worker     }
298*4a64e381SAndroid Build Coastguard Worker }
299*4a64e381SAndroid Build Coastguard Worker 
TimeoutFree(AvahiTimeout * aTimer)300*4a64e381SAndroid Build Coastguard Worker void AvahiPoller::TimeoutFree(AvahiTimeout *aTimer)
301*4a64e381SAndroid Build Coastguard Worker {
302*4a64e381SAndroid Build Coastguard Worker     aTimer->mPoller.TimeoutFree(*aTimer);
303*4a64e381SAndroid Build Coastguard Worker }
304*4a64e381SAndroid Build Coastguard Worker 
TimeoutFree(AvahiTimeout & aTimer)305*4a64e381SAndroid Build Coastguard Worker void AvahiPoller::TimeoutFree(AvahiTimeout &aTimer)
306*4a64e381SAndroid Build Coastguard Worker {
307*4a64e381SAndroid Build Coastguard Worker     for (Timers::iterator it = mTimers.begin(); it != mTimers.end(); ++it)
308*4a64e381SAndroid Build Coastguard Worker     {
309*4a64e381SAndroid Build Coastguard Worker         if (*it == &aTimer)
310*4a64e381SAndroid Build Coastguard Worker         {
311*4a64e381SAndroid Build Coastguard Worker             mTimers.erase(it);
312*4a64e381SAndroid Build Coastguard Worker             delete &aTimer;
313*4a64e381SAndroid Build Coastguard Worker             break;
314*4a64e381SAndroid Build Coastguard Worker         }
315*4a64e381SAndroid Build Coastguard Worker     }
316*4a64e381SAndroid Build Coastguard Worker }
317*4a64e381SAndroid Build Coastguard Worker 
Update(MainloopContext & aMainloop)318*4a64e381SAndroid Build Coastguard Worker void AvahiPoller::Update(MainloopContext &aMainloop)
319*4a64e381SAndroid Build Coastguard Worker {
320*4a64e381SAndroid Build Coastguard Worker     Timepoint now = Clock::now();
321*4a64e381SAndroid Build Coastguard Worker 
322*4a64e381SAndroid Build Coastguard Worker     for (AvahiWatch *watch : mWatches)
323*4a64e381SAndroid Build Coastguard Worker     {
324*4a64e381SAndroid Build Coastguard Worker         int             fd     = watch->mFd;
325*4a64e381SAndroid Build Coastguard Worker         AvahiWatchEvent events = watch->mEvents;
326*4a64e381SAndroid Build Coastguard Worker 
327*4a64e381SAndroid Build Coastguard Worker         if (AVAHI_WATCH_IN & events)
328*4a64e381SAndroid Build Coastguard Worker         {
329*4a64e381SAndroid Build Coastguard Worker             FD_SET(fd, &aMainloop.mReadFdSet);
330*4a64e381SAndroid Build Coastguard Worker         }
331*4a64e381SAndroid Build Coastguard Worker 
332*4a64e381SAndroid Build Coastguard Worker         if (AVAHI_WATCH_OUT & events)
333*4a64e381SAndroid Build Coastguard Worker         {
334*4a64e381SAndroid Build Coastguard Worker             FD_SET(fd, &aMainloop.mWriteFdSet);
335*4a64e381SAndroid Build Coastguard Worker         }
336*4a64e381SAndroid Build Coastguard Worker 
337*4a64e381SAndroid Build Coastguard Worker         if (AVAHI_WATCH_ERR & events)
338*4a64e381SAndroid Build Coastguard Worker         {
339*4a64e381SAndroid Build Coastguard Worker             FD_SET(fd, &aMainloop.mErrorFdSet);
340*4a64e381SAndroid Build Coastguard Worker         }
341*4a64e381SAndroid Build Coastguard Worker 
342*4a64e381SAndroid Build Coastguard Worker         if (AVAHI_WATCH_HUP & events)
343*4a64e381SAndroid Build Coastguard Worker         {
344*4a64e381SAndroid Build Coastguard Worker             // TODO what do with this event type?
345*4a64e381SAndroid Build Coastguard Worker         }
346*4a64e381SAndroid Build Coastguard Worker 
347*4a64e381SAndroid Build Coastguard Worker         aMainloop.mMaxFd = std::max(aMainloop.mMaxFd, fd);
348*4a64e381SAndroid Build Coastguard Worker 
349*4a64e381SAndroid Build Coastguard Worker         watch->mHappened = 0;
350*4a64e381SAndroid Build Coastguard Worker     }
351*4a64e381SAndroid Build Coastguard Worker 
352*4a64e381SAndroid Build Coastguard Worker     for (AvahiTimeout *timer : mTimers)
353*4a64e381SAndroid Build Coastguard Worker     {
354*4a64e381SAndroid Build Coastguard Worker         Timepoint timeout = timer->mTimeout;
355*4a64e381SAndroid Build Coastguard Worker 
356*4a64e381SAndroid Build Coastguard Worker         if (timeout == Timepoint::min())
357*4a64e381SAndroid Build Coastguard Worker         {
358*4a64e381SAndroid Build Coastguard Worker             continue;
359*4a64e381SAndroid Build Coastguard Worker         }
360*4a64e381SAndroid Build Coastguard Worker 
361*4a64e381SAndroid Build Coastguard Worker         if (timeout <= now)
362*4a64e381SAndroid Build Coastguard Worker         {
363*4a64e381SAndroid Build Coastguard Worker             aMainloop.mTimeout = ToTimeval(Microseconds::zero());
364*4a64e381SAndroid Build Coastguard Worker             break;
365*4a64e381SAndroid Build Coastguard Worker         }
366*4a64e381SAndroid Build Coastguard Worker         else
367*4a64e381SAndroid Build Coastguard Worker         {
368*4a64e381SAndroid Build Coastguard Worker             auto delay = std::chrono::duration_cast<Microseconds>(timeout - now);
369*4a64e381SAndroid Build Coastguard Worker 
370*4a64e381SAndroid Build Coastguard Worker             if (delay < FromTimeval<Microseconds>(aMainloop.mTimeout))
371*4a64e381SAndroid Build Coastguard Worker             {
372*4a64e381SAndroid Build Coastguard Worker                 aMainloop.mTimeout = ToTimeval(delay);
373*4a64e381SAndroid Build Coastguard Worker             }
374*4a64e381SAndroid Build Coastguard Worker         }
375*4a64e381SAndroid Build Coastguard Worker     }
376*4a64e381SAndroid Build Coastguard Worker }
377*4a64e381SAndroid Build Coastguard Worker 
Process(const MainloopContext & aMainloop)378*4a64e381SAndroid Build Coastguard Worker void AvahiPoller::Process(const MainloopContext &aMainloop)
379*4a64e381SAndroid Build Coastguard Worker {
380*4a64e381SAndroid Build Coastguard Worker     Timepoint now          = Clock::now();
381*4a64e381SAndroid Build Coastguard Worker     bool      shouldReport = false;
382*4a64e381SAndroid Build Coastguard Worker 
383*4a64e381SAndroid Build Coastguard Worker     for (AvahiWatch *watch : mWatches)
384*4a64e381SAndroid Build Coastguard Worker     {
385*4a64e381SAndroid Build Coastguard Worker         int             fd     = watch->mFd;
386*4a64e381SAndroid Build Coastguard Worker         AvahiWatchEvent events = watch->mEvents;
387*4a64e381SAndroid Build Coastguard Worker 
388*4a64e381SAndroid Build Coastguard Worker         watch->mHappened = 0;
389*4a64e381SAndroid Build Coastguard Worker 
390*4a64e381SAndroid Build Coastguard Worker         if ((AVAHI_WATCH_IN & events) && FD_ISSET(fd, &aMainloop.mReadFdSet))
391*4a64e381SAndroid Build Coastguard Worker         {
392*4a64e381SAndroid Build Coastguard Worker             watch->mHappened |= AVAHI_WATCH_IN;
393*4a64e381SAndroid Build Coastguard Worker         }
394*4a64e381SAndroid Build Coastguard Worker 
395*4a64e381SAndroid Build Coastguard Worker         if ((AVAHI_WATCH_OUT & events) && FD_ISSET(fd, &aMainloop.mWriteFdSet))
396*4a64e381SAndroid Build Coastguard Worker         {
397*4a64e381SAndroid Build Coastguard Worker             watch->mHappened |= AVAHI_WATCH_OUT;
398*4a64e381SAndroid Build Coastguard Worker         }
399*4a64e381SAndroid Build Coastguard Worker 
400*4a64e381SAndroid Build Coastguard Worker         if ((AVAHI_WATCH_ERR & events) && FD_ISSET(fd, &aMainloop.mErrorFdSet))
401*4a64e381SAndroid Build Coastguard Worker         {
402*4a64e381SAndroid Build Coastguard Worker             watch->mHappened |= AVAHI_WATCH_ERR;
403*4a64e381SAndroid Build Coastguard Worker         }
404*4a64e381SAndroid Build Coastguard Worker 
405*4a64e381SAndroid Build Coastguard Worker         if (watch->mHappened != 0)
406*4a64e381SAndroid Build Coastguard Worker         {
407*4a64e381SAndroid Build Coastguard Worker             watch->mShouldReport = true;
408*4a64e381SAndroid Build Coastguard Worker             shouldReport         = true;
409*4a64e381SAndroid Build Coastguard Worker         }
410*4a64e381SAndroid Build Coastguard Worker     }
411*4a64e381SAndroid Build Coastguard Worker 
412*4a64e381SAndroid Build Coastguard Worker     // When we invoke the callback for an `AvahiWatch` or `AvahiTimeout`,
413*4a64e381SAndroid Build Coastguard Worker     // the Avahi module can call any of `mAvahiPoll` APIs we provided to
414*4a64e381SAndroid Build Coastguard Worker     // it. For example, it can update or free any of `AvahiWatch/Timeout`
415*4a64e381SAndroid Build Coastguard Worker     // entries, which in turn, modifies our `mWatches` or `mTimers` list.
416*4a64e381SAndroid Build Coastguard Worker     // So, before invoking the callback, we update the entry's state and
417*4a64e381SAndroid Build Coastguard Worker     // then restart the iteration over the `mWacthes` list to find the
418*4a64e381SAndroid Build Coastguard Worker     // next entry to report, as the list may have changed.
419*4a64e381SAndroid Build Coastguard Worker 
420*4a64e381SAndroid Build Coastguard Worker     while (shouldReport)
421*4a64e381SAndroid Build Coastguard Worker     {
422*4a64e381SAndroid Build Coastguard Worker         shouldReport = false;
423*4a64e381SAndroid Build Coastguard Worker 
424*4a64e381SAndroid Build Coastguard Worker         for (AvahiWatch *watch : mWatches)
425*4a64e381SAndroid Build Coastguard Worker         {
426*4a64e381SAndroid Build Coastguard Worker             if (watch->mShouldReport)
427*4a64e381SAndroid Build Coastguard Worker             {
428*4a64e381SAndroid Build Coastguard Worker                 shouldReport         = true;
429*4a64e381SAndroid Build Coastguard Worker                 watch->mShouldReport = false;
430*4a64e381SAndroid Build Coastguard Worker                 watch->mCallback(watch, watch->mFd, WatchGetEvents(watch), watch->mContext);
431*4a64e381SAndroid Build Coastguard Worker 
432*4a64e381SAndroid Build Coastguard Worker                 break;
433*4a64e381SAndroid Build Coastguard Worker             }
434*4a64e381SAndroid Build Coastguard Worker         }
435*4a64e381SAndroid Build Coastguard Worker     }
436*4a64e381SAndroid Build Coastguard Worker 
437*4a64e381SAndroid Build Coastguard Worker     for (AvahiTimeout *timer : mTimers)
438*4a64e381SAndroid Build Coastguard Worker     {
439*4a64e381SAndroid Build Coastguard Worker         if (timer->mTimeout == Timepoint::min())
440*4a64e381SAndroid Build Coastguard Worker         {
441*4a64e381SAndroid Build Coastguard Worker             continue;
442*4a64e381SAndroid Build Coastguard Worker         }
443*4a64e381SAndroid Build Coastguard Worker 
444*4a64e381SAndroid Build Coastguard Worker         if (timer->mTimeout <= now)
445*4a64e381SAndroid Build Coastguard Worker         {
446*4a64e381SAndroid Build Coastguard Worker             timer->mShouldReport = true;
447*4a64e381SAndroid Build Coastguard Worker             shouldReport         = true;
448*4a64e381SAndroid Build Coastguard Worker         }
449*4a64e381SAndroid Build Coastguard Worker     }
450*4a64e381SAndroid Build Coastguard Worker 
451*4a64e381SAndroid Build Coastguard Worker     while (shouldReport)
452*4a64e381SAndroid Build Coastguard Worker     {
453*4a64e381SAndroid Build Coastguard Worker         shouldReport = false;
454*4a64e381SAndroid Build Coastguard Worker 
455*4a64e381SAndroid Build Coastguard Worker         for (AvahiTimeout *timer : mTimers)
456*4a64e381SAndroid Build Coastguard Worker         {
457*4a64e381SAndroid Build Coastguard Worker             if (timer->mShouldReport)
458*4a64e381SAndroid Build Coastguard Worker             {
459*4a64e381SAndroid Build Coastguard Worker                 shouldReport         = true;
460*4a64e381SAndroid Build Coastguard Worker                 timer->mShouldReport = false;
461*4a64e381SAndroid Build Coastguard Worker                 timer->mCallback(timer, timer->mContext);
462*4a64e381SAndroid Build Coastguard Worker 
463*4a64e381SAndroid Build Coastguard Worker                 break;
464*4a64e381SAndroid Build Coastguard Worker             }
465*4a64e381SAndroid Build Coastguard Worker         }
466*4a64e381SAndroid Build Coastguard Worker     }
467*4a64e381SAndroid Build Coastguard Worker }
468*4a64e381SAndroid Build Coastguard Worker 
PublisherAvahi(StateCallback aStateCallback)469*4a64e381SAndroid Build Coastguard Worker PublisherAvahi::PublisherAvahi(StateCallback aStateCallback)
470*4a64e381SAndroid Build Coastguard Worker     : mClient(nullptr)
471*4a64e381SAndroid Build Coastguard Worker     , mPoller(MakeUnique<AvahiPoller>())
472*4a64e381SAndroid Build Coastguard Worker     , mState(State::kIdle)
473*4a64e381SAndroid Build Coastguard Worker     , mStateCallback(std::move(aStateCallback))
474*4a64e381SAndroid Build Coastguard Worker {
475*4a64e381SAndroid Build Coastguard Worker }
476*4a64e381SAndroid Build Coastguard Worker 
~PublisherAvahi(void)477*4a64e381SAndroid Build Coastguard Worker PublisherAvahi::~PublisherAvahi(void)
478*4a64e381SAndroid Build Coastguard Worker {
479*4a64e381SAndroid Build Coastguard Worker     Stop();
480*4a64e381SAndroid Build Coastguard Worker }
481*4a64e381SAndroid Build Coastguard Worker 
~AvahiServiceRegistration(void)482*4a64e381SAndroid Build Coastguard Worker PublisherAvahi::AvahiServiceRegistration::~AvahiServiceRegistration(void)
483*4a64e381SAndroid Build Coastguard Worker {
484*4a64e381SAndroid Build Coastguard Worker     ReleaseGroup(mEntryGroup);
485*4a64e381SAndroid Build Coastguard Worker }
486*4a64e381SAndroid Build Coastguard Worker 
~AvahiHostRegistration(void)487*4a64e381SAndroid Build Coastguard Worker PublisherAvahi::AvahiHostRegistration::~AvahiHostRegistration(void)
488*4a64e381SAndroid Build Coastguard Worker {
489*4a64e381SAndroid Build Coastguard Worker     ReleaseGroup(mEntryGroup);
490*4a64e381SAndroid Build Coastguard Worker }
491*4a64e381SAndroid Build Coastguard Worker 
~AvahiKeyRegistration(void)492*4a64e381SAndroid Build Coastguard Worker PublisherAvahi::AvahiKeyRegistration::~AvahiKeyRegistration(void)
493*4a64e381SAndroid Build Coastguard Worker {
494*4a64e381SAndroid Build Coastguard Worker     ReleaseGroup(mEntryGroup);
495*4a64e381SAndroid Build Coastguard Worker }
496*4a64e381SAndroid Build Coastguard Worker 
Start(void)497*4a64e381SAndroid Build Coastguard Worker otbrError PublisherAvahi::Start(void)
498*4a64e381SAndroid Build Coastguard Worker {
499*4a64e381SAndroid Build Coastguard Worker     otbrError error      = OTBR_ERROR_NONE;
500*4a64e381SAndroid Build Coastguard Worker     int       avahiError = AVAHI_OK;
501*4a64e381SAndroid Build Coastguard Worker 
502*4a64e381SAndroid Build Coastguard Worker     assert(mClient == nullptr);
503*4a64e381SAndroid Build Coastguard Worker 
504*4a64e381SAndroid Build Coastguard Worker     mClient = avahi_client_new(mPoller->GetAvahiPoll(), AVAHI_CLIENT_NO_FAIL, HandleClientState, this, &avahiError);
505*4a64e381SAndroid Build Coastguard Worker 
506*4a64e381SAndroid Build Coastguard Worker     if (avahiError != AVAHI_OK)
507*4a64e381SAndroid Build Coastguard Worker     {
508*4a64e381SAndroid Build Coastguard Worker         otbrLogErr("Failed to create avahi client: %s!", avahi_strerror(avahiError));
509*4a64e381SAndroid Build Coastguard Worker         error = OTBR_ERROR_MDNS;
510*4a64e381SAndroid Build Coastguard Worker     }
511*4a64e381SAndroid Build Coastguard Worker 
512*4a64e381SAndroid Build Coastguard Worker     return error;
513*4a64e381SAndroid Build Coastguard Worker }
514*4a64e381SAndroid Build Coastguard Worker 
IsStarted(void) const515*4a64e381SAndroid Build Coastguard Worker bool PublisherAvahi::IsStarted(void) const
516*4a64e381SAndroid Build Coastguard Worker {
517*4a64e381SAndroid Build Coastguard Worker     return mClient != nullptr;
518*4a64e381SAndroid Build Coastguard Worker }
519*4a64e381SAndroid Build Coastguard Worker 
Stop(void)520*4a64e381SAndroid Build Coastguard Worker void PublisherAvahi::Stop(void)
521*4a64e381SAndroid Build Coastguard Worker {
522*4a64e381SAndroid Build Coastguard Worker     mServiceRegistrations.clear();
523*4a64e381SAndroid Build Coastguard Worker     mHostRegistrations.clear();
524*4a64e381SAndroid Build Coastguard Worker 
525*4a64e381SAndroid Build Coastguard Worker     mSubscribedServices.clear();
526*4a64e381SAndroid Build Coastguard Worker     mSubscribedHosts.clear();
527*4a64e381SAndroid Build Coastguard Worker 
528*4a64e381SAndroid Build Coastguard Worker     if (mClient)
529*4a64e381SAndroid Build Coastguard Worker     {
530*4a64e381SAndroid Build Coastguard Worker         avahi_client_free(mClient);
531*4a64e381SAndroid Build Coastguard Worker         mClient = nullptr;
532*4a64e381SAndroid Build Coastguard Worker     }
533*4a64e381SAndroid Build Coastguard Worker 
534*4a64e381SAndroid Build Coastguard Worker     mState = Mdns::Publisher::State::kIdle;
535*4a64e381SAndroid Build Coastguard Worker }
536*4a64e381SAndroid Build Coastguard Worker 
HandleClientState(AvahiClient * aClient,AvahiClientState aState,void * aContext)537*4a64e381SAndroid Build Coastguard Worker void PublisherAvahi::HandleClientState(AvahiClient *aClient, AvahiClientState aState, void *aContext)
538*4a64e381SAndroid Build Coastguard Worker {
539*4a64e381SAndroid Build Coastguard Worker     static_cast<PublisherAvahi *>(aContext)->HandleClientState(aClient, aState);
540*4a64e381SAndroid Build Coastguard Worker }
541*4a64e381SAndroid Build Coastguard Worker 
HandleGroupState(AvahiEntryGroup * aGroup,AvahiEntryGroupState aState,void * aContext)542*4a64e381SAndroid Build Coastguard Worker void PublisherAvahi::HandleGroupState(AvahiEntryGroup *aGroup, AvahiEntryGroupState aState, void *aContext)
543*4a64e381SAndroid Build Coastguard Worker {
544*4a64e381SAndroid Build Coastguard Worker     static_cast<PublisherAvahi *>(aContext)->HandleGroupState(aGroup, aState);
545*4a64e381SAndroid Build Coastguard Worker }
546*4a64e381SAndroid Build Coastguard Worker 
HandleGroupState(AvahiEntryGroup * aGroup,AvahiEntryGroupState aState)547*4a64e381SAndroid Build Coastguard Worker void PublisherAvahi::HandleGroupState(AvahiEntryGroup *aGroup, AvahiEntryGroupState aState)
548*4a64e381SAndroid Build Coastguard Worker {
549*4a64e381SAndroid Build Coastguard Worker     switch (aState)
550*4a64e381SAndroid Build Coastguard Worker     {
551*4a64e381SAndroid Build Coastguard Worker     case AVAHI_ENTRY_GROUP_ESTABLISHED:
552*4a64e381SAndroid Build Coastguard Worker         otbrLogInfo("Avahi group (@%p) is established", aGroup);
553*4a64e381SAndroid Build Coastguard Worker         CallHostOrServiceCallback(aGroup, OTBR_ERROR_NONE);
554*4a64e381SAndroid Build Coastguard Worker         break;
555*4a64e381SAndroid Build Coastguard Worker 
556*4a64e381SAndroid Build Coastguard Worker     case AVAHI_ENTRY_GROUP_COLLISION:
557*4a64e381SAndroid Build Coastguard Worker         otbrLogInfo("Avahi group (@%p) name conflicted", aGroup);
558*4a64e381SAndroid Build Coastguard Worker         CallHostOrServiceCallback(aGroup, OTBR_ERROR_DUPLICATED);
559*4a64e381SAndroid Build Coastguard Worker         break;
560*4a64e381SAndroid Build Coastguard Worker 
561*4a64e381SAndroid Build Coastguard Worker     case AVAHI_ENTRY_GROUP_FAILURE:
562*4a64e381SAndroid Build Coastguard Worker         otbrLogErr("Avahi group (@%p) failed: %s!", aGroup,
563*4a64e381SAndroid Build Coastguard Worker                    avahi_strerror(avahi_client_errno(avahi_entry_group_get_client(aGroup))));
564*4a64e381SAndroid Build Coastguard Worker         CallHostOrServiceCallback(aGroup, OTBR_ERROR_MDNS);
565*4a64e381SAndroid Build Coastguard Worker         break;
566*4a64e381SAndroid Build Coastguard Worker 
567*4a64e381SAndroid Build Coastguard Worker     case AVAHI_ENTRY_GROUP_UNCOMMITED:
568*4a64e381SAndroid Build Coastguard Worker     case AVAHI_ENTRY_GROUP_REGISTERING:
569*4a64e381SAndroid Build Coastguard Worker         break;
570*4a64e381SAndroid Build Coastguard Worker     }
571*4a64e381SAndroid Build Coastguard Worker }
572*4a64e381SAndroid Build Coastguard Worker 
CallHostOrServiceCallback(AvahiEntryGroup * aGroup,otbrError aError)573*4a64e381SAndroid Build Coastguard Worker void PublisherAvahi::CallHostOrServiceCallback(AvahiEntryGroup *aGroup, otbrError aError)
574*4a64e381SAndroid Build Coastguard Worker {
575*4a64e381SAndroid Build Coastguard Worker     ServiceRegistration *serviceReg;
576*4a64e381SAndroid Build Coastguard Worker     HostRegistration    *hostReg;
577*4a64e381SAndroid Build Coastguard Worker     KeyRegistration     *keyReg;
578*4a64e381SAndroid Build Coastguard Worker 
579*4a64e381SAndroid Build Coastguard Worker     if ((serviceReg = FindServiceRegistration(aGroup)) != nullptr)
580*4a64e381SAndroid Build Coastguard Worker     {
581*4a64e381SAndroid Build Coastguard Worker         if (aError == OTBR_ERROR_NONE)
582*4a64e381SAndroid Build Coastguard Worker         {
583*4a64e381SAndroid Build Coastguard Worker             serviceReg->Complete(aError);
584*4a64e381SAndroid Build Coastguard Worker         }
585*4a64e381SAndroid Build Coastguard Worker         else
586*4a64e381SAndroid Build Coastguard Worker         {
587*4a64e381SAndroid Build Coastguard Worker             RemoveServiceRegistration(serviceReg->mName, serviceReg->mType, aError);
588*4a64e381SAndroid Build Coastguard Worker         }
589*4a64e381SAndroid Build Coastguard Worker     }
590*4a64e381SAndroid Build Coastguard Worker     else if ((hostReg = FindHostRegistration(aGroup)) != nullptr)
591*4a64e381SAndroid Build Coastguard Worker     {
592*4a64e381SAndroid Build Coastguard Worker         if (aError == OTBR_ERROR_NONE)
593*4a64e381SAndroid Build Coastguard Worker         {
594*4a64e381SAndroid Build Coastguard Worker             hostReg->Complete(aError);
595*4a64e381SAndroid Build Coastguard Worker         }
596*4a64e381SAndroid Build Coastguard Worker         else
597*4a64e381SAndroid Build Coastguard Worker         {
598*4a64e381SAndroid Build Coastguard Worker             RemoveHostRegistration(hostReg->mName, aError);
599*4a64e381SAndroid Build Coastguard Worker         }
600*4a64e381SAndroid Build Coastguard Worker     }
601*4a64e381SAndroid Build Coastguard Worker     else if ((keyReg = FindKeyRegistration(aGroup)) != nullptr)
602*4a64e381SAndroid Build Coastguard Worker     {
603*4a64e381SAndroid Build Coastguard Worker         if (aError == OTBR_ERROR_NONE)
604*4a64e381SAndroid Build Coastguard Worker         {
605*4a64e381SAndroid Build Coastguard Worker             keyReg->Complete(aError);
606*4a64e381SAndroid Build Coastguard Worker         }
607*4a64e381SAndroid Build Coastguard Worker         else
608*4a64e381SAndroid Build Coastguard Worker         {
609*4a64e381SAndroid Build Coastguard Worker             RemoveKeyRegistration(keyReg->mName, aError);
610*4a64e381SAndroid Build Coastguard Worker         }
611*4a64e381SAndroid Build Coastguard Worker     }
612*4a64e381SAndroid Build Coastguard Worker     else
613*4a64e381SAndroid Build Coastguard Worker     {
614*4a64e381SAndroid Build Coastguard Worker         otbrLogWarning("No registered service or host matches avahi group @%p", aGroup);
615*4a64e381SAndroid Build Coastguard Worker     }
616*4a64e381SAndroid Build Coastguard Worker }
617*4a64e381SAndroid Build Coastguard Worker 
CreateGroup(AvahiClient * aClient)618*4a64e381SAndroid Build Coastguard Worker AvahiEntryGroup *PublisherAvahi::CreateGroup(AvahiClient *aClient)
619*4a64e381SAndroid Build Coastguard Worker {
620*4a64e381SAndroid Build Coastguard Worker     AvahiEntryGroup *group = avahi_entry_group_new(aClient, HandleGroupState, this);
621*4a64e381SAndroid Build Coastguard Worker 
622*4a64e381SAndroid Build Coastguard Worker     if (group == nullptr)
623*4a64e381SAndroid Build Coastguard Worker     {
624*4a64e381SAndroid Build Coastguard Worker         otbrLogErr("Failed to create entry avahi group: %s", avahi_strerror(avahi_client_errno(aClient)));
625*4a64e381SAndroid Build Coastguard Worker     }
626*4a64e381SAndroid Build Coastguard Worker 
627*4a64e381SAndroid Build Coastguard Worker     return group;
628*4a64e381SAndroid Build Coastguard Worker }
629*4a64e381SAndroid Build Coastguard Worker 
ReleaseGroup(AvahiEntryGroup * aGroup)630*4a64e381SAndroid Build Coastguard Worker void PublisherAvahi::ReleaseGroup(AvahiEntryGroup *aGroup)
631*4a64e381SAndroid Build Coastguard Worker {
632*4a64e381SAndroid Build Coastguard Worker     int error;
633*4a64e381SAndroid Build Coastguard Worker 
634*4a64e381SAndroid Build Coastguard Worker     otbrLogInfo("Releasing avahi entry group @%p", aGroup);
635*4a64e381SAndroid Build Coastguard Worker 
636*4a64e381SAndroid Build Coastguard Worker     error = avahi_entry_group_reset(aGroup);
637*4a64e381SAndroid Build Coastguard Worker 
638*4a64e381SAndroid Build Coastguard Worker     if (error != 0)
639*4a64e381SAndroid Build Coastguard Worker     {
640*4a64e381SAndroid Build Coastguard Worker         otbrLogErr("Failed to reset entry group for avahi error: %s", avahi_strerror(error));
641*4a64e381SAndroid Build Coastguard Worker     }
642*4a64e381SAndroid Build Coastguard Worker 
643*4a64e381SAndroid Build Coastguard Worker     error = avahi_entry_group_free(aGroup);
644*4a64e381SAndroid Build Coastguard Worker     if (error != 0)
645*4a64e381SAndroid Build Coastguard Worker     {
646*4a64e381SAndroid Build Coastguard Worker         otbrLogErr("Failed to free entry group for avahi error: %s", avahi_strerror(error));
647*4a64e381SAndroid Build Coastguard Worker     }
648*4a64e381SAndroid Build Coastguard Worker }
649*4a64e381SAndroid Build Coastguard Worker 
HandleClientState(AvahiClient * aClient,AvahiClientState aState)650*4a64e381SAndroid Build Coastguard Worker void PublisherAvahi::HandleClientState(AvahiClient *aClient, AvahiClientState aState)
651*4a64e381SAndroid Build Coastguard Worker {
652*4a64e381SAndroid Build Coastguard Worker     otbrLogInfo("Avahi client state changed to %d", aState);
653*4a64e381SAndroid Build Coastguard Worker 
654*4a64e381SAndroid Build Coastguard Worker     switch (aState)
655*4a64e381SAndroid Build Coastguard Worker     {
656*4a64e381SAndroid Build Coastguard Worker     case AVAHI_CLIENT_S_RUNNING:
657*4a64e381SAndroid Build Coastguard Worker         // The server has startup successfully and registered its host
658*4a64e381SAndroid Build Coastguard Worker         // name on the network, so it's time to create our services.
659*4a64e381SAndroid Build Coastguard Worker         otbrLogInfo("Avahi client is ready");
660*4a64e381SAndroid Build Coastguard Worker         mClient = aClient;
661*4a64e381SAndroid Build Coastguard Worker         mState  = State::kReady;
662*4a64e381SAndroid Build Coastguard Worker         mStateCallback(mState);
663*4a64e381SAndroid Build Coastguard Worker         break;
664*4a64e381SAndroid Build Coastguard Worker 
665*4a64e381SAndroid Build Coastguard Worker     case AVAHI_CLIENT_FAILURE:
666*4a64e381SAndroid Build Coastguard Worker         otbrLogErr("Avahi client failed to start: %s", avahi_strerror(avahi_client_errno(aClient)));
667*4a64e381SAndroid Build Coastguard Worker         mState = State::kIdle;
668*4a64e381SAndroid Build Coastguard Worker         mStateCallback(mState);
669*4a64e381SAndroid Build Coastguard Worker         Stop();
670*4a64e381SAndroid Build Coastguard Worker         Start();
671*4a64e381SAndroid Build Coastguard Worker         break;
672*4a64e381SAndroid Build Coastguard Worker 
673*4a64e381SAndroid Build Coastguard Worker     case AVAHI_CLIENT_S_COLLISION:
674*4a64e381SAndroid Build Coastguard Worker         // Let's drop our registered services. When the server is back
675*4a64e381SAndroid Build Coastguard Worker         // in AVAHI_SERVER_RUNNING state we will register them again
676*4a64e381SAndroid Build Coastguard Worker         // with the new host name.
677*4a64e381SAndroid Build Coastguard Worker         otbrLogErr("Avahi client collision detected: %s", avahi_strerror(avahi_client_errno(aClient)));
678*4a64e381SAndroid Build Coastguard Worker 
679*4a64e381SAndroid Build Coastguard Worker         // fall through
680*4a64e381SAndroid Build Coastguard Worker 
681*4a64e381SAndroid Build Coastguard Worker     case AVAHI_CLIENT_S_REGISTERING:
682*4a64e381SAndroid Build Coastguard Worker         // The server records are now being established. This might be
683*4a64e381SAndroid Build Coastguard Worker         // caused by a host name change. We need to wait for our own
684*4a64e381SAndroid Build Coastguard Worker         // records to register until the host name is properly established.
685*4a64e381SAndroid Build Coastguard Worker         mServiceRegistrations.clear();
686*4a64e381SAndroid Build Coastguard Worker         mHostRegistrations.clear();
687*4a64e381SAndroid Build Coastguard Worker         break;
688*4a64e381SAndroid Build Coastguard Worker 
689*4a64e381SAndroid Build Coastguard Worker     case AVAHI_CLIENT_CONNECTING:
690*4a64e381SAndroid Build Coastguard Worker         otbrLogInfo("Avahi client is connecting to the server");
691*4a64e381SAndroid Build Coastguard Worker         break;
692*4a64e381SAndroid Build Coastguard Worker     }
693*4a64e381SAndroid Build Coastguard Worker }
694*4a64e381SAndroid Build Coastguard Worker 
PublishServiceImpl(const std::string & aHostName,const std::string & aName,const std::string & aType,const SubTypeList & aSubTypeList,uint16_t aPort,const TxtData & aTxtData,ResultCallback && aCallback)695*4a64e381SAndroid Build Coastguard Worker otbrError PublisherAvahi::PublishServiceImpl(const std::string &aHostName,
696*4a64e381SAndroid Build Coastguard Worker                                              const std::string &aName,
697*4a64e381SAndroid Build Coastguard Worker                                              const std::string &aType,
698*4a64e381SAndroid Build Coastguard Worker                                              const SubTypeList &aSubTypeList,
699*4a64e381SAndroid Build Coastguard Worker                                              uint16_t           aPort,
700*4a64e381SAndroid Build Coastguard Worker                                              const TxtData     &aTxtData,
701*4a64e381SAndroid Build Coastguard Worker                                              ResultCallback   &&aCallback)
702*4a64e381SAndroid Build Coastguard Worker {
703*4a64e381SAndroid Build Coastguard Worker     otbrError         error             = OTBR_ERROR_NONE;
704*4a64e381SAndroid Build Coastguard Worker     int               avahiError        = AVAHI_OK;
705*4a64e381SAndroid Build Coastguard Worker     SubTypeList       sortedSubTypeList = SortSubTypeList(aSubTypeList);
706*4a64e381SAndroid Build Coastguard Worker     const std::string logHostName       = !aHostName.empty() ? aHostName : "localhost";
707*4a64e381SAndroid Build Coastguard Worker     std::string       fullHostName;
708*4a64e381SAndroid Build Coastguard Worker     std::string       serviceName = aName;
709*4a64e381SAndroid Build Coastguard Worker     AvahiEntryGroup  *group       = nullptr;
710*4a64e381SAndroid Build Coastguard Worker 
711*4a64e381SAndroid Build Coastguard Worker     // Aligned with AvahiStringList
712*4a64e381SAndroid Build Coastguard Worker     AvahiStringList  txtBuffer[(kMaxSizeOfTxtRecord - 1) / sizeof(AvahiStringList) + 1];
713*4a64e381SAndroid Build Coastguard Worker     AvahiStringList *txtHead = nullptr;
714*4a64e381SAndroid Build Coastguard Worker 
715*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(mState == State::kReady, error = OTBR_ERROR_INVALID_STATE);
716*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(mClient != nullptr, error = OTBR_ERROR_INVALID_STATE);
717*4a64e381SAndroid Build Coastguard Worker 
718*4a64e381SAndroid Build Coastguard Worker     if (!aHostName.empty())
719*4a64e381SAndroid Build Coastguard Worker     {
720*4a64e381SAndroid Build Coastguard Worker         fullHostName = MakeFullHostName(aHostName);
721*4a64e381SAndroid Build Coastguard Worker     }
722*4a64e381SAndroid Build Coastguard Worker     if (serviceName.empty())
723*4a64e381SAndroid Build Coastguard Worker     {
724*4a64e381SAndroid Build Coastguard Worker         serviceName = avahi_client_get_host_name(mClient);
725*4a64e381SAndroid Build Coastguard Worker     }
726*4a64e381SAndroid Build Coastguard Worker 
727*4a64e381SAndroid Build Coastguard Worker     aCallback = HandleDuplicateServiceRegistration(aHostName, serviceName, aType, sortedSubTypeList, aPort, aTxtData,
728*4a64e381SAndroid Build Coastguard Worker                                                    std::move(aCallback));
729*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(!aCallback.IsNull());
730*4a64e381SAndroid Build Coastguard Worker 
731*4a64e381SAndroid Build Coastguard Worker     SuccessOrExit(error = TxtDataToAvahiStringList(aTxtData, txtBuffer, sizeof(txtBuffer), txtHead));
732*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit((group = CreateGroup(mClient)) != nullptr, error = OTBR_ERROR_MDNS);
733*4a64e381SAndroid Build Coastguard Worker     avahiError = avahi_entry_group_add_service_strlst(group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, AvahiPublishFlags{},
734*4a64e381SAndroid Build Coastguard Worker                                                       serviceName.c_str(), aType.c_str(),
735*4a64e381SAndroid Build Coastguard Worker                                                       /* domain */ nullptr, fullHostName.c_str(), aPort, txtHead);
736*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(avahiError == AVAHI_OK);
737*4a64e381SAndroid Build Coastguard Worker 
738*4a64e381SAndroid Build Coastguard Worker     for (const std::string &subType : aSubTypeList)
739*4a64e381SAndroid Build Coastguard Worker     {
740*4a64e381SAndroid Build Coastguard Worker         otbrLogInfo("Add subtype %s for service %s.%s", subType.c_str(), serviceName.c_str(), aType.c_str());
741*4a64e381SAndroid Build Coastguard Worker         std::string fullSubType = subType + "._sub." + aType;
742*4a64e381SAndroid Build Coastguard Worker         avahiError              = avahi_entry_group_add_service_subtype(group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC,
743*4a64e381SAndroid Build Coastguard Worker                                                                         AvahiPublishFlags{}, serviceName.c_str(), aType.c_str(),
744*4a64e381SAndroid Build Coastguard Worker                                                                         /* domain */ nullptr, fullSubType.c_str());
745*4a64e381SAndroid Build Coastguard Worker         VerifyOrExit(avahiError == AVAHI_OK);
746*4a64e381SAndroid Build Coastguard Worker     }
747*4a64e381SAndroid Build Coastguard Worker 
748*4a64e381SAndroid Build Coastguard Worker     otbrLogInfo("Commit avahi service %s.%s", serviceName.c_str(), aType.c_str());
749*4a64e381SAndroid Build Coastguard Worker     avahiError = avahi_entry_group_commit(group);
750*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(avahiError == AVAHI_OK);
751*4a64e381SAndroid Build Coastguard Worker 
752*4a64e381SAndroid Build Coastguard Worker     AddServiceRegistration(std::unique_ptr<AvahiServiceRegistration>(new AvahiServiceRegistration(
753*4a64e381SAndroid Build Coastguard Worker         aHostName, serviceName, aType, sortedSubTypeList, aPort, aTxtData, std::move(aCallback), group, this)));
754*4a64e381SAndroid Build Coastguard Worker 
755*4a64e381SAndroid Build Coastguard Worker exit:
756*4a64e381SAndroid Build Coastguard Worker     if (avahiError != AVAHI_OK || error != OTBR_ERROR_NONE)
757*4a64e381SAndroid Build Coastguard Worker     {
758*4a64e381SAndroid Build Coastguard Worker         if (avahiError != AVAHI_OK)
759*4a64e381SAndroid Build Coastguard Worker         {
760*4a64e381SAndroid Build Coastguard Worker             error = OTBR_ERROR_MDNS;
761*4a64e381SAndroid Build Coastguard Worker             otbrLogErr("Failed to publish service for avahi error: %s!", avahi_strerror(avahiError));
762*4a64e381SAndroid Build Coastguard Worker         }
763*4a64e381SAndroid Build Coastguard Worker 
764*4a64e381SAndroid Build Coastguard Worker         if (group != nullptr)
765*4a64e381SAndroid Build Coastguard Worker         {
766*4a64e381SAndroid Build Coastguard Worker             ReleaseGroup(group);
767*4a64e381SAndroid Build Coastguard Worker         }
768*4a64e381SAndroid Build Coastguard Worker         std::move(aCallback)(error);
769*4a64e381SAndroid Build Coastguard Worker     }
770*4a64e381SAndroid Build Coastguard Worker     return error;
771*4a64e381SAndroid Build Coastguard Worker }
772*4a64e381SAndroid Build Coastguard Worker 
UnpublishService(const std::string & aName,const std::string & aType,ResultCallback && aCallback)773*4a64e381SAndroid Build Coastguard Worker void PublisherAvahi::UnpublishService(const std::string &aName, const std::string &aType, ResultCallback &&aCallback)
774*4a64e381SAndroid Build Coastguard Worker {
775*4a64e381SAndroid Build Coastguard Worker     otbrError error = OTBR_ERROR_NONE;
776*4a64e381SAndroid Build Coastguard Worker 
777*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(mState == Publisher::State::kReady, error = OTBR_ERROR_INVALID_STATE);
778*4a64e381SAndroid Build Coastguard Worker     RemoveServiceRegistration(aName, aType, OTBR_ERROR_ABORTED);
779*4a64e381SAndroid Build Coastguard Worker 
780*4a64e381SAndroid Build Coastguard Worker exit:
781*4a64e381SAndroid Build Coastguard Worker     std::move(aCallback)(error);
782*4a64e381SAndroid Build Coastguard Worker }
783*4a64e381SAndroid Build Coastguard Worker 
PublishHostImpl(const std::string & aName,const AddressList & aAddresses,ResultCallback && aCallback)784*4a64e381SAndroid Build Coastguard Worker otbrError PublisherAvahi::PublishHostImpl(const std::string &aName,
785*4a64e381SAndroid Build Coastguard Worker                                           const AddressList &aAddresses,
786*4a64e381SAndroid Build Coastguard Worker                                           ResultCallback   &&aCallback)
787*4a64e381SAndroid Build Coastguard Worker {
788*4a64e381SAndroid Build Coastguard Worker     otbrError        error      = OTBR_ERROR_NONE;
789*4a64e381SAndroid Build Coastguard Worker     int              avahiError = AVAHI_OK;
790*4a64e381SAndroid Build Coastguard Worker     std::string      fullHostName;
791*4a64e381SAndroid Build Coastguard Worker     AvahiEntryGroup *group = nullptr;
792*4a64e381SAndroid Build Coastguard Worker 
793*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(mState == State::kReady, error = OTBR_ERROR_INVALID_STATE);
794*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(mClient != nullptr, error = OTBR_ERROR_INVALID_STATE);
795*4a64e381SAndroid Build Coastguard Worker 
796*4a64e381SAndroid Build Coastguard Worker     aCallback = HandleDuplicateHostRegistration(aName, aAddresses, std::move(aCallback));
797*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(!aCallback.IsNull());
798*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(!aAddresses.empty(), std::move(aCallback)(OTBR_ERROR_NONE));
799*4a64e381SAndroid Build Coastguard Worker 
800*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit((group = CreateGroup(mClient)) != nullptr, error = OTBR_ERROR_MDNS);
801*4a64e381SAndroid Build Coastguard Worker 
802*4a64e381SAndroid Build Coastguard Worker     fullHostName = MakeFullHostName(aName);
803*4a64e381SAndroid Build Coastguard Worker     for (const auto &address : aAddresses)
804*4a64e381SAndroid Build Coastguard Worker     {
805*4a64e381SAndroid Build Coastguard Worker         AvahiAddress avahiAddress;
806*4a64e381SAndroid Build Coastguard Worker 
807*4a64e381SAndroid Build Coastguard Worker         avahiAddress.proto = AVAHI_PROTO_INET6;
808*4a64e381SAndroid Build Coastguard Worker         memcpy(avahiAddress.data.ipv6.address, address.m8, sizeof(address.m8));
809*4a64e381SAndroid Build Coastguard Worker         avahiError = avahi_entry_group_add_address(group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, AVAHI_PUBLISH_NO_REVERSE,
810*4a64e381SAndroid Build Coastguard Worker                                                    fullHostName.c_str(), &avahiAddress);
811*4a64e381SAndroid Build Coastguard Worker         VerifyOrExit(avahiError == AVAHI_OK);
812*4a64e381SAndroid Build Coastguard Worker     }
813*4a64e381SAndroid Build Coastguard Worker 
814*4a64e381SAndroid Build Coastguard Worker     otbrLogInfo("Commit avahi host %s", aName.c_str());
815*4a64e381SAndroid Build Coastguard Worker     avahiError = avahi_entry_group_commit(group);
816*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(avahiError == AVAHI_OK);
817*4a64e381SAndroid Build Coastguard Worker 
818*4a64e381SAndroid Build Coastguard Worker     AddHostRegistration(std::unique_ptr<AvahiHostRegistration>(
819*4a64e381SAndroid Build Coastguard Worker         new AvahiHostRegistration(aName, aAddresses, std::move(aCallback), group, this)));
820*4a64e381SAndroid Build Coastguard Worker 
821*4a64e381SAndroid Build Coastguard Worker exit:
822*4a64e381SAndroid Build Coastguard Worker     if (avahiError != AVAHI_OK || error != OTBR_ERROR_NONE)
823*4a64e381SAndroid Build Coastguard Worker     {
824*4a64e381SAndroid Build Coastguard Worker         if (avahiError != AVAHI_OK)
825*4a64e381SAndroid Build Coastguard Worker         {
826*4a64e381SAndroid Build Coastguard Worker             error = OTBR_ERROR_MDNS;
827*4a64e381SAndroid Build Coastguard Worker             otbrLogErr("Failed to publish host for avahi error: %s!", avahi_strerror(avahiError));
828*4a64e381SAndroid Build Coastguard Worker         }
829*4a64e381SAndroid Build Coastguard Worker 
830*4a64e381SAndroid Build Coastguard Worker         if (group != nullptr)
831*4a64e381SAndroid Build Coastguard Worker         {
832*4a64e381SAndroid Build Coastguard Worker             ReleaseGroup(group);
833*4a64e381SAndroid Build Coastguard Worker         }
834*4a64e381SAndroid Build Coastguard Worker         std::move(aCallback)(error);
835*4a64e381SAndroid Build Coastguard Worker     }
836*4a64e381SAndroid Build Coastguard Worker     return error;
837*4a64e381SAndroid Build Coastguard Worker }
838*4a64e381SAndroid Build Coastguard Worker 
UnpublishHost(const std::string & aName,ResultCallback && aCallback)839*4a64e381SAndroid Build Coastguard Worker void PublisherAvahi::UnpublishHost(const std::string &aName, ResultCallback &&aCallback)
840*4a64e381SAndroid Build Coastguard Worker {
841*4a64e381SAndroid Build Coastguard Worker     otbrError error = OTBR_ERROR_NONE;
842*4a64e381SAndroid Build Coastguard Worker 
843*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(mState == Publisher::State::kReady, error = OTBR_ERROR_INVALID_STATE);
844*4a64e381SAndroid Build Coastguard Worker     RemoveHostRegistration(aName, OTBR_ERROR_ABORTED);
845*4a64e381SAndroid Build Coastguard Worker 
846*4a64e381SAndroid Build Coastguard Worker exit:
847*4a64e381SAndroid Build Coastguard Worker     std::move(aCallback)(error);
848*4a64e381SAndroid Build Coastguard Worker }
849*4a64e381SAndroid Build Coastguard Worker 
PublishKeyImpl(const std::string & aName,const KeyData & aKeyData,ResultCallback && aCallback)850*4a64e381SAndroid Build Coastguard Worker otbrError PublisherAvahi::PublishKeyImpl(const std::string &aName, const KeyData &aKeyData, ResultCallback &&aCallback)
851*4a64e381SAndroid Build Coastguard Worker {
852*4a64e381SAndroid Build Coastguard Worker     otbrError        error      = OTBR_ERROR_NONE;
853*4a64e381SAndroid Build Coastguard Worker     int              avahiError = AVAHI_OK;
854*4a64e381SAndroid Build Coastguard Worker     std::string      fullKeyName;
855*4a64e381SAndroid Build Coastguard Worker     AvahiEntryGroup *group = nullptr;
856*4a64e381SAndroid Build Coastguard Worker 
857*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(mState == State::kReady, error = OTBR_ERROR_INVALID_STATE);
858*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(mClient != nullptr, error = OTBR_ERROR_INVALID_STATE);
859*4a64e381SAndroid Build Coastguard Worker 
860*4a64e381SAndroid Build Coastguard Worker     aCallback = HandleDuplicateKeyRegistration(aName, aKeyData, std::move(aCallback));
861*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(!aCallback.IsNull());
862*4a64e381SAndroid Build Coastguard Worker 
863*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit((group = CreateGroup(mClient)) != nullptr, error = OTBR_ERROR_MDNS);
864*4a64e381SAndroid Build Coastguard Worker 
865*4a64e381SAndroid Build Coastguard Worker     fullKeyName = MakeFullKeyName(aName);
866*4a64e381SAndroid Build Coastguard Worker 
867*4a64e381SAndroid Build Coastguard Worker     avahiError = avahi_entry_group_add_record(group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, AVAHI_PUBLISH_UNIQUE,
868*4a64e381SAndroid Build Coastguard Worker                                               fullKeyName.c_str(), AVAHI_DNS_CLASS_IN, kDnsKeyRecordType, kDefaultTtl,
869*4a64e381SAndroid Build Coastguard Worker                                               aKeyData.data(), aKeyData.size());
870*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(avahiError == AVAHI_OK);
871*4a64e381SAndroid Build Coastguard Worker 
872*4a64e381SAndroid Build Coastguard Worker     otbrLogInfo("Commit avahi key record for %s", aName.c_str());
873*4a64e381SAndroid Build Coastguard Worker     avahiError = avahi_entry_group_commit(group);
874*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(avahiError == AVAHI_OK);
875*4a64e381SAndroid Build Coastguard Worker 
876*4a64e381SAndroid Build Coastguard Worker     AddKeyRegistration(std::unique_ptr<AvahiKeyRegistration>(
877*4a64e381SAndroid Build Coastguard Worker         new AvahiKeyRegistration(aName, aKeyData, std::move(aCallback), group, this)));
878*4a64e381SAndroid Build Coastguard Worker 
879*4a64e381SAndroid Build Coastguard Worker exit:
880*4a64e381SAndroid Build Coastguard Worker     if (avahiError != AVAHI_OK || error != OTBR_ERROR_NONE)
881*4a64e381SAndroid Build Coastguard Worker     {
882*4a64e381SAndroid Build Coastguard Worker         if (avahiError != AVAHI_OK)
883*4a64e381SAndroid Build Coastguard Worker         {
884*4a64e381SAndroid Build Coastguard Worker             error = OTBR_ERROR_MDNS;
885*4a64e381SAndroid Build Coastguard Worker             otbrLogErr("Failed to publish key record - avahi error: %s!", avahi_strerror(avahiError));
886*4a64e381SAndroid Build Coastguard Worker         }
887*4a64e381SAndroid Build Coastguard Worker 
888*4a64e381SAndroid Build Coastguard Worker         if (group != nullptr)
889*4a64e381SAndroid Build Coastguard Worker         {
890*4a64e381SAndroid Build Coastguard Worker             ReleaseGroup(group);
891*4a64e381SAndroid Build Coastguard Worker         }
892*4a64e381SAndroid Build Coastguard Worker         std::move(aCallback)(error);
893*4a64e381SAndroid Build Coastguard Worker     }
894*4a64e381SAndroid Build Coastguard Worker     return error;
895*4a64e381SAndroid Build Coastguard Worker }
896*4a64e381SAndroid Build Coastguard Worker 
UnpublishKey(const std::string & aName,ResultCallback && aCallback)897*4a64e381SAndroid Build Coastguard Worker void PublisherAvahi::UnpublishKey(const std::string &aName, ResultCallback &&aCallback)
898*4a64e381SAndroid Build Coastguard Worker {
899*4a64e381SAndroid Build Coastguard Worker     otbrError error = OTBR_ERROR_NONE;
900*4a64e381SAndroid Build Coastguard Worker 
901*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(mState == Publisher::State::kReady, error = OTBR_ERROR_INVALID_STATE);
902*4a64e381SAndroid Build Coastguard Worker     RemoveKeyRegistration(aName, OTBR_ERROR_ABORTED);
903*4a64e381SAndroid Build Coastguard Worker 
904*4a64e381SAndroid Build Coastguard Worker exit:
905*4a64e381SAndroid Build Coastguard Worker     std::move(aCallback)(error);
906*4a64e381SAndroid Build Coastguard Worker }
907*4a64e381SAndroid Build Coastguard Worker 
TxtDataToAvahiStringList(const TxtData & aTxtData,AvahiStringList * aBuffer,size_t aBufferSize,AvahiStringList * & aHead)908*4a64e381SAndroid Build Coastguard Worker otbrError PublisherAvahi::TxtDataToAvahiStringList(const TxtData    &aTxtData,
909*4a64e381SAndroid Build Coastguard Worker                                                    AvahiStringList  *aBuffer,
910*4a64e381SAndroid Build Coastguard Worker                                                    size_t            aBufferSize,
911*4a64e381SAndroid Build Coastguard Worker                                                    AvahiStringList *&aHead)
912*4a64e381SAndroid Build Coastguard Worker {
913*4a64e381SAndroid Build Coastguard Worker     otbrError        error = OTBR_ERROR_NONE;
914*4a64e381SAndroid Build Coastguard Worker     size_t           used  = 0;
915*4a64e381SAndroid Build Coastguard Worker     AvahiStringList *last  = nullptr;
916*4a64e381SAndroid Build Coastguard Worker     AvahiStringList *curr  = aBuffer;
917*4a64e381SAndroid Build Coastguard Worker     const uint8_t   *next;
918*4a64e381SAndroid Build Coastguard Worker     const uint8_t   *data    = aTxtData.data();
919*4a64e381SAndroid Build Coastguard Worker     const uint8_t   *dataEnd = aTxtData.data() + aTxtData.size();
920*4a64e381SAndroid Build Coastguard Worker 
921*4a64e381SAndroid Build Coastguard Worker     aHead = nullptr;
922*4a64e381SAndroid Build Coastguard Worker 
923*4a64e381SAndroid Build Coastguard Worker     while (data < dataEnd)
924*4a64e381SAndroid Build Coastguard Worker     {
925*4a64e381SAndroid Build Coastguard Worker         uint8_t entryLength = *data++;
926*4a64e381SAndroid Build Coastguard Worker         size_t  needed      = sizeof(AvahiStringList) - sizeof(AvahiStringList::text) + entryLength;
927*4a64e381SAndroid Build Coastguard Worker 
928*4a64e381SAndroid Build Coastguard Worker         if (entryLength == 0)
929*4a64e381SAndroid Build Coastguard Worker         {
930*4a64e381SAndroid Build Coastguard Worker             continue;
931*4a64e381SAndroid Build Coastguard Worker         }
932*4a64e381SAndroid Build Coastguard Worker 
933*4a64e381SAndroid Build Coastguard Worker         VerifyOrExit(data + entryLength <= dataEnd, error = OTBR_ERROR_PARSE);
934*4a64e381SAndroid Build Coastguard Worker 
935*4a64e381SAndroid Build Coastguard Worker         VerifyOrExit(used + needed <= aBufferSize, error = OTBR_ERROR_INVALID_ARGS);
936*4a64e381SAndroid Build Coastguard Worker         curr->next = last;
937*4a64e381SAndroid Build Coastguard Worker         last       = curr;
938*4a64e381SAndroid Build Coastguard Worker 
939*4a64e381SAndroid Build Coastguard Worker         memcpy(curr->text, data, entryLength);
940*4a64e381SAndroid Build Coastguard Worker         curr->size = entryLength;
941*4a64e381SAndroid Build Coastguard Worker 
942*4a64e381SAndroid Build Coastguard Worker         data += entryLength;
943*4a64e381SAndroid Build Coastguard Worker 
944*4a64e381SAndroid Build Coastguard Worker         next = curr->text + curr->size;
945*4a64e381SAndroid Build Coastguard Worker         curr = OTBR_ALIGNED(next, AvahiStringList *);
946*4a64e381SAndroid Build Coastguard Worker         used = static_cast<size_t>(reinterpret_cast<uint8_t *>(curr) - reinterpret_cast<uint8_t *>(aBuffer));
947*4a64e381SAndroid Build Coastguard Worker     }
948*4a64e381SAndroid Build Coastguard Worker 
949*4a64e381SAndroid Build Coastguard Worker     aHead = last;
950*4a64e381SAndroid Build Coastguard Worker 
951*4a64e381SAndroid Build Coastguard Worker exit:
952*4a64e381SAndroid Build Coastguard Worker     return error;
953*4a64e381SAndroid Build Coastguard Worker }
954*4a64e381SAndroid Build Coastguard Worker 
FindServiceRegistration(const AvahiEntryGroup * aEntryGroup)955*4a64e381SAndroid Build Coastguard Worker Publisher::ServiceRegistration *PublisherAvahi::FindServiceRegistration(const AvahiEntryGroup *aEntryGroup)
956*4a64e381SAndroid Build Coastguard Worker {
957*4a64e381SAndroid Build Coastguard Worker     ServiceRegistration *result = nullptr;
958*4a64e381SAndroid Build Coastguard Worker 
959*4a64e381SAndroid Build Coastguard Worker     for (const auto &kv : mServiceRegistrations)
960*4a64e381SAndroid Build Coastguard Worker     {
961*4a64e381SAndroid Build Coastguard Worker         const auto &serviceReg = static_cast<const AvahiServiceRegistration &>(*kv.second);
962*4a64e381SAndroid Build Coastguard Worker         if (serviceReg.GetEntryGroup() == aEntryGroup)
963*4a64e381SAndroid Build Coastguard Worker         {
964*4a64e381SAndroid Build Coastguard Worker             result = kv.second.get();
965*4a64e381SAndroid Build Coastguard Worker             break;
966*4a64e381SAndroid Build Coastguard Worker         }
967*4a64e381SAndroid Build Coastguard Worker     }
968*4a64e381SAndroid Build Coastguard Worker 
969*4a64e381SAndroid Build Coastguard Worker     return result;
970*4a64e381SAndroid Build Coastguard Worker }
971*4a64e381SAndroid Build Coastguard Worker 
FindHostRegistration(const AvahiEntryGroup * aEntryGroup)972*4a64e381SAndroid Build Coastguard Worker Publisher::HostRegistration *PublisherAvahi::FindHostRegistration(const AvahiEntryGroup *aEntryGroup)
973*4a64e381SAndroid Build Coastguard Worker {
974*4a64e381SAndroid Build Coastguard Worker     HostRegistration *result = nullptr;
975*4a64e381SAndroid Build Coastguard Worker 
976*4a64e381SAndroid Build Coastguard Worker     for (const auto &kv : mHostRegistrations)
977*4a64e381SAndroid Build Coastguard Worker     {
978*4a64e381SAndroid Build Coastguard Worker         const auto &hostReg = static_cast<const AvahiHostRegistration &>(*kv.second);
979*4a64e381SAndroid Build Coastguard Worker         if (hostReg.GetEntryGroup() == aEntryGroup)
980*4a64e381SAndroid Build Coastguard Worker         {
981*4a64e381SAndroid Build Coastguard Worker             result = kv.second.get();
982*4a64e381SAndroid Build Coastguard Worker             break;
983*4a64e381SAndroid Build Coastguard Worker         }
984*4a64e381SAndroid Build Coastguard Worker     }
985*4a64e381SAndroid Build Coastguard Worker 
986*4a64e381SAndroid Build Coastguard Worker     return result;
987*4a64e381SAndroid Build Coastguard Worker }
988*4a64e381SAndroid Build Coastguard Worker 
FindKeyRegistration(const AvahiEntryGroup * aEntryGroup)989*4a64e381SAndroid Build Coastguard Worker Publisher::KeyRegistration *PublisherAvahi::FindKeyRegistration(const AvahiEntryGroup *aEntryGroup)
990*4a64e381SAndroid Build Coastguard Worker {
991*4a64e381SAndroid Build Coastguard Worker     KeyRegistration *result = nullptr;
992*4a64e381SAndroid Build Coastguard Worker 
993*4a64e381SAndroid Build Coastguard Worker     for (const auto &entry : mKeyRegistrations)
994*4a64e381SAndroid Build Coastguard Worker     {
995*4a64e381SAndroid Build Coastguard Worker         const auto &keyReg = static_cast<const AvahiKeyRegistration &>(*entry.second);
996*4a64e381SAndroid Build Coastguard Worker         if (keyReg.GetEntryGroup() == aEntryGroup)
997*4a64e381SAndroid Build Coastguard Worker         {
998*4a64e381SAndroid Build Coastguard Worker             result = entry.second.get();
999*4a64e381SAndroid Build Coastguard Worker             break;
1000*4a64e381SAndroid Build Coastguard Worker         }
1001*4a64e381SAndroid Build Coastguard Worker     }
1002*4a64e381SAndroid Build Coastguard Worker 
1003*4a64e381SAndroid Build Coastguard Worker     return result;
1004*4a64e381SAndroid Build Coastguard Worker }
1005*4a64e381SAndroid Build Coastguard Worker 
SubscribeService(const std::string & aType,const std::string & aInstanceName)1006*4a64e381SAndroid Build Coastguard Worker void PublisherAvahi::SubscribeService(const std::string &aType, const std::string &aInstanceName)
1007*4a64e381SAndroid Build Coastguard Worker {
1008*4a64e381SAndroid Build Coastguard Worker     auto service = MakeUnique<ServiceSubscription>(*this, aType, aInstanceName);
1009*4a64e381SAndroid Build Coastguard Worker 
1010*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(mState == Publisher::State::kReady);
1011*4a64e381SAndroid Build Coastguard Worker     mSubscribedServices.push_back(std::move(service));
1012*4a64e381SAndroid Build Coastguard Worker 
1013*4a64e381SAndroid Build Coastguard Worker     otbrLogInfo("Subscribe service %s.%s (total %zu)", aInstanceName.c_str(), aType.c_str(),
1014*4a64e381SAndroid Build Coastguard Worker                 mSubscribedServices.size());
1015*4a64e381SAndroid Build Coastguard Worker 
1016*4a64e381SAndroid Build Coastguard Worker     if (aInstanceName.empty())
1017*4a64e381SAndroid Build Coastguard Worker     {
1018*4a64e381SAndroid Build Coastguard Worker         mSubscribedServices.back()->Browse();
1019*4a64e381SAndroid Build Coastguard Worker     }
1020*4a64e381SAndroid Build Coastguard Worker     else
1021*4a64e381SAndroid Build Coastguard Worker     {
1022*4a64e381SAndroid Build Coastguard Worker         mSubscribedServices.back()->Resolve(AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, aInstanceName, aType);
1023*4a64e381SAndroid Build Coastguard Worker     }
1024*4a64e381SAndroid Build Coastguard Worker 
1025*4a64e381SAndroid Build Coastguard Worker exit:
1026*4a64e381SAndroid Build Coastguard Worker     return;
1027*4a64e381SAndroid Build Coastguard Worker }
1028*4a64e381SAndroid Build Coastguard Worker 
UnsubscribeService(const std::string & aType,const std::string & aInstanceName)1029*4a64e381SAndroid Build Coastguard Worker void PublisherAvahi::UnsubscribeService(const std::string &aType, const std::string &aInstanceName)
1030*4a64e381SAndroid Build Coastguard Worker {
1031*4a64e381SAndroid Build Coastguard Worker     ServiceSubscriptionList::iterator it;
1032*4a64e381SAndroid Build Coastguard Worker 
1033*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(mState == Publisher::State::kReady);
1034*4a64e381SAndroid Build Coastguard Worker     it = std::find_if(mSubscribedServices.begin(), mSubscribedServices.end(),
1035*4a64e381SAndroid Build Coastguard Worker                       [&aType, &aInstanceName](const std::unique_ptr<ServiceSubscription> &aService) {
1036*4a64e381SAndroid Build Coastguard Worker                           return aService->mType == aType && aService->mInstanceName == aInstanceName;
1037*4a64e381SAndroid Build Coastguard Worker                       });
1038*4a64e381SAndroid Build Coastguard Worker 
1039*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(it != mSubscribedServices.end());
1040*4a64e381SAndroid Build Coastguard Worker 
1041*4a64e381SAndroid Build Coastguard Worker     {
1042*4a64e381SAndroid Build Coastguard Worker         std::unique_ptr<ServiceSubscription> service = std::move(*it);
1043*4a64e381SAndroid Build Coastguard Worker 
1044*4a64e381SAndroid Build Coastguard Worker         mSubscribedServices.erase(it);
1045*4a64e381SAndroid Build Coastguard Worker         service->Release();
1046*4a64e381SAndroid Build Coastguard Worker     }
1047*4a64e381SAndroid Build Coastguard Worker 
1048*4a64e381SAndroid Build Coastguard Worker     otbrLogInfo("Unsubscribe service %s.%s (left %zu)", aInstanceName.c_str(), aType.c_str(),
1049*4a64e381SAndroid Build Coastguard Worker                 mSubscribedServices.size());
1050*4a64e381SAndroid Build Coastguard Worker 
1051*4a64e381SAndroid Build Coastguard Worker exit:
1052*4a64e381SAndroid Build Coastguard Worker     return;
1053*4a64e381SAndroid Build Coastguard Worker }
1054*4a64e381SAndroid Build Coastguard Worker 
OnServiceResolveFailedImpl(const std::string & aType,const std::string & aInstanceName,int32_t aErrorCode)1055*4a64e381SAndroid Build Coastguard Worker void PublisherAvahi::OnServiceResolveFailedImpl(const std::string &aType,
1056*4a64e381SAndroid Build Coastguard Worker                                                 const std::string &aInstanceName,
1057*4a64e381SAndroid Build Coastguard Worker                                                 int32_t            aErrorCode)
1058*4a64e381SAndroid Build Coastguard Worker {
1059*4a64e381SAndroid Build Coastguard Worker     otbrLogWarning("Resolve service %s.%s failed: %s", aInstanceName.c_str(), aType.c_str(),
1060*4a64e381SAndroid Build Coastguard Worker                    avahi_strerror(aErrorCode));
1061*4a64e381SAndroid Build Coastguard Worker }
1062*4a64e381SAndroid Build Coastguard Worker 
OnHostResolveFailedImpl(const std::string & aHostName,int32_t aErrorCode)1063*4a64e381SAndroid Build Coastguard Worker void PublisherAvahi::OnHostResolveFailedImpl(const std::string &aHostName, int32_t aErrorCode)
1064*4a64e381SAndroid Build Coastguard Worker {
1065*4a64e381SAndroid Build Coastguard Worker     otbrLogWarning("Resolve host %s failed: %s", aHostName.c_str(), avahi_strerror(aErrorCode));
1066*4a64e381SAndroid Build Coastguard Worker }
1067*4a64e381SAndroid Build Coastguard Worker 
DnsErrorToOtbrError(int32_t aErrorCode)1068*4a64e381SAndroid Build Coastguard Worker otbrError PublisherAvahi::DnsErrorToOtbrError(int32_t aErrorCode)
1069*4a64e381SAndroid Build Coastguard Worker {
1070*4a64e381SAndroid Build Coastguard Worker     return otbr::Mdns::DnsErrorToOtbrError(aErrorCode);
1071*4a64e381SAndroid Build Coastguard Worker }
1072*4a64e381SAndroid Build Coastguard Worker 
SubscribeHost(const std::string & aHostName)1073*4a64e381SAndroid Build Coastguard Worker void PublisherAvahi::SubscribeHost(const std::string &aHostName)
1074*4a64e381SAndroid Build Coastguard Worker {
1075*4a64e381SAndroid Build Coastguard Worker     auto host = MakeUnique<HostSubscription>(*this, aHostName);
1076*4a64e381SAndroid Build Coastguard Worker 
1077*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(mState == Publisher::State::kReady);
1078*4a64e381SAndroid Build Coastguard Worker 
1079*4a64e381SAndroid Build Coastguard Worker     mSubscribedHosts.push_back(std::move(host));
1080*4a64e381SAndroid Build Coastguard Worker 
1081*4a64e381SAndroid Build Coastguard Worker     otbrLogInfo("Subscribe host %s (total %zu)", aHostName.c_str(), mSubscribedHosts.size());
1082*4a64e381SAndroid Build Coastguard Worker 
1083*4a64e381SAndroid Build Coastguard Worker     mSubscribedHosts.back()->Resolve();
1084*4a64e381SAndroid Build Coastguard Worker 
1085*4a64e381SAndroid Build Coastguard Worker exit:
1086*4a64e381SAndroid Build Coastguard Worker     return;
1087*4a64e381SAndroid Build Coastguard Worker }
1088*4a64e381SAndroid Build Coastguard Worker 
UnsubscribeHost(const std::string & aHostName)1089*4a64e381SAndroid Build Coastguard Worker void PublisherAvahi::UnsubscribeHost(const std::string &aHostName)
1090*4a64e381SAndroid Build Coastguard Worker {
1091*4a64e381SAndroid Build Coastguard Worker     HostSubscriptionList::iterator it;
1092*4a64e381SAndroid Build Coastguard Worker 
1093*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(mState == Publisher::State::kReady);
1094*4a64e381SAndroid Build Coastguard Worker     it = std::find_if(
1095*4a64e381SAndroid Build Coastguard Worker         mSubscribedHosts.begin(), mSubscribedHosts.end(),
1096*4a64e381SAndroid Build Coastguard Worker         [&aHostName](const std::unique_ptr<HostSubscription> &aHost) { return aHost->mHostName == aHostName; });
1097*4a64e381SAndroid Build Coastguard Worker 
1098*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(it != mSubscribedHosts.end());
1099*4a64e381SAndroid Build Coastguard Worker 
1100*4a64e381SAndroid Build Coastguard Worker     {
1101*4a64e381SAndroid Build Coastguard Worker         std::unique_ptr<HostSubscription> host = std::move(*it);
1102*4a64e381SAndroid Build Coastguard Worker 
1103*4a64e381SAndroid Build Coastguard Worker         mSubscribedHosts.erase(it);
1104*4a64e381SAndroid Build Coastguard Worker         host->Release();
1105*4a64e381SAndroid Build Coastguard Worker     }
1106*4a64e381SAndroid Build Coastguard Worker 
1107*4a64e381SAndroid Build Coastguard Worker     otbrLogInfo("Unsubscribe host %s (remaining %zu)", aHostName.c_str(), mSubscribedHosts.size());
1108*4a64e381SAndroid Build Coastguard Worker 
1109*4a64e381SAndroid Build Coastguard Worker exit:
1110*4a64e381SAndroid Build Coastguard Worker     return;
1111*4a64e381SAndroid Build Coastguard Worker }
1112*4a64e381SAndroid Build Coastguard Worker 
Create(StateCallback aStateCallback)1113*4a64e381SAndroid Build Coastguard Worker Publisher *Publisher::Create(StateCallback aStateCallback)
1114*4a64e381SAndroid Build Coastguard Worker {
1115*4a64e381SAndroid Build Coastguard Worker     return new PublisherAvahi(std::move(aStateCallback));
1116*4a64e381SAndroid Build Coastguard Worker }
1117*4a64e381SAndroid Build Coastguard Worker 
Destroy(Publisher * aPublisher)1118*4a64e381SAndroid Build Coastguard Worker void Publisher::Destroy(Publisher *aPublisher)
1119*4a64e381SAndroid Build Coastguard Worker {
1120*4a64e381SAndroid Build Coastguard Worker     delete static_cast<PublisherAvahi *>(aPublisher);
1121*4a64e381SAndroid Build Coastguard Worker }
1122*4a64e381SAndroid Build Coastguard Worker 
Browse(void)1123*4a64e381SAndroid Build Coastguard Worker void PublisherAvahi::ServiceSubscription::Browse(void)
1124*4a64e381SAndroid Build Coastguard Worker {
1125*4a64e381SAndroid Build Coastguard Worker     assert(mPublisherAvahi->mClient != nullptr);
1126*4a64e381SAndroid Build Coastguard Worker 
1127*4a64e381SAndroid Build Coastguard Worker     otbrLogInfo("Browse service %s", mType.c_str());
1128*4a64e381SAndroid Build Coastguard Worker     mServiceBrowser =
1129*4a64e381SAndroid Build Coastguard Worker         avahi_service_browser_new(mPublisherAvahi->mClient, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, mType.c_str(),
1130*4a64e381SAndroid Build Coastguard Worker                                   /* domain */ nullptr, static_cast<AvahiLookupFlags>(0), HandleBrowseResult, this);
1131*4a64e381SAndroid Build Coastguard Worker     if (!mServiceBrowser)
1132*4a64e381SAndroid Build Coastguard Worker     {
1133*4a64e381SAndroid Build Coastguard Worker         otbrLogWarning("Failed to browse service %s: %s", mType.c_str(),
1134*4a64e381SAndroid Build Coastguard Worker                        avahi_strerror(avahi_client_errno(mPublisherAvahi->mClient)));
1135*4a64e381SAndroid Build Coastguard Worker     }
1136*4a64e381SAndroid Build Coastguard Worker }
1137*4a64e381SAndroid Build Coastguard Worker 
Release(void)1138*4a64e381SAndroid Build Coastguard Worker void PublisherAvahi::ServiceSubscription::Release(void)
1139*4a64e381SAndroid Build Coastguard Worker {
1140*4a64e381SAndroid Build Coastguard Worker     std::vector<std::string> instanceNames;
1141*4a64e381SAndroid Build Coastguard Worker 
1142*4a64e381SAndroid Build Coastguard Worker     for (const auto &resolvers : mServiceResolvers)
1143*4a64e381SAndroid Build Coastguard Worker     {
1144*4a64e381SAndroid Build Coastguard Worker         instanceNames.push_back(resolvers.first);
1145*4a64e381SAndroid Build Coastguard Worker     }
1146*4a64e381SAndroid Build Coastguard Worker     for (const auto &name : instanceNames)
1147*4a64e381SAndroid Build Coastguard Worker     {
1148*4a64e381SAndroid Build Coastguard Worker         RemoveServiceResolver(name);
1149*4a64e381SAndroid Build Coastguard Worker     }
1150*4a64e381SAndroid Build Coastguard Worker 
1151*4a64e381SAndroid Build Coastguard Worker     if (mServiceBrowser != nullptr)
1152*4a64e381SAndroid Build Coastguard Worker     {
1153*4a64e381SAndroid Build Coastguard Worker         avahi_service_browser_free(mServiceBrowser);
1154*4a64e381SAndroid Build Coastguard Worker         mServiceBrowser = nullptr;
1155*4a64e381SAndroid Build Coastguard Worker     }
1156*4a64e381SAndroid Build Coastguard Worker }
1157*4a64e381SAndroid Build Coastguard Worker 
HandleBrowseResult(AvahiServiceBrowser * aServiceBrowser,AvahiIfIndex aInterfaceIndex,AvahiProtocol aProtocol,AvahiBrowserEvent aEvent,const char * aName,const char * aType,const char * aDomain,AvahiLookupResultFlags aFlags,void * aContext)1158*4a64e381SAndroid Build Coastguard Worker void PublisherAvahi::ServiceSubscription::HandleBrowseResult(AvahiServiceBrowser   *aServiceBrowser,
1159*4a64e381SAndroid Build Coastguard Worker                                                              AvahiIfIndex           aInterfaceIndex,
1160*4a64e381SAndroid Build Coastguard Worker                                                              AvahiProtocol          aProtocol,
1161*4a64e381SAndroid Build Coastguard Worker                                                              AvahiBrowserEvent      aEvent,
1162*4a64e381SAndroid Build Coastguard Worker                                                              const char            *aName,
1163*4a64e381SAndroid Build Coastguard Worker                                                              const char            *aType,
1164*4a64e381SAndroid Build Coastguard Worker                                                              const char            *aDomain,
1165*4a64e381SAndroid Build Coastguard Worker                                                              AvahiLookupResultFlags aFlags,
1166*4a64e381SAndroid Build Coastguard Worker                                                              void                  *aContext)
1167*4a64e381SAndroid Build Coastguard Worker {
1168*4a64e381SAndroid Build Coastguard Worker     static_cast<PublisherAvahi::ServiceSubscription *>(aContext)->HandleBrowseResult(
1169*4a64e381SAndroid Build Coastguard Worker         aServiceBrowser, aInterfaceIndex, aProtocol, aEvent, aName, aType, aDomain, aFlags);
1170*4a64e381SAndroid Build Coastguard Worker }
1171*4a64e381SAndroid Build Coastguard Worker 
HandleBrowseResult(AvahiServiceBrowser * aServiceBrowser,AvahiIfIndex aInterfaceIndex,AvahiProtocol aProtocol,AvahiBrowserEvent aEvent,const char * aName,const char * aType,const char * aDomain,AvahiLookupResultFlags aFlags)1172*4a64e381SAndroid Build Coastguard Worker void PublisherAvahi::ServiceSubscription::HandleBrowseResult(AvahiServiceBrowser   *aServiceBrowser,
1173*4a64e381SAndroid Build Coastguard Worker                                                              AvahiIfIndex           aInterfaceIndex,
1174*4a64e381SAndroid Build Coastguard Worker                                                              AvahiProtocol          aProtocol,
1175*4a64e381SAndroid Build Coastguard Worker                                                              AvahiBrowserEvent      aEvent,
1176*4a64e381SAndroid Build Coastguard Worker                                                              const char            *aName,
1177*4a64e381SAndroid Build Coastguard Worker                                                              const char            *aType,
1178*4a64e381SAndroid Build Coastguard Worker                                                              const char            *aDomain,
1179*4a64e381SAndroid Build Coastguard Worker                                                              AvahiLookupResultFlags aFlags)
1180*4a64e381SAndroid Build Coastguard Worker {
1181*4a64e381SAndroid Build Coastguard Worker     OTBR_UNUSED_VARIABLE(aServiceBrowser);
1182*4a64e381SAndroid Build Coastguard Worker     OTBR_UNUSED_VARIABLE(aProtocol);
1183*4a64e381SAndroid Build Coastguard Worker     OTBR_UNUSED_VARIABLE(aDomain);
1184*4a64e381SAndroid Build Coastguard Worker 
1185*4a64e381SAndroid Build Coastguard Worker     assert(mServiceBrowser == aServiceBrowser);
1186*4a64e381SAndroid Build Coastguard Worker 
1187*4a64e381SAndroid Build Coastguard Worker     otbrLogInfo("Browse service reply: %s.%s proto %d inf %u event %d flags %d", aName, aType, aProtocol,
1188*4a64e381SAndroid Build Coastguard Worker                 aInterfaceIndex, static_cast<int>(aEvent), static_cast<int>(aFlags));
1189*4a64e381SAndroid Build Coastguard Worker 
1190*4a64e381SAndroid Build Coastguard Worker     switch (aEvent)
1191*4a64e381SAndroid Build Coastguard Worker     {
1192*4a64e381SAndroid Build Coastguard Worker     case AVAHI_BROWSER_NEW:
1193*4a64e381SAndroid Build Coastguard Worker         Resolve(aInterfaceIndex, aProtocol, aName, aType);
1194*4a64e381SAndroid Build Coastguard Worker         break;
1195*4a64e381SAndroid Build Coastguard Worker     case AVAHI_BROWSER_REMOVE:
1196*4a64e381SAndroid Build Coastguard Worker         mPublisherAvahi->OnServiceRemoved(static_cast<uint32_t>(aInterfaceIndex), aType, aName);
1197*4a64e381SAndroid Build Coastguard Worker         RemoveServiceResolver(aName);
1198*4a64e381SAndroid Build Coastguard Worker         break;
1199*4a64e381SAndroid Build Coastguard Worker     case AVAHI_BROWSER_CACHE_EXHAUSTED:
1200*4a64e381SAndroid Build Coastguard Worker     case AVAHI_BROWSER_ALL_FOR_NOW:
1201*4a64e381SAndroid Build Coastguard Worker         // do nothing
1202*4a64e381SAndroid Build Coastguard Worker         break;
1203*4a64e381SAndroid Build Coastguard Worker     case AVAHI_BROWSER_FAILURE:
1204*4a64e381SAndroid Build Coastguard Worker         mPublisherAvahi->OnServiceResolveFailed(aType, aName, avahi_client_errno(mPublisherAvahi->mClient));
1205*4a64e381SAndroid Build Coastguard Worker         break;
1206*4a64e381SAndroid Build Coastguard Worker     }
1207*4a64e381SAndroid Build Coastguard Worker }
1208*4a64e381SAndroid Build Coastguard Worker 
Resolve(uint32_t aInterfaceIndex,AvahiProtocol aProtocol,const std::string & aInstanceName,const std::string & aType)1209*4a64e381SAndroid Build Coastguard Worker void PublisherAvahi::ServiceSubscription::Resolve(uint32_t           aInterfaceIndex,
1210*4a64e381SAndroid Build Coastguard Worker                                                   AvahiProtocol      aProtocol,
1211*4a64e381SAndroid Build Coastguard Worker                                                   const std::string &aInstanceName,
1212*4a64e381SAndroid Build Coastguard Worker                                                   const std::string &aType)
1213*4a64e381SAndroid Build Coastguard Worker {
1214*4a64e381SAndroid Build Coastguard Worker     auto serviceResolver = MakeUnique<ServiceResolver>();
1215*4a64e381SAndroid Build Coastguard Worker 
1216*4a64e381SAndroid Build Coastguard Worker     mPublisherAvahi->mServiceInstanceResolutionBeginTime[std::make_pair(aInstanceName, aType)] = Clock::now();
1217*4a64e381SAndroid Build Coastguard Worker 
1218*4a64e381SAndroid Build Coastguard Worker     otbrLogInfo("Resolve service %s.%s inf %" PRIu32, aInstanceName.c_str(), aType.c_str(), aInterfaceIndex);
1219*4a64e381SAndroid Build Coastguard Worker 
1220*4a64e381SAndroid Build Coastguard Worker     serviceResolver->mType            = aType;
1221*4a64e381SAndroid Build Coastguard Worker     serviceResolver->mPublisherAvahi  = this->mPublisherAvahi;
1222*4a64e381SAndroid Build Coastguard Worker     serviceResolver->mServiceResolver = avahi_service_resolver_new(
1223*4a64e381SAndroid Build Coastguard Worker         mPublisherAvahi->mClient, aInterfaceIndex, aProtocol, aInstanceName.c_str(), aType.c_str(),
1224*4a64e381SAndroid Build Coastguard Worker         /* domain */ nullptr, AVAHI_PROTO_UNSPEC, static_cast<AvahiLookupFlags>(AVAHI_LOOKUP_NO_ADDRESS),
1225*4a64e381SAndroid Build Coastguard Worker         &ServiceResolver::HandleResolveServiceResult, serviceResolver.get());
1226*4a64e381SAndroid Build Coastguard Worker 
1227*4a64e381SAndroid Build Coastguard Worker     if (serviceResolver->mServiceResolver != nullptr)
1228*4a64e381SAndroid Build Coastguard Worker     {
1229*4a64e381SAndroid Build Coastguard Worker         AddServiceResolver(aInstanceName, serviceResolver.release());
1230*4a64e381SAndroid Build Coastguard Worker     }
1231*4a64e381SAndroid Build Coastguard Worker     else
1232*4a64e381SAndroid Build Coastguard Worker     {
1233*4a64e381SAndroid Build Coastguard Worker         otbrLogErr("Failed to resolve serivce %s: %s", mType.c_str(),
1234*4a64e381SAndroid Build Coastguard Worker                    avahi_strerror(avahi_client_errno(mPublisherAvahi->mClient)));
1235*4a64e381SAndroid Build Coastguard Worker     }
1236*4a64e381SAndroid Build Coastguard Worker }
1237*4a64e381SAndroid Build Coastguard Worker 
HandleResolveServiceResult(AvahiServiceResolver * aServiceResolver,AvahiIfIndex aInterfaceIndex,AvahiProtocol aProtocol,AvahiResolverEvent aEvent,const char * aName,const char * aType,const char * aDomain,const char * aHostName,const AvahiAddress * aAddress,uint16_t aPort,AvahiStringList * aTxt,AvahiLookupResultFlags aFlags,void * aContext)1238*4a64e381SAndroid Build Coastguard Worker void PublisherAvahi::ServiceResolver::HandleResolveServiceResult(AvahiServiceResolver  *aServiceResolver,
1239*4a64e381SAndroid Build Coastguard Worker                                                                  AvahiIfIndex           aInterfaceIndex,
1240*4a64e381SAndroid Build Coastguard Worker                                                                  AvahiProtocol          aProtocol,
1241*4a64e381SAndroid Build Coastguard Worker                                                                  AvahiResolverEvent     aEvent,
1242*4a64e381SAndroid Build Coastguard Worker                                                                  const char            *aName,
1243*4a64e381SAndroid Build Coastguard Worker                                                                  const char            *aType,
1244*4a64e381SAndroid Build Coastguard Worker                                                                  const char            *aDomain,
1245*4a64e381SAndroid Build Coastguard Worker                                                                  const char            *aHostName,
1246*4a64e381SAndroid Build Coastguard Worker                                                                  const AvahiAddress    *aAddress,
1247*4a64e381SAndroid Build Coastguard Worker                                                                  uint16_t               aPort,
1248*4a64e381SAndroid Build Coastguard Worker                                                                  AvahiStringList       *aTxt,
1249*4a64e381SAndroid Build Coastguard Worker                                                                  AvahiLookupResultFlags aFlags,
1250*4a64e381SAndroid Build Coastguard Worker                                                                  void                  *aContext)
1251*4a64e381SAndroid Build Coastguard Worker {
1252*4a64e381SAndroid Build Coastguard Worker     static_cast<PublisherAvahi::ServiceResolver *>(aContext)->HandleResolveServiceResult(
1253*4a64e381SAndroid Build Coastguard Worker         aServiceResolver, aInterfaceIndex, aProtocol, aEvent, aName, aType, aDomain, aHostName, aAddress, aPort, aTxt,
1254*4a64e381SAndroid Build Coastguard Worker         aFlags);
1255*4a64e381SAndroid Build Coastguard Worker }
1256*4a64e381SAndroid Build Coastguard Worker 
HandleResolveServiceResult(AvahiServiceResolver * aServiceResolver,AvahiIfIndex aInterfaceIndex,AvahiProtocol aProtocol,AvahiResolverEvent aEvent,const char * aName,const char * aType,const char * aDomain,const char * aHostName,const AvahiAddress * aAddress,uint16_t aPort,AvahiStringList * aTxt,AvahiLookupResultFlags aFlags)1257*4a64e381SAndroid Build Coastguard Worker void PublisherAvahi::ServiceResolver::HandleResolveServiceResult(AvahiServiceResolver  *aServiceResolver,
1258*4a64e381SAndroid Build Coastguard Worker                                                                  AvahiIfIndex           aInterfaceIndex,
1259*4a64e381SAndroid Build Coastguard Worker                                                                  AvahiProtocol          aProtocol,
1260*4a64e381SAndroid Build Coastguard Worker                                                                  AvahiResolverEvent     aEvent,
1261*4a64e381SAndroid Build Coastguard Worker                                                                  const char            *aName,
1262*4a64e381SAndroid Build Coastguard Worker                                                                  const char            *aType,
1263*4a64e381SAndroid Build Coastguard Worker                                                                  const char            *aDomain,
1264*4a64e381SAndroid Build Coastguard Worker                                                                  const char            *aHostName,
1265*4a64e381SAndroid Build Coastguard Worker                                                                  const AvahiAddress    *aAddress,
1266*4a64e381SAndroid Build Coastguard Worker                                                                  uint16_t               aPort,
1267*4a64e381SAndroid Build Coastguard Worker                                                                  AvahiStringList       *aTxt,
1268*4a64e381SAndroid Build Coastguard Worker                                                                  AvahiLookupResultFlags aFlags)
1269*4a64e381SAndroid Build Coastguard Worker {
1270*4a64e381SAndroid Build Coastguard Worker     OT_UNUSED_VARIABLE(aServiceResolver);
1271*4a64e381SAndroid Build Coastguard Worker     OT_UNUSED_VARIABLE(aInterfaceIndex);
1272*4a64e381SAndroid Build Coastguard Worker     OT_UNUSED_VARIABLE(aProtocol);
1273*4a64e381SAndroid Build Coastguard Worker     OT_UNUSED_VARIABLE(aType);
1274*4a64e381SAndroid Build Coastguard Worker     OT_UNUSED_VARIABLE(aDomain);
1275*4a64e381SAndroid Build Coastguard Worker     OT_UNUSED_VARIABLE(aAddress);
1276*4a64e381SAndroid Build Coastguard Worker 
1277*4a64e381SAndroid Build Coastguard Worker     size_t totalTxtSize = 0;
1278*4a64e381SAndroid Build Coastguard Worker     bool   resolved     = false;
1279*4a64e381SAndroid Build Coastguard Worker     int    avahiError   = AVAHI_OK;
1280*4a64e381SAndroid Build Coastguard Worker 
1281*4a64e381SAndroid Build Coastguard Worker     otbrLog(aEvent == AVAHI_RESOLVER_FOUND ? OTBR_LOG_INFO : OTBR_LOG_WARNING, OTBR_LOG_TAG,
1282*4a64e381SAndroid Build Coastguard Worker             "Resolve service reply: protocol %d %s.%s.%s = host %s port %" PRIu16 " flags %d event %d", aProtocol,
1283*4a64e381SAndroid Build Coastguard Worker             aName, aType, aDomain, aHostName, aPort, static_cast<int>(aFlags), static_cast<int>(aEvent));
1284*4a64e381SAndroid Build Coastguard Worker 
1285*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(aEvent == AVAHI_RESOLVER_FOUND, avahiError = avahi_client_errno(mPublisherAvahi->mClient));
1286*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(aHostName != nullptr, avahiError = AVAHI_ERR_INVALID_HOST_NAME);
1287*4a64e381SAndroid Build Coastguard Worker 
1288*4a64e381SAndroid Build Coastguard Worker     mInstanceInfo.mNetifIndex = static_cast<uint32_t>(aInterfaceIndex);
1289*4a64e381SAndroid Build Coastguard Worker     mInstanceInfo.mName       = aName;
1290*4a64e381SAndroid Build Coastguard Worker     mInstanceInfo.mHostName   = std::string(aHostName) + ".";
1291*4a64e381SAndroid Build Coastguard Worker     mInstanceInfo.mPort       = aPort;
1292*4a64e381SAndroid Build Coastguard Worker 
1293*4a64e381SAndroid Build Coastguard Worker     otbrLogInfo("Resolve service reply: flags=%u, host=%s", aFlags, aHostName);
1294*4a64e381SAndroid Build Coastguard Worker 
1295*4a64e381SAndroid Build Coastguard Worker     // TODO priority
1296*4a64e381SAndroid Build Coastguard Worker     // TODO weight
1297*4a64e381SAndroid Build Coastguard Worker     // TODO use a more proper TTL
1298*4a64e381SAndroid Build Coastguard Worker     mInstanceInfo.mTtl = kDefaultTtl;
1299*4a64e381SAndroid Build Coastguard Worker     for (auto p = aTxt; p; p = avahi_string_list_get_next(p))
1300*4a64e381SAndroid Build Coastguard Worker     {
1301*4a64e381SAndroid Build Coastguard Worker         totalTxtSize += avahi_string_list_get_size(p) + 1;
1302*4a64e381SAndroid Build Coastguard Worker     }
1303*4a64e381SAndroid Build Coastguard Worker     mInstanceInfo.mTxtData.resize(totalTxtSize);
1304*4a64e381SAndroid Build Coastguard Worker     avahi_string_list_serialize(aTxt, mInstanceInfo.mTxtData.data(), totalTxtSize);
1305*4a64e381SAndroid Build Coastguard Worker 
1306*4a64e381SAndroid Build Coastguard Worker     // NOTE: Avahi only returns one of the host's addresses in the service resolution callback. However, the address may
1307*4a64e381SAndroid Build Coastguard Worker     // be link-local so it may not be preferred from Thread's perspective. We want to go through the complete list of
1308*4a64e381SAndroid Build Coastguard Worker     // addresses associated with the host and choose a routable address. Therefore, as below we will resolve the host
1309*4a64e381SAndroid Build Coastguard Worker     // and go through all its addresses.
1310*4a64e381SAndroid Build Coastguard Worker 
1311*4a64e381SAndroid Build Coastguard Worker     resolved = true;
1312*4a64e381SAndroid Build Coastguard Worker 
1313*4a64e381SAndroid Build Coastguard Worker exit:
1314*4a64e381SAndroid Build Coastguard Worker     if (resolved)
1315*4a64e381SAndroid Build Coastguard Worker     {
1316*4a64e381SAndroid Build Coastguard Worker         // In case the callback is triggered when a service instance is updated, there may already be a record browser.
1317*4a64e381SAndroid Build Coastguard Worker         // We should free it before switching to the new record browser.
1318*4a64e381SAndroid Build Coastguard Worker         if (mRecordBrowser)
1319*4a64e381SAndroid Build Coastguard Worker         {
1320*4a64e381SAndroid Build Coastguard Worker             avahi_record_browser_free(mRecordBrowser);
1321*4a64e381SAndroid Build Coastguard Worker             mRecordBrowser = nullptr;
1322*4a64e381SAndroid Build Coastguard Worker             mInstanceInfo.mAddresses.clear();
1323*4a64e381SAndroid Build Coastguard Worker         }
1324*4a64e381SAndroid Build Coastguard Worker         // NOTE: This `ServiceResolver` object may be freed in `OnServiceResolved`.
1325*4a64e381SAndroid Build Coastguard Worker         mRecordBrowser = avahi_record_browser_new(mPublisherAvahi->mClient, aInterfaceIndex, AVAHI_PROTO_UNSPEC,
1326*4a64e381SAndroid Build Coastguard Worker                                                   aHostName, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_AAAA,
1327*4a64e381SAndroid Build Coastguard Worker                                                   static_cast<AvahiLookupFlags>(0), HandleResolveHostResult, this);
1328*4a64e381SAndroid Build Coastguard Worker         if (!mRecordBrowser)
1329*4a64e381SAndroid Build Coastguard Worker         {
1330*4a64e381SAndroid Build Coastguard Worker             resolved   = false;
1331*4a64e381SAndroid Build Coastguard Worker             avahiError = avahi_client_errno(mPublisherAvahi->mClient);
1332*4a64e381SAndroid Build Coastguard Worker         }
1333*4a64e381SAndroid Build Coastguard Worker     }
1334*4a64e381SAndroid Build Coastguard Worker     if (!resolved && avahiError != AVAHI_OK)
1335*4a64e381SAndroid Build Coastguard Worker     {
1336*4a64e381SAndroid Build Coastguard Worker         mPublisherAvahi->OnServiceResolveFailed(aType, aName, avahiError);
1337*4a64e381SAndroid Build Coastguard Worker     }
1338*4a64e381SAndroid Build Coastguard Worker }
1339*4a64e381SAndroid Build Coastguard Worker 
HandleResolveHostResult(AvahiRecordBrowser * aRecordBrowser,AvahiIfIndex aInterfaceIndex,AvahiProtocol aProtocol,AvahiBrowserEvent aEvent,const char * aName,uint16_t aClazz,uint16_t aType,const void * aRdata,size_t aSize,AvahiLookupResultFlags aFlags,void * aContext)1340*4a64e381SAndroid Build Coastguard Worker void PublisherAvahi::ServiceResolver::HandleResolveHostResult(AvahiRecordBrowser    *aRecordBrowser,
1341*4a64e381SAndroid Build Coastguard Worker                                                               AvahiIfIndex           aInterfaceIndex,
1342*4a64e381SAndroid Build Coastguard Worker                                                               AvahiProtocol          aProtocol,
1343*4a64e381SAndroid Build Coastguard Worker                                                               AvahiBrowserEvent      aEvent,
1344*4a64e381SAndroid Build Coastguard Worker                                                               const char            *aName,
1345*4a64e381SAndroid Build Coastguard Worker                                                               uint16_t               aClazz,
1346*4a64e381SAndroid Build Coastguard Worker                                                               uint16_t               aType,
1347*4a64e381SAndroid Build Coastguard Worker                                                               const void            *aRdata,
1348*4a64e381SAndroid Build Coastguard Worker                                                               size_t                 aSize,
1349*4a64e381SAndroid Build Coastguard Worker                                                               AvahiLookupResultFlags aFlags,
1350*4a64e381SAndroid Build Coastguard Worker                                                               void                  *aContext)
1351*4a64e381SAndroid Build Coastguard Worker {
1352*4a64e381SAndroid Build Coastguard Worker     static_cast<PublisherAvahi::ServiceResolver *>(aContext)->HandleResolveHostResult(
1353*4a64e381SAndroid Build Coastguard Worker         aRecordBrowser, aInterfaceIndex, aProtocol, aEvent, aName, aClazz, aType, aRdata, aSize, aFlags);
1354*4a64e381SAndroid Build Coastguard Worker }
1355*4a64e381SAndroid Build Coastguard Worker 
HandleResolveHostResult(AvahiRecordBrowser * aRecordBrowser,AvahiIfIndex aInterfaceIndex,AvahiProtocol aProtocol,AvahiBrowserEvent aEvent,const char * aName,uint16_t aClazz,uint16_t aType,const void * aRdata,size_t aSize,AvahiLookupResultFlags aFlags)1356*4a64e381SAndroid Build Coastguard Worker void PublisherAvahi::ServiceResolver::HandleResolveHostResult(AvahiRecordBrowser    *aRecordBrowser,
1357*4a64e381SAndroid Build Coastguard Worker                                                               AvahiIfIndex           aInterfaceIndex,
1358*4a64e381SAndroid Build Coastguard Worker                                                               AvahiProtocol          aProtocol,
1359*4a64e381SAndroid Build Coastguard Worker                                                               AvahiBrowserEvent      aEvent,
1360*4a64e381SAndroid Build Coastguard Worker                                                               const char            *aName,
1361*4a64e381SAndroid Build Coastguard Worker                                                               uint16_t               aClazz,
1362*4a64e381SAndroid Build Coastguard Worker                                                               uint16_t               aType,
1363*4a64e381SAndroid Build Coastguard Worker                                                               const void            *aRdata,
1364*4a64e381SAndroid Build Coastguard Worker                                                               size_t                 aSize,
1365*4a64e381SAndroid Build Coastguard Worker                                                               AvahiLookupResultFlags aFlags)
1366*4a64e381SAndroid Build Coastguard Worker {
1367*4a64e381SAndroid Build Coastguard Worker     OTBR_UNUSED_VARIABLE(aRecordBrowser);
1368*4a64e381SAndroid Build Coastguard Worker     OTBR_UNUSED_VARIABLE(aInterfaceIndex);
1369*4a64e381SAndroid Build Coastguard Worker     OTBR_UNUSED_VARIABLE(aProtocol);
1370*4a64e381SAndroid Build Coastguard Worker     OTBR_UNUSED_VARIABLE(aEvent);
1371*4a64e381SAndroid Build Coastguard Worker     OTBR_UNUSED_VARIABLE(aClazz);
1372*4a64e381SAndroid Build Coastguard Worker     OTBR_UNUSED_VARIABLE(aType);
1373*4a64e381SAndroid Build Coastguard Worker     OTBR_UNUSED_VARIABLE(aFlags);
1374*4a64e381SAndroid Build Coastguard Worker 
1375*4a64e381SAndroid Build Coastguard Worker     Ip6Address address;
1376*4a64e381SAndroid Build Coastguard Worker     bool       resolved   = false;
1377*4a64e381SAndroid Build Coastguard Worker     int        avahiError = AVAHI_OK;
1378*4a64e381SAndroid Build Coastguard Worker 
1379*4a64e381SAndroid Build Coastguard Worker     otbrLog(aEvent != AVAHI_BROWSER_FAILURE ? OTBR_LOG_INFO : OTBR_LOG_WARNING, OTBR_LOG_TAG,
1380*4a64e381SAndroid Build Coastguard Worker             "Resolve host reply: %s inf %d protocol %d class %" PRIu16 " type %" PRIu16 " size %zu flags %d event %d",
1381*4a64e381SAndroid Build Coastguard Worker             aName, aInterfaceIndex, aProtocol, aClazz, aType, aSize, static_cast<int>(aFlags),
1382*4a64e381SAndroid Build Coastguard Worker             static_cast<int>(aEvent));
1383*4a64e381SAndroid Build Coastguard Worker 
1384*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(aEvent == AVAHI_BROWSER_NEW || aEvent == AVAHI_BROWSER_REMOVE);
1385*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(aSize == OTBR_IP6_ADDRESS_SIZE || aSize == OTBR_IP4_ADDRESS_SIZE,
1386*4a64e381SAndroid Build Coastguard Worker                  otbrLogErr("Unexpected address data length: %zu", aSize), avahiError = AVAHI_ERR_INVALID_ADDRESS);
1387*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(aSize == OTBR_IP6_ADDRESS_SIZE, otbrLogInfo("IPv4 address ignored"),
1388*4a64e381SAndroid Build Coastguard Worker                  avahiError = AVAHI_ERR_INVALID_ADDRESS);
1389*4a64e381SAndroid Build Coastguard Worker     address = Ip6Address(*static_cast<const uint8_t(*)[OTBR_IP6_ADDRESS_SIZE]>(aRdata));
1390*4a64e381SAndroid Build Coastguard Worker 
1391*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(!address.IsLinkLocal() && !address.IsMulticast() && !address.IsLoopback() && !address.IsUnspecified(),
1392*4a64e381SAndroid Build Coastguard Worker                  avahiError = AVAHI_ERR_INVALID_ADDRESS);
1393*4a64e381SAndroid Build Coastguard Worker     otbrLogInfo("Resolved host address: %s %s", aEvent == AVAHI_BROWSER_NEW ? "add" : "remove",
1394*4a64e381SAndroid Build Coastguard Worker                 address.ToString().c_str());
1395*4a64e381SAndroid Build Coastguard Worker     if (aEvent == AVAHI_BROWSER_NEW)
1396*4a64e381SAndroid Build Coastguard Worker     {
1397*4a64e381SAndroid Build Coastguard Worker         mInstanceInfo.AddAddress(address);
1398*4a64e381SAndroid Build Coastguard Worker     }
1399*4a64e381SAndroid Build Coastguard Worker     else
1400*4a64e381SAndroid Build Coastguard Worker     {
1401*4a64e381SAndroid Build Coastguard Worker         mInstanceInfo.RemoveAddress(address);
1402*4a64e381SAndroid Build Coastguard Worker     }
1403*4a64e381SAndroid Build Coastguard Worker     resolved = true;
1404*4a64e381SAndroid Build Coastguard Worker 
1405*4a64e381SAndroid Build Coastguard Worker exit:
1406*4a64e381SAndroid Build Coastguard Worker     if (resolved)
1407*4a64e381SAndroid Build Coastguard Worker     {
1408*4a64e381SAndroid Build Coastguard Worker         // NOTE: This `HostSubscrption` object may be freed in `OnHostResolved`.
1409*4a64e381SAndroid Build Coastguard Worker         mPublisherAvahi->OnServiceResolved(mType, mInstanceInfo);
1410*4a64e381SAndroid Build Coastguard Worker     }
1411*4a64e381SAndroid Build Coastguard Worker     else if (avahiError != AVAHI_OK)
1412*4a64e381SAndroid Build Coastguard Worker     {
1413*4a64e381SAndroid Build Coastguard Worker         mPublisherAvahi->OnServiceResolveFailed(mType, mInstanceInfo.mName, avahiError);
1414*4a64e381SAndroid Build Coastguard Worker     }
1415*4a64e381SAndroid Build Coastguard Worker }
1416*4a64e381SAndroid Build Coastguard Worker 
AddServiceResolver(const std::string & aInstanceName,ServiceResolver * aServiceResolver)1417*4a64e381SAndroid Build Coastguard Worker void PublisherAvahi::ServiceSubscription::AddServiceResolver(const std::string &aInstanceName,
1418*4a64e381SAndroid Build Coastguard Worker                                                              ServiceResolver   *aServiceResolver)
1419*4a64e381SAndroid Build Coastguard Worker {
1420*4a64e381SAndroid Build Coastguard Worker     assert(aServiceResolver != nullptr);
1421*4a64e381SAndroid Build Coastguard Worker     mServiceResolvers[aInstanceName].insert(aServiceResolver);
1422*4a64e381SAndroid Build Coastguard Worker 
1423*4a64e381SAndroid Build Coastguard Worker     otbrLogDebug("Added service resolver for instance %s", aInstanceName.c_str());
1424*4a64e381SAndroid Build Coastguard Worker }
1425*4a64e381SAndroid Build Coastguard Worker 
RemoveServiceResolver(const std::string & aInstanceName)1426*4a64e381SAndroid Build Coastguard Worker void PublisherAvahi::ServiceSubscription::RemoveServiceResolver(const std::string &aInstanceName)
1427*4a64e381SAndroid Build Coastguard Worker {
1428*4a64e381SAndroid Build Coastguard Worker     int numResolvers = 0;
1429*4a64e381SAndroid Build Coastguard Worker 
1430*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(mServiceResolvers.find(aInstanceName) != mServiceResolvers.end());
1431*4a64e381SAndroid Build Coastguard Worker 
1432*4a64e381SAndroid Build Coastguard Worker     numResolvers = mServiceResolvers[aInstanceName].size();
1433*4a64e381SAndroid Build Coastguard Worker 
1434*4a64e381SAndroid Build Coastguard Worker     for (auto resolver : mServiceResolvers[aInstanceName])
1435*4a64e381SAndroid Build Coastguard Worker     {
1436*4a64e381SAndroid Build Coastguard Worker         delete resolver;
1437*4a64e381SAndroid Build Coastguard Worker     }
1438*4a64e381SAndroid Build Coastguard Worker 
1439*4a64e381SAndroid Build Coastguard Worker     mServiceResolvers.erase(aInstanceName);
1440*4a64e381SAndroid Build Coastguard Worker 
1441*4a64e381SAndroid Build Coastguard Worker exit:
1442*4a64e381SAndroid Build Coastguard Worker     otbrLogDebug("Removed %d service resolver for instance %s", numResolvers, aInstanceName.c_str());
1443*4a64e381SAndroid Build Coastguard Worker     return;
1444*4a64e381SAndroid Build Coastguard Worker }
1445*4a64e381SAndroid Build Coastguard Worker 
Release(void)1446*4a64e381SAndroid Build Coastguard Worker void PublisherAvahi::HostSubscription::Release(void)
1447*4a64e381SAndroid Build Coastguard Worker {
1448*4a64e381SAndroid Build Coastguard Worker     if (mRecordBrowser != nullptr)
1449*4a64e381SAndroid Build Coastguard Worker     {
1450*4a64e381SAndroid Build Coastguard Worker         avahi_record_browser_free(mRecordBrowser);
1451*4a64e381SAndroid Build Coastguard Worker         mRecordBrowser = nullptr;
1452*4a64e381SAndroid Build Coastguard Worker     }
1453*4a64e381SAndroid Build Coastguard Worker }
1454*4a64e381SAndroid Build Coastguard Worker 
Resolve(void)1455*4a64e381SAndroid Build Coastguard Worker void PublisherAvahi::HostSubscription::Resolve(void)
1456*4a64e381SAndroid Build Coastguard Worker {
1457*4a64e381SAndroid Build Coastguard Worker     std::string fullHostName = MakeFullHostName(mHostName);
1458*4a64e381SAndroid Build Coastguard Worker 
1459*4a64e381SAndroid Build Coastguard Worker     mPublisherAvahi->mHostResolutionBeginTime[mHostName] = Clock::now();
1460*4a64e381SAndroid Build Coastguard Worker 
1461*4a64e381SAndroid Build Coastguard Worker     otbrLogInfo("Resolve host %s inf %d", fullHostName.c_str(), static_cast<int>(AVAHI_IF_UNSPEC));
1462*4a64e381SAndroid Build Coastguard Worker     mRecordBrowser = avahi_record_browser_new(mPublisherAvahi->mClient, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC,
1463*4a64e381SAndroid Build Coastguard Worker                                               fullHostName.c_str(), AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_AAAA,
1464*4a64e381SAndroid Build Coastguard Worker                                               static_cast<AvahiLookupFlags>(0), HandleResolveResult, this);
1465*4a64e381SAndroid Build Coastguard Worker     if (!mRecordBrowser)
1466*4a64e381SAndroid Build Coastguard Worker     {
1467*4a64e381SAndroid Build Coastguard Worker         otbrLogErr("Failed to resolve host %s: %s", fullHostName.c_str(),
1468*4a64e381SAndroid Build Coastguard Worker                    avahi_strerror(avahi_client_errno(mPublisherAvahi->mClient)));
1469*4a64e381SAndroid Build Coastguard Worker     }
1470*4a64e381SAndroid Build Coastguard Worker }
1471*4a64e381SAndroid Build Coastguard Worker 
HandleResolveResult(AvahiRecordBrowser * aRecordBrowser,AvahiIfIndex aInterfaceIndex,AvahiProtocol aProtocol,AvahiBrowserEvent aEvent,const char * aName,uint16_t aClazz,uint16_t aType,const void * aRdata,size_t aSize,AvahiLookupResultFlags aFlags,void * aContext)1472*4a64e381SAndroid Build Coastguard Worker void PublisherAvahi::HostSubscription::HandleResolveResult(AvahiRecordBrowser    *aRecordBrowser,
1473*4a64e381SAndroid Build Coastguard Worker                                                            AvahiIfIndex           aInterfaceIndex,
1474*4a64e381SAndroid Build Coastguard Worker                                                            AvahiProtocol          aProtocol,
1475*4a64e381SAndroid Build Coastguard Worker                                                            AvahiBrowserEvent      aEvent,
1476*4a64e381SAndroid Build Coastguard Worker                                                            const char            *aName,
1477*4a64e381SAndroid Build Coastguard Worker                                                            uint16_t               aClazz,
1478*4a64e381SAndroid Build Coastguard Worker                                                            uint16_t               aType,
1479*4a64e381SAndroid Build Coastguard Worker                                                            const void            *aRdata,
1480*4a64e381SAndroid Build Coastguard Worker                                                            size_t                 aSize,
1481*4a64e381SAndroid Build Coastguard Worker                                                            AvahiLookupResultFlags aFlags,
1482*4a64e381SAndroid Build Coastguard Worker                                                            void                  *aContext)
1483*4a64e381SAndroid Build Coastguard Worker {
1484*4a64e381SAndroid Build Coastguard Worker     static_cast<PublisherAvahi::HostSubscription *>(aContext)->HandleResolveResult(
1485*4a64e381SAndroid Build Coastguard Worker         aRecordBrowser, aInterfaceIndex, aProtocol, aEvent, aName, aClazz, aType, aRdata, aSize, aFlags);
1486*4a64e381SAndroid Build Coastguard Worker }
1487*4a64e381SAndroid Build Coastguard Worker 
HandleResolveResult(AvahiRecordBrowser * aRecordBrowser,AvahiIfIndex aInterfaceIndex,AvahiProtocol aProtocol,AvahiBrowserEvent aEvent,const char * aName,uint16_t aClazz,uint16_t aType,const void * aRdata,size_t aSize,AvahiLookupResultFlags aFlags)1488*4a64e381SAndroid Build Coastguard Worker void PublisherAvahi::HostSubscription::HandleResolveResult(AvahiRecordBrowser    *aRecordBrowser,
1489*4a64e381SAndroid Build Coastguard Worker                                                            AvahiIfIndex           aInterfaceIndex,
1490*4a64e381SAndroid Build Coastguard Worker                                                            AvahiProtocol          aProtocol,
1491*4a64e381SAndroid Build Coastguard Worker                                                            AvahiBrowserEvent      aEvent,
1492*4a64e381SAndroid Build Coastguard Worker                                                            const char            *aName,
1493*4a64e381SAndroid Build Coastguard Worker                                                            uint16_t               aClazz,
1494*4a64e381SAndroid Build Coastguard Worker                                                            uint16_t               aType,
1495*4a64e381SAndroid Build Coastguard Worker                                                            const void            *aRdata,
1496*4a64e381SAndroid Build Coastguard Worker                                                            size_t                 aSize,
1497*4a64e381SAndroid Build Coastguard Worker                                                            AvahiLookupResultFlags aFlags)
1498*4a64e381SAndroid Build Coastguard Worker {
1499*4a64e381SAndroid Build Coastguard Worker     OTBR_UNUSED_VARIABLE(aRecordBrowser);
1500*4a64e381SAndroid Build Coastguard Worker     OTBR_UNUSED_VARIABLE(aProtocol);
1501*4a64e381SAndroid Build Coastguard Worker     OTBR_UNUSED_VARIABLE(aEvent);
1502*4a64e381SAndroid Build Coastguard Worker     OTBR_UNUSED_VARIABLE(aClazz);
1503*4a64e381SAndroid Build Coastguard Worker     OTBR_UNUSED_VARIABLE(aType);
1504*4a64e381SAndroid Build Coastguard Worker     OTBR_UNUSED_VARIABLE(aFlags);
1505*4a64e381SAndroid Build Coastguard Worker 
1506*4a64e381SAndroid Build Coastguard Worker     Ip6Address address;
1507*4a64e381SAndroid Build Coastguard Worker     bool       resolved   = false;
1508*4a64e381SAndroid Build Coastguard Worker     int        avahiError = AVAHI_OK;
1509*4a64e381SAndroid Build Coastguard Worker 
1510*4a64e381SAndroid Build Coastguard Worker     otbrLog(aEvent != AVAHI_BROWSER_FAILURE ? OTBR_LOG_INFO : OTBR_LOG_WARNING, OTBR_LOG_TAG,
1511*4a64e381SAndroid Build Coastguard Worker             "Resolve host reply: %s inf %d protocol %d class %" PRIu16 " type %" PRIu16 " size %zu flags %d event %d",
1512*4a64e381SAndroid Build Coastguard Worker             aName, aInterfaceIndex, aProtocol, aClazz, aType, aSize, static_cast<int>(aFlags),
1513*4a64e381SAndroid Build Coastguard Worker             static_cast<int>(aEvent));
1514*4a64e381SAndroid Build Coastguard Worker 
1515*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(aEvent == AVAHI_BROWSER_NEW || aEvent == AVAHI_BROWSER_REMOVE);
1516*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(aSize == OTBR_IP6_ADDRESS_SIZE || aSize == OTBR_IP4_ADDRESS_SIZE,
1517*4a64e381SAndroid Build Coastguard Worker                  otbrLogErr("Unexpected address data length: %zu", aSize), avahiError = AVAHI_ERR_INVALID_ADDRESS);
1518*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(aSize == OTBR_IP6_ADDRESS_SIZE, otbrLogInfo("IPv4 address ignored"),
1519*4a64e381SAndroid Build Coastguard Worker                  avahiError = AVAHI_ERR_INVALID_ADDRESS);
1520*4a64e381SAndroid Build Coastguard Worker     address = Ip6Address(*static_cast<const uint8_t(*)[OTBR_IP6_ADDRESS_SIZE]>(aRdata));
1521*4a64e381SAndroid Build Coastguard Worker 
1522*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(!address.IsLinkLocal() && !address.IsMulticast() && !address.IsLoopback() && !address.IsUnspecified(),
1523*4a64e381SAndroid Build Coastguard Worker                  avahiError = AVAHI_ERR_INVALID_ADDRESS);
1524*4a64e381SAndroid Build Coastguard Worker     otbrLogInfo("Resolved host address: %s %s", aEvent == AVAHI_BROWSER_NEW ? "add" : "remove",
1525*4a64e381SAndroid Build Coastguard Worker                 address.ToString().c_str());
1526*4a64e381SAndroid Build Coastguard Worker 
1527*4a64e381SAndroid Build Coastguard Worker     mHostInfo.mHostName = std::string(aName) + ".";
1528*4a64e381SAndroid Build Coastguard Worker     if (aEvent == AVAHI_BROWSER_NEW)
1529*4a64e381SAndroid Build Coastguard Worker     {
1530*4a64e381SAndroid Build Coastguard Worker         mHostInfo.AddAddress(address);
1531*4a64e381SAndroid Build Coastguard Worker     }
1532*4a64e381SAndroid Build Coastguard Worker     else
1533*4a64e381SAndroid Build Coastguard Worker     {
1534*4a64e381SAndroid Build Coastguard Worker         mHostInfo.RemoveAddress(address);
1535*4a64e381SAndroid Build Coastguard Worker     }
1536*4a64e381SAndroid Build Coastguard Worker     mHostInfo.mNetifIndex = static_cast<uint32_t>(aInterfaceIndex);
1537*4a64e381SAndroid Build Coastguard Worker     // TODO: Use a more proper TTL
1538*4a64e381SAndroid Build Coastguard Worker     mHostInfo.mTtl = kDefaultTtl;
1539*4a64e381SAndroid Build Coastguard Worker     resolved       = true;
1540*4a64e381SAndroid Build Coastguard Worker 
1541*4a64e381SAndroid Build Coastguard Worker exit:
1542*4a64e381SAndroid Build Coastguard Worker     if (resolved)
1543*4a64e381SAndroid Build Coastguard Worker     {
1544*4a64e381SAndroid Build Coastguard Worker         // NOTE: This `HostSubscrption` object may be freed in `OnHostResolved`.
1545*4a64e381SAndroid Build Coastguard Worker         mPublisherAvahi->OnHostResolved(mHostName, mHostInfo);
1546*4a64e381SAndroid Build Coastguard Worker     }
1547*4a64e381SAndroid Build Coastguard Worker     else if (avahiError != AVAHI_OK)
1548*4a64e381SAndroid Build Coastguard Worker     {
1549*4a64e381SAndroid Build Coastguard Worker         mPublisherAvahi->OnHostResolveFailed(mHostName, avahiError);
1550*4a64e381SAndroid Build Coastguard Worker     }
1551*4a64e381SAndroid Build Coastguard Worker }
1552*4a64e381SAndroid Build Coastguard Worker 
1553*4a64e381SAndroid Build Coastguard Worker } // namespace Mdns
1554*4a64e381SAndroid Build Coastguard Worker 
1555*4a64e381SAndroid Build Coastguard Worker } // namespace otbr
1556