Matter SDK Coverage Report
Current view: top level - lib/dnssd - TxtFields.cpp (source / functions) Coverage Total Hit
Test: SHA:b879ecb8e99e175eea0a293a888bda853da2b19c Lines: 100.0 % 140 140
Test Date: 2025-01-17 19:00:11 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            3 : uint32_t GetDeviceType(const ByteSpan & value)
     165              : {
     166            3 :     return MakeU32FromAsciiDecimal(value);
     167              : }
     168              : 
     169            4 : void GetDeviceName(const ByteSpan & value, char * name)
     170              : {
     171            4 :     Platform::CopyString(name, kMaxDeviceNameLen + 1, value);
     172            4 : }
     173              : 
     174            8 : void GetRotatingDeviceId(const ByteSpan & value, uint8_t * rotatingId, size_t * len)
     175              : {
     176            8 :     *len = Encoding::HexToBytes(reinterpret_cast<const char *>(value.data()), value.size(), rotatingId, kMaxRotatingIdLen);
     177            8 : }
     178              : 
     179           16 : uint16_t GetPairingHint(const ByteSpan & value)
     180              : {
     181           16 :     return MakeU16FromAsciiDecimal(value);
     182              : }
     183              : 
     184           16 : void GetPairingInstruction(const ByteSpan & value, char * pairingInstruction)
     185              : {
     186           16 :     Platform::CopyString(pairingInstruction, kMaxPairingInstructionLen + 1, value);
     187           16 : }
     188              : 
     189            4 : uint8_t GetCommissionerPasscode(const ByteSpan & value)
     190              : {
     191            4 :     return MakeBoolFromAsciiDecimal(value);
     192              : }
     193              : 
     194           43 : std::optional<System::Clock::Milliseconds32> GetRetryInterval(const ByteSpan & value)
     195              : {
     196           43 :     const auto undefined     = std::numeric_limits<uint32_t>::max();
     197           43 :     const auto retryInterval = MakeU32FromAsciiDecimal(value, undefined);
     198              : 
     199           43 :     if (retryInterval != undefined && retryInterval <= kMaxRetryInterval.count())
     200           19 :         return std::make_optional(System::Clock::Milliseconds32(retryInterval));
     201              : 
     202           24 :     return std::nullopt;
     203              : }
     204              : 
     205           16 : std::optional<System::Clock::Milliseconds16> GetRetryActiveThreshold(const ByteSpan & value)
     206              : {
     207           16 :     const auto retryInterval = MakeU16FromAsciiDecimal(value);
     208              : 
     209           16 :     if (retryInterval == 0)
     210              :     {
     211           12 :         return std::nullopt;
     212              :     }
     213              : 
     214            4 :     return std::make_optional(System::Clock::Milliseconds16(retryInterval));
     215              : }
     216              : 
     217          245 : TxtFieldKey GetTxtFieldKey(const ByteSpan & key)
     218              : {
     219         2011 :     for (auto & info : txtFieldInfo)
     220              :     {
     221         2005 :         if (IsKey(key, info.keyStr))
     222              :         {
     223          239 :             return info.key;
     224              :         }
     225              :     }
     226            6 :     return TxtFieldKey::kUnknown;
     227              : }
     228              : 
     229              : } // namespace Internal
     230              : 
     231           74 : void FillNodeDataFromTxt(const ByteSpan & key, const ByteSpan & val, CommissionNodeData & nodeData)
     232              : {
     233           74 :     TxtFieldKey keyType = Internal::GetTxtFieldKey(key);
     234           74 :     switch (keyType)
     235              :     {
     236           14 :     case TxtFieldKey::kLongDiscriminator:
     237           14 :         nodeData.longDiscriminator = Internal::GetLongDiscriminator(val);
     238           14 :         break;
     239           14 :     case TxtFieldKey::kVendorProduct:
     240           14 :         nodeData.vendorId  = Internal::GetVendor(val);
     241           14 :         nodeData.productId = Internal::GetProduct(val);
     242           14 :         break;
     243           13 :     case TxtFieldKey::kCommissioningMode:
     244           13 :         nodeData.commissioningMode = Internal::GetCommissioningMode(val);
     245           13 :         break;
     246            1 :     case TxtFieldKey::kDeviceType:
     247            1 :         nodeData.deviceType = Internal::GetDeviceType(val);
     248            1 :         break;
     249            2 :     case TxtFieldKey::kDeviceName:
     250            2 :         Internal::GetDeviceName(val, nodeData.deviceName);
     251            2 :         break;
     252            1 :     case TxtFieldKey::kRotatingDeviceId:
     253            1 :         Internal::GetRotatingDeviceId(val, nodeData.rotatingId, &nodeData.rotatingIdLen);
     254            1 :         break;
     255           13 :     case TxtFieldKey::kPairingInstruction:
     256           13 :         Internal::GetPairingInstruction(val, nodeData.pairingInstruction);
     257           13 :         break;
     258           13 :     case TxtFieldKey::kPairingHint:
     259           13 :         nodeData.pairingHint = Internal::GetPairingHint(val);
     260           13 :         break;
     261            1 :     case TxtFieldKey::kCommissionerPasscode:
     262            1 :         nodeData.supportsCommissionerGeneratedPasscode = Internal::GetCommissionerPasscode(val);
     263            1 :         break;
     264            2 :     default:
     265            2 :         FillNodeDataFromTxt(key, val, static_cast<CommonResolutionData &>(nodeData));
     266            2 :         break;
     267              :     }
     268           74 : }
     269              : 
     270          151 : void FillNodeDataFromTxt(const ByteSpan & key, const ByteSpan & value, CommonResolutionData & nodeData)
     271              : {
     272          151 :     switch (Internal::GetTxtFieldKey(key))
     273              :     {
     274           21 :     case TxtFieldKey::kSessionIdleInterval:
     275           21 :         nodeData.mrpRetryIntervalIdle = Internal::GetRetryInterval(value);
     276           21 :         break;
     277           22 :     case TxtFieldKey::kSessionActiveInterval:
     278           22 :         nodeData.mrpRetryIntervalActive = Internal::GetRetryInterval(value);
     279           22 :         break;
     280           16 :     case TxtFieldKey::kSessionActiveThreshold:
     281           16 :         nodeData.mrpRetryActiveThreshold = Internal::GetRetryActiveThreshold(value);
     282           16 :         break;
     283           20 :     case TxtFieldKey::kTcpSupported: {
     284              :         // bit 0 is reserved and deprecated
     285           20 :         uint8_t support            = Internal::MakeU8FromAsciiDecimal(value);
     286           20 :         nodeData.supportsTcpClient = (support & (1 << Internal::kTCPClient)) != 0;
     287           20 :         nodeData.supportsTcpServer = (support & (1 << Internal::kTCPServer)) != 0;
     288           20 :         break;
     289              :     }
     290            6 :     case TxtFieldKey::kLongIdleTimeICD:
     291            6 :         nodeData.isICDOperatingAsLIT = Internal::MakeOptionalBoolFromAsciiDecimal(value);
     292            6 :         break;
     293           66 :     default:
     294           66 :         break;
     295              :     }
     296          151 : }
     297              : 
     298              : } // namespace Dnssd
     299              : } // namespace chip
        

Generated by: LCOV version 2.0-1