1 /* 2 * Copyright (c) 2017, The OpenThread Authors. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 3. Neither the name of the copyright holder nor the 13 * names of its contributors may be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /** 30 * @file 31 * This file includes definition for mDNS publisher based on avahi. 32 */ 33 34 #ifndef OTBR_AGENT_MDNS_AVAHI_HPP_ 35 #define OTBR_AGENT_MDNS_AVAHI_HPP_ 36 37 #include <memory> 38 #include <set> 39 #include <vector> 40 41 #include <avahi-client/client.h> 42 #include <avahi-client/lookup.h> 43 #include <avahi-client/publish.h> 44 #include <avahi-common/domain.h> 45 #include <avahi-common/watch.h> 46 47 #include "mdns.hpp" 48 #include "common/code_utils.hpp" 49 #include "common/mainloop.hpp" 50 #include "common/time.hpp" 51 52 /** 53 * @addtogroup border-router-mdns 54 * 55 * @brief 56 * This module includes definition for avahi-based mDNS publisher. 57 * 58 * @{ 59 */ 60 61 namespace otbr { 62 63 namespace Mdns { 64 65 class AvahiPoller; 66 67 /** 68 * This class implements mDNS publisher with avahi. 69 * 70 */ 71 class PublisherAvahi : public Publisher 72 { 73 public: 74 PublisherAvahi(StateCallback aStateCallback); 75 ~PublisherAvahi(void) override; 76 77 void UnpublishService(const std::string &aName, const std::string &aType, ResultCallback &&aCallback) override; 78 void UnpublishHost(const std::string &aName, ResultCallback &&aCallback) override; 79 void SubscribeService(const std::string &aType, const std::string &aInstanceName) override; 80 void UnsubscribeService(const std::string &aType, const std::string &aInstanceName) override; 81 void SubscribeHost(const std::string &aHostName) override; 82 void UnsubscribeHost(const std::string &aHostName) override; 83 otbrError Start(void) override; 84 bool IsStarted(void) const override; 85 void Stop(void) override; 86 87 protected: 88 void PublishServiceImpl(const std::string &aHostName, 89 const std::string &aName, 90 const std::string &aType, 91 const SubTypeList &aSubTypeList, 92 uint16_t aPort, 93 const TxtList & aTxtList, 94 ResultCallback && aCallback) override; 95 void PublishHostImpl(const std::string & aName, 96 const std::vector<uint8_t> &aAddress, 97 ResultCallback && aCallback) override; 98 void OnServiceResolveFailedImpl(const std::string &aType, 99 const std::string &aInstanceName, 100 int32_t aErrorCode) override; 101 void OnHostResolveFailedImpl(const std::string &aHostName, int32_t aErrorCode) override; 102 otbrError DnsErrorToOtbrError(int32_t aErrorCode) override; 103 104 private: 105 static constexpr size_t kMaxSizeOfTxtRecord = 1024; 106 static constexpr uint32_t kDefaultTtl = 10; // In seconds. 107 108 class AvahiServiceRegistration : public ServiceRegistration 109 { 110 public: AvahiServiceRegistration(const std::string & aHostName,const std::string & aName,const std::string & aType,const SubTypeList & aSubTypeList,uint16_t aPort,const TxtList & aTxtList,ResultCallback && aCallback,AvahiEntryGroup * aEntryGroup,PublisherAvahi * aPublisher)111 AvahiServiceRegistration(const std::string &aHostName, 112 const std::string &aName, 113 const std::string &aType, 114 const SubTypeList &aSubTypeList, 115 uint16_t aPort, 116 const TxtList & aTxtList, 117 ResultCallback && aCallback, 118 AvahiEntryGroup * aEntryGroup, 119 PublisherAvahi * aPublisher) 120 : ServiceRegistration(aHostName, 121 aName, 122 aType, 123 aSubTypeList, 124 aPort, 125 aTxtList, 126 std::move(aCallback), 127 aPublisher) 128 , mEntryGroup(aEntryGroup) 129 { 130 } 131 132 ~AvahiServiceRegistration(void) override; GetEntryGroup(void) const133 const AvahiEntryGroup *GetEntryGroup(void) const { return mEntryGroup; } 134 135 private: 136 AvahiEntryGroup *mEntryGroup; 137 }; 138 139 class AvahiHostRegistration : public HostRegistration 140 { 141 public: AvahiHostRegistration(const std::string & aName,const std::vector<uint8_t> & aAddress,ResultCallback && aCallback,AvahiEntryGroup * aEntryGroup,PublisherAvahi * aPublisher)142 AvahiHostRegistration(const std::string & aName, 143 const std::vector<uint8_t> &aAddress, 144 ResultCallback && aCallback, 145 AvahiEntryGroup * aEntryGroup, 146 PublisherAvahi * aPublisher) 147 : HostRegistration(aName, aAddress, std::move(aCallback), aPublisher) 148 , mEntryGroup(aEntryGroup) 149 { 150 } 151 152 ~AvahiHostRegistration(void) override; GetEntryGroup(void) const153 const AvahiEntryGroup *GetEntryGroup(void) const { return mEntryGroup; } 154 155 private: 156 AvahiEntryGroup *mEntryGroup; 157 }; 158 159 struct Subscription : private ::NonCopyable 160 { 161 PublisherAvahi *mPublisherAvahi; 162 Subscriptionotbr::Mdns::PublisherAvahi::Subscription163 explicit Subscription(PublisherAvahi &aPublisherAvahi) 164 : mPublisherAvahi(&aPublisherAvahi) 165 { 166 } 167 }; 168 169 struct ServiceSubscription : public Subscription 170 { ServiceSubscriptionotbr::Mdns::PublisherAvahi::ServiceSubscription171 explicit ServiceSubscription(PublisherAvahi &aPublisherAvahi, std::string aType, std::string aInstanceName) 172 : Subscription(aPublisherAvahi) 173 , mType(std::move(aType)) 174 , mInstanceName(std::move(aInstanceName)) 175 , mServiceBrowser(nullptr) 176 { 177 } 178 ~ServiceSubscriptionotbr::Mdns::PublisherAvahi::ServiceSubscription179 ~ServiceSubscription() { Release(); } 180 181 void Release(void); 182 void Browse(void); 183 void Resolve(uint32_t aInterfaceIndex, 184 AvahiProtocol aProtocol, 185 const std::string &aInstanceName, 186 const std::string &aType); 187 void AddServiceResolver(AvahiServiceResolver *aServiceResolver); 188 void RemoveServiceResolver(AvahiServiceResolver *aServiceResolver); 189 190 static void HandleBrowseResult(AvahiServiceBrowser * aServiceBrowser, 191 AvahiIfIndex aInterfaceIndex, 192 AvahiProtocol aProtocol, 193 AvahiBrowserEvent aEvent, 194 const char * aName, 195 const char * aType, 196 const char * aDomain, 197 AvahiLookupResultFlags aFlags, 198 void * aContext); 199 200 void HandleBrowseResult(AvahiServiceBrowser * aServiceBrowser, 201 AvahiIfIndex aInterfaceIndex, 202 AvahiProtocol aProtocol, 203 AvahiBrowserEvent aEvent, 204 const char * aName, 205 const char * aType, 206 const char * aDomain, 207 AvahiLookupResultFlags aFlags); 208 209 static void HandleResolveResult(AvahiServiceResolver * aServiceResolver, 210 AvahiIfIndex aInterfaceIndex, 211 AvahiProtocol Protocol, 212 AvahiResolverEvent aEvent, 213 const char * aName, 214 const char * aType, 215 const char * aDomain, 216 const char * aHostName, 217 const AvahiAddress * aAddress, 218 uint16_t aPort, 219 AvahiStringList * aTxt, 220 AvahiLookupResultFlags aFlags, 221 void * aContext); 222 223 void HandleResolveResult(AvahiServiceResolver * aServiceResolver, 224 AvahiIfIndex aInterfaceIndex, 225 AvahiProtocol Protocol, 226 AvahiResolverEvent aEvent, 227 const char * aName, 228 const char * aType, 229 const char * aDomain, 230 const char * aHostName, 231 const AvahiAddress * aAddress, 232 uint16_t aPort, 233 AvahiStringList * aTxt, 234 AvahiLookupResultFlags aFlags); 235 236 std::string mType; 237 std::string mInstanceName; 238 AvahiServiceBrowser * mServiceBrowser; 239 std::set<AvahiServiceResolver *> mServiceResolvers; 240 }; 241 242 struct HostSubscription : public Subscription 243 { HostSubscriptionotbr::Mdns::PublisherAvahi::HostSubscription244 explicit HostSubscription(PublisherAvahi &aAvahiPublisher, std::string aHostName) 245 : Subscription(aAvahiPublisher) 246 , mHostName(std::move(aHostName)) 247 , mRecordBrowser(nullptr) 248 { 249 } 250 ~HostSubscriptionotbr::Mdns::PublisherAvahi::HostSubscription251 ~HostSubscription() { Release(); } 252 253 void Release(void); 254 void Resolve(void); 255 static void HandleResolveResult(AvahiRecordBrowser * aRecordBrowser, 256 AvahiIfIndex aInterfaceIndex, 257 AvahiProtocol aProtocol, 258 AvahiBrowserEvent aEvent, 259 const char * aName, 260 uint16_t aClazz, 261 uint16_t aType, 262 const void * aRdata, 263 size_t aSize, 264 AvahiLookupResultFlags aFlags, 265 void * aContext); 266 267 void HandleResolveResult(AvahiRecordBrowser * aRecordBrowser, 268 AvahiIfIndex aInterfaceIndex, 269 AvahiProtocol aProtocol, 270 AvahiBrowserEvent aEvent, 271 const char * aName, 272 uint16_t aClazz, 273 uint16_t aType, 274 const void * aRdata, 275 size_t aSize, 276 AvahiLookupResultFlags aFlags); 277 278 std::string mHostName; 279 DiscoveredHostInfo mHostInfo; 280 AvahiRecordBrowser *mRecordBrowser; 281 }; 282 283 typedef std::vector<std::unique_ptr<ServiceSubscription>> ServiceSubscriptionList; 284 typedef std::vector<std::unique_ptr<HostSubscription>> HostSubscriptionList; 285 286 static void HandleClientState(AvahiClient *aClient, AvahiClientState aState, void *aContext); 287 void HandleClientState(AvahiClient *aClient, AvahiClientState aState); 288 289 AvahiEntryGroup *CreateGroup(AvahiClient *aClient); 290 static void ReleaseGroup(AvahiEntryGroup *aGroup); 291 292 static void HandleGroupState(AvahiEntryGroup *aGroup, AvahiEntryGroupState aState, void *aContext); 293 void HandleGroupState(AvahiEntryGroup *aGroup, AvahiEntryGroupState aState); 294 void CallHostOrServiceCallback(AvahiEntryGroup *aGroup, otbrError aError); 295 296 static otbrError TxtListToAvahiStringList(const TxtList & aTxtList, 297 AvahiStringList * aBuffer, 298 size_t aBufferSize, 299 AvahiStringList *&aHead); 300 301 ServiceRegistration *FindServiceRegistration(const AvahiEntryGroup *aEntryGroup); 302 HostRegistration * FindHostRegistration(const AvahiEntryGroup *aEntryGroup); 303 304 AvahiClient * mClient; 305 std::unique_ptr<AvahiPoller> mPoller; 306 State mState; 307 StateCallback mStateCallback; 308 309 ServiceSubscriptionList mSubscribedServices; 310 HostSubscriptionList mSubscribedHosts; 311 }; 312 313 } // namespace Mdns 314 315 } // namespace otbr 316 317 /** 318 * @} 319 */ 320 #endif // OTBR_AGENT_MDNS_AVAHI_HPP_ 321