blob: 483ac50d9128a0b59617a4e00a8b3b2104e6049e [file] [log] [blame]
Jiacheng Guo5de29292020-10-26 14:41:40 +08001/*
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 Freemand0c47d22023-08-22 09:32:24 -040023#include <atomic>
Jiacheng Guo5de29292020-10-26 14:41:40 +080024#include <chrono>
Andrei Litvina9a42592023-09-15 16:06:28 -040025#include <list>
Jiacheng Guo5de29292020-10-26 14:41:40 +080026#include <map>
27#include <memory>
C Freeman5c52be52021-12-11 02:59:55 -050028#include <string>
Jiacheng Guo5de29292020-10-26 14:41:40 +080029#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 Kasperczykd9e02a02021-10-12 09:19:23 +020038#include "lib/dnssd/platform/Dnssd.h"
Jiacheng Guo5de29292020-10-26 14:41:40 +080039
40struct AvahiWatch
41{
Kevin Schoedel82cf1b12021-08-23 09:20:13 -040042 int mSocket;
43 chip::System::SocketWatchToken mSocketWatch;
Jiacheng Guo5de29292020-10-26 14:41:40 +080044 AvahiWatchCallback mCallback; ///< The function to be called when interested events happened on mFd.
Kevin Schoedel82cf1b12021-08-23 09:20:13 -040045 AvahiWatchEvent mPendingIO; ///< The pending events from the currently active or most recent callback.
Jiacheng Guo5de29292020-10-26 14:41:40 +080046 void * mContext; ///< A pointer to application-specific context.
47 void * mPoller; ///< The poller created this watch.
48};
49
50struct 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
59namespace chip {
Kamil Kasperczykd9e02a02021-10-12 09:19:23 +020060namespace Dnssd {
Jiacheng Guo5de29292020-10-26 14:41:40 +080061
62class Poller
63{
64public:
65 Poller(void);
66
Kevin Schoedel9692e9a2021-06-23 09:11:52 -040067 void HandleTimeout();
Jiacheng Guo5de29292020-10-26 14:41:40 +080068
69 const AvahiPoll * GetAvahiPoll(void) const { return &mAvahiPoller; }
70
71private:
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 Schoedel016b1d52021-09-13 14:59:09 -040092 void SystemTimerUpdate(AvahiTimeout * timer);
93 static void SystemTimerCallback(System::Layer * layer, void * data);
94
Jiacheng Guo5de29292020-10-26 14:41:40 +080095 std::vector<std::unique_ptr<AvahiWatch>> mWatches;
96 std::vector<std::unique_ptr<AvahiTimeout>> mTimers;
Kevin Schoedel016b1d52021-09-13 14:59:09 -040097 std::chrono::steady_clock::time_point mEarliestTimeout;
98
Jiacheng Guo5de29292020-10-26 14:41:40 +080099 AvahiPoll mAvahiPoller;
100};
101
102class MdnsAvahi
103{
104public:
Karsten Sperling38d6a482023-09-29 15:50:08 +1300105 MdnsAvahi(const MdnsAvahi &) = delete;
Jiacheng Guo5de29292020-10-26 14:41:40 +0800106 MdnsAvahi & operator=(const MdnsAvahi &) = delete;
107
Kamil Kasperczykd9e02a02021-10-12 09:19:23 +0200108 CHIP_ERROR Init(DnssdAsyncReturnCallback initCallback, DnssdAsyncReturnCallback errorCallback, void * context);
Michael Spang63870492022-06-28 08:41:08 -0400109 void Shutdown();
Jiacheng Guo5ad65182020-10-30 04:14:16 +0800110 CHIP_ERROR SetHostname(const char * hostname);
Vivien Nicolasad68b4b2022-02-11 14:25:17 +0100111 CHIP_ERROR PublishService(const DnssdService & service, DnssdPublishCallback callback, void * context);
Jiacheng Guo5de29292020-10-26 14:41:40 +0800112 CHIP_ERROR StopPublish();
Kamil Kasperczykd9e02a02021-10-12 09:19:23 +0200113 CHIP_ERROR Browse(const char * type, DnssdServiceProtocol protocol, chip::Inet::IPAddressType addressType,
C Freemand0c47d22023-08-22 09:32:24 -0400114 chip::Inet::InterfaceId interface, DnssdBrowseCallback callback, void * context, intptr_t * browseIdentifier);
115 CHIP_ERROR StopBrowse(intptr_t browseIdentifier);
Kamil Kasperczykd9e02a02021-10-12 09:19:23 +0200116 CHIP_ERROR Resolve(const char * name, const char * type, DnssdServiceProtocol protocol, chip::Inet::IPAddressType addressType,
Damian Królik38fe11e2021-11-03 20:36:00 +0100117 chip::Inet::IPAddressType transportType, chip::Inet::InterfaceId interface, DnssdResolveCallback callback,
118 void * context);
Andrei Litvina9a42592023-09-15 16:06:28 -0400119 void StopResolve(const char * name);
Jiacheng Guo5de29292020-10-26 14:41:40 +0800120
121 Poller & GetPoller() { return mPoller; }
122
123 static MdnsAvahi & GetInstance() { return sInstance; }
124
Jiacheng Guo5de29292020-10-26 14:41:40 +0800125private:
126 struct BrowseContext
127 {
128 MdnsAvahi * mInstance;
Kamil Kasperczykd9e02a02021-10-12 09:19:23 +0200129 DnssdBrowseCallback mCallback;
Jiacheng Guo5de29292020-10-26 14:41:40 +0800130 void * mContext;
Damian Królik38fe11e2021-11-03 20:36:00 +0100131 Inet::IPAddressType mAddressType;
Kamil Kasperczykd9e02a02021-10-12 09:19:23 +0200132 std::vector<DnssdService> mServices;
C Freemand0c47d22023-08-22 09:32:24 -0400133 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 Guo5de29292020-10-26 14:41:40 +0800138 };
139
140 struct ResolveContext
141 {
Andrei Litvina9a42592023-09-15 16:06:28 -0400142 size_t mNumber; // unique number for this context
Jiacheng Guo5de29292020-10-26 14:41:40 +0800143 MdnsAvahi * mInstance;
Kamil Kasperczykd9e02a02021-10-12 09:19:23 +0200144 DnssdResolveCallback mCallback;
Jiacheng Guo5de29292020-10-26 14:41:40 +0800145 void * mContext;
C Freeman5c52be52021-12-11 02:59:55 -0500146 char mName[Common::kInstanceNameMaxLength + 1];
147 AvahiIfIndex mInterface;
148 AvahiProtocol mTransport;
149 AvahiProtocol mAddressType;
150 std::string mFullType;
Andrei Litvina9a42592023-09-15 16:06:28 -0400151 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 Guo5de29292020-10-26 14:41:40 +0800162 };
163
Lukas Zellerb6caecf2023-07-16 01:50:32 +0200164 MdnsAvahi() : mClient(nullptr) {}
Jiacheng Guo5de29292020-10-26 14:41:40 +0800165 static MdnsAvahi sInstance;
166
Andrei Litvina9a42592023-09-15 16:06:28 -0400167 /// 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 Guo5de29292020-10-26 14:41:40 +0800174 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 Freemand0c47d22023-08-22 09:32:24 -0400183 static void BrowseRetryCallback(chip::System::Layer * aLayer, void * appState);
Jiacheng Guo5de29292020-10-26 14:41:40 +0800184 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 Kasperczykd9e02a02021-10-12 09:19:23 +0200189 DnssdAsyncReturnCallback mInitCallback;
190 DnssdAsyncReturnCallback mErrorCallback;
Jiacheng Guo5de29292020-10-26 14:41:40 +0800191 void * mAsyncReturnContext;
192
Jiacheng Guo5de29292020-10-26 14:41:40 +0800193 AvahiClient * mClient;
Lukas Zellerb6caecf2023-07-16 01:50:32 +0200194 std::map<std::string, AvahiEntryGroup *> mPublishedGroups;
Jiacheng Guo5de29292020-10-26 14:41:40 +0800195 Poller mPoller;
C Freemand0c47d22023-08-22 09:32:24 -0400196 static constexpr size_t kMaxBrowseRetries = 4;
Andrei Litvina9a42592023-09-15 16:06:28 -0400197
198 // Handling of allocated resolves
199 size_t mResolveCount = 0;
200 std::list<ResolveContext *> mAllocatedResolves;
Jiacheng Guo5de29292020-10-26 14:41:40 +0800201};
202
Kamil Kasperczykd9e02a02021-10-12 09:19:23 +0200203} // namespace Dnssd
Jiacheng Guo5de29292020-10-26 14:41:40 +0800204} // namespace chip