Matter SDK Coverage Report
Current view: top level - lib/dnssd - TxtFields.cpp (source / functions) Coverage Total Hit
Test: SHA:9151e79d6b5c010f18e3a3da0b048f38196f06c6 Lines: 100.0 % 140 140
Test Date: 2025-07-02 07:09:01 Functions: 100.0 % 23 23

            Line data    Source code
       1              : /*
       2              :  *
       3              :  *    Copyright (c) 2021 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              : #include "TxtFields.h"
      19              : 
      20              : #include <algorithm>
      21              : #include <cctype>
      22              : #include <climits>
      23              : #include <cstdio>
      24              : #include <inttypes.h>
      25              : #include <limits>
      26              : #include <stdlib.h>
      27              : #include <string.h>
      28              : 
      29              : #include <lib/core/CHIPSafeCasts.h>
      30              : #include <lib/dnssd/Advertiser.h>
      31              : #include <lib/dnssd/Resolver.h>
      32              : #include <lib/support/BytesToHex.h>
      33              : #include <lib/support/CHIPMemString.h>
      34              : #include <lib/support/SafeInt.h>
      35              : 
      36              : namespace chip {
      37              : namespace Dnssd {
      38              : 
      39              : namespace Internal {
      40              : 
      41              : constexpr uint8_t kTCPClient = 1;
      42              : constexpr uint8_t kTCPServer = 2;
      43              : 
      44              : namespace {
      45              : 
      46         2174 : char SafeToLower(uint8_t ch)
      47              : {
      48         2174 :     return static_cast<char>(std::tolower(static_cast<unsigned char>(ch)));
      49              : }
      50         2005 : bool IsKey(const ByteSpan & key, const char * desired)
      51              : {
      52         2005 :     if (key.size() != strlen(desired))
      53              :     {
      54         1284 :         return false;
      55              :     }
      56              : 
      57          721 :     auto desired_bytes = Uint8::from_const_char(desired);
      58         1326 :     for (size_t i = 0; i < key.size(); ++i)
      59              :     {
      60         1087 :         if (SafeToLower(key.data()[i]) != SafeToLower(desired_bytes[i]))
      61              :         {
      62          482 :             return false;
      63              :         }
      64              :     }
      65          239 :     return true;
      66              : }
      67              : 
      68          167 : uint32_t MakeU32FromAsciiDecimal(const ByteSpan & val, uint32_t defaultValue = 0)
      69              : {
      70              :     // +1 because `digits10` means the number of decimal digits that fit in `uint32_t`,
      71              :     // not how many digits are enough to represent any `uint32_t`
      72              :     // +1 for null-terminator
      73              :     char nullTerminatedValue[std::numeric_limits<uint32_t>::digits10 + 2];
      74              : 
      75              :     // value is too long to store `uint32_t`
      76          167 :     if (val.size() >= sizeof(nullTerminatedValue))
      77            6 :         return defaultValue;
      78              : 
      79              :     // value contains leading zeros
      80          161 :     if (val.size() > 1 && *val.data() == static_cast<uint8_t>('0'))
      81           12 :         return defaultValue;
      82              : 
      83          149 :     Platform::CopyString(nullTerminatedValue, sizeof(nullTerminatedValue), val);
      84              : 
      85              :     char * endPtr;
      86          149 :     unsigned long num = strtoul(nullTerminatedValue, &endPtr, 10);
      87              : 
      88          149 :     if (endPtr > nullTerminatedValue && *endPtr == '\0' && num != ULONG_MAX && CanCastTo<uint32_t>(num))
      89          133 :         return static_cast<uint32_t>(num);
      90              : 
      91           16 :     return defaultValue;
      92              : }
      93              : 
      94           84 : uint16_t MakeU16FromAsciiDecimal(const ByteSpan & val)
      95              : {
      96           84 :     const uint32_t num = MakeU32FromAsciiDecimal(val);
      97           84 :     return CanCastTo<uint16_t>(num) ? static_cast<uint16_t>(num) : 0;
      98              : }
      99              : 
     100           37 : uint8_t MakeU8FromAsciiDecimal(const ByteSpan & val)
     101              : {
     102           37 :     const uint32_t num = MakeU32FromAsciiDecimal(val);
     103           37 :     return CanCastTo<uint8_t>(num) ? static_cast<uint8_t>(num) : 0;
     104              : }
     105              : 
     106            4 : bool MakeBoolFromAsciiDecimal(const ByteSpan & val)
     107              : {
     108            4 :     return val.size() == 1 && static_cast<char>(*val.data()) == '1';
     109              : }
     110              : 
     111            6 : std::optional<bool> MakeOptionalBoolFromAsciiDecimal(const ByteSpan & val)
     112              : {
     113            6 :     char character = static_cast<char>(*val.data());
     114            6 :     if (val.size() == 1 && ((character == '1') || (character == '0')))
     115              :     {
     116            4 :         return std::make_optional(character == '1');
     117              :     }
     118            2 :     return std::nullopt;
     119              : }
     120              : 
     121           38 : size_t GetPlusSignIdx(const ByteSpan & value)
     122              : {
     123              :     // First value is the vendor id, second (after the +) is the product.
     124          196 :     for (size_t i = 0; i < value.size(); ++i)
     125              :     {
     126          194 :         if (static_cast<char>(value.data()[i]) == '+')
     127              :         {
     128           36 :             return i;
     129              :         }
     130              :     }
     131            2 :     return value.size();
     132              : }
     133              : 
     134              : } // namespace
     135              : 
     136           19 : uint16_t GetProduct(const ByteSpan & value)
     137              : {
     138           19 :     size_t plussign = GetPlusSignIdx(value);
     139           19 :     if (plussign < value.size() - 1)
     140              :     {
     141           17 :         const uint8_t * productStrStart = value.data() + plussign + 1;
     142           17 :         size_t productStrLen            = value.size() - plussign - 1;
     143           17 :         return MakeU16FromAsciiDecimal(ByteSpan(productStrStart, productStrLen));
     144              :     }
     145            2 :     return 0;
     146              : }
     147              : 
     148           19 : uint16_t GetVendor(const ByteSpan & value)
     149              : {
     150           19 :     size_t plussign = GetPlusSignIdx(value);
     151           19 :     return MakeU16FromAsciiDecimal(ByteSpan(value.data(), plussign));
     152              : }
     153              : 
     154           16 : uint16_t GetLongDiscriminator(const ByteSpan & value)
     155              : {
     156           16 :     return MakeU16FromAsciiDecimal(value);
     157              : }
     158              : 
     159           17 : uint8_t GetCommissioningMode(const ByteSpan & value)
     160              : {
     161           17 :     return MakeU8FromAsciiDecimal(value);
     162              : }
     163              : 
     164              : #if CHIP_DEVICE_CONFIG_ENABLE_JOINT_FABRIC
     165              : BitFlags<JointFabricMode> GetJointFabricMode(const ByteSpan & value)
     166              : {
     167              :     return BitFlags<JointFabricMode>(MakeU8FromAsciiDecimal(value));
     168              : }
     169              : #endif // CHIP_DEVICE_CONFIG_ENABLE_JOINT_FABRIC
     170              : 
     171            3 : uint32_t GetDeviceType(const ByteSpan & value)
     172              : {
     173            3 :     return MakeU32FromAsciiDecimal(value);
     174              : }
     175              : 
     176            4 : void GetDeviceName(const ByteSpan & value, char * name)
     177              : {
     178            4 :     Platform::CopyString(name, kMaxDeviceNameLen + 1, value);
     179            4 : }
     180              : 
     181            8 : void GetRotatingDeviceId(const ByteSpan & value, uint8_t * rotatingId, size_t * len)
     182              : {
     183            8 :     *len = Encoding::HexToBytes(reinterpret_cast<const char *>(value.data()), value.size(), rotatingId, kMaxRotatingIdLen);
     184            8 : }
     185              : 
     186           16 : uint16_t GetPairingHint(const ByteSpan & value)
     187              : {
     188           16 :     return MakeU16FromAsciiDecimal(value);
     189              : }
     190              : 
     191           16 : void GetPairingInstruction(const ByteSpan & value, char * pairingInstruction)
     192              : {
     193           16 :     Platform::CopyString(pairingInstruction, kMaxPairingInstructionLen + 1, value);
     194           16 : }
     195              : 
     196            4 : uint8_t GetCommissionerPasscode(const ByteSpan & value)
     197              : {
     198            4 :     return MakeBoolFromAsciiDecimal(value);
     199              : }
     200              : 
     201           43 : std::optional<System::Clock::Milliseconds32> GetRetryInterval(const ByteSpan & value)
     202              : {
     203           43 :     const auto undefined     = std::numeric_limits<uint32_t>::max();
     204           43 :     const auto retryInterval = MakeU32FromAsciiDecimal(value, undefined);
     205              : 
     206           43 :     if (retryInterval != undefined && retryInterval <= kMaxRetryInterval.count())
     207           19 :         return std::make_optional(System::Clock::Milliseconds32(retryInterval));
     208              : 
     209           24 :     return std::nullopt;
     210              : }
     211              : 
     212           16 : std::optional<System::Clock::Milliseconds16> GetRetryActiveThreshold(const ByteSpan & value)
     213              : {
     214           16 :     const auto retryInterval = MakeU16FromAsciiDecimal(value);
     215              : 
     216           16 :     if (retryInterval == 0)
     217              :     {
     218           12 :         return std::nullopt;
     219              :     }
     220              : 
     221            4 :     return std::make_optional(System::Clock::Milliseconds16(retryInterval));
     222              : }
     223              : 
     224          245 : TxtFieldKey GetTxtFieldKey(const ByteSpan & key)
     225              : {
     226         2011 :     for (auto & info : txtFieldInfo)
     227              :     {
     228         2005 :         if (IsKey(key, info.keyStr))
     229              :         {
     230          239 :             return info.key;
     231              :         }
     232              :     }
     233            6 :     return TxtFieldKey::kUnknown;
     234              : }
     235              : 
     236              : } // namespace Internal
     237              : 
     238           74 : void FillNodeDataFromTxt(const ByteSpan & key, const ByteSpan & val, CommissionNodeData & nodeData)
     239              : {
     240           74 :     TxtFieldKey keyType = Internal::GetTxtFieldKey(key);
     241           74 :     switch (keyType)
     242              :     {
     243           14 :     case TxtFieldKey::kLongDiscriminator:
     244           14 :         nodeData.longDiscriminator = Internal::GetLongDiscriminator(val);
     245           14 :         break;
     246           14 :     case TxtFieldKey::kVendorProduct:
     247           14 :         nodeData.vendorId  = Internal::GetVendor(val);
     248           14 :         nodeData.productId = Internal::GetProduct(val);
     249           14 :         break;
     250           13 :     case TxtFieldKey::kCommissioningMode:
     251           13 :         nodeData.commissioningMode = Internal::GetCommissioningMode(val);
     252           13 :         break;
     253            1 :     case TxtFieldKey::kDeviceType:
     254            1 :         nodeData.deviceType = Internal::GetDeviceType(val);
     255            1 :         break;
     256            2 :     case TxtFieldKey::kDeviceName:
     257            2 :         Internal::GetDeviceName(val, nodeData.deviceName);
     258            2 :         break;
     259            1 :     case TxtFieldKey::kRotatingDeviceId:
     260            1 :         Internal::GetRotatingDeviceId(val, nodeData.rotatingId, &nodeData.rotatingIdLen);
     261            1 :         break;
     262           13 :     case TxtFieldKey::kPairingInstruction:
     263           13 :         Internal::GetPairingInstruction(val, nodeData.pairingInstruction);
     264           13 :         break;
     265           13 :     case TxtFieldKey::kPairingHint:
     266           13 :         nodeData.pairingHint = Internal::GetPairingHint(val);
     267           13 :         break;
     268            1 :     case TxtFieldKey::kCommissionerPasscode:
     269            1 :         nodeData.supportsCommissionerGeneratedPasscode = Internal::GetCommissionerPasscode(val);
     270            1 :         break;
     271              : #if CHIP_DEVICE_CONFIG_ENABLE_JOINT_FABRIC
     272              :     case TxtFieldKey::kJointFabricMode:
     273              :         nodeData.jointFabricMode = Internal::GetJointFabricMode(val);
     274              :         break;
     275              : #endif // CHIP_DEVICE_CONFIG_ENABLE_JOINT_FABRIC
     276            2 :     default:
     277            2 :         FillNodeDataFromTxt(key, val, static_cast<CommonResolutionData &>(nodeData));
     278            2 :         break;
     279              :     }
     280           74 : }
     281              : 
     282          151 : void FillNodeDataFromTxt(const ByteSpan & key, const ByteSpan & value, CommonResolutionData & nodeData)
     283              : {
     284          151 :     switch (Internal::GetTxtFieldKey(key))
     285              :     {
     286           21 :     case TxtFieldKey::kSessionIdleInterval:
     287           21 :         nodeData.mrpRetryIntervalIdle = Internal::GetRetryInterval(value);
     288           21 :         break;
     289           22 :     case TxtFieldKey::kSessionActiveInterval:
     290           22 :         nodeData.mrpRetryIntervalActive = Internal::GetRetryInterval(value);
     291           22 :         break;
     292           16 :     case TxtFieldKey::kSessionActiveThreshold:
     293           16 :         nodeData.mrpRetryActiveThreshold = Internal::GetRetryActiveThreshold(value);
     294           16 :         break;
     295           20 :     case TxtFieldKey::kTcpSupported: {
     296              :         // bit 0 is reserved and deprecated
     297           20 :         uint8_t support            = Internal::MakeU8FromAsciiDecimal(value);
     298           20 :         nodeData.supportsTcpClient = (support & (1 << Internal::kTCPClient)) != 0;
     299           20 :         nodeData.supportsTcpServer = (support & (1 << Internal::kTCPServer)) != 0;
     300           20 :         break;
     301              :     }
     302            6 :     case TxtFieldKey::kLongIdleTimeICD:
     303            6 :         nodeData.isICDOperatingAsLIT = Internal::MakeOptionalBoolFromAsciiDecimal(value);
     304            6 :         break;
     305           66 :     default:
     306           66 :         break;
     307              :     }
     308          151 : }
     309              : 
     310              : } // namespace Dnssd
     311              : } // namespace chip
        

Generated by: LCOV version 2.0-1