Matter SDK Coverage Report
Current view: top level - lib/dnssd/minimal_mdns - Server.cpp (source / functions) Coverage Total Hit
Test: SHA:b879ecb8e99e175eea0a293a888bda853da2b19c Lines: 61.7 % 162 100
Test Date: 2025-01-17 19:00:11 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           14 :     ShutdownOnError(ServerBase * s) : mServer(s) {}
      34           14 :     ~ShutdownOnError()
      35              :     {
      36           14 :         if (mServer != nullptr)
      37              :         {
      38            0 :             mServer->Shutdown();
      39              :         }
      40           14 :     }
      41              : 
      42           14 :     CHIP_ERROR ReturnSuccess()
      43              :     {
      44           14 :         mServer = nullptr;
      45           14 :         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           42 :     chip::Inet::UDPEndPoint * 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::UDPEndPoint * 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           72 :     InterfaceTypeFilterDelegate(chip::Inet::InterfaceId interface, chip::Inet::IPAddressType type,
      93           72 :                                 ServerBase::BroadcastSendDelegate * child) :
      94           72 :         mInterface(interface),
      95           72 :         mAddressType(type), mChild(child)
      96           72 :     {}
      97              : 
      98           84 :     chip::Inet::UDPEndPoint * Accept(ServerBase::EndpointInfo * info) override
      99              :     {
     100           84 :         if ((info->mInterfaceId != mInterface) && (info->mInterfaceId != chip::Inet::InterfaceId::Null()))
     101              :         {
     102            0 :             return nullptr;
     103              :         }
     104              : 
     105           84 :         if ((mAddressType != chip::Inet::IPAddressType::kAny) && (info->mAddressType != mAddressType))
     106              :         {
     107           42 :             return nullptr;
     108              :         }
     109              : 
     110           42 :         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          280 : chip::Inet::IPAddress Get(chip::Inet::IPAddressType addressType)
     125              : {
     126              :     chip::Inet::IPAddress address;
     127              : #if INET_CONFIG_ENABLE_IPV4
     128          280 :     if (addressType == chip::Inet::IPAddressType::kIPv4)
     129              :     {
     130          140 :         VerifyOrDie(chip::Inet::IPAddress::FromString("224.0.0.251", address));
     131              :     }
     132              :     else
     133              : #endif
     134              :     {
     135          140 :         VerifyOrDie(chip::Inet::IPAddress::FromString("FF02::FB", address));
     136              :     }
     137          280 :     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           76 : ServerBase::~ServerBase()
     164              : {
     165           76 :     Shutdown();
     166           76 : }
     167              : 
     168           81 : void ServerBase::Shutdown()
     169              : {
     170           81 :     ShutdownEndpoints();
     171           81 :     mIsInitialized = false;
     172           81 : }
     173              : 
     174          122 : void ServerBase::ShutdownEndpoints()
     175              : {
     176          122 :     mEndpoints.ReleaseAll();
     177          122 : }
     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 != nullptr)
     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           14 : CHIP_ERROR ServerBase::Listen(chip::Inet::EndPointManager<chip::Inet::UDPEndPoint> * udpEndPointManager, ListenIterator * it,
     199              :                               uint16_t port)
     200              : {
     201           14 :     ShutdownEndpoints(); // ensure everything starts fresh
     202              : 
     203           14 :     chip::Inet::InterfaceId interfaceId = chip::Inet::InterfaceId::Null();
     204              :     chip::Inet::IPAddressType addressType;
     205              : 
     206           14 :     ShutdownOnError autoShutdown(this);
     207              : 
     208           42 :     while (it->Next(&interfaceId, &addressType))
     209              :     {
     210              :         chip::Inet::UDPEndPoint * listenUdp;
     211           28 :         ReturnErrorOnFailure(udpEndPointManager->NewEndPoint(&listenUdp));
     212           28 :         std::unique_ptr<chip::Inet::UDPEndPoint, EndpointInfo::EndPointDeletor> endPointHolder(listenUdp, {});
     213              : 
     214           28 :         ReturnErrorOnFailure(listenUdp->Bind(addressType, chip::Inet::IPAddress::Any, port, interfaceId));
     215              : 
     216           28 :         ReturnErrorOnFailure(listenUdp->Listen(OnUdpPacketReceived, nullptr /*OnReceiveError*/, this));
     217              : 
     218           28 :         CHIP_ERROR err = listenUdp->JoinMulticastGroup(interfaceId, BroadcastIpAddresses::Get(addressType));
     219              : 
     220           28 :         if (err != CHIP_NO_ERROR)
     221              :         {
     222              :             char interfaceName[chip::Inet::InterfaceId::kMaxIfNameLength];
     223            0 :             interfaceId.GetInterfaceName(interfaceName, sizeof(interfaceName));
     224              : 
     225              :             // Log only as non-fatal error. Failure to join will mean we reply to unicast queries only.
     226            0 :             ChipLogError(DeviceLayer, "MDNS failed to join multicast group on %s for address type %s: %" CHIP_ERROR_FORMAT,
     227              :                          interfaceName, AddressTypeStr(addressType), err.Format());
     228              : 
     229            0 :             endPointHolder.reset();
     230              :         }
     231              : 
     232              : #if CHIP_MINMDNS_USE_EPHEMERAL_UNICAST_PORT
     233              :         // Separate UDP endpoint for unicast queries, bound to 0 (i.e. pick random ephemeral port)
     234              :         //   - helps in not having conflicts on port 5353, will receive unicast replies directly
     235              :         //   - has a *DRAWBACK* of unicast queries being considered LEGACY by mdns since they do
     236              :         //     not originate from 5353 and the answers will include a query section.
     237              :         chip::Inet::UDPEndPoint * unicastQueryUdp;
     238           28 :         ReturnErrorOnFailure(udpEndPointManager->NewEndPoint(&unicastQueryUdp));
     239           28 :         std::unique_ptr<chip::Inet::UDPEndPoint, EndpointInfo::EndPointDeletor> endPointHolderUnicast(unicastQueryUdp, {});
     240           28 :         ReturnErrorOnFailure(unicastQueryUdp->Bind(addressType, chip::Inet::IPAddress::Any, 0, interfaceId));
     241           28 :         ReturnErrorOnFailure(unicastQueryUdp->Listen(OnUdpPacketReceived, nullptr /*OnReceiveError*/, this));
     242              : #endif
     243              : 
     244              : #if CHIP_MINMDNS_USE_EPHEMERAL_UNICAST_PORT
     245           28 :         if (endPointHolder || endPointHolderUnicast)
     246              :         {
     247              :             // If allocation fails, the rref will not be consumed, so that the endpoint will also be freed correctly
     248           28 :             mEndpoints.CreateObject(interfaceId, addressType, std::move(endPointHolder), std::move(endPointHolderUnicast));
     249              :         }
     250              : #else
     251              :         if (endPointHolder)
     252              :         {
     253              :             // If allocation fails, the rref will not be consumed, so that the endpoint will also be freed correctly
     254              :             mEndpoints.CreateObject(interfaceId, addressType, std::move(endPointHolder));
     255              :         }
     256              : #endif
     257              : 
     258              :         // If at least one IPv6 interface is used by the mDNS server, notify the application that DNS-SD is ready.
     259           28 :         if (!mIsInitialized && addressType == chip::Inet::IPAddressType::kIPv6)
     260              :         {
     261              : #if !CHIP_DEVICE_LAYER_NONE
     262            2 :             chip::DeviceLayer::ChipDeviceEvent event{};
     263            2 :             event.Type = chip::DeviceLayer::DeviceEventType::kDnssdInitialized;
     264            2 :             chip::DeviceLayer::PlatformMgr().PostEventOrDie(&event);
     265              : #endif
     266            2 :             mIsInitialized = true;
     267              :         }
     268           28 :     }
     269              : 
     270           14 :     return autoShutdown.ReturnSuccess();
     271           14 : }
     272              : 
     273            0 : CHIP_ERROR ServerBase::DirectSend(chip::System::PacketBufferHandle && data, const chip::Inet::IPAddress & addr, uint16_t port,
     274              :                                   chip::Inet::InterfaceId interface)
     275              : {
     276            0 :     CHIP_ERROR err = CHIP_ERROR_NOT_CONNECTED;
     277            0 :     mEndpoints.ForEachActiveObject([&](auto * info) {
     278            0 :         if (info->mListenUdp == nullptr)
     279              :         {
     280            0 :             return chip::Loop::Continue;
     281              :         }
     282              : 
     283            0 :         if (info->mAddressType != addr.Type())
     284              :         {
     285            0 :             return chip::Loop::Continue;
     286              :         }
     287              : 
     288            0 :         chip::Inet::InterfaceId boundIf = info->mListenUdp->GetBoundInterface();
     289              : 
     290            0 :         if ((boundIf.IsPresent()) && (boundIf != interface))
     291              :         {
     292            0 :             return chip::Loop::Continue;
     293              :         }
     294              : 
     295            0 :         err = info->mListenUdp->SendTo(addr, port, std::move(data));
     296            0 :         return chip::Loop::Break;
     297              :     });
     298              : 
     299            0 :     return err;
     300              : }
     301              : 
     302            0 : CHIP_ERROR ServerBase::BroadcastUnicastQuery(chip::System::PacketBufferHandle && data, uint16_t port)
     303              : {
     304            0 :     QuerySocketPickerDelegate socketPicker;
     305            0 :     return BroadcastImpl(std::move(data), port, &socketPicker);
     306            0 : }
     307              : 
     308            0 : CHIP_ERROR ServerBase::BroadcastUnicastQuery(chip::System::PacketBufferHandle && data, uint16_t port,
     309              :                                              chip::Inet::InterfaceId interface, chip::Inet::IPAddressType addressType)
     310              : {
     311            0 :     QuerySocketPickerDelegate socketPicker;
     312            0 :     InterfaceTypeFilterDelegate filter(interface, addressType, &socketPicker);
     313              : 
     314            0 :     return BroadcastImpl(std::move(data), port, &filter);
     315            0 : }
     316              : 
     317           72 : CHIP_ERROR ServerBase::BroadcastSend(chip::System::PacketBufferHandle && data, uint16_t port, chip::Inet::InterfaceId interface,
     318              :                                      chip::Inet::IPAddressType addressType)
     319              : {
     320           72 :     ListenSocketPickerDelegate socketPicker;
     321           72 :     InterfaceTypeFilterDelegate filter(interface, addressType, &socketPicker);
     322              : 
     323           72 :     return BroadcastImpl(std::move(data), port, &filter);
     324           72 : }
     325              : 
     326            0 : CHIP_ERROR ServerBase::BroadcastSend(chip::System::PacketBufferHandle && data, uint16_t port)
     327              : {
     328            0 :     ListenSocketPickerDelegate socketPicker;
     329            0 :     return BroadcastImpl(std::move(data), port, &socketPicker);
     330            0 : }
     331              : 
     332           72 : CHIP_ERROR ServerBase::BroadcastImpl(chip::System::PacketBufferHandle && data, uint16_t port, BroadcastSendDelegate * delegate)
     333              : {
     334              :     // Broadcast requires sending data multiple times, each of which may error
     335              :     // out, yet broadcast only has a single error code.
     336              :     //
     337              :     // The general logic of error handling is:
     338              :     //   - if no send done at all, return error
     339              :     //   - if at least one broadcast succeeds, assume success overall
     340              :     //   + some internal consistency validations for state error.
     341              : 
     342           72 :     unsigned successes   = 0;
     343           72 :     unsigned failures    = 0;
     344           72 :     CHIP_ERROR lastError = CHIP_ERROR_NO_ENDPOINT;
     345              : 
     346           72 :     if (chip::Loop::Break == mEndpoints.ForEachActiveObject([&](auto * info) {
     347           84 :             chip::Inet::UDPEndPoint * udp = delegate->Accept(info);
     348              : 
     349           84 :             if (udp == nullptr)
     350              :             {
     351           42 :                 return chip::Loop::Continue;
     352              :             }
     353              : 
     354           42 :             CHIP_ERROR err = CHIP_NO_ERROR;
     355              : 
     356              :             /// The same packet needs to be sent over potentially multiple interfaces.
     357              :             /// LWIP does not like having a pbuf sent over serparate interfaces, hence we create a copy
     358              :             /// for sending via `CloneData`
     359              :             ///
     360              :             /// TODO: this wastes one copy of the data and that could be optimized away
     361           42 :             chip::System::PacketBufferHandle tempBuf = data.CloneData();
     362           42 :             if (tempBuf.IsNull())
     363              :             {
     364              :                 // Not enough memory available to clone pbuf
     365            0 :                 err = CHIP_ERROR_NO_MEMORY;
     366              :             }
     367           42 :             else if (info->mAddressType == chip::Inet::IPAddressType::kIPv6)
     368              :             {
     369           21 :                 err = udp->SendTo(mIpv6BroadcastAddress, port, std::move(tempBuf), udp->GetBoundInterface());
     370              :             }
     371              : #if INET_CONFIG_ENABLE_IPV4
     372           21 :             else if (info->mAddressType == chip::Inet::IPAddressType::kIPv4)
     373              :             {
     374           21 :                 err = udp->SendTo(mIpv4BroadcastAddress, port, std::move(tempBuf), udp->GetBoundInterface());
     375              :             }
     376              : #endif
     377              :             else
     378              :             {
     379              :                 // This is a general error of internal consistency: every address has a known type. Fail completely otherwise.
     380            0 :                 lastError = CHIP_ERROR_INCORRECT_STATE;
     381            0 :                 return chip::Loop::Break;
     382              :             }
     383              : 
     384           42 :             if (err == CHIP_NO_ERROR)
     385              :             {
     386           42 :                 successes++;
     387              :             }
     388              :             else
     389              :             {
     390            0 :                 failures++;
     391            0 :                 lastError = err;
     392              : #if CHIP_DETAIL_LOGGING
     393              :                 char ifaceName[chip::Inet::InterfaceId::kMaxIfNameLength];
     394            0 :                 err = info->mInterfaceId.GetInterfaceName(ifaceName, sizeof(ifaceName));
     395            0 :                 if (err != CHIP_NO_ERROR)
     396            0 :                     strcpy(ifaceName, "???");
     397            0 :                 ChipLogDetail(Discovery, "Warning: Attempt to mDNS broadcast failed on %s:  %s", ifaceName, lastError.AsString());
     398              : #endif
     399              :             }
     400           42 :             return chip::Loop::Continue;
     401           42 :         }))
     402              :     {
     403            0 :         return lastError;
     404              :     }
     405              : 
     406           72 :     if (failures != 0)
     407              :     {
     408              :         // if we had failures, log if the final status was success or failure, to make log reading
     409              :         // easier. Some mDNS failures may be expected (e.g. for interfaces unavailable)
     410            0 :         if (successes != 0)
     411              :         {
     412            0 :             ChipLogDetail(Discovery, "mDNS broadcast had only partial success: %u successes and %u failures.", successes, failures);
     413              :         }
     414              :         else
     415              :         {
     416            0 :             ChipLogProgress(Discovery, "mDNS broadcast full failed in %u separate send attempts.", failures);
     417              :         }
     418              :     }
     419              : 
     420           72 :     if (!successes)
     421              :     {
     422           30 :         return lastError;
     423              :     }
     424              : 
     425           42 :     return CHIP_NO_ERROR;
     426              : }
     427              : 
     428           12 : void ServerBase::OnUdpPacketReceived(chip::Inet::UDPEndPoint * endPoint, chip::System::PacketBufferHandle && buffer,
     429              :                                      const chip::Inet::IPPacketInfo * info)
     430              : {
     431           12 :     ServerBase * srv = static_cast<ServerBase *>(endPoint->mAppState);
     432           12 :     if (!srv->mDelegate)
     433              :     {
     434            0 :         return;
     435              :     }
     436              : 
     437           12 :     mdns::Minimal::BytesRange data(buffer->Start(), buffer->Start() + buffer->DataLength());
     438           12 :     if (data.Size() < HeaderRef::kSizeBytes)
     439              :     {
     440            0 :         ChipLogError(Discovery, "Packet to small for mDNS data: %d bytes", static_cast<int>(data.Size()));
     441            0 :         return;
     442              :     }
     443              : 
     444           12 :     if (HeaderRef(const_cast<uint8_t *>(data.Start())).GetFlags().IsQuery())
     445              :     {
     446              :         // Only consider queries that are received on the same interface we are listening on.
     447              :         // Without this, queries show up on all addresses on all interfaces, resulting
     448              :         // in more replies than one would expect.
     449            0 :         if (endPoint->GetBoundInterface() == info->Interface)
     450              :         {
     451            0 :             srv->mDelegate->OnQuery(data, info);
     452              :         }
     453              :     }
     454              :     else
     455              :     {
     456           12 :         srv->mDelegate->OnResponse(data, info);
     457              :     }
     458              : }
     459              : 
     460              : } // namespace Minimal
     461              : } // namespace mdns
        

Generated by: LCOV version 2.0-1