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