Line data Source code
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 <algorithm>
21 : #include <cstdint>
22 : #include <optional>
23 :
24 : #include <lib/core/CHIPError.h>
25 : #include <lib/core/PeerId.h>
26 : #include <lib/dnssd/TxtFields.h>
27 : #include <lib/support/CHIPMemString.h>
28 : #include <lib/support/SafeString.h>
29 : #include <lib/support/Span.h>
30 :
31 : namespace chip {
32 : namespace Dnssd {
33 :
34 : static constexpr uint16_t kMdnsPort = 5353;
35 : // Need 8 bytes to fit a thread mac.
36 : static constexpr size_t kMaxMacSize = 8;
37 :
38 : enum class CommssionAdvertiseMode : uint8_t
39 : {
40 : kCommissionableNode,
41 : kCommissioner,
42 : };
43 :
44 : enum class CommissioningMode
45 : {
46 : kDisabled, // Commissioning Mode is disabled, CM=0 in DNS-SD key/value pairs
47 : kEnabledBasic, // Basic Commissioning Mode, CM=1 in DNS-SD key/value pairs
48 : kEnabledEnhanced // Enhanced Commissioning Mode, CM=2 in DNS-SD key/value pairs
49 : };
50 :
51 : enum class ICDModeAdvertise : uint8_t
52 : {
53 : kNone, // The device does not support the LIT feature-set. No ICD= key is advertised in DNS-SD.
54 : kSIT, // The ICD supports the LIT feature-set, but is currently operating as a SIT. ICD=0 in DNS-SD key/value pairs.
55 : kLIT, // The ICD is currently operating as a LIT. ICD=1 in DNS-SD key/value pairs.
56 : };
57 :
58 : enum class TCPModeAdvertise : uint16_t
59 : {
60 : kNone = 0, // The device does not support TCP.
61 : kTCPClient = 1 << 1, // The device supports the TCP client.
62 : kTCPServer = 1 << 2, // The device supports the TCP server.
63 : kTCPClientServer = (kTCPClient | kTCPServer), // The device supports both the TCP client and server.
64 : };
65 :
66 : template <class Derived>
67 : class BaseAdvertisingParams
68 : {
69 : public:
70 : static constexpr uint8_t kCommonTxtMaxNumber = KeyCount(TxtKeyUse::kCommon);
71 : static constexpr size_t kCommonTxtMaxKeySize = MaxKeyLen(TxtKeyUse::kCommon);
72 : static constexpr size_t kCommonTxtMaxValueSize = MaxValueLen(TxtKeyUse::kCommon);
73 : static constexpr size_t kCommonTxtTotalKeySize = TotalKeyLen(TxtKeyUse::kCommon);
74 : static constexpr size_t kCommonTxtTotalValueSize = TotalValueLen(TxtKeyUse::kCommon);
75 :
76 7 : Derived & SetPort(uint16_t port)
77 : {
78 7 : mPort = port;
79 7 : return *reinterpret_cast<Derived *>(this);
80 : }
81 19 : uint16_t GetPort() const { return mPort; }
82 :
83 7 : Derived & SetInterfaceId(Inet::InterfaceId interfaceId)
84 : {
85 7 : mInterfaceId = interfaceId;
86 7 : return *reinterpret_cast<Derived *>(this);
87 : }
88 :
89 : Inet::InterfaceId GetInterfaceId() const { return mInterfaceId; }
90 :
91 7 : Derived & EnableIpV4(bool enable)
92 : {
93 7 : mEnableIPv4 = enable;
94 7 : return *reinterpret_cast<Derived *>(this);
95 : }
96 19 : bool IsIPv4Enabled() const { return mEnableIPv4; }
97 7 : Derived & SetMac(chip::ByteSpan mac)
98 : {
99 7 : mMacLength = std::min(mac.size(), kMaxMacSize);
100 7 : memcpy(mMacStorage, mac.data(), mMacLength);
101 7 : return *reinterpret_cast<Derived *>(this);
102 : }
103 19 : const chip::ByteSpan GetMac() const { return chip::ByteSpan(mMacStorage, mMacLength); }
104 :
105 : // Common Flags
106 7 : Derived & SetLocalMRPConfig(const std::optional<ReliableMessageProtocolConfig> & config)
107 : {
108 7 : mLocalMRPConfig = config;
109 7 : return *reinterpret_cast<Derived *>(this);
110 : }
111 19 : const std::optional<ReliableMessageProtocolConfig> & GetLocalMRPConfig() const { return mLocalMRPConfig; }
112 :
113 0 : Derived & SetTCPSupportModes(TCPModeAdvertise tcpSupportModes)
114 : {
115 0 : mTcpSupportModes = tcpSupportModes;
116 0 : return *reinterpret_cast<Derived *>(this);
117 : }
118 22 : TCPModeAdvertise GetTCPSupportModes() const { return mTcpSupportModes; }
119 :
120 : Derived & SetICDModeToAdvertise(ICDModeAdvertise operatingMode)
121 : {
122 : mICDModeAdvertise = operatingMode;
123 : return *reinterpret_cast<Derived *>(this);
124 : }
125 26 : ICDModeAdvertise GetICDModeToAdvertise() const { return mICDModeAdvertise; }
126 :
127 : private:
128 : uint16_t mPort = CHIP_PORT;
129 : Inet::InterfaceId mInterfaceId = Inet::InterfaceId::Null();
130 : bool mEnableIPv4 = true;
131 : uint8_t mMacStorage[kMaxMacSize] = {};
132 : size_t mMacLength = 0;
133 : std::optional<ReliableMessageProtocolConfig> mLocalMRPConfig;
134 : TCPModeAdvertise mTcpSupportModes = TCPModeAdvertise::kNone;
135 : ICDModeAdvertise mICDModeAdvertise = ICDModeAdvertise::kNone;
136 : };
137 :
138 : /// Defines parameters required for advertising a CHIP node
139 : /// over mDNS as an 'operationally ready' node.
140 : class OperationalAdvertisingParameters : public BaseAdvertisingParams<OperationalAdvertisingParameters>
141 : {
142 : public:
143 : // Operational uses only common keys
144 : static constexpr uint8_t kTxtMaxNumber = kCommonTxtMaxNumber;
145 : static constexpr uint8_t kTxtMaxKeySize = kCommonTxtMaxKeySize;
146 : static constexpr uint8_t kTxtMaxValueSize = kCommonTxtMaxValueSize;
147 : static constexpr size_t kTxtTotalKeySize = kCommonTxtTotalKeySize;
148 : static constexpr size_t kTxtTotalValueSize = kCommonTxtTotalValueSize;
149 :
150 0 : OperationalAdvertisingParameters & SetPeerId(const PeerId & peerId)
151 : {
152 0 : mPeerId = peerId;
153 0 : return *this;
154 : }
155 16 : PeerId GetPeerId() const { return mPeerId; }
156 :
157 : CompressedFabricId GetCompressedFabricId() const { return mPeerId.GetCompressedFabricId(); }
158 :
159 : private:
160 : PeerId mPeerId;
161 : };
162 :
163 : class CommissionAdvertisingParameters : public BaseAdvertisingParams<CommissionAdvertisingParameters>
164 : {
165 : public:
166 : static constexpr uint8_t kTxtMaxNumber = kCommonTxtMaxNumber + KeyCount(TxtKeyUse::kCommission);
167 : static constexpr uint8_t kTxtMaxKeySize = std::max(kCommonTxtMaxKeySize, MaxKeyLen(TxtKeyUse::kCommission));
168 : static constexpr uint8_t kTxtMaxValueSize = std::max(kCommonTxtMaxValueSize, MaxValueLen(TxtKeyUse::kCommission));
169 : static constexpr size_t kTxtTotalKeySize = kCommonTxtTotalKeySize + TotalKeyLen(TxtKeyUse::kCommission);
170 : static constexpr size_t kTxtTotalValueSize = kCommonTxtTotalValueSize + TotalValueLen(TxtKeyUse::kCommission);
171 :
172 7 : CommissionAdvertisingParameters & SetShortDiscriminator(uint8_t discriminator)
173 : {
174 7 : mShortDiscriminator = discriminator;
175 7 : return *this;
176 : }
177 18 : uint8_t GetShortDiscriminator() const { return mShortDiscriminator; }
178 :
179 7 : CommissionAdvertisingParameters & SetLongDiscriminator(uint16_t discriminator)
180 : {
181 7 : mLongDiscriminator = discriminator;
182 7 : return *this;
183 : }
184 29 : uint16_t GetLongDiscriminator() const { return mLongDiscriminator; }
185 :
186 7 : CommissionAdvertisingParameters & SetVendorId(std::optional<uint16_t> vendorId)
187 : {
188 7 : mVendorId = vendorId;
189 7 : return *this;
190 : }
191 29 : std::optional<uint16_t> GetVendorId() const { return mVendorId; }
192 :
193 7 : CommissionAdvertisingParameters & SetProductId(std::optional<uint16_t> productId)
194 : {
195 7 : mProductId = productId;
196 7 : return *this;
197 : }
198 18 : std::optional<uint16_t> GetProductId() const { return mProductId; }
199 :
200 7 : CommissionAdvertisingParameters & SetCommissioningMode(CommissioningMode mode)
201 : {
202 7 : mCommissioningMode = mode;
203 7 : return *this;
204 : }
205 29 : CommissioningMode GetCommissioningMode() const { return mCommissioningMode; }
206 :
207 0 : CommissionAdvertisingParameters & SetDeviceType(std::optional<uint32_t> deviceType)
208 : {
209 0 : mDeviceType = deviceType;
210 0 : return *this;
211 : }
212 22 : std::optional<uint32_t> GetDeviceType() const { return mDeviceType; }
213 :
214 0 : CommissionAdvertisingParameters & SetDeviceName(std::optional<const char *> deviceName)
215 : {
216 0 : if (deviceName.has_value())
217 : {
218 0 : Platform::CopyString(mDeviceName, sizeof(mDeviceName), *deviceName);
219 0 : mDeviceNameHasValue = true;
220 : }
221 : else
222 : {
223 0 : mDeviceNameHasValue = false;
224 : }
225 0 : return *this;
226 : }
227 11 : std::optional<const char *> GetDeviceName() const
228 : {
229 22 : return mDeviceNameHasValue ? std::make_optional<const char *>(mDeviceName) : std::nullopt;
230 : }
231 :
232 : CommissionAdvertisingParameters & SetRotatingDeviceId(std::optional<const char *> rotatingId)
233 : {
234 : if (rotatingId.has_value())
235 : {
236 : Platform::CopyString(mRotatingId, sizeof(mRotatingId), *rotatingId);
237 : mRotatingIdHasValue = true;
238 : }
239 : else
240 : {
241 : mRotatingIdHasValue = false;
242 : }
243 : return *this;
244 : }
245 11 : std::optional<const char *> GetRotatingDeviceId() const
246 : {
247 22 : return mRotatingIdHasValue ? std::make_optional<const char *>(mRotatingId) : std::nullopt;
248 : }
249 :
250 7 : CommissionAdvertisingParameters & SetPairingInstruction(std::optional<const char *> pairingInstr)
251 : {
252 7 : if (pairingInstr.has_value())
253 : {
254 7 : Platform::CopyString(mPairingInstr, sizeof(mPairingInstr), *pairingInstr);
255 7 : mPairingInstrHasValue = true;
256 : }
257 : else
258 : {
259 0 : mPairingInstrHasValue = false;
260 : }
261 7 : return *this;
262 : }
263 11 : std::optional<const char *> GetPairingInstruction() const
264 : {
265 22 : return mPairingInstrHasValue ? std::make_optional<const char *>(mPairingInstr) : std::nullopt;
266 : }
267 :
268 7 : CommissionAdvertisingParameters & SetPairingHint(std::optional<uint16_t> pairingHint)
269 : {
270 7 : mPairingHint = pairingHint;
271 7 : return *this;
272 : }
273 11 : std::optional<uint16_t> GetPairingHint() const { return mPairingHint; }
274 :
275 7 : CommissionAdvertisingParameters & SetCommissionAdvertiseMode(CommssionAdvertiseMode mode)
276 : {
277 7 : mMode = mode;
278 7 : return *this;
279 : }
280 77 : CommssionAdvertiseMode GetCommissionAdvertiseMode() const { return mMode; }
281 :
282 : CommissionAdvertisingParameters & SetCommissionerPasscodeSupported(std::optional<bool> commissionerPasscodeSupported)
283 : {
284 : mCommissionerPasscodeSupported = commissionerPasscodeSupported;
285 : return *this;
286 : }
287 7 : std::optional<bool> GetCommissionerPasscodeSupported() const { return mCommissionerPasscodeSupported; }
288 :
289 : private:
290 : uint8_t mShortDiscriminator = 0;
291 : uint16_t mLongDiscriminator = 0; // 12-bit according to spec
292 : CommssionAdvertiseMode mMode = CommssionAdvertiseMode::kCommissionableNode;
293 : CommissioningMode mCommissioningMode = CommissioningMode::kEnabledBasic;
294 : std::optional<uint16_t> mVendorId;
295 : std::optional<uint16_t> mProductId;
296 : std::optional<uint32_t> mDeviceType;
297 : std::optional<uint16_t> mPairingHint;
298 :
299 : char mDeviceName[kKeyDeviceNameMaxLength + 1];
300 : bool mDeviceNameHasValue = false;
301 :
302 : char mRotatingId[kKeyRotatingDeviceIdMaxLength + 1];
303 : bool mRotatingIdHasValue = false;
304 :
305 : char mPairingInstr[kKeyPairingInstructionMaxLength + 1];
306 : bool mPairingInstrHasValue = false;
307 :
308 : std::optional<bool> mCommissionerPasscodeSupported;
309 : };
310 :
311 : /**
312 : * Interface for advertising CHIP DNS-SD services.
313 : *
314 : * A user of this interface must first initialize the advertiser using the `Init` method.
315 : *
316 : * Then, whenever advertised services need to be refreshed, the following sequence of events must
317 : * occur:
318 : * 1. Call the `RemoveServices` method.
319 : * 2. Call one of the `Advertise` methods for each service to be added or updated.
320 : * 3. Call the `FinalizeServiceUpdate` method to finalize the update and apply all pending changes.
321 : */
322 : class ServiceAdvertiser
323 : {
324 : public:
325 3 : virtual ~ServiceAdvertiser() {}
326 :
327 : /**
328 : * Initializes the advertiser.
329 : *
330 : * The method must be called before other methods of this class.
331 : * If the advertiser has already been initialized, the method exits immediately with no error.
332 : */
333 : virtual CHIP_ERROR Init(chip::Inet::EndPointManager<chip::Inet::UDPEndPoint> * udpEndPointManager) = 0;
334 :
335 : /**
336 : * Returns whether the advertiser has completed the initialization.
337 : *
338 : * Returns true if the advertiser is ready to advertise services.
339 : */
340 : virtual bool IsInitialized() = 0;
341 :
342 : /**
343 : * Shuts down the advertiser.
344 : */
345 : virtual void Shutdown() = 0;
346 :
347 : /**
348 : * Removes or marks all services being advertised for removal.
349 : *
350 : * Depending on the implementation, the method may either stop advertising existing services
351 : * immediately, or mark them for removal upon the subsequent `FinalizeServiceUpdate` method call.
352 : */
353 : virtual CHIP_ERROR RemoveServices() = 0;
354 :
355 : /**
356 : * Advertises the given operational node service.
357 : */
358 : virtual CHIP_ERROR Advertise(const OperationalAdvertisingParameters & params) = 0;
359 :
360 : /**
361 : * Advertises the given commissionable/commissioner node service.
362 : */
363 : virtual CHIP_ERROR Advertise(const CommissionAdvertisingParameters & params) = 0;
364 :
365 : /**
366 : * Finalizes updating advertised services.
367 : *
368 : * This method can be used by some implementations to apply changes made with the `RemoveServices`
369 : * and `Advertise` methods in case they could not be applied immediately.
370 : */
371 : virtual CHIP_ERROR FinalizeServiceUpdate() = 0;
372 :
373 : /**
374 : * Returns the commissionable node service instance name formatted as hex string.
375 : */
376 : virtual CHIP_ERROR GetCommissionableInstanceName(char * instanceName, size_t maxLength) const = 0;
377 :
378 : /**
379 : * Generates an updated commissionable instance name. This happens
380 : * automatically when Init() is called, but may be needed at other times as
381 : * well.
382 : */
383 : virtual CHIP_ERROR UpdateCommissionableInstanceName() = 0;
384 :
385 : /**
386 : * Returns the system-wide implementation of the service advertiser.
387 : *
388 : * The method returns a reference to the advertiser object configured by
389 : * a user using the \c ServiceAdvertiser::SetInstance() method, or the
390 : * default advertiser returned by the \c GetDefaultAdvertiser() function.
391 : */
392 : static ServiceAdvertiser & Instance();
393 :
394 : /**
395 : * Sets the system-wide implementation of the service advertiser.
396 : */
397 : static void SetInstance(ServiceAdvertiser & advertiser);
398 :
399 : private:
400 : static ServiceAdvertiser * sInstance;
401 : };
402 :
403 : /**
404 : * Returns the default implementation of the service advertiser.
405 : */
406 : extern ServiceAdvertiser & GetDefaultAdvertiser();
407 :
408 : } // namespace Dnssd
409 : } // namespace chip
|