/* * * Copyright (c) 2020 Project CHIP Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include #include #include #include #include #include #include namespace chip { namespace Dnssd { static constexpr uint16_t kMdnsPort = 5353; // Need 8 bytes to fit a thread mac. static constexpr size_t kMaxMacSize = 8; enum class CommssionAdvertiseMode : uint8_t { kCommissionableNode, kCommissioner, }; enum class CommissioningMode { kDisabled, // Commissioning Mode is disabled, CM=0 in DNS-SD key/value pairs kEnabledBasic, // Basic Commissioning Mode, CM=1 in DNS-SD key/value pairs kEnabledEnhanced // Enhanced Commissioning Mode, CM=2 in DNS-SD key/value pairs }; enum class ICDModeAdvertise : uint8_t { kNone, // The device does not support the LIT feature-set. No ICD= key is advertised in DNS-SD. kSIT, // The ICD supports the LIT feature-set, but is currently operating as a SIT. ICD=0 in DNS-SD key/value pairs. kLIT, // The ICD is currently operating as a LIT. ICD=1 in DNS-SD key/value pairs. }; enum class TCPModeAdvertise : uint16_t { kNone = 0, // The device does not support TCP. kTCPClient = 1 << 1, // The device supports the TCP client. kTCPServer = 1 << 2, // The device supports the TCP server. kTCPClientServer = (kTCPClient | kTCPServer), // The device supports both the TCP client and server. }; template class BaseAdvertisingParams { public: static constexpr uint8_t kCommonTxtMaxNumber = KeyCount(TxtKeyUse::kCommon); static constexpr size_t kCommonTxtMaxKeySize = MaxKeyLen(TxtKeyUse::kCommon); static constexpr size_t kCommonTxtMaxValueSize = MaxValueLen(TxtKeyUse::kCommon); static constexpr size_t kCommonTxtTotalKeySize = TotalKeyLen(TxtKeyUse::kCommon); static constexpr size_t kCommonTxtTotalValueSize = TotalValueLen(TxtKeyUse::kCommon); Derived & SetPort(uint16_t port) { mPort = port; return *reinterpret_cast(this); } uint16_t GetPort() const { return mPort; } Derived & SetInterfaceId(Inet::InterfaceId interfaceId) { mInterfaceId = interfaceId; return *reinterpret_cast(this); } Inet::InterfaceId GetInterfaceId() const { return mInterfaceId; } Derived & EnableIpV4(bool enable) { mEnableIPv4 = enable; return *reinterpret_cast(this); } bool IsIPv4Enabled() const { return mEnableIPv4; } Derived & SetMac(chip::ByteSpan mac) { mMacLength = std::min(mac.size(), kMaxMacSize); memcpy(mMacStorage, mac.data(), mMacLength); return *reinterpret_cast(this); } const chip::ByteSpan GetMac() const { return chip::ByteSpan(mMacStorage, mMacLength); } // Common Flags Derived & SetLocalMRPConfig(const std::optional & config) { mLocalMRPConfig = config; return *reinterpret_cast(this); } const std::optional & GetLocalMRPConfig() const { return mLocalMRPConfig; } Derived & SetTCPSupportModes(TCPModeAdvertise tcpSupportModes) { mTcpSupportModes = tcpSupportModes; return *reinterpret_cast(this); } TCPModeAdvertise GetTCPSupportModes() const { return mTcpSupportModes; } Derived & SetICDModeToAdvertise(ICDModeAdvertise operatingMode) { mICDModeAdvertise = operatingMode; return *reinterpret_cast(this); } ICDModeAdvertise GetICDModeToAdvertise() const { return mICDModeAdvertise; } private: uint16_t mPort = CHIP_PORT; Inet::InterfaceId mInterfaceId = Inet::InterfaceId::Null(); bool mEnableIPv4 = true; uint8_t mMacStorage[kMaxMacSize] = {}; size_t mMacLength = 0; std::optional mLocalMRPConfig; TCPModeAdvertise mTcpSupportModes = TCPModeAdvertise::kNone; ICDModeAdvertise mICDModeAdvertise = ICDModeAdvertise::kNone; }; /// Defines parameters required for advertising a CHIP node /// over mDNS as an 'operationally ready' node. class OperationalAdvertisingParameters : public BaseAdvertisingParams { public: // Operational uses only common keys static constexpr uint8_t kTxtMaxNumber = kCommonTxtMaxNumber; static constexpr uint8_t kTxtMaxKeySize = kCommonTxtMaxKeySize; static constexpr uint8_t kTxtMaxValueSize = kCommonTxtMaxValueSize; static constexpr size_t kTxtTotalKeySize = kCommonTxtTotalKeySize; static constexpr size_t kTxtTotalValueSize = kCommonTxtTotalValueSize; OperationalAdvertisingParameters & SetPeerId(const PeerId & peerId) { mPeerId = peerId; return *this; } PeerId GetPeerId() const { return mPeerId; } CompressedFabricId GetCompressedFabricId() const { return mPeerId.GetCompressedFabricId(); } private: PeerId mPeerId; }; class CommissionAdvertisingParameters : public BaseAdvertisingParams { public: static constexpr uint8_t kTxtMaxNumber = kCommonTxtMaxNumber + KeyCount(TxtKeyUse::kCommission); static constexpr uint8_t kTxtMaxKeySize = std::max(kCommonTxtMaxKeySize, MaxKeyLen(TxtKeyUse::kCommission)); static constexpr uint8_t kTxtMaxValueSize = std::max(kCommonTxtMaxValueSize, MaxValueLen(TxtKeyUse::kCommission)); static constexpr size_t kTxtTotalKeySize = kCommonTxtTotalKeySize + TotalKeyLen(TxtKeyUse::kCommission); static constexpr size_t kTxtTotalValueSize = kCommonTxtTotalValueSize + TotalValueLen(TxtKeyUse::kCommission); CommissionAdvertisingParameters & SetShortDiscriminator(uint8_t discriminator) { mShortDiscriminator = discriminator; return *this; } uint8_t GetShortDiscriminator() const { return mShortDiscriminator; } CommissionAdvertisingParameters & SetLongDiscriminator(uint16_t discriminator) { mLongDiscriminator = discriminator; return *this; } uint16_t GetLongDiscriminator() const { return mLongDiscriminator; } CommissionAdvertisingParameters & SetVendorId(std::optional vendorId) { mVendorId = vendorId; return *this; } std::optional GetVendorId() const { return mVendorId; } CommissionAdvertisingParameters & SetProductId(std::optional productId) { mProductId = productId; return *this; } std::optional GetProductId() const { return mProductId; } CommissionAdvertisingParameters & SetCommissioningMode(CommissioningMode mode) { mCommissioningMode = mode; return *this; } CommissioningMode GetCommissioningMode() const { return mCommissioningMode; } CommissionAdvertisingParameters & SetDeviceType(std::optional deviceType) { mDeviceType = deviceType; return *this; } std::optional GetDeviceType() const { return mDeviceType; } CommissionAdvertisingParameters & SetDeviceName(std::optional deviceName) { if (deviceName.has_value()) { Platform::CopyString(mDeviceName, sizeof(mDeviceName), *deviceName); mDeviceNameHasValue = true; } else { mDeviceNameHasValue = false; } return *this; } std::optional GetDeviceName() const { return mDeviceNameHasValue ? std::make_optional(mDeviceName) : std::nullopt; } CommissionAdvertisingParameters & SetRotatingDeviceId(std::optional rotatingId) { if (rotatingId.has_value()) { Platform::CopyString(mRotatingId, sizeof(mRotatingId), *rotatingId); mRotatingIdHasValue = true; } else { mRotatingIdHasValue = false; } return *this; } std::optional GetRotatingDeviceId() const { return mRotatingIdHasValue ? std::make_optional(mRotatingId) : std::nullopt; } CommissionAdvertisingParameters & SetPairingInstruction(std::optional pairingInstr) { if (pairingInstr.has_value()) { Platform::CopyString(mPairingInstr, sizeof(mPairingInstr), *pairingInstr); mPairingInstrHasValue = true; } else { mPairingInstrHasValue = false; } return *this; } std::optional GetPairingInstruction() const { return mPairingInstrHasValue ? std::make_optional(mPairingInstr) : std::nullopt; } CommissionAdvertisingParameters & SetPairingHint(std::optional pairingHint) { mPairingHint = pairingHint; return *this; } std::optional GetPairingHint() const { return mPairingHint; } CommissionAdvertisingParameters & SetCommissionAdvertiseMode(CommssionAdvertiseMode mode) { mMode = mode; return *this; } CommssionAdvertiseMode GetCommissionAdvertiseMode() const { return mMode; } CommissionAdvertisingParameters & SetCommissionerPasscodeSupported(std::optional commissionerPasscodeSupported) { mCommissionerPasscodeSupported = commissionerPasscodeSupported; return *this; } std::optional GetCommissionerPasscodeSupported() const { return mCommissionerPasscodeSupported; } private: uint8_t mShortDiscriminator = 0; uint16_t mLongDiscriminator = 0; // 12-bit according to spec CommssionAdvertiseMode mMode = CommssionAdvertiseMode::kCommissionableNode; CommissioningMode mCommissioningMode = CommissioningMode::kEnabledBasic; std::optional mVendorId; std::optional mProductId; std::optional mDeviceType; std::optional mPairingHint; char mDeviceName[kKeyDeviceNameMaxLength + 1]; bool mDeviceNameHasValue = false; char mRotatingId[kKeyRotatingDeviceIdMaxLength + 1]; bool mRotatingIdHasValue = false; char mPairingInstr[kKeyPairingInstructionMaxLength + 1]; bool mPairingInstrHasValue = false; std::optional mCommissionerPasscodeSupported; }; /** * Interface for advertising CHIP DNS-SD services. * * A user of this interface must first initialize the advertiser using the `Init` method. * * Then, whenever advertised services need to be refreshed, the following sequence of events must * occur: * 1. Call the `RemoveServices` method. * 2. Call one of the `Advertise` methods for each service to be added or updated. * 3. Call the `FinalizeServiceUpdate` method to finalize the update and apply all pending changes. */ class ServiceAdvertiser { public: virtual ~ServiceAdvertiser() {} /** * Initializes the advertiser. * * The method must be called before other methods of this class. * If the advertiser has already been initialized, the method exits immediately with no error. */ virtual CHIP_ERROR Init(chip::Inet::EndPointManager * udpEndPointManager) = 0; /** * Returns whether the advertiser has completed the initialization. * * Returns true if the advertiser is ready to advertise services. */ virtual bool IsInitialized() = 0; /** * Shuts down the advertiser. */ virtual void Shutdown() = 0; /** * Removes or marks all services being advertised for removal. * * Depending on the implementation, the method may either stop advertising existing services * immediately, or mark them for removal upon the subsequent `FinalizeServiceUpdate` method call. */ virtual CHIP_ERROR RemoveServices() = 0; /** * Advertises the given operational node service. */ virtual CHIP_ERROR Advertise(const OperationalAdvertisingParameters & params) = 0; /** * Advertises the given commissionable/commissioner node service. */ virtual CHIP_ERROR Advertise(const CommissionAdvertisingParameters & params) = 0; /** * Finalizes updating advertised services. * * This method can be used by some implementations to apply changes made with the `RemoveServices` * and `Advertise` methods in case they could not be applied immediately. */ virtual CHIP_ERROR FinalizeServiceUpdate() = 0; /** * Returns the commissionable node service instance name formatted as hex string. */ virtual CHIP_ERROR GetCommissionableInstanceName(char * instanceName, size_t maxLength) const = 0; /** * Generates an updated commissionable instance name. This happens * automatically when Init() is called, but may be needed at other times as * well. */ virtual CHIP_ERROR UpdateCommissionableInstanceName() = 0; /** * Returns the system-wide implementation of the service advertiser. * * The method returns a reference to the advertiser object configured by * a user using the \c ServiceAdvertiser::SetInstance() method, or the * default advertiser returned by the \c GetDefaultAdvertiser() function. */ static ServiceAdvertiser & Instance(); /** * Sets the system-wide implementation of the service advertiser. */ static void SetInstance(ServiceAdvertiser & advertiser); private: static ServiceAdvertiser * sInstance; }; /** * Returns the default implementation of the service advertiser. */ extern ServiceAdvertiser & GetDefaultAdvertiser(); } // namespace Dnssd } // namespace chip