/* * Copyright (c) 2024, The OpenThread Authors. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holder nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef OTBR_ANDROID_MDNS_PUBLISHER_HPP_ #define OTBR_ANDROID_MDNS_PUBLISHER_HPP_ #include "mdns/mdns.hpp" #include #include #include #include #include #include #include namespace otbr { namespace Android { using Status = ::ndk::ScopedAStatus; using aidl::com::android::server::thread::openthread::BnNsdDiscoverServiceCallback; using aidl::com::android::server::thread::openthread::BnNsdResolveHostCallback; using aidl::com::android::server::thread::openthread::BnNsdResolveServiceCallback; using aidl::com::android::server::thread::openthread::BnNsdStatusReceiver; using aidl::com::android::server::thread::openthread::DnsTxtAttribute; using aidl::com::android::server::thread::openthread::INsdPublisher; class MdnsPublisher : public Mdns::Publisher { public: explicit MdnsPublisher(Publisher::StateCallback aCallback) : mStateCallback(std::move(aCallback)) , mNextListenerId(0) { } ~MdnsPublisher(void) { Stop(); } /** Sets the INsdPublisher which forwards the mDNS API requests to the NsdManager in system_server. */ void SetINsdPublisher(std::shared_ptr aINsdPublisher); otbrError Start(void) override { return OTBR_ERROR_NONE; } void Stop(void) override { mServiceRegistrations.clear(); mHostRegistrations.clear(); if (mNsdPublisher != nullptr) { mNsdPublisher->reset(); } } bool IsStarted(void) const override { return mNsdPublisher != nullptr; } void UnpublishService(const std::string &aName, const std::string &aType, ResultCallback &&aCallback) override; void UnpublishHost(const std::string &aName, ResultCallback &&aCallback) override; void UnpublishKey(const std::string &aName, ResultCallback &&aCallback) override; void SubscribeService(const std::string &aType, const std::string &aInstanceName) override; void UnsubscribeService(const std::string &aType, const std::string &aInstanceName) override; void SubscribeHost(const std::string &aHostName) override; void UnsubscribeHost(const std::string &aHostName) override; class NsdStatusReceiver : public BnNsdStatusReceiver { public: explicit NsdStatusReceiver(Mdns::Publisher::ResultCallback aCallback) : mCallback(std::move(aCallback)) { } Status onSuccess(void) override; Status onError(int aError) override; private: Mdns::Publisher::ResultCallback mCallback; }; struct ServiceResolver : private ::NonCopyable { explicit ServiceResolver(int aListenerId, std::shared_ptr aNsdPublisher) : mListenerId(aListenerId) , mNsdPublisher(std::move(aNsdPublisher)) { } ~ServiceResolver(void) { if (mNsdPublisher) { mNsdPublisher->stopServiceResolution(mListenerId); } } int mListenerId; std::shared_ptr mNsdPublisher; }; struct ServiceSubscription : public std::enable_shared_from_this, private ::NonCopyable { explicit ServiceSubscription(std::string aType, std::string aName, MdnsPublisher &aPublisher, std::shared_ptr aNsdPublisher) : mType(std::move(aType)) , mName(std::move(aName)) , mPublisher(aPublisher) , mNsdPublisher(std::move(aNsdPublisher)) , mBrowseListenerId(-1) { } ~ServiceSubscription(void) { Release(); } void Release(void); void Browse(void); void Resolve(const std::string &aName, const std::string &aType); void AddServiceResolver(const std::string &aName, ServiceResolver *aResolver); void RemoveServiceResolver(const std::string &aInstanceName); std::string mType; std::string mName; MdnsPublisher &mPublisher; std::shared_ptr mNsdPublisher; int32_t mBrowseListenerId; std::map> mResolvers; }; struct HostSubscription : private ::NonCopyable { explicit HostSubscription(std::string aName, MdnsPublisher &aPublisher, std::shared_ptr aNsdPublisher, int listenerId) : mName(std::move(aName)) , mPublisher(aPublisher) , mNsdPublisher(std::move(aNsdPublisher)) , mListenerId(listenerId) { } ~HostSubscription(void) { Release(); } void Release(void) { mNsdPublisher->stopHostResolution(mListenerId); } std::string mName; MdnsPublisher &mPublisher; std::shared_ptr mNsdPublisher; const int32_t mListenerId; }; class NsdDiscoverServiceCallback : public BnNsdDiscoverServiceCallback { public: explicit NsdDiscoverServiceCallback(std::weak_ptr aSubscription) : mSubscription(std::move(aSubscription)) { } Status onServiceDiscovered(const std::string &aName, const std::string &aType, bool aIsFound); private: std::weak_ptr mSubscription; }; class NsdResolveServiceCallback : public BnNsdResolveServiceCallback { public: explicit NsdResolveServiceCallback(std::weak_ptr aSubscription) : mSubscription(std::move(aSubscription)) { } Status onServiceResolved(const std::string &aHostname, int aNetifIndex, const std::string &aName, const std::string &aType, int aPort, const std::vector &aAddresses, const std::vector &aTxt, int aTtlSeconds); private: std::weak_ptr mSubscription; }; class NsdResolveHostCallback : public BnNsdResolveHostCallback { public: explicit NsdResolveHostCallback(std::weak_ptr aSubscription) : mSubscription(std::move(aSubscription)) { } Status onHostResolved(const std::string &aName, const std::vector &aAddresses); private: std::weak_ptr mSubscription; }; protected: otbrError PublishServiceImpl(const std::string &aHostName, const std::string &aName, const std::string &aType, const SubTypeList &aSubTypeList, uint16_t aPort, const TxtData &aTxtData, ResultCallback &&aCallback) override; otbrError PublishHostImpl(const std::string &aName, const AddressList &aAddresses, ResultCallback &&aCallback); otbrError PublishKeyImpl(const std::string &aName, const KeyData &aKeyData, ResultCallback &&aCallback) override; void OnServiceResolveFailedImpl(const std::string &aType, const std::string &aInstanceName, int32_t aErrorCode); void OnHostResolveFailedImpl(const std::string &aHostName, int32_t aErrorCode); otbrError DnsErrorToOtbrError(int32_t aError); private: class NsdServiceRegistration : public ServiceRegistration { public: NsdServiceRegistration(const std::string &aHostName, const std::string &aName, const std::string &aType, const SubTypeList &aSubTypeList, uint16_t aPort, const TxtData &aTxtData, ResultCallback &&aCallback, MdnsPublisher *aPublisher, int32_t aListenerId, std::weak_ptr aINsdPublisher) : ServiceRegistration(aHostName, aName, aType, aSubTypeList, aPort, aTxtData, std::move(aCallback), aPublisher) , mListenerId(aListenerId) , mNsdPublisher(std::move(aINsdPublisher)) { } ~NsdServiceRegistration(void) override; const int32_t mListenerId; std::shared_ptr mUnregisterReceiver; private: std::weak_ptr mNsdPublisher; }; class NsdHostRegistration : public HostRegistration { public: NsdHostRegistration(const std::string &aName, const AddressList &aAddresses, ResultCallback &&aCallback, MdnsPublisher *aPublisher, int32_t aListenerId, std::weak_ptr aINsdPublisher) : HostRegistration(aName, aAddresses, std::move(aCallback), aPublisher) , mListenerId(aListenerId) , mNsdPublisher(aINsdPublisher) { } ~NsdHostRegistration(void) override; const int32_t mListenerId; std::shared_ptr mUnregisterReceiver; private: std::weak_ptr mNsdPublisher; }; typedef std::vector> ServiceSubscriptionList; typedef std::vector> HostSubscriptionList; static constexpr int kDefaultResolvedTtl = 10; static constexpr int kMinResolvedTtl = 1; static constexpr int kMaxResolvedTtl = 10; int32_t AllocateListenerId(void); StateCallback mStateCallback; int32_t mNextListenerId; std::shared_ptr mNsdPublisher = nullptr; ServiceSubscriptionList mServiceSubscriptions; HostSubscriptionList mHostSubscriptions; }; } // namespace Android } // namespace otbr #endif // OTBR_ANDROID_MDNS_PUBLISHER_HPP_