Matter SDK Coverage Report
Current view: top level - lib/dnssd/minimal_mdns - Server.cpp (source / functions) Coverage Total Hit
Test: SHA:e98a48c2e59f85a25417956e1d105721433aa5d1 Lines: 61.7 % 162 100
Test Date: 2026-01-09 16:53:50 Functions: 65.4 % 26 17

            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              : #include "Server.h"
      19              : 
      20              : #include <errno.h>
      21              : #include <utility>
      22              : 
      23              : #include <lib/dnssd/minimal_mdns/core/DnsHeader.h>
      24              : #include <platform/CHIPDeviceLayer.h>
      25              : 
      26              : namespace mdns {
      27              : namespace Minimal {
      28              : namespace {
      29              : 
      30              : class ShutdownOnError
      31              : {
      32              : public:
      33           18 :     ShutdownOnError(ServerBase * s) : mServer(s) {}
      34           18 :     ~ShutdownOnError()
      35              :     {
      36           18 :         if (mServer != nullptr)
      37              :         {
      38            0 :             mServer->Shutdown();
      39              :         }
      40           18 :     }
      41              : 
      42           18 :     CHIP_ERROR ReturnSuccess()
      43              :     {
      44           18 :         mServer = nullptr;
      45           18 :         return CHIP_NO_ERROR;
      46              :     }
      47              : 
      48              : private:
      49              :     ServerBase * mServer;
      50              : };
      51              : 
      52              : /**
      53              :  * Extracts the Listening UDP Endpoint from an underlying ServerBase::EndpointInfo
      54              :  */
      55              : class ListenSocketPickerDelegate : public ServerBase::BroadcastSendDelegate
      56              : {
      57              : public:
      58           48 :     chip::Inet::UDPEndPointHandle Accept(ServerBase::EndpointInfo * info) override { return info->mListenUdp; }
      59              : };
      60              : 
      61              : #if CHIP_MINMDNS_USE_EPHEMERAL_UNICAST_PORT
      62              : 
      63              : /**
      64              :  * Extracts the Querying UDP Endpoint from an underlying ServerBase::EndpointInfo
      65              :  */
      66              : class QuerySocketPickerDelegate : public ServerBase::BroadcastSendDelegate
      67              : {
      68              : public:
      69            0 :     chip::Inet::UDPEndPointHandle Accept(ServerBase::EndpointInfo * info) override { return info->mUnicastQueryUdp; }
      70              : };
      71              : 
      72              : #else
      73              : 
      74              : using QuerySocketPickerDelegate = ListenSocketPickerDelegate;
      75              : 
      76              : #endif
      77              : 
      78              : /**
      79              :  * Validates that an endpoint belongs to a specific interface/ip address type before forwarding the
      80              :  * endpoint accept logic to another BroadcastSendDelegate.
      81              :  *
      82              :  * Usage like:
      83              :  *
      84              :  * SomeDelegate *child = ....;
      85              :  * InterfaceTypeFilterDelegate filter(interfaceId, IPAddressType::IPv6, child);
      86              :  *
      87              :  * UDPEndPoint *udp = filter.Accept(endpointInfo);
      88              :  */
      89              : class InterfaceTypeFilterDelegate : public ServerBase::BroadcastSendDelegate
      90              : {
      91              : public:
      92           78 :     InterfaceTypeFilterDelegate(chip::Inet::InterfaceId interface, chip::Inet::IPAddressType type,
      93           78 :                                 ServerBase::BroadcastSendDelegate * child) :
      94           78 :         mInterface(interface),
      95           78 :         mAddressType(type), mChild(child)
      96           78 :     {}
      97              : 
      98           96 :     chip::Inet::UDPEndPointHandle Accept(ServerBase::EndpointInfo * info) override
      99              :     {
     100           96 :         if ((info->mInterfaceId != mInterface) && (info->mInterfaceId != chip::Inet::InterfaceId::Null()))
     101              :         {
     102            0 :             return nullptr;
     103              :         }
     104              : 
     105           96 :         if ((mAddressType != chip::Inet::IPAddressType::kAny) && (info->mAddressType != mAddressType))
     106              :         {
     107           48 :             return nullptr;
     108              :         }
     109              : 
     110           48 :         return mChild->Accept(info);
     111              :     }
     112              : 
     113              : private:
     114              :     chip::Inet::InterfaceId mInterface;
     115              :     chip::Inet::IPAddressType mAddressType;
     116              :     ServerBase::BroadcastSendDelegate * mChild = nullptr;
     117              : };
     118              : 
     119              : } // namespace
     120              : 
     121              : namespace BroadcastIpAddresses {
     122              : 
     123              : // Get standard mDNS Broadcast addresses
     124          372 : chip::Inet::IPAddress Get(chip::Inet::IPAddressType addressType)
     125              : {
     126              :     chip::Inet::IPAddress address;
     127              : #if INET_CONFIG_ENABLE_IPV4
     128          372 :     if (addressType == chip::Inet::IPAddressType::kIPv4)
     129              :     {
     130          186 :         VerifyOrDie(chip::Inet::IPAddress::FromString("224.0.0.251", address));
     131              :     }
     132              :     else
     133              : #endif
     134              :     {
     135          186 :         VerifyOrDie(chip::Inet::IPAddress::FromString("FF02::FB", address));
     136              :     }
     137          372 :     return address;
     138              : }
     139              : 
     140              : } // namespace BroadcastIpAddresses
     141              : 
     142              : namespace {
     143              : 
     144              : #if CHIP_ERROR_LOGGING
     145            0 : const char * AddressTypeStr(chip::Inet::IPAddressType addressType)
     146              : {
     147            0 :     switch (addressType)
     148              :     {
     149            0 :     case chip::Inet::IPAddressType::kIPv6:
     150            0 :         return "IPv6";
     151              : #if INET_CONFIG_ENABLE_IPV4
     152            0 :     case chip::Inet::IPAddressType::kIPv4:
     153            0 :         return "IPv4";
     154              : #endif // INET_CONFIG_ENABLE_IPV4
     155            0 :     default:
     156            0 :         return "UNKNOWN";
     157              :     }
     158              : }
     159              : #endif
     160              : 
     161              : } // namespace
     162              : 
     163          109 : ServerBase::~ServerBase()
     164              : {
     165          109 :     Shutdown();
     166          109 : }
     167              : 
     168          114 : void ServerBase::Shutdown()
     169              : {
     170          114 :     ShutdownEndpoints();
     171          114 :     mIsInitialized = false;
     172          114 : }
     173              : 
     174          167 : void ServerBase::ShutdownEndpoints()
     175              : {
     176          167 :     mEndpoints.ReleaseAll();
     177          167 : }
     178              : 
     179            0 : void ServerBase::ShutdownEndpoint(EndpointInfo & aEndpoint)
     180              : {
     181            0 :     mEndpoints.ReleaseObject(&aEndpoint);
     182            0 : }
     183              : 
     184            2 : bool ServerBase::IsListening() const
     185              : {
     186            2 :     bool listening = false;
     187            2 :     mEndpoints.ForEachActiveObject([&](auto * endpoint) {
     188            1 :         if (endpoint->mListenUdp)
     189              :         {
     190            1 :             listening = true;
     191            1 :             return chip::Loop::Break;
     192              :         }
     193            0 :         return chip::Loop::Continue;
     194              :     });
     195            2 :     return listening;
     196              : }
     197              : 
     198           18 : CHIP_ERROR ServerBase::Listen(chip::Inet::EndPointManager<chip::Inet::UDPEndPoint> * udpEndPointManager, ListenIterator * it,
     199              :                               uint16_t port)
     200              : {
     201           18 :     ShutdownEndpoints(); // ensure everything starts fresh
     202              : 
     203           18 :     chip::Inet::InterfaceId interfaceId = chip::Inet::InterfaceId::Null();
     204              :     chip::Inet::IPAddressType addressType;
     205              : 
     206           18 :     ShutdownOnError autoShutdown(this);
     207              : 
     208           54 :     while (it->Next(&interfaceId, &addressType))
     209              :     {
     210           36 :         chip::Inet::UDPEndPointHandle listenUdp;
     211           36 :         ReturnErrorOnFailure(udpEndPointManager->NewEndPoint(listenUdp));
     212              : 
     213           36 :         ReturnErrorOnFailure(listenUdp->Bind(addressType, chip::Inet::IPAddress::Any, port, interfaceId));
     214              : 
     215           36 :         ReturnErrorOnFailure(listenUdp->Listen(OnUdpPacketReceived, nullptr /*OnReceiveError*/, this));
     216              : 
     217           36 :         CHIP_ERROR err = listenUdp->JoinMulticastGroup(interfaceId, BroadcastIpAddresses::Get(addressType));
     218              : 
     219           72 :         if (err != CHIP_NO_ERROR)
     220              :         {
     221              :             char interfaceName[chip::Inet::InterfaceId::kMaxIfNameLength];
     222            0 :             TEMPORARY_RETURN_IGNORED interfaceId.GetInterfaceName(interfaceName, sizeof(interfaceName));
     223              : 
     224              :             // Log only as non-fatal error. Failure to join will mean we reply to unicast queries only.
     225            0 :             ChipLogError(DeviceLayer, "MDNS failed to join multicast group on %s for address type %s: %" CHIP_ERROR_FORMAT,
     226              :                          interfaceName, AddressTypeStr(addressType), err.Format());
     227              : 
     228            0 :             listenUdp.Release();
     229              :         }
     230              : 
     231              : #if CHIP_MINMDNS_USE_EPHEMERAL_UNICAST_PORT
     232              :         // Separate UDP endpoint for unicast queries, bound to 0 (i.e. pick random ephemeral port)
     233              :         //   - helps in not having conflicts on port 5353, will receive unicast replies directly
     234              :         //   - has a *DRAWBACK* of unicast queries being considered LEGACY by mdns since they do
     235              :         //     not originate from 5353 and the answers will include a query section.
     236           36 :         chip::Inet::UDPEndPointHandle unicastQueryUdp;
     237           36 :         ReturnErrorOnFailure(udpEndPointManager->NewEndPoint(unicastQueryUdp));
     238           36 :         ReturnErrorOnFailure(unicastQueryUdp->Bind(addressType, chip::Inet::IPAddress::Any, 0, interfaceId));
     239           36 :         ReturnErrorOnFailure(unicastQueryUdp->Listen(OnUdpPacketReceived, nullptr /*OnReceiveError*/, this));
     240              : #endif
     241              : 
     242              : #if CHIP_MINMDNS_USE_EPHEMERAL_UNICAST_PORT
     243           36 :         if (listenUdp || unicastQueryUdp)
     244              :         {
     245              :             // If allocation fails, the rref will not be consumed, so that the endpoint will also be freed correctly
     246           36 :             mEndpoints.CreateObject(interfaceId, addressType, std::move(listenUdp), std::move(unicastQueryUdp));
     247              :         }
     248              : #else
     249              :         if (listenUdp)
     250              :         {
     251              :             // If allocation fails, the rref will not be consumed, so that the endpoint will also be freed correctly
     252              :             mEndpoints.CreateObject(interfaceId, addressType, std::move(listenUdp));
     253              :         }
     254              : #endif
     255              : 
     256              :         // If at least one IPv6 interface is used by the mDNS server, notify the application that DNS-SD is ready.
     257           36 :         if (!mIsInitialized && addressType == chip::Inet::IPAddressType::kIPv6)
     258              :         {
     259              : #if !CHIP_DEVICE_LAYER_NONE
     260            2 :             chip::DeviceLayer::ChipDeviceEvent event{};
     261            2 :             event.Type = chip::DeviceLayer::DeviceEventType::kDnssdInitialized;
     262            2 :             chip::DeviceLayer::PlatformMgr().PostEventOrDie(&event);
     263              : #endif
     264            2 :             mIsInitialized = true;
     265              :         }
     266           36 :     }
     267              : 
     268           18 :     return autoShutdown.ReturnSuccess();
     269           18 : }
     270              : 
     271            0 : CHIP_ERROR ServerBase::DirectSend(chip::System::PacketBufferHandle && data, const chip::Inet::IPAddress & addr, uint16_t port,
     272              :                                   chip::Inet::InterfaceId interface)
     273              : {
     274            0 :     CHIP_ERROR err = CHIP_ERROR_NOT_CONNECTED;
     275            0 :     mEndpoints.ForEachActiveObject([&](auto * info) {
     276            0 :         if (info->mListenUdp.IsNull())
     277              :         {
     278            0 :             return chip::Loop::Continue;
     279              :         }
     280              : 
     281            0 :         if (info->mAddressType != addr.Type())
     282              :         {
     283            0 :             return chip::Loop::Continue;
     284              :         }
     285              : 
     286            0 :         chip::Inet::InterfaceId boundIf = info->mListenUdp->GetBoundInterface();
     287              : 
     288            0 :         if ((boundIf.IsPresent()) && (boundIf != interface))
     289              :         {
     290            0 :             return chip::Loop::Continue;
     291              :         }
     292              : 
     293            0 :         err = info->mListenUdp->SendTo(addr, port, std::move(data));
     294            0 :         return chip::Loop::Break;
     295              :     });
     296              : 
     297            0 :     return err;
     298              : }
     299              : 
     300            0 : CHIP_ERROR ServerBase::BroadcastUnicastQuery(chip::System::PacketBufferHandle && data, uint16_t port)
     301              : {
     302            0 :     QuerySocketPickerDelegate socketPicker;
     303            0 :     return BroadcastImpl(std::move(data), port, &socketPicker);
     304            0 : }
     305              : 
     306            0 : CHIP_ERROR ServerBase::BroadcastUnicastQuery(chip::System::PacketBufferHandle && data, uint16_t port,
     307              :                                              chip::Inet::InterfaceId interface, chip::Inet::IPAddressType addressType)
     308              : {
     309            0 :     QuerySocketPickerDelegate socketPicker;
     310            0 :     InterfaceTypeFilterDelegate filter(interface, addressType, &socketPicker);
     311              : 
     312            0 :     return BroadcastImpl(std::move(data), port, &filter);
     313            0 : }
     314              : 
     315           78 : CHIP_ERROR ServerBase::BroadcastSend(chip::System::PacketBufferHandle && data, uint16_t port, chip::Inet::InterfaceId interface,
     316              :                                      chip::Inet::IPAddressType addressType)
     317              : {
     318           78 :     ListenSocketPickerDelegate socketPicker;
     319           78 :     InterfaceTypeFilterDelegate filter(interface, addressType, &socketPicker);
     320              : 
     321           78 :     return BroadcastImpl(std::move(data), port, &filter);
     322           78 : }
     323              : 
     324            0 : CHIP_ERROR ServerBase::BroadcastSend(chip::System::PacketBufferHandle && data, uint16_t port)
     325              : {
     326            0 :     ListenSocketPickerDelegate socketPicker;
     327            0 :     return BroadcastImpl(std::move(data), port, &socketPicker);
     328            0 : }
     329              : 
     330           78 : CHIP_ERROR ServerBase::BroadcastImpl(chip::System::PacketBufferHandle && data, uint16_t port, BroadcastSendDelegate * delegate)
     331              : {
     332              :     // Broadcast requires sending data multiple times, each of which may error
     333              :     // out, yet broadcast only has a single error code.
     334              :     //
     335              :     // The general logic of error handling is:
     336              :     //   - if no send done at all, return error
     337              :     //   - if at least one broadcast succeeds, assume success overall
     338              :     //   + some internal consistency validations for state error.
     339              : 
     340           78 :     unsigned successes   = 0;
     341           78 :     unsigned failures    = 0;
     342           78 :     CHIP_ERROR lastError = CHIP_ERROR_NO_ENDPOINT;
     343              : 
     344           78 :     if (chip::Loop::Break == mEndpoints.ForEachActiveObject([&](auto * info) {
     345           96 :             auto udp = delegate->Accept(info);
     346              : 
     347           96 :             if (udp.IsNull())
     348              :             {
     349           48 :                 return chip::Loop::Continue;
     350              :             }
     351              : 
     352           48 :             CHIP_ERROR err = CHIP_NO_ERROR;
     353              : 
     354              :             /// The same packet needs to be sent over potentially multiple interfaces.
     355              :             /// LWIP does not like having a pbuf sent over serparate interfaces, hence we create a copy
     356              :             /// for sending via `CloneData`
     357              :             ///
     358              :             /// TODO: this wastes one copy of the data and that could be optimized away
     359           48 :             chip::System::PacketBufferHandle tempBuf = data.CloneData();
     360           48 :             if (tempBuf.IsNull())
     361              :             {
     362              :                 // Not enough memory available to clone pbuf
     363            0 :                 err = CHIP_ERROR_NO_MEMORY;
     364              :             }
     365           48 :             else if (info->mAddressType == chip::Inet::IPAddressType::kIPv6)
     366              :             {
     367           24 :                 err = udp->SendTo(mIpv6BroadcastAddress, port, std::move(tempBuf), udp->GetBoundInterface());
     368              :             }
     369              : #if INET_CONFIG_ENABLE_IPV4
     370           24 :             else if (info->mAddressType == chip::Inet::IPAddressType::kIPv4)
     371              :             {
     372           24 :                 err = udp->SendTo(mIpv4BroadcastAddress, port, std::move(tempBuf), udp->GetBoundInterface());
     373              :             }
     374              : #endif
     375              :             else
     376              :             {
     377              :                 // This is a general error of internal consistency: every address has a known type. Fail completely otherwise.
     378            0 :                 lastError = CHIP_ERROR_INCORRECT_STATE;
     379            0 :                 return chip::Loop::Break;
     380              :             }
     381              : 
     382           96 :             if (err == CHIP_NO_ERROR)
     383              :             {
     384           48 :                 successes++;
     385              :             }
     386              :             else
     387              :             {
     388            0 :                 failures++;
     389            0 :                 lastError = err;
     390              : #if CHIP_DETAIL_LOGGING
     391              :                 char ifaceName[chip::Inet::InterfaceId::kMaxIfNameLength];
     392            0 :                 err = info->mInterfaceId.GetInterfaceName(ifaceName, sizeof(ifaceName));
     393            0 :                 if (err != CHIP_NO_ERROR)
     394            0 :                     strcpy(ifaceName, "???");
     395            0 :                 ChipLogDetail(Discovery, "Warning: Attempt to mDNS broadcast failed on %s:  %s", ifaceName, lastError.AsString());
     396              : #endif
     397              :             }
     398           48 :             return chip::Loop::Continue;
     399           96 :         }))
     400              :     {
     401            0 :         return lastError;
     402              :     }
     403              : 
     404           78 :     if (failures != 0)
     405              :     {
     406              :         // if we had failures, log if the final status was success or failure, to make log reading
     407              :         // easier. Some mDNS failures may be expected (e.g. for interfaces unavailable)
     408            0 :         if (successes != 0)
     409              :         {
     410            0 :             ChipLogDetail(Discovery, "mDNS broadcast had only partial success: %u successes and %u failures.", successes, failures);
     411              :         }
     412              :         else
     413              :         {
     414            0 :             ChipLogProgress(Discovery, "mDNS broadcast full failed in %u separate send attempts.", failures);
     415              :         }
     416              :     }
     417              : 
     418           78 :     if (!successes)
     419              :     {
     420           30 :         return lastError;
     421              :     }
     422              : 
     423           48 :     return CHIP_NO_ERROR;
     424              : }
     425              : 
     426           10 : void ServerBase::OnUdpPacketReceived(chip::Inet::UDPEndPoint * endPoint, chip::System::PacketBufferHandle && buffer,
     427              :                                      const chip::Inet::IPPacketInfo * info)
     428              : {
     429           10 :     ServerBase * srv = static_cast<ServerBase *>(endPoint->mAppState);
     430           10 :     if (!srv->mDelegate)
     431              :     {
     432            0 :         return;
     433              :     }
     434              : 
     435           10 :     mdns::Minimal::BytesRange data(buffer->Start(), buffer->Start() + buffer->DataLength());
     436           10 :     if (data.Size() < HeaderRef::kSizeBytes)
     437              :     {
     438            0 :         ChipLogError(Discovery, "Packet too small for mDNS data: %d bytes", static_cast<int>(data.Size()));
     439            0 :         return;
     440              :     }
     441              : 
     442           10 :     if (HeaderRef(const_cast<uint8_t *>(data.Start())).GetFlags().IsQuery())
     443              :     {
     444              :         // Only consider queries that are received on the same interface we are listening on.
     445              :         // Without this, queries show up on all addresses on all interfaces, resulting
     446              :         // in more replies than one would expect.
     447            0 :         if (endPoint->GetBoundInterface() == info->Interface)
     448              :         {
     449            0 :             srv->mDelegate->OnQuery(data, info);
     450              :         }
     451              :     }
     452              :     else
     453              :     {
     454           10 :         srv->mDelegate->OnResponse(data, info);
     455              :     }
     456              : }
     457              : 
     458              : } // namespace Minimal
     459              : } // namespace mdns
        

Generated by: LCOV version 2.0-1