diff options
Diffstat (limited to 'src/mdns/mdns_avahi.hpp')
-rw-r--r-- | src/mdns/mdns_avahi.hpp | 459 |
1 files changed, 111 insertions, 348 deletions
diff --git a/src/mdns/mdns_avahi.hpp b/src/mdns/mdns_avahi.hpp index 1eea53d5..efd7e940 100644 --- a/src/mdns/mdns_avahi.hpp +++ b/src/mdns/mdns_avahi.hpp @@ -28,12 +28,14 @@ /** * @file - * This file includes definition for mDNS service based on avahi. + * This file includes definition for mDNS publisher based on avahi. */ #ifndef OTBR_AGENT_MDNS_AVAHI_HPP_ #define OTBR_AGENT_MDNS_AVAHI_HPP_ +#include <memory> +#include <set> #include <vector> #include <avahi-client/client.h> @@ -43,6 +45,7 @@ #include <avahi-common/watch.h> #include "mdns.hpp" +#include "common/code_utils.hpp" #include "common/mainloop.hpp" #include "common/time.hpp" @@ -50,327 +53,110 @@ * @addtogroup border-router-mdns * * @brief - * This module includes definition for avahi-based mDNS service. + * This module includes definition for avahi-based mDNS publisher. * * @{ */ -/** - * This structure implements AvahiWatch. - * - */ -struct AvahiWatch -{ - int mFd; ///< The file descriptor to watch. - AvahiWatchEvent mEvents; ///< The interested events. - int mHappened; ///< The events happened. - AvahiWatchCallback mCallback; ///< The function to be called when interested events happened on mFd. - void * mContext; ///< A pointer to application-specific context. - void * mPoller; ///< The poller created this watch. - - /** - * The constructor to initialize an Avahi watch. - * - * @param[in] aFd The file descriptor to watch. - * @param[in] aEvents The events to watch. - * @param[in] aCallback The function to be called when events happend on this file descriptor. - * @param[in] aContext A pointer to application-specific context. - * @param[in] aPoller The Poller this watcher belongs to. - * - */ - AvahiWatch(int aFd, AvahiWatchEvent aEvents, AvahiWatchCallback aCallback, void *aContext, void *aPoller) - : mFd(aFd) - , mEvents(aEvents) - , mCallback(aCallback) - , mContext(aContext) - , mPoller(aPoller) - { - } -}; - -/** - * This structure implements the AvahiTimeout. - * - */ -struct AvahiTimeout -{ - otbr::Timepoint mTimeout; ///< Absolute time when this timer timeout. - AvahiTimeoutCallback mCallback; ///< The function to be called when timeout. - void * mContext; ///< The pointer to application-specific context. - void * mPoller; ///< The poller created this timer. - - /** - * The constructor to initialize an AvahiTimeout. - * - * @param[in] aTimeout A pointer to the time after which the callback should be called. - * @param[in] aCallback The function to be called after timeout. - * @param[in] aContext A pointer to application-specific context. - * @param[in] aPoller The Poller this timeout belongs to. - * - */ - AvahiTimeout(const struct timeval *aTimeout, AvahiTimeoutCallback aCallback, void *aContext, void *aPoller); -}; - namespace otbr { namespace Mdns { -/** - * This class implements the AvahiPoll. - * - */ -class Poller : public MainloopProcessor -{ -public: - /** - * The constructor to initialize a Poller. - * - */ - Poller(void); - - /** - * This method updates the mainloop context. - * - * @param[inout] aMainloop A reference to the mainloop to be updated. - * - */ - void Update(MainloopContext &aMainloop) override; - - /** - * This method processes mainloop events. - * - * @param[in] aMainloop A reference to the mainloop context. - * - */ - void Process(const MainloopContext &aMainloop) override; - - /** - * This method returns the AvahiPoll. - * - * @returns A pointer to the AvahiPoll. - * - */ - const AvahiPoll *GetAvahiPoll(void) const { return &mAvahiPoller; } - -private: - typedef std::vector<AvahiWatch *> Watches; - typedef std::vector<AvahiTimeout *> Timers; - - static AvahiWatch * WatchNew(const struct AvahiPoll *aPoller, - int aFd, - AvahiWatchEvent aEvent, - AvahiWatchCallback aCallback, - void * aContext); - AvahiWatch * WatchNew(int aFd, AvahiWatchEvent aEvent, AvahiWatchCallback aCallback, void *aContext); - static void WatchUpdate(AvahiWatch *aWatch, AvahiWatchEvent aEvent); - static AvahiWatchEvent WatchGetEvents(AvahiWatch *aWatch); - static void WatchFree(AvahiWatch *aWatch); - void WatchFree(AvahiWatch &aWatch); - static AvahiTimeout * TimeoutNew(const AvahiPoll * aPoller, - const struct timeval *aTimeout, - AvahiTimeoutCallback aCallback, - void * aContext); - AvahiTimeout * TimeoutNew(const struct timeval *aTimeout, AvahiTimeoutCallback aCallback, void *aContext); - static void TimeoutUpdate(AvahiTimeout *aTimer, const struct timeval *aTimeout); - static void TimeoutFree(AvahiTimeout *aTimer); - void TimeoutFree(AvahiTimeout &aTimer); - - Watches mWatches; - Timers mTimers; - AvahiPoll mAvahiPoller; -}; +class AvahiPoller; /** - * This class implements mDNS service with avahi. + * This class implements mDNS publisher with avahi. * */ class PublisherAvahi : public Publisher { public: - /** - * The constructor to initialize a Publisher. - * - * @param[in] aProtocol The protocol used for publishing. IPv4, IPv6 or both. - * @param[in] aDomain The domain of the host. nullptr to use default. - * @param[in] aHandler The function to be called when state changes. - * @param[in] aContext A pointer to application-specific context. - * - */ - PublisherAvahi(int aProtocol, const char *aDomain, StateHandler aHandler, void *aContext); - + PublisherAvahi(StateCallback aStateCallback); ~PublisherAvahi(void) override; - /** - * This method publishes or updates a service. - * - * @param[in] aHostName The name of the host which this service resides on. If NULL is provided, - * this service resides on local host and it is the implementation to provide - * specific host name. Otherwise, the caller MUST publish the host with method - * PublishHost. - * @param[in] aPort The port number of this service. - * @param[in] aName The name of this service. - * @param[in] aType The type of this service. - * @param[in] aSubTypeList A list of service subtypes. - * @param[in] aTxtList A list of TXT name/value pairs. - * - * @retval OTBR_ERROR_NONE Successfully published or updated the service. - * @retval OTBR_ERROR_ERRNO Failed to publish or update the service. - * - */ - otbrError PublishService(const char * aHostName, - uint16_t aPort, - const char * aName, - const char * aType, - const SubTypeList &aSubTypeList, - const TxtList & aTxtList) override; - - /** - * This method un-publishes a service. - * - * @param[in] aName The name of this service. - * @param[in] aType The type of this service. - * - * @retval OTBR_ERROR_NONE Successfully un-published the service. - * @retval OTBR_ERROR_ERRNO Failed to un-publish the service. - * - */ - otbrError UnpublishService(const char *aName, const char *aType) override; - - /** - * This method publishes or updates a host. - * - * Publishing a host is advertising an AAAA RR for the host name. This method should be called - * before a service with non-null host name is published. - * - * @param[in] aName The name of the host. - * @param[in] aAddress The address of the host. - * @param[in] aAddressLength The length of @p aAddress. - * - * @retval OTBR_ERROR_NONE Successfully published or updated the host. - * @retval OTBR_ERROR_ERRNO Failed to publish or update the host. - * - */ - otbrError PublishHost(const char *aName, const uint8_t *aAddress, uint8_t aAddressLength) override; - - /** - * This method un-publishes a host. - * - * @param[in] aName A host name. - * - * @retval OTBR_ERROR_NONE Successfully un-published the host. - * @retval OTBR_ERROR_ERRNO Failed to un-publish the host. - * - * @note All services reside on this host should be un-published by UnpublishService. - * - */ - otbrError UnpublishHost(const char *aName) override; - - /** - * This method subscribes a given service or service instance. If @p aInstanceName is not empty, this method - * subscribes the service instance. Otherwise, this method subscribes the service. - * - * mDNS implementations should use the `DiscoveredServiceInstanceCallback` function to notify discovered service - * instances. - * - * @note Discovery Proxy implementation guarantees no duplicate subscriptions for the same service or service - * instance. - * - * @param[in] aType The service type. - * @param[in] aInstanceName The service instance to subscribe, or empty to subscribe the service. - * - */ - void SubscribeService(const std::string &aType, const std::string &aInstanceName) override; - - /** - * This method unsubscribes a given service or service instance. If @p aInstanceName is not empty, this method - * unsubscribes the service instance. Otherwise, this method unsubscribes the service. - * - * @note Discovery Proxy implementation guarantees no redundant unsubscription for a service or service instance. - * - * @param[in] aType The service type. - * @param[in] aInstanceName The service instance to unsubscribe, or empty to unsubscribe the service. - * - */ - void UnsubscribeService(const std::string &aType, const std::string &aInstanceName) override; - - /** - * This method subscribes a given host. - * - * mDNS implementations should use the `DiscoveredHostCallback` function to notify discovered hosts. - * - * @note Discovery Proxy implementation guarantees no duplicate subscriptions for the same host. - * - * @param[in] aHostName The host name (without domain). - * - */ - void SubscribeHost(const std::string &aHostName) override; - - /** - * This method unsubscribes a given host. - * - * @note Discovery Proxy implementation guarantees no redundant unsubscription for a host. - * - * @param[in] aHostName The host name (without domain). - * - */ - void UnsubscribeHost(const std::string &aHostName) override; - - /** - * This method starts the mDNS service. - * - * @retval OTBR_ERROR_NONE Successfully started mDNS service; - * @retval OTBR_ERROR_MDNS Failed to start mDNS service. - * - */ + void UnpublishService(const std::string &aName, const std::string &aType, ResultCallback &&aCallback) override; + void UnpublishHost(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; otbrError Start(void) override; - - /** - * This method checks if publisher has been started. - * - * @retval true Already started. - * @retval false Not started. - * - */ - bool IsStarted(void) const override; - - /** - * This method stops the mDNS service. - * - */ - void Stop(void) override; + bool IsStarted(void) const override; + void Stop(void) override; + +protected: + void PublishServiceImpl(const std::string &aHostName, + const std::string &aName, + const std::string &aType, + const SubTypeList &aSubTypeList, + uint16_t aPort, + const TxtList & aTxtList, + ResultCallback && aCallback) override; + void PublishHostImpl(const std::string & aName, + const std::vector<uint8_t> &aAddress, + ResultCallback && aCallback) override; + void OnServiceResolveFailedImpl(const std::string &aType, + const std::string &aInstanceName, + int32_t aErrorCode) override; + void OnHostResolveFailedImpl(const std::string &aHostName, int32_t aErrorCode) override; + otbrError DnsErrorToOtbrError(int32_t aErrorCode) override; private: - enum + static constexpr size_t kMaxSizeOfTxtRecord = 1024; + static constexpr uint32_t kDefaultTtl = 10; // In seconds. + + class AvahiServiceRegistration : public ServiceRegistration { - kMaxSizeOfTxtRecord = 1024, - kMaxSizeOfServiceName = AVAHI_LABEL_MAX, - kMaxSizeOfHost = AVAHI_LABEL_MAX, - kMaxSizeOfDomain = AVAHI_LABEL_MAX, - kMaxSizeOfServiceType = AVAHI_LABEL_MAX, - kDefaultTtl = 10, + 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) + : ServiceRegistration(aHostName, + aName, + aType, + aSubTypeList, + aPort, + aTxtList, + std::move(aCallback), + aPublisher) + , mEntryGroup(aEntryGroup) + { + } + + ~AvahiServiceRegistration(void) override; + const AvahiEntryGroup *GetEntryGroup(void) const { return mEntryGroup; } + + private: + AvahiEntryGroup *mEntryGroup; }; - struct Service + class AvahiHostRegistration : public HostRegistration { - std::string mName; - std::string mType; - SubTypeList mSubTypeList; - std::string mHostName; - uint16_t mPort = 0; - AvahiEntryGroup *mGroup = nullptr; - TxtList mTxtList; - }; + public: + AvahiHostRegistration(const std::string & aName, + const std::vector<uint8_t> &aAddress, + ResultCallback && aCallback, + AvahiEntryGroup * aEntryGroup, + PublisherAvahi * aPublisher) + : HostRegistration(aName, aAddress, std::move(aCallback), aPublisher) + , mEntryGroup(aEntryGroup) + { + } - typedef std::vector<Service> Services; + ~AvahiHostRegistration(void) override; + const AvahiEntryGroup *GetEntryGroup(void) const { return mEntryGroup; } - struct Host - { - std::string mHostName; - AvahiAddress mAddress = {}; - AvahiEntryGroup *mGroup = nullptr; + private: + AvahiEntryGroup *mEntryGroup; }; - struct Subscription + struct Subscription : private ::NonCopyable { PublisherAvahi *mPublisherAvahi; @@ -387,18 +173,19 @@ private: , mType(std::move(aType)) , mInstanceName(std::move(aInstanceName)) , mServiceBrowser(nullptr) - , mServiceResolver(nullptr) { } + ~ServiceSubscription() { Release(); } + void Release(void); void Browse(void); - void Resolve(uint32_t aInterfaceIndex, - AvahiProtocol aProtocol, - const char * aInstanceName, - const char * aType, - const char * aDomain); - void GetAddrInfo(uint32_t aInterfaceIndex); + void Resolve(uint32_t aInterfaceIndex, + AvahiProtocol aProtocol, + const std::string &aInstanceName, + const std::string &aType); + void AddServiceResolver(AvahiServiceResolver *aServiceResolver); + void RemoveServiceResolver(AvahiServiceResolver *aServiceResolver); static void HandleBrowseResult(AvahiServiceBrowser * aServiceBrowser, AvahiIfIndex aInterfaceIndex, @@ -446,22 +233,23 @@ private: AvahiStringList * aTxt, AvahiLookupResultFlags aFlags); - std::string mType; - std::string mInstanceName; - DiscoveredInstanceInfo mInstanceInfo; - AvahiServiceBrowser * mServiceBrowser; - AvahiServiceResolver * mServiceResolver; + std::string mType; + std::string mInstanceName; + AvahiServiceBrowser * mServiceBrowser; + std::set<AvahiServiceResolver *> mServiceResolvers; }; struct HostSubscription : public Subscription { - explicit HostSubscription(PublisherAvahi &aMDnsSd, std::string aHostName) - : Subscription(aMDnsSd) + explicit HostSubscription(PublisherAvahi &aAvahiPublisher, std::string aHostName) + : Subscription(aAvahiPublisher) , mHostName(std::move(aHostName)) , mRecordBrowser(nullptr) { } + ~HostSubscription() { Release(); } + void Release(void); void Resolve(void); static void HandleResolveResult(AvahiRecordBrowser * aRecordBrowser, @@ -492,56 +280,31 @@ private: AvahiRecordBrowser *mRecordBrowser; }; - typedef std::vector<Host> Hosts; - typedef std::vector<ServiceSubscription> ServiceSubscriptionList; - typedef std::vector<HostSubscription> HostSubscriptionList; + typedef std::vector<std::unique_ptr<ServiceSubscription>> ServiceSubscriptionList; + typedef std::vector<std::unique_ptr<HostSubscription>> HostSubscriptionList; static void HandleClientState(AvahiClient *aClient, AvahiClientState aState, void *aContext); void HandleClientState(AvahiClient *aClient, AvahiClientState aState); - Hosts::iterator FindHost(const char *aHostName); - otbrError CreateHost(AvahiClient &aClient, const char *aHostName, Hosts::iterator &aOutHostIt); - - Services::iterator FindService(const char *aName, const char *aType); - Services::iterator FindService(AvahiEntryGroup *aGroup); - otbrError CreateService(AvahiClient & aClient, - const char * aName, - const char * aType, - Services::iterator &aOutServiceIt); - static bool IsServiceOutdated(const Service & aService, - const char * aNewHostName, - uint16_t aNewPort, - const SubTypeList &aNewSubTypeList); - - otbrError CreateGroup(AvahiClient &aClient, AvahiEntryGroup *&aOutGroup); - static otbrError ResetGroup(AvahiEntryGroup *aGroup); - static otbrError FreeGroup(AvahiEntryGroup *aGroup); - void FreeAllGroups(void); - static void HandleGroupState(AvahiEntryGroup *aGroup, AvahiEntryGroupState aState, void *aContext); - void HandleGroupState(AvahiEntryGroup *aGroup, AvahiEntryGroupState aState); - void CallHostOrServiceCallback(AvahiEntryGroup *aGroup, otbrError aError) const; + AvahiEntryGroup *CreateGroup(AvahiClient *aClient); + static void ReleaseGroup(AvahiEntryGroup *aGroup); + + static void HandleGroupState(AvahiEntryGroup *aGroup, AvahiEntryGroupState aState, void *aContext); + void HandleGroupState(AvahiEntryGroup *aGroup, AvahiEntryGroupState aState); + void CallHostOrServiceCallback(AvahiEntryGroup *aGroup, otbrError aError); static otbrError TxtListToAvahiStringList(const TxtList & aTxtList, AvahiStringList * aBuffer, size_t aBufferSize, AvahiStringList *&aHead); - std::string MakeFullName(const char *aName); - - void OnServiceResolved(ServiceSubscription &aService); - static void OnServiceResolveFailed(const ServiceSubscription &aService, int aErrorCode); - void OnHostResolved(HostSubscription &aHost); - void OnHostResolveFailed(const HostSubscription &aHost, int aErrorCode); - - AvahiClient *mClient; - Hosts mHosts; - Services mServices; - Poller mPoller; - int mProtocol; - const char * mDomain; - State mState; - StateHandler mStateHandler; - void * mContext; + ServiceRegistration *FindServiceRegistration(const AvahiEntryGroup *aEntryGroup); + HostRegistration * FindHostRegistration(const AvahiEntryGroup *aEntryGroup); + + AvahiClient * mClient; + std::unique_ptr<AvahiPoller> mPoller; + State mState; + StateCallback mStateCallback; ServiceSubscriptionList mSubscribedServices; HostSubscriptionList mSubscribedHosts; |