/* * * Copyright (c) 2020 Project CHIP Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct AvahiWatch { int mSocket; chip::System::SocketWatchToken mSocketWatch; AvahiWatchCallback mCallback; ///< The function to be called when interested events happened on mFd. AvahiWatchEvent mPendingIO; ///< The pending events from the currently active or most recent callback. void * mContext; ///< A pointer to application-specific context. void * mPoller; ///< The poller created this watch. }; struct AvahiTimeout { std::chrono::steady_clock::time_point mAbsTimeout; ///< Absolute time when this timer timeout. AvahiTimeoutCallback mCallback; ///< The function to be called when timeout. bool mEnabled; ///< Whether the timeout is enabled. void * mContext; ///< The pointer to application-specific context. void * mPoller; ///< The poller created this timer. }; namespace chip { namespace Dnssd { class Poller { public: Poller(void); void HandleTimeout(); const AvahiPoll * GetAvahiPoll(void) const { return &mAvahiPoller; } private: static AvahiWatch * WatchNew(const struct AvahiPoll * poller, int fd, AvahiWatchEvent event, AvahiWatchCallback callback, void * context); AvahiWatch * WatchNew(int fd, AvahiWatchEvent event, AvahiWatchCallback callback, void * context); static void WatchUpdate(AvahiWatch * watch, AvahiWatchEvent event); static AvahiWatchEvent WatchGetEvents(AvahiWatch * watch); static void WatchFree(AvahiWatch * watch); void WatchFree(AvahiWatch & watch); static AvahiTimeout * TimeoutNew(const AvahiPoll * poller, const struct timeval * timeout, AvahiTimeoutCallback callback, void * context); AvahiTimeout * TimeoutNew(const struct timeval * timeout, AvahiTimeoutCallback callback, void * context); static void TimeoutUpdate(AvahiTimeout * timer, const struct timeval * timeout); static void TimeoutFree(AvahiTimeout * timer); void TimeoutFree(AvahiTimeout & timer); void SystemTimerUpdate(AvahiTimeout * timer); static void SystemTimerCallback(System::Layer * layer, void * data); std::vector> mWatches; std::vector> mTimers; std::chrono::steady_clock::time_point mEarliestTimeout; AvahiPoll mAvahiPoller; }; class MdnsAvahi { public: MdnsAvahi(const MdnsAvahi &) = delete; MdnsAvahi & operator=(const MdnsAvahi &) = delete; CHIP_ERROR Init(DnssdAsyncReturnCallback initCallback, DnssdAsyncReturnCallback errorCallback, void * context); void Shutdown(); CHIP_ERROR SetHostname(const char * hostname); CHIP_ERROR PublishService(const DnssdService & service, DnssdPublishCallback callback, void * context); CHIP_ERROR StopPublish(); CHIP_ERROR Browse(const char * type, DnssdServiceProtocol protocol, chip::Inet::IPAddressType addressType, chip::Inet::InterfaceId interface, DnssdBrowseCallback callback, void * context, intptr_t * browseIdentifier); CHIP_ERROR StopBrowse(intptr_t browseIdentifier); CHIP_ERROR Resolve(const char * name, const char * type, DnssdServiceProtocol protocol, chip::Inet::IPAddressType addressType, chip::Inet::IPAddressType transportType, chip::Inet::InterfaceId interface, DnssdResolveCallback callback, void * context); void StopResolve(const char * name); Poller & GetPoller() { return mPoller; } static MdnsAvahi & GetInstance() { return sInstance; } private: struct BrowseContext { MdnsAvahi * mInstance; DnssdBrowseCallback mCallback; void * mContext; Inet::IPAddressType mAddressType; std::vector mServices; size_t mBrowseRetries; AvahiIfIndex mInterface; std::string mProtocol; chip::System::Clock::Timeout mNextRetryDelay = chip::System::Clock::Seconds16(1); std::atomic_bool mStopped{ false }; }; struct ResolveContext { size_t mNumber; // unique number for this context MdnsAvahi * mInstance; DnssdResolveCallback mCallback; void * mContext; char mName[Common::kInstanceNameMaxLength + 1]; AvahiIfIndex mInterface; AvahiProtocol mTransport; AvahiProtocol mAddressType; std::string mFullType; uint8_t mAttempts = 0; AvahiServiceResolver * mResolver = nullptr; ~ResolveContext() { if (mResolver != nullptr) { avahi_service_resolver_free(mResolver); mResolver = nullptr; } } }; MdnsAvahi() : mClient(nullptr) {} static MdnsAvahi sInstance; /// Allocates a new resolve context with a unique `mNumber` ResolveContext * AllocateResolveContext(); ResolveContext * ResolveContextForHandle(size_t handle); void FreeResolveContext(size_t handle); void FreeResolveContext(const char * name); static void HandleClientState(AvahiClient * client, AvahiClientState state, void * context); void HandleClientState(AvahiClient * client, AvahiClientState state); static void HandleGroupState(AvahiEntryGroup * group, AvahiEntryGroupState state, void * context); void HandleGroupState(AvahiEntryGroup * group, AvahiEntryGroupState state); static void HandleBrowse(AvahiServiceBrowser * broswer, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, const char * name, const char * type, const char * domain, AvahiLookupResultFlags flags, void * userdata); static void BrowseRetryCallback(chip::System::Layer * aLayer, void * appState); static void HandleResolve(AvahiServiceResolver * resolver, AvahiIfIndex interface, AvahiProtocol protocol, AvahiResolverEvent event, const char * name, const char * type, const char * domain, const char * host_name, const AvahiAddress * address, uint16_t port, AvahiStringList * txt, AvahiLookupResultFlags flags, void * userdata); DnssdAsyncReturnCallback mInitCallback; DnssdAsyncReturnCallback mErrorCallback; void * mAsyncReturnContext; AvahiClient * mClient; std::map mPublishedGroups; Poller mPoller; static constexpr size_t kMaxBrowseRetries = 4; // Handling of allocated resolves size_t mResolveCount = 0; std::list mAllocatedResolves; }; } // namespace Dnssd } // namespace chip