Jiacheng Guo | 5de2929 | 2020-10-26 14:41:40 +0800 | [diff] [blame] | 1 | /* |
| 2 | * |
| 3 | * Copyright (c) 2020 Project CHIP Authors |
| 4 | * |
| 5 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 6 | * you may not use this file except in compliance with the License. |
| 7 | * You may obtain a copy of the License at |
| 8 | * |
| 9 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 10 | * |
| 11 | * Unless required by applicable law or agreed to in writing, software |
| 12 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 14 | * See the License for the specific language governing permissions and |
| 15 | * limitations under the License. |
| 16 | */ |
| 17 | |
| 18 | #pragma once |
| 19 | |
| 20 | #include <sys/select.h> |
| 21 | #include <unistd.h> |
| 22 | |
C Freeman | d0c47d2 | 2023-08-22 09:32:24 -0400 | [diff] [blame] | 23 | #include <atomic> |
Jiacheng Guo | 5de2929 | 2020-10-26 14:41:40 +0800 | [diff] [blame] | 24 | #include <chrono> |
Andrei Litvin | a9a4259 | 2023-09-15 16:06:28 -0400 | [diff] [blame] | 25 | #include <list> |
Jiacheng Guo | 5de2929 | 2020-10-26 14:41:40 +0800 | [diff] [blame] | 26 | #include <map> |
| 27 | #include <memory> |
C Freeman | 5c52be5 | 2021-12-11 02:59:55 -0500 | [diff] [blame] | 28 | #include <string> |
Jiacheng Guo | 5de2929 | 2020-10-26 14:41:40 +0800 | [diff] [blame] | 29 | #include <vector> |
| 30 | |
| 31 | #include <avahi-client/client.h> |
| 32 | #include <avahi-client/lookup.h> |
| 33 | #include <avahi-client/publish.h> |
| 34 | #include <avahi-common/domain.h> |
| 35 | #include <avahi-common/error.h> |
| 36 | #include <avahi-common/watch.h> |
| 37 | |
Kamil Kasperczyk | d9e02a0 | 2021-10-12 09:19:23 +0200 | [diff] [blame] | 38 | #include "lib/dnssd/platform/Dnssd.h" |
Jiacheng Guo | 5de2929 | 2020-10-26 14:41:40 +0800 | [diff] [blame] | 39 | |
| 40 | struct AvahiWatch |
| 41 | { |
Kevin Schoedel | 82cf1b1 | 2021-08-23 09:20:13 -0400 | [diff] [blame] | 42 | int mSocket; |
| 43 | chip::System::SocketWatchToken mSocketWatch; |
Jiacheng Guo | 5de2929 | 2020-10-26 14:41:40 +0800 | [diff] [blame] | 44 | AvahiWatchCallback mCallback; ///< The function to be called when interested events happened on mFd. |
Kevin Schoedel | 82cf1b1 | 2021-08-23 09:20:13 -0400 | [diff] [blame] | 45 | AvahiWatchEvent mPendingIO; ///< The pending events from the currently active or most recent callback. |
Jiacheng Guo | 5de2929 | 2020-10-26 14:41:40 +0800 | [diff] [blame] | 46 | void * mContext; ///< A pointer to application-specific context. |
| 47 | void * mPoller; ///< The poller created this watch. |
| 48 | }; |
| 49 | |
| 50 | struct AvahiTimeout |
| 51 | { |
| 52 | std::chrono::steady_clock::time_point mAbsTimeout; ///< Absolute time when this timer timeout. |
| 53 | AvahiTimeoutCallback mCallback; ///< The function to be called when timeout. |
| 54 | bool mEnabled; ///< Whether the timeout is enabled. |
| 55 | void * mContext; ///< The pointer to application-specific context. |
| 56 | void * mPoller; ///< The poller created this timer. |
| 57 | }; |
| 58 | |
| 59 | namespace chip { |
Kamil Kasperczyk | d9e02a0 | 2021-10-12 09:19:23 +0200 | [diff] [blame] | 60 | namespace Dnssd { |
Jiacheng Guo | 5de2929 | 2020-10-26 14:41:40 +0800 | [diff] [blame] | 61 | |
| 62 | class Poller |
| 63 | { |
| 64 | public: |
| 65 | Poller(void); |
| 66 | |
Kevin Schoedel | 9692e9a | 2021-06-23 09:11:52 -0400 | [diff] [blame] | 67 | void HandleTimeout(); |
Jiacheng Guo | 5de2929 | 2020-10-26 14:41:40 +0800 | [diff] [blame] | 68 | |
| 69 | const AvahiPoll * GetAvahiPoll(void) const { return &mAvahiPoller; } |
| 70 | |
| 71 | private: |
| 72 | static AvahiWatch * WatchNew(const struct AvahiPoll * poller, int fd, AvahiWatchEvent event, AvahiWatchCallback callback, |
| 73 | void * context); |
| 74 | AvahiWatch * WatchNew(int fd, AvahiWatchEvent event, AvahiWatchCallback callback, void * context); |
| 75 | |
| 76 | static void WatchUpdate(AvahiWatch * watch, AvahiWatchEvent event); |
| 77 | |
| 78 | static AvahiWatchEvent WatchGetEvents(AvahiWatch * watch); |
| 79 | |
| 80 | static void WatchFree(AvahiWatch * watch); |
| 81 | void WatchFree(AvahiWatch & watch); |
| 82 | |
| 83 | static AvahiTimeout * TimeoutNew(const AvahiPoll * poller, const struct timeval * timeout, AvahiTimeoutCallback callback, |
| 84 | void * context); |
| 85 | AvahiTimeout * TimeoutNew(const struct timeval * timeout, AvahiTimeoutCallback callback, void * context); |
| 86 | |
| 87 | static void TimeoutUpdate(AvahiTimeout * timer, const struct timeval * timeout); |
| 88 | |
| 89 | static void TimeoutFree(AvahiTimeout * timer); |
| 90 | void TimeoutFree(AvahiTimeout & timer); |
| 91 | |
Kevin Schoedel | 016b1d5 | 2021-09-13 14:59:09 -0400 | [diff] [blame] | 92 | void SystemTimerUpdate(AvahiTimeout * timer); |
| 93 | static void SystemTimerCallback(System::Layer * layer, void * data); |
| 94 | |
Jiacheng Guo | 5de2929 | 2020-10-26 14:41:40 +0800 | [diff] [blame] | 95 | std::vector<std::unique_ptr<AvahiWatch>> mWatches; |
| 96 | std::vector<std::unique_ptr<AvahiTimeout>> mTimers; |
Kevin Schoedel | 016b1d5 | 2021-09-13 14:59:09 -0400 | [diff] [blame] | 97 | std::chrono::steady_clock::time_point mEarliestTimeout; |
| 98 | |
Jiacheng Guo | 5de2929 | 2020-10-26 14:41:40 +0800 | [diff] [blame] | 99 | AvahiPoll mAvahiPoller; |
| 100 | }; |
| 101 | |
| 102 | class MdnsAvahi |
| 103 | { |
| 104 | public: |
Karsten Sperling | 38d6a48 | 2023-09-29 15:50:08 +1300 | [diff] [blame] | 105 | MdnsAvahi(const MdnsAvahi &) = delete; |
Jiacheng Guo | 5de2929 | 2020-10-26 14:41:40 +0800 | [diff] [blame] | 106 | MdnsAvahi & operator=(const MdnsAvahi &) = delete; |
| 107 | |
Kamil Kasperczyk | d9e02a0 | 2021-10-12 09:19:23 +0200 | [diff] [blame] | 108 | CHIP_ERROR Init(DnssdAsyncReturnCallback initCallback, DnssdAsyncReturnCallback errorCallback, void * context); |
Michael Spang | 6387049 | 2022-06-28 08:41:08 -0400 | [diff] [blame] | 109 | void Shutdown(); |
Jiacheng Guo | 5ad6518 | 2020-10-30 04:14:16 +0800 | [diff] [blame] | 110 | CHIP_ERROR SetHostname(const char * hostname); |
Vivien Nicolas | ad68b4b | 2022-02-11 14:25:17 +0100 | [diff] [blame] | 111 | CHIP_ERROR PublishService(const DnssdService & service, DnssdPublishCallback callback, void * context); |
Jiacheng Guo | 5de2929 | 2020-10-26 14:41:40 +0800 | [diff] [blame] | 112 | CHIP_ERROR StopPublish(); |
Kamil Kasperczyk | d9e02a0 | 2021-10-12 09:19:23 +0200 | [diff] [blame] | 113 | CHIP_ERROR Browse(const char * type, DnssdServiceProtocol protocol, chip::Inet::IPAddressType addressType, |
C Freeman | d0c47d2 | 2023-08-22 09:32:24 -0400 | [diff] [blame] | 114 | chip::Inet::InterfaceId interface, DnssdBrowseCallback callback, void * context, intptr_t * browseIdentifier); |
| 115 | CHIP_ERROR StopBrowse(intptr_t browseIdentifier); |
Kamil Kasperczyk | d9e02a0 | 2021-10-12 09:19:23 +0200 | [diff] [blame] | 116 | CHIP_ERROR Resolve(const char * name, const char * type, DnssdServiceProtocol protocol, chip::Inet::IPAddressType addressType, |
Damian Królik | 38fe11e | 2021-11-03 20:36:00 +0100 | [diff] [blame] | 117 | chip::Inet::IPAddressType transportType, chip::Inet::InterfaceId interface, DnssdResolveCallback callback, |
| 118 | void * context); |
Andrei Litvin | a9a4259 | 2023-09-15 16:06:28 -0400 | [diff] [blame] | 119 | void StopResolve(const char * name); |
Jiacheng Guo | 5de2929 | 2020-10-26 14:41:40 +0800 | [diff] [blame] | 120 | |
| 121 | Poller & GetPoller() { return mPoller; } |
| 122 | |
| 123 | static MdnsAvahi & GetInstance() { return sInstance; } |
| 124 | |
Jiacheng Guo | 5de2929 | 2020-10-26 14:41:40 +0800 | [diff] [blame] | 125 | private: |
| 126 | struct BrowseContext |
| 127 | { |
| 128 | MdnsAvahi * mInstance; |
Kamil Kasperczyk | d9e02a0 | 2021-10-12 09:19:23 +0200 | [diff] [blame] | 129 | DnssdBrowseCallback mCallback; |
Jiacheng Guo | 5de2929 | 2020-10-26 14:41:40 +0800 | [diff] [blame] | 130 | void * mContext; |
Damian Królik | 38fe11e | 2021-11-03 20:36:00 +0100 | [diff] [blame] | 131 | Inet::IPAddressType mAddressType; |
Kamil Kasperczyk | d9e02a0 | 2021-10-12 09:19:23 +0200 | [diff] [blame] | 132 | std::vector<DnssdService> mServices; |
C Freeman | d0c47d2 | 2023-08-22 09:32:24 -0400 | [diff] [blame] | 133 | size_t mBrowseRetries; |
| 134 | AvahiIfIndex mInterface; |
| 135 | std::string mProtocol; |
| 136 | chip::System::Clock::Timeout mNextRetryDelay = chip::System::Clock::Seconds16(1); |
| 137 | std::atomic_bool mStopped{ false }; |
Jiacheng Guo | 5de2929 | 2020-10-26 14:41:40 +0800 | [diff] [blame] | 138 | }; |
| 139 | |
| 140 | struct ResolveContext |
| 141 | { |
Andrei Litvin | a9a4259 | 2023-09-15 16:06:28 -0400 | [diff] [blame] | 142 | size_t mNumber; // unique number for this context |
Jiacheng Guo | 5de2929 | 2020-10-26 14:41:40 +0800 | [diff] [blame] | 143 | MdnsAvahi * mInstance; |
Kamil Kasperczyk | d9e02a0 | 2021-10-12 09:19:23 +0200 | [diff] [blame] | 144 | DnssdResolveCallback mCallback; |
Jiacheng Guo | 5de2929 | 2020-10-26 14:41:40 +0800 | [diff] [blame] | 145 | void * mContext; |
C Freeman | 5c52be5 | 2021-12-11 02:59:55 -0500 | [diff] [blame] | 146 | char mName[Common::kInstanceNameMaxLength + 1]; |
| 147 | AvahiIfIndex mInterface; |
| 148 | AvahiProtocol mTransport; |
| 149 | AvahiProtocol mAddressType; |
| 150 | std::string mFullType; |
Andrei Litvin | a9a4259 | 2023-09-15 16:06:28 -0400 | [diff] [blame] | 151 | uint8_t mAttempts = 0; |
| 152 | AvahiServiceResolver * mResolver = nullptr; |
| 153 | |
| 154 | ~ResolveContext() |
| 155 | { |
| 156 | if (mResolver != nullptr) |
| 157 | { |
| 158 | avahi_service_resolver_free(mResolver); |
| 159 | mResolver = nullptr; |
| 160 | } |
| 161 | } |
Jiacheng Guo | 5de2929 | 2020-10-26 14:41:40 +0800 | [diff] [blame] | 162 | }; |
| 163 | |
Lukas Zeller | b6caecf | 2023-07-16 01:50:32 +0200 | [diff] [blame] | 164 | MdnsAvahi() : mClient(nullptr) {} |
Jiacheng Guo | 5de2929 | 2020-10-26 14:41:40 +0800 | [diff] [blame] | 165 | static MdnsAvahi sInstance; |
| 166 | |
Andrei Litvin | a9a4259 | 2023-09-15 16:06:28 -0400 | [diff] [blame] | 167 | /// Allocates a new resolve context with a unique `mNumber` |
| 168 | ResolveContext * AllocateResolveContext(); |
| 169 | |
| 170 | ResolveContext * ResolveContextForHandle(size_t handle); |
| 171 | void FreeResolveContext(size_t handle); |
| 172 | void FreeResolveContext(const char * name); |
| 173 | |
Jiacheng Guo | 5de2929 | 2020-10-26 14:41:40 +0800 | [diff] [blame] | 174 | static void HandleClientState(AvahiClient * client, AvahiClientState state, void * context); |
| 175 | void HandleClientState(AvahiClient * client, AvahiClientState state); |
| 176 | |
| 177 | static void HandleGroupState(AvahiEntryGroup * group, AvahiEntryGroupState state, void * context); |
| 178 | void HandleGroupState(AvahiEntryGroup * group, AvahiEntryGroupState state); |
| 179 | |
| 180 | static void HandleBrowse(AvahiServiceBrowser * broswer, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, |
| 181 | const char * name, const char * type, const char * domain, AvahiLookupResultFlags flags, |
| 182 | void * userdata); |
C Freeman | d0c47d2 | 2023-08-22 09:32:24 -0400 | [diff] [blame] | 183 | static void BrowseRetryCallback(chip::System::Layer * aLayer, void * appState); |
Jiacheng Guo | 5de2929 | 2020-10-26 14:41:40 +0800 | [diff] [blame] | 184 | static void HandleResolve(AvahiServiceResolver * resolver, AvahiIfIndex interface, AvahiProtocol protocol, |
| 185 | AvahiResolverEvent event, const char * name, const char * type, const char * domain, |
| 186 | const char * host_name, const AvahiAddress * address, uint16_t port, AvahiStringList * txt, |
| 187 | AvahiLookupResultFlags flags, void * userdata); |
| 188 | |
Kamil Kasperczyk | d9e02a0 | 2021-10-12 09:19:23 +0200 | [diff] [blame] | 189 | DnssdAsyncReturnCallback mInitCallback; |
| 190 | DnssdAsyncReturnCallback mErrorCallback; |
Jiacheng Guo | 5de2929 | 2020-10-26 14:41:40 +0800 | [diff] [blame] | 191 | void * mAsyncReturnContext; |
| 192 | |
Jiacheng Guo | 5de2929 | 2020-10-26 14:41:40 +0800 | [diff] [blame] | 193 | AvahiClient * mClient; |
Lukas Zeller | b6caecf | 2023-07-16 01:50:32 +0200 | [diff] [blame] | 194 | std::map<std::string, AvahiEntryGroup *> mPublishedGroups; |
Jiacheng Guo | 5de2929 | 2020-10-26 14:41:40 +0800 | [diff] [blame] | 195 | Poller mPoller; |
C Freeman | d0c47d2 | 2023-08-22 09:32:24 -0400 | [diff] [blame] | 196 | static constexpr size_t kMaxBrowseRetries = 4; |
Andrei Litvin | a9a4259 | 2023-09-15 16:06:28 -0400 | [diff] [blame] | 197 | |
| 198 | // Handling of allocated resolves |
| 199 | size_t mResolveCount = 0; |
| 200 | std::list<ResolveContext *> mAllocatedResolves; |
Jiacheng Guo | 5de2929 | 2020-10-26 14:41:40 +0800 | [diff] [blame] | 201 | }; |
| 202 | |
Kamil Kasperczyk | d9e02a0 | 2021-10-12 09:19:23 +0200 | [diff] [blame] | 203 | } // namespace Dnssd |
Jiacheng Guo | 5de2929 | 2020-10-26 14:41:40 +0800 | [diff] [blame] | 204 | } // namespace chip |