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