1 /*
2 * Copyright (c) 2025, The OpenThread Authors.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. Neither the name of the copyright holder nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 /**
30 * @file
31 * This file includes implementation of OpenThread DNS-SD platform APIs on the posix platform.
32 */
33
34 #define OTBR_LOG_TAG "DNSSD"
35
36 #include "host/posix/dnssd.hpp"
37
38 #include <string>
39
40 #include <openthread/platform/dnssd.h>
41
42 #include "common/code_utils.hpp"
43 #include "common/logging.hpp"
44 #include "common/types.hpp"
45
MakeRegisterCallback(otInstance * aInstance,otPlatDnssdRegisterCallback aCallback)46 static otbr::DnssdPlatform::RegisterCallback MakeRegisterCallback(otInstance *aInstance,
47 otPlatDnssdRegisterCallback aCallback)
48 {
49 return [aInstance, aCallback](otPlatDnssdRequestId aRequestId, otError aError) {
50 if (aCallback)
51 {
52 aCallback(aInstance, aRequestId, aError);
53 }
54 };
55 }
56
otPlatDnssdGetState(otInstance * aInstance)57 extern "C" otPlatDnssdState otPlatDnssdGetState(otInstance *aInstance)
58 {
59 OTBR_UNUSED_VARIABLE(aInstance);
60
61 return otbr::DnssdPlatform::Get().GetState();
62 }
63
otPlatDnssdRegisterService(otInstance * aInstance,const otPlatDnssdService * aService,otPlatDnssdRequestId aRequestId,otPlatDnssdRegisterCallback aCallback)64 extern "C" void otPlatDnssdRegisterService(otInstance *aInstance,
65 const otPlatDnssdService *aService,
66 otPlatDnssdRequestId aRequestId,
67 otPlatDnssdRegisterCallback aCallback)
68 {
69 OTBR_UNUSED_VARIABLE(aInstance);
70
71 otbr::DnssdPlatform::Get().RegisterService(*aService, aRequestId, MakeRegisterCallback(aInstance, aCallback));
72 }
73
otPlatDnssdUnregisterService(otInstance * aInstance,const otPlatDnssdService * aService,otPlatDnssdRequestId aRequestId,otPlatDnssdRegisterCallback aCallback)74 extern "C" void otPlatDnssdUnregisterService(otInstance *aInstance,
75 const otPlatDnssdService *aService,
76 otPlatDnssdRequestId aRequestId,
77 otPlatDnssdRegisterCallback aCallback)
78 {
79 OTBR_UNUSED_VARIABLE(aInstance);
80
81 otbr::DnssdPlatform::Get().UnregisterService(*aService, aRequestId, MakeRegisterCallback(aInstance, aCallback));
82 }
83
otPlatDnssdRegisterHost(otInstance * aInstance,const otPlatDnssdHost * aHost,otPlatDnssdRequestId aRequestId,otPlatDnssdRegisterCallback aCallback)84 extern "C" void otPlatDnssdRegisterHost(otInstance *aInstance,
85 const otPlatDnssdHost *aHost,
86 otPlatDnssdRequestId aRequestId,
87 otPlatDnssdRegisterCallback aCallback)
88 {
89 OTBR_UNUSED_VARIABLE(aInstance);
90
91 otbr::DnssdPlatform::Get().RegisterHost(*aHost, aRequestId, MakeRegisterCallback(aInstance, aCallback));
92 }
93
otPlatDnssdUnregisterHost(otInstance * aInstance,const otPlatDnssdHost * aHost,otPlatDnssdRequestId aRequestId,otPlatDnssdRegisterCallback aCallback)94 extern "C" void otPlatDnssdUnregisterHost(otInstance *aInstance,
95 const otPlatDnssdHost *aHost,
96 otPlatDnssdRequestId aRequestId,
97 otPlatDnssdRegisterCallback aCallback)
98 {
99 OTBR_UNUSED_VARIABLE(aInstance);
100
101 otbr::DnssdPlatform::Get().UnregisterHost(*aHost, aRequestId, MakeRegisterCallback(aInstance, aCallback));
102 }
103
otPlatDnssdRegisterKey(otInstance * aInstance,const otPlatDnssdKey * aKey,otPlatDnssdRequestId aRequestId,otPlatDnssdRegisterCallback aCallback)104 extern "C" void otPlatDnssdRegisterKey(otInstance *aInstance,
105 const otPlatDnssdKey *aKey,
106 otPlatDnssdRequestId aRequestId,
107 otPlatDnssdRegisterCallback aCallback)
108 {
109 OTBR_UNUSED_VARIABLE(aInstance);
110
111 otbr::DnssdPlatform::Get().RegisterKey(*aKey, aRequestId, MakeRegisterCallback(aInstance, aCallback));
112 }
113
otPlatDnssdUnregisterKey(otInstance * aInstance,const otPlatDnssdKey * aKey,otPlatDnssdRequestId aRequestId,otPlatDnssdRegisterCallback aCallback)114 extern "C" void otPlatDnssdUnregisterKey(otInstance *aInstance,
115 const otPlatDnssdKey *aKey,
116 otPlatDnssdRequestId aRequestId,
117 otPlatDnssdRegisterCallback aCallback)
118 {
119 OTBR_UNUSED_VARIABLE(aInstance);
120
121 otbr::DnssdPlatform::Get().UnregisterKey(*aKey, aRequestId, MakeRegisterCallback(aInstance, aCallback));
122 }
123
otPlatDnssdStartBrowser(otInstance * aInstance,const otPlatDnssdBrowser * aBrowser)124 extern "C" void otPlatDnssdStartBrowser(otInstance *aInstance, const otPlatDnssdBrowser *aBrowser)
125 {
126 OTBR_UNUSED_VARIABLE(aInstance);
127 OTBR_UNUSED_VARIABLE(aBrowser);
128 }
129
otPlatDnssdStopBrowser(otInstance * aInstance,const otPlatDnssdBrowser * aBrowser)130 extern "C" void otPlatDnssdStopBrowser(otInstance *aInstance, const otPlatDnssdBrowser *aBrowser)
131 {
132 OTBR_UNUSED_VARIABLE(aInstance);
133 OTBR_UNUSED_VARIABLE(aBrowser);
134 }
135
otPlatDnssdStartSrvResolver(otInstance * aInstance,const otPlatDnssdSrvResolver * aResolver)136 extern "C" void otPlatDnssdStartSrvResolver(otInstance *aInstance, const otPlatDnssdSrvResolver *aResolver)
137 {
138 OTBR_UNUSED_VARIABLE(aInstance);
139 OTBR_UNUSED_VARIABLE(aResolver);
140 }
141
otPlatDnssdStopSrvResolver(otInstance * aInstance,const otPlatDnssdSrvResolver * aResolver)142 extern "C" void otPlatDnssdStopSrvResolver(otInstance *aInstance, const otPlatDnssdSrvResolver *aResolver)
143 {
144 OTBR_UNUSED_VARIABLE(aInstance);
145 OTBR_UNUSED_VARIABLE(aResolver);
146 }
147
otPlatDnssdStartTxtResolver(otInstance * aInstance,const otPlatDnssdTxtResolver * aResolver)148 extern "C" void otPlatDnssdStartTxtResolver(otInstance *aInstance, const otPlatDnssdTxtResolver *aResolver)
149 {
150 OTBR_UNUSED_VARIABLE(aInstance);
151 OTBR_UNUSED_VARIABLE(aResolver);
152 }
153
otPlatDnssdStopTxtResolver(otInstance * aInstance,const otPlatDnssdTxtResolver * aResolver)154 extern "C" void otPlatDnssdStopTxtResolver(otInstance *aInstance, const otPlatDnssdTxtResolver *aResolver)
155 {
156 OTBR_UNUSED_VARIABLE(aInstance);
157 OTBR_UNUSED_VARIABLE(aResolver);
158 }
159
otPlatDnssdStartIp6AddressResolver(otInstance * aInstance,const otPlatDnssdAddressResolver * aResolver)160 extern "C" void otPlatDnssdStartIp6AddressResolver(otInstance *aInstance, const otPlatDnssdAddressResolver *aResolver)
161 {
162 OTBR_UNUSED_VARIABLE(aInstance);
163 OTBR_UNUSED_VARIABLE(aResolver);
164 }
165
otPlatDnssdStopIp6AddressResolver(otInstance * aInstance,const otPlatDnssdAddressResolver * aResolver)166 extern "C" void otPlatDnssdStopIp6AddressResolver(otInstance *aInstance, const otPlatDnssdAddressResolver *aResolver)
167 {
168 OTBR_UNUSED_VARIABLE(aInstance);
169 OTBR_UNUSED_VARIABLE(aResolver);
170 }
171
otPlatDnssdStartIp4AddressResolver(otInstance * aInstance,const otPlatDnssdAddressResolver * aResolver)172 void otPlatDnssdStartIp4AddressResolver(otInstance *aInstance, const otPlatDnssdAddressResolver *aResolver)
173 {
174 OTBR_UNUSED_VARIABLE(aInstance);
175 OTBR_UNUSED_VARIABLE(aResolver);
176 }
177
otPlatDnssdStopIp4AddressResolver(otInstance * aInstance,const otPlatDnssdAddressResolver * aResolver)178 void otPlatDnssdStopIp4AddressResolver(otInstance *aInstance, const otPlatDnssdAddressResolver *aResolver)
179 {
180 OTBR_UNUSED_VARIABLE(aInstance);
181 OTBR_UNUSED_VARIABLE(aResolver);
182 }
183
184 //----------------------------------------------------------------------------------------------------------------------
185
186 namespace otbr {
187
188 DnssdPlatform *DnssdPlatform::sDnssdPlatform = nullptr;
189
DnssdPlatform(Mdns::Publisher & aPublisher)190 DnssdPlatform::DnssdPlatform(Mdns::Publisher &aPublisher)
191 : mPublisher(aPublisher)
192 , mState(kStateStopped)
193 , mRunning(false)
194 , mPublisherState(Mdns::Publisher::State::kIdle)
195 {
196 sDnssdPlatform = this;
197 }
198
Start(void)199 void DnssdPlatform::Start(void)
200 {
201 if (!mRunning)
202 {
203 mRunning = true;
204 UpdateState();
205 }
206 }
207
Stop(void)208 void DnssdPlatform::Stop(void)
209 {
210 if (mRunning)
211 {
212 mRunning = false;
213 UpdateState();
214 }
215 }
216
UpdateState(void)217 void DnssdPlatform::UpdateState(void)
218 {
219 if (mRunning && (mPublisherState == Mdns::Publisher::State::kReady))
220 {
221 VerifyOrExit(mState != kStateReady);
222
223 mState = kStateReady;
224 }
225 else
226 {
227 VerifyOrExit(mState != kStateStopped);
228
229 mState = kStateStopped;
230 }
231
232 if (mStateChangeCallback)
233 {
234 mStateChangeCallback(mState);
235 }
236
237 exit:
238 return;
239 }
240
MakePublisherCallback(RequestId aRequestId,RegisterCallback aCallback)241 Mdns::Publisher::ResultCallback DnssdPlatform::MakePublisherCallback(RequestId aRequestId, RegisterCallback aCallback)
242 {
243 return [aRequestId, aCallback](otbrError aError) {
244 if (aCallback != nullptr)
245 {
246 aCallback(aRequestId, OtbrErrorToOtError(aError));
247 }
248 };
249 }
250
SetDnssdStateChangedCallback(DnssdStateChangeCallback aCallback)251 void DnssdPlatform::SetDnssdStateChangedCallback(DnssdStateChangeCallback aCallback)
252 {
253 mStateChangeCallback = aCallback;
254 }
255
RegisterService(const Service & aService,RequestId aRequestId,RegisterCallback aCallback)256 void DnssdPlatform::RegisterService(const Service &aService, RequestId aRequestId, RegisterCallback aCallback)
257 {
258 Mdns::Publisher::SubTypeList subTypeList;
259 Mdns::Publisher::TxtData txtData(aService.mTxtData, aService.mTxtData + aService.mTxtDataLength);
260
261 for (uint16_t index = 0; index < aService.mSubTypeLabelsLength; index++)
262 {
263 subTypeList.push_back(aService.mSubTypeLabels[index]);
264 }
265
266 mPublisher.PublishService(aService.mHostName, aService.mServiceInstance, aService.mServiceType, subTypeList,
267 aService.mPort, txtData, MakePublisherCallback(aRequestId, aCallback));
268 }
269
UnregisterService(const Service & aService,RequestId aRequestId,RegisterCallback aCallback)270 void DnssdPlatform::UnregisterService(const Service &aService, RequestId aRequestId, RegisterCallback aCallback)
271 {
272 mPublisher.UnpublishService(aService.mServiceInstance, aService.mServiceType,
273 MakePublisherCallback(aRequestId, aCallback));
274 }
275
RegisterHost(const Host & aHost,RequestId aRequestId,RegisterCallback aCallback)276 void DnssdPlatform::RegisterHost(const Host &aHost, RequestId aRequestId, RegisterCallback aCallback)
277 {
278 Mdns::Publisher::AddressList addressList;
279
280 for (uint16_t index = 0; index < aHost.mAddressesLength; index++)
281 {
282 addressList.push_back(Ip6Address(aHost.mAddresses[index].mFields.m8));
283 }
284
285 mPublisher.PublishHost(aHost.mHostName, addressList, MakePublisherCallback(aRequestId, aCallback));
286 }
287
UnregisterHost(const Host & aHost,RequestId aRequestId,RegisterCallback aCallback)288 void DnssdPlatform::UnregisterHost(const Host &aHost, RequestId aRequestId, RegisterCallback aCallback)
289 {
290 mPublisher.UnpublishHost(aHost.mHostName, MakePublisherCallback(aRequestId, aCallback));
291 }
292
KeyNameFor(const Key & aKey)293 std::string DnssdPlatform::KeyNameFor(const Key &aKey)
294 {
295 std::string name(aKey.mName);
296
297 if (aKey.mServiceType != nullptr)
298 {
299 // TODO: current code would not work with service instance labels that include a '.'
300 name += ".";
301 name += aKey.mServiceType;
302 }
303
304 return name;
305 }
306
RegisterKey(const Key & aKey,RequestId aRequestId,RegisterCallback aCallback)307 void DnssdPlatform::RegisterKey(const Key &aKey, RequestId aRequestId, RegisterCallback aCallback)
308 {
309 Mdns::Publisher::KeyData keyData(aKey.mKeyData, aKey.mKeyData + aKey.mKeyDataLength);
310
311 mPublisher.PublishKey(KeyNameFor(aKey), keyData, MakePublisherCallback(aRequestId, aCallback));
312 }
313
UnregisterKey(const Key & aKey,RequestId aRequestId,RegisterCallback aCallback)314 void DnssdPlatform::UnregisterKey(const Key &aKey, RequestId aRequestId, RegisterCallback aCallback)
315 {
316 mPublisher.UnpublishKey(KeyNameFor(aKey), MakePublisherCallback(aRequestId, aCallback));
317 }
318
HandleMdnsState(Mdns::Publisher::State aState)319 void DnssdPlatform::HandleMdnsState(Mdns::Publisher::State aState)
320 {
321 if (mPublisherState != aState)
322 {
323 mPublisherState = aState;
324 UpdateState();
325 }
326 }
327
328 } // namespace otbr
329