LCOV - code coverage report
Current view: top level - lib/dnssd/minimal_mdns - Server.cpp (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 100 162 61.7 %
Date: 2024-02-15 08:20:41 Functions: 17 26 65.4 %

          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          17 :     ShutdownOnError(ServerBase * s) : mServer(s) {}
      34          17 :     ~ShutdownOnError()
      35             :     {
      36          17 :         if (mServer != nullptr)
      37             :         {
      38           0 :             mServer->Shutdown();
      39             :         }
      40          17 :     }
      41             : 
      42          17 :     CHIP_ERROR ReturnSuccess()
      43             :     {
      44          17 :         mServer = nullptr;
      45          17 :         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::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          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::UDPEndPoint * 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         232 : chip::Inet::IPAddress Get(chip::Inet::IPAddressType addressType)
     125             : {
     126             :     chip::Inet::IPAddress address;
     127             : #if INET_CONFIG_ENABLE_IPV4
     128         232 :     if (addressType == chip::Inet::IPAddressType::kIPv4)
     129             :     {
     130         116 :         VerifyOrDie(chip::Inet::IPAddress::FromString("224.0.0.251", address));
     131             :     }
     132             :     else
     133             : #endif
     134             :     {
     135         116 :         VerifyOrDie(chip::Inet::IPAddress::FromString("FF02::FB", address));
     136             :     }
     137         232 :     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          42 : ServerBase::~ServerBase()
     164             : {
     165          42 :     Shutdown();
     166          42 : }
     167             : 
     168          47 : void ServerBase::Shutdown()
     169             : {
     170          47 :     ShutdownEndpoints();
     171          47 :     mIsInitialized = false;
     172          47 : }
     173             : 
     174          97 : void ServerBase::ShutdownEndpoints()
     175             : {
     176          97 :     mEndpoints.ReleaseAll();
     177          97 : }
     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          17 : CHIP_ERROR ServerBase::Listen(chip::Inet::EndPointManager<chip::Inet::UDPEndPoint> * udpEndPointManager, ListenIterator * it,
     199             :                               uint16_t port)
     200             : {
     201          17 :     ShutdownEndpoints(); // ensure everything starts fresh
     202             : 
     203          17 :     chip::Inet::InterfaceId interfaceId = chip::Inet::InterfaceId::Null();
     204             :     chip::Inet::IPAddressType addressType;
     205             : 
     206          17 :     ShutdownOnError autoShutdown(this);
     207             : 
     208          51 :     while (it->Next(&interfaceId, &addressType))
     209             :     {
     210             :         chip::Inet::UDPEndPoint * listenUdp;
     211          34 :         ReturnErrorOnFailure(udpEndPointManager->NewEndPoint(&listenUdp));
     212          34 :         std::unique_ptr<chip::Inet::UDPEndPoint, EndpointInfo::EndPointDeletor> endPointHolder(listenUdp, {});
     213             : 
     214          34 :         ReturnErrorOnFailure(listenUdp->Bind(addressType, chip::Inet::IPAddress::Any, port, interfaceId));
     215             : 
     216          34 :         ReturnErrorOnFailure(listenUdp->Listen(OnUdpPacketReceived, nullptr /*OnReceiveError*/, this));
     217             : 
     218          34 :         CHIP_ERROR err = listenUdp->JoinMulticastGroup(interfaceId, BroadcastIpAddresses::Get(addressType));
     219             : 
     220          34 :         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          34 :         ReturnErrorOnFailure(udpEndPointManager->NewEndPoint(&unicastQueryUdp));
     239          34 :         std::unique_ptr<chip::Inet::UDPEndPoint, EndpointInfo::EndPointDeletor> endPointHolderUnicast(unicastQueryUdp, {});
     240          34 :         ReturnErrorOnFailure(unicastQueryUdp->Bind(addressType, chip::Inet::IPAddress::Any, 0, interfaceId));
     241          34 :         ReturnErrorOnFailure(unicastQueryUdp->Listen(OnUdpPacketReceived, nullptr /*OnReceiveError*/, this));
     242             : #endif
     243             : 
     244             : #if CHIP_MINMDNS_USE_EPHEMERAL_UNICAST_PORT
     245          34 :         if (endPointHolder || endPointHolderUnicast)
     246             :         {
     247             :             // If allocation fails, the rref will not be consumed, so that the endpoint will also be freed correctly
     248          34 :             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          34 :         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          34 :     }
     269             : 
     270          17 :     return autoShutdown.ReturnSuccess();
     271          17 : }
     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          78 : CHIP_ERROR ServerBase::BroadcastSend(chip::System::PacketBufferHandle && data, uint16_t port, chip::Inet::InterfaceId interface,
     318             :                                      chip::Inet::IPAddressType addressType)
     319             : {
     320          78 :     ListenSocketPickerDelegate socketPicker;
     321          78 :     InterfaceTypeFilterDelegate filter(interface, addressType, &socketPicker);
     322             : 
     323          78 :     return BroadcastImpl(std::move(data), port, &filter);
     324          78 : }
     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          78 : 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          78 :     unsigned successes   = 0;
     343          78 :     unsigned failures    = 0;
     344          78 :     CHIP_ERROR lastError = CHIP_ERROR_NO_ENDPOINT;
     345             : 
     346          78 :     if (chip::Loop::Break == mEndpoints.ForEachActiveObject([&](auto * info) {
     347          96 :             chip::Inet::UDPEndPoint * udp = delegate->Accept(info);
     348             : 
     349          96 :             if (udp == nullptr)
     350             :             {
     351          48 :                 return chip::Loop::Continue;
     352             :             }
     353             : 
     354          48 :             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          48 :             chip::System::PacketBufferHandle tempBuf = data.CloneData();
     362          48 :             if (tempBuf.IsNull())
     363             :             {
     364             :                 // Not enough memory available to clone pbuf
     365           0 :                 err = CHIP_ERROR_NO_MEMORY;
     366             :             }
     367          48 :             else if (info->mAddressType == chip::Inet::IPAddressType::kIPv6)
     368             :             {
     369          24 :                 err = udp->SendTo(mIpv6BroadcastAddress, port, std::move(tempBuf), udp->GetBoundInterface());
     370             :             }
     371             : #if INET_CONFIG_ENABLE_IPV4
     372          24 :             else if (info->mAddressType == chip::Inet::IPAddressType::kIPv4)
     373             :             {
     374          24 :                 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          48 :             if (err == CHIP_NO_ERROR)
     385             :             {
     386          48 :                 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          48 :             return chip::Loop::Continue;
     401          48 :         }))
     402             :     {
     403           0 :         return lastError;
     404             :     }
     405             : 
     406          78 :     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          78 :     if (!successes)
     421             :     {
     422          30 :         return lastError;
     423             :     }
     424             : 
     425          48 :     return CHIP_NO_ERROR;
     426             : }
     427             : 
     428          32 : void ServerBase::OnUdpPacketReceived(chip::Inet::UDPEndPoint * endPoint, chip::System::PacketBufferHandle && buffer,
     429             :                                      const chip::Inet::IPPacketInfo * info)
     430             : {
     431          32 :     ServerBase * srv = static_cast<ServerBase *>(endPoint->mAppState);
     432          32 :     if (!srv->mDelegate)
     433             :     {
     434           0 :         return;
     435             :     }
     436             : 
     437          32 :     mdns::Minimal::BytesRange data(buffer->Start(), buffer->Start() + buffer->DataLength());
     438          32 :     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          32 :     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          32 :         srv->mDelegate->OnResponse(data, info);
     457             :     }
     458             : }
     459             : 
     460             : } // namespace Minimal
     461             : } // namespace mdns

Generated by: LCOV version 1.14