Matter SDK Coverage Report
Current view: top level - inet - UDPEndPointImplSockets.cpp (source / functions) Coverage Total Hit
Test: SHA:209dc18e4021e7d0dff8120ccc585909391dd862 Lines: 76.6 % 320 245
Test Date: 2026-06-16 07:34:53 Functions: 82.4 % 17 14

            Line data    Source code
       1              : /*
       2              :  *
       3              :  *    Copyright (c) 2020-2025 Project CHIP Authors
       4              :  *    Copyright (c) 2018 Google LLC.
       5              :  *    Copyright (c) 2013-2018 Nest Labs, Inc.
       6              :  *
       7              :  *    Licensed under the Apache License, Version 2.0 (the "License");
       8              :  *    you may not use this file except in compliance with the License.
       9              :  *    You may obtain a copy of the License at
      10              :  *
      11              :  *        http://www.apache.org/licenses/LICENSE-2.0
      12              :  *
      13              :  *    Unless required by applicable law or agreed to in writing, software
      14              :  *    distributed under the License is distributed on an "AS IS" BASIS,
      15              :  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      16              :  *    See the License for the specific language governing permissions and
      17              :  *    limitations under the License.
      18              :  */
      19              : 
      20              : /**
      21              :  * This file implements Inet::UDPEndPoint using sockets.
      22              :  */
      23              : 
      24              : // Required to properly support underlying RFC3542-related fields to IPV6_PKTINFO
      25              : // on Darwin.
      26              : #define __APPLE_USE_RFC_3542
      27              : #include <inet/UDPEndPointImplSockets.h>
      28              : 
      29              : #include <lib/support/CodeUtils.h>
      30              : #include <lib/support/SafeInt.h>
      31              : #include <lib/support/logging/CHIPLogging.h>
      32              : 
      33              : #if CHIP_SYSTEM_CONFIG_USE_POSIX_SOCKETS
      34              : #if HAVE_SYS_SOCKET_H
      35              : #include <sys/socket.h>
      36              : #endif // HAVE_SYS_SOCKET_H
      37              : #include <net/if.h>
      38              : #include <netinet/in.h>
      39              : #include <sys/ioctl.h>
      40              : #endif // CHIP_SYSTEM_CONFIG_USE_POSIX_SOCKETS
      41              : 
      42              : #if CHIP_SYSTEM_CONFIG_USE_ZEPHYR_SOCKETS || CHIP_SYSTEM_CONFIG_USE_ZEPHYR_SOCKET_EXTENSIONS
      43              : #include "ZephyrSocket.h" // nogncheck
      44              : #endif
      45              : 
      46              : #include <cerrno>
      47              : #include <unistd.h>
      48              : #include <utility>
      49              : 
      50              : // SOCK_CLOEXEC not defined on all platforms, e.g. iOS/macOS:
      51              : #ifndef SOCK_CLOEXEC
      52              : #define SOCK_CLOEXEC 0
      53              : #endif
      54              : 
      55              : // On MbedOS, INADDR_ANY does not seem to exist...
      56              : #ifndef INADDR_ANY
      57              : #define INADDR_ANY 0
      58              : #endif
      59              : 
      60              : /*
      61              :  * Some systems define both IPV6_{ADD,DROP}_MEMBERSHIP and
      62              :  * IPV6_{JOIN,LEAVE}_GROUP while others only define
      63              :  * IPV6_{JOIN,LEAVE}_GROUP. Prefer the "_MEMBERSHIP" flavor for
      64              :  * parallelism with IPv4 and create the alias to the availabile
      65              :  * definitions.
      66              :  */
      67              : #if defined(IPV6_ADD_MEMBERSHIP)
      68              : #define INET_IPV6_ADD_MEMBERSHIP IPV6_ADD_MEMBERSHIP
      69              : #elif defined(IPV6_JOIN_GROUP)
      70              : #define INET_IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
      71              : #elif !CHIP_SYSTEM_CONFIG_USE_PLATFORM_MULTICAST_API
      72              : #error                                                                                                                             \
      73              :     "Neither IPV6_ADD_MEMBERSHIP nor IPV6_JOIN_GROUP are defined which are required for generalized IPv6 multicast group support."
      74              : #endif // IPV6_ADD_MEMBERSHIP
      75              : 
      76              : #if defined(IPV6_DROP_MEMBERSHIP)
      77              : #define INET_IPV6_DROP_MEMBERSHIP IPV6_DROP_MEMBERSHIP
      78              : #elif defined(IPV6_LEAVE_GROUP)
      79              : #define INET_IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP
      80              : #elif !CHIP_SYSTEM_CONFIG_USE_PLATFORM_MULTICAST_API
      81              : #error                                                                                                                             \
      82              :     "Neither IPV6_DROP_MEMBERSHIP nor IPV6_LEAVE_GROUP are defined which are required for generalized IPv6 multicast group support."
      83              : #endif // IPV6_DROP_MEMBERSHIP
      84              : 
      85              : namespace chip {
      86              : namespace Inet {
      87              : 
      88              : namespace {
      89              : 
      90           59 : CHIP_ERROR IPv6Bind(int socket, const IPAddress & address, uint16_t port, InterfaceId interface)
      91              : {
      92              :     struct sockaddr_in6 sa;
      93           59 :     memset(&sa, 0, sizeof(sa));
      94           59 :     sa.sin6_family                        = AF_INET6;
      95           59 :     sa.sin6_port                          = htons(port);
      96           59 :     sa.sin6_addr                          = address.ToIPv6();
      97           59 :     InterfaceId::PlatformType interfaceId = interface.GetPlatformInterface();
      98           59 :     if (!CanCastTo<decltype(sa.sin6_scope_id)>(interfaceId))
      99              :     {
     100            0 :         return CHIP_ERROR_INCORRECT_STATE;
     101              :     }
     102           59 :     sa.sin6_scope_id = static_cast<decltype(sa.sin6_scope_id)>(interfaceId);
     103              : 
     104           59 :     CHIP_ERROR status = CHIP_NO_ERROR;
     105              : 
     106              :     // NOLINTNEXTLINE(clang-analyzer-unix.StdCLibraryFunctions): Function called only with valid socket after GetSocket
     107           59 :     if (bind(socket, reinterpret_cast<const sockaddr *>(&sa), static_cast<unsigned>(sizeof(sa))) != 0)
     108              :     {
     109            0 :         status = CHIP_ERROR_POSIX(errno);
     110              :     }
     111              :     else
     112              :     {
     113              : #ifdef IPV6_MULTICAST_IF
     114              :         // Instruct the kernel that any messages to multicast destinations should be
     115              :         // sent down the interface specified by the caller.
     116           59 :         setsockopt(socket, IPPROTO_IPV6, IPV6_MULTICAST_IF, &interfaceId, sizeof(interfaceId));
     117              : #endif // defined(IPV6_MULTICAST_IF)
     118              :     }
     119              : 
     120              : #ifdef IPV6_MULTICAST_HOPS
     121              :     // Instruct the kernel that any messages to multicast destinations should be
     122              :     // set with the configured hop limit value.
     123           59 :     int hops = INET_CONFIG_IP_MULTICAST_HOP_LIMIT;
     124           59 :     setsockopt(socket, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hops, sizeof(hops));
     125              : #endif // defined(IPV6_MULTICAST_HOPS)
     126              : 
     127           59 :     return status;
     128              : }
     129              : 
     130              : #if INET_CONFIG_ENABLE_IPV4
     131           58 : CHIP_ERROR IPv4Bind(int socket, const IPAddress & address, uint16_t port)
     132              : {
     133              :     struct sockaddr_in sa;
     134           58 :     memset(&sa, 0, sizeof(sa));
     135           58 :     sa.sin_family = AF_INET;
     136           58 :     sa.sin_port   = htons(port);
     137           58 :     sa.sin_addr   = address.ToIPv4();
     138              : 
     139           58 :     CHIP_ERROR status = CHIP_NO_ERROR;
     140              : 
     141              :     // NOLINTNEXTLINE(clang-analyzer-unix.StdCLibraryFunctions): Function called only with valid socket after GetSocket
     142           58 :     if (bind(socket, reinterpret_cast<const sockaddr *>(&sa), static_cast<unsigned>(sizeof(sa))) != 0)
     143              :     {
     144            1 :         status = CHIP_ERROR_POSIX(errno);
     145              :     }
     146              :     else
     147              :     {
     148              :         // Allow socket transmitting broadcast packets.
     149           57 :         constexpr int enable = 1;
     150           57 :         setsockopt(socket, SOL_SOCKET, SO_BROADCAST, &enable, sizeof(enable));
     151              : 
     152              : #ifdef IP_MULTICAST_IF
     153              :         // Instruct the kernel that any messages to multicast destinations should be
     154              :         // sent down the interface to which the specified IPv4 address is bound.
     155           57 :         setsockopt(socket, IPPROTO_IP, IP_MULTICAST_IF, &sa, sizeof(sa));
     156              : #endif // defined(IP_MULTICAST_IF)
     157              :     }
     158              : 
     159              : #ifdef IP_MULTICAST_TTL
     160              :     // Instruct the kernel that any messages to multicast destinations should be
     161              :     // set with the configured hop limit value.
     162           58 :     constexpr int ttl = INET_CONFIG_IP_MULTICAST_HOP_LIMIT;
     163           58 :     setsockopt(socket, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl));
     164              : #endif // defined(IP_MULTICAST_TTL)
     165              : 
     166           58 :     return status;
     167              : }
     168              : #endif // INET_CONFIG_ENABLE_IPV4
     169              : 
     170              : } // anonymous namespace
     171              : 
     172              : #if CHIP_SYSTEM_CONFIG_USE_PLATFORM_MULTICAST_API
     173              : UDPEndPointImplSockets::MulticastGroupHandler UDPEndPointImplSockets::sMulticastGroupHandler;
     174              : #endif // CHIP_SYSTEM_CONFIG_USE_PLATFORM_MULTICAST_API
     175              : 
     176          118 : CHIP_ERROR UDPEndPointImplSockets::BindImpl(IPAddressType addressType, const IPAddress & addr, uint16_t port, InterfaceId interface)
     177              : {
     178              :     // Make sure we have the appropriate type of socket.
     179          118 :     ReturnErrorOnFailure(GetSocket(addressType));
     180              : 
     181          117 :     if (addressType == IPAddressType::kIPv6)
     182              :     {
     183           59 :         ReturnErrorOnFailure(IPv6Bind(mSocket, addr, port, interface));
     184              :     }
     185              : #if INET_CONFIG_ENABLE_IPV4
     186           58 :     else if (addressType == IPAddressType::kIPv4)
     187              :     {
     188           58 :         ReturnErrorOnFailure(IPv4Bind(mSocket, addr, port));
     189              :     }
     190              : #endif // INET_CONFIG_ENABLE_IPV4
     191              :     else
     192              :     {
     193            0 :         return INET_ERROR_WRONG_ADDRESS_TYPE;
     194              :     }
     195              : 
     196          116 :     mBoundPort   = port;
     197          116 :     mBoundIntfId = interface;
     198              : 
     199              :     // If an ephemeral port was requested, retrieve the actual bound port.
     200          116 :     if (port == 0)
     201              :     {
     202              :         SockAddr boundAddr;
     203           60 :         socklen_t boundAddrLen = sizeof(boundAddr);
     204              : 
     205           60 :         if (getsockname(mSocket, &boundAddr.any, &boundAddrLen) == 0)
     206              :         {
     207           60 :             if (boundAddr.any.sa_family == AF_INET)
     208              :             {
     209           30 :                 mBoundPort = ntohs(boundAddr.in.sin_port);
     210              :             }
     211           30 :             else if (boundAddr.any.sa_family == AF_INET6)
     212              :             {
     213           30 :                 mBoundPort = ntohs(boundAddr.in6.sin6_port);
     214              :             }
     215              :         }
     216              :     }
     217              : 
     218          116 :     return CHIP_NO_ERROR;
     219              : }
     220              : 
     221            1 : CHIP_ERROR UDPEndPointImplSockets::BindInterfaceImpl(IPAddressType addressType, InterfaceId interfaceId)
     222              : {
     223              :     // Make sure we have the appropriate type of socket.
     224            1 :     ReturnErrorOnFailure(GetSocket(addressType));
     225              : 
     226              : #if HAVE_SO_BINDTODEVICE
     227            1 :     CHIP_ERROR status = CHIP_NO_ERROR;
     228              : 
     229            1 :     if (interfaceId.IsPresent())
     230              :     {
     231              :         // Start filtering on the passed interface.
     232              :         char interfaceName[IF_NAMESIZE];
     233            1 :         if (if_indextoname(interfaceId.GetPlatformInterface(), interfaceName) == nullptr)
     234              :         {
     235            0 :             status = CHIP_ERROR_POSIX(errno);
     236              :         }
     237            1 :         else if (setsockopt(mSocket, SOL_SOCKET, SO_BINDTODEVICE, interfaceName, socklen_t(strlen(interfaceName))) == -1)
     238              :         {
     239            0 :             status = CHIP_ERROR_POSIX(errno);
     240              :         }
     241              :     }
     242              :     else
     243              :     {
     244              :         // Stop interface-based filtering.
     245            0 :         if (setsockopt(mSocket, SOL_SOCKET, SO_BINDTODEVICE, "", 0) == -1)
     246              :         {
     247            0 :             status = CHIP_ERROR_POSIX(errno);
     248              :         }
     249              :     }
     250              : 
     251            2 :     if (status == CHIP_NO_ERROR)
     252              :     {
     253            1 :         mBoundIntfId = interfaceId;
     254              :     }
     255              : 
     256            1 :     return status;
     257              : #else  // !HAVE_SO_BINDTODEVICE
     258              :     return CHIP_ERROR_NOT_IMPLEMENTED;
     259              : #endif // HAVE_SO_BINDTODEVICE
     260              : }
     261              : 
     262           67 : InterfaceId UDPEndPointImplSockets::GetBoundInterface() const
     263              : {
     264           67 :     return mBoundIntfId;
     265              : }
     266              : 
     267            4 : uint16_t UDPEndPointImplSockets::GetBoundPort() const
     268              : {
     269            4 :     return mBoundPort;
     270              : }
     271              : 
     272          116 : CHIP_ERROR UDPEndPointImplSockets::ListenImpl()
     273              : {
     274              :     // Wait for ability to read on this endpoint.
     275          116 :     auto * layer = static_cast<System::LayerSockets *>(&GetSystemLayer());
     276          116 :     ReturnErrorOnFailure(layer->SetCallback(mWatch, HandlePendingIO, reinterpret_cast<intptr_t>(this)));
     277          116 :     return layer->RequestCallbackOnPendingRead(mWatch);
     278              : }
     279              : 
     280           70 : CHIP_ERROR UDPEndPointImplSockets::SendMsgImpl(const IPPacketInfo * aPktInfo, System::PacketBufferHandle && msg)
     281              : {
     282              :     // Ensure packet buffer is not null
     283           70 :     VerifyOrReturnError(!msg.IsNull(), CHIP_ERROR_INVALID_ARGUMENT);
     284              : 
     285              :     // Make sure we have the appropriate type of socket based on the
     286              :     // destination address.
     287           70 :     ReturnErrorOnFailure(GetSocket(aPktInfo->DestAddress.Type()));
     288              : 
     289              :     // Ensure the destination address type is compatible with the endpoint address type.
     290           70 :     VerifyOrReturnError(mAddrType == aPktInfo->DestAddress.Type(), CHIP_ERROR_INVALID_ARGUMENT);
     291              : 
     292              :     // For now the entire message must fit within a single buffer.
     293           70 :     VerifyOrReturnError(!msg->HasChainedBuffer(), CHIP_ERROR_MESSAGE_TOO_LONG);
     294              : 
     295              :     struct iovec msgIOV;
     296           70 :     msgIOV.iov_base = msg->Start();
     297           70 :     msgIOV.iov_len  = msg->DataLength();
     298              : 
     299              : #if defined(IP_PKTINFO) || defined(IPV6_PKTINFO)
     300              :     uint8_t controlData[256];
     301           70 :     memset(controlData, 0, sizeof(controlData));
     302              : #endif // defined(IP_PKTINFO) || defined(IPV6_PKTINFO)
     303              : 
     304              :     struct msghdr msgHeader;
     305           70 :     memset(&msgHeader, 0, sizeof(msgHeader));
     306           70 :     msgHeader.msg_iov    = &msgIOV;
     307           70 :     msgHeader.msg_iovlen = 1;
     308              : 
     309              :     // Construct a sockaddr_in/sockaddr_in6 structure containing the destination information.
     310              :     SockAddr peerSockAddr;
     311           70 :     memset(&peerSockAddr, 0, sizeof(peerSockAddr));
     312           70 :     msgHeader.msg_name = &peerSockAddr;
     313           70 :     if (mAddrType == IPAddressType::kIPv6)
     314              :     {
     315           35 :         peerSockAddr.in6.sin6_family     = AF_INET6;
     316           35 :         peerSockAddr.in6.sin6_port       = htons(aPktInfo->DestPort);
     317           35 :         peerSockAddr.in6.sin6_addr       = aPktInfo->DestAddress.ToIPv6();
     318           35 :         InterfaceId::PlatformType intfId = aPktInfo->Interface.GetPlatformInterface();
     319           35 :         VerifyOrReturnError(CanCastTo<decltype(peerSockAddr.in6.sin6_scope_id)>(intfId), CHIP_ERROR_INCORRECT_STATE);
     320           35 :         peerSockAddr.in6.sin6_scope_id = static_cast<decltype(peerSockAddr.in6.sin6_scope_id)>(intfId);
     321           35 :         msgHeader.msg_namelen          = sizeof(sockaddr_in6);
     322              :     }
     323              : #if INET_CONFIG_ENABLE_IPV4
     324              :     else
     325              :     {
     326           35 :         peerSockAddr.in.sin_family = AF_INET;
     327           35 :         peerSockAddr.in.sin_port   = htons(aPktInfo->DestPort);
     328           35 :         peerSockAddr.in.sin_addr   = aPktInfo->DestAddress.ToIPv4();
     329           35 :         msgHeader.msg_namelen      = sizeof(sockaddr_in);
     330              :     }
     331              : #endif // INET_CONFIG_ENABLE_IPV4
     332              : 
     333              :     // If the endpoint has been bound to a particular interface,
     334              :     // and the caller didn't supply a specific interface to send
     335              :     // on, use the bound interface. This appears to be necessary
     336              :     // for messages to multicast addresses, which under Linux
     337              :     // don't seem to get sent out the correct interface, despite
     338              :     // the socket being bound.
     339           70 :     InterfaceId intf = aPktInfo->Interface;
     340           70 :     if (!intf.IsPresent())
     341              :     {
     342            4 :         intf = mBoundIntfId;
     343              :     }
     344              : 
     345              : #if INET_CONFIG_UDP_SOCKET_PKTINFO
     346              :     // If the packet should be sent over a specific interface, or with a specific source
     347              :     // address, construct an IP_PKTINFO/IPV6_PKTINFO "control message" to that effect
     348              :     // add add it to the message header.  If the local OS doesn't support IP_PKTINFO/IPV6_PKTINFO
     349              :     // fail with an error.
     350           70 :     if (intf.IsPresent() || aPktInfo->SrcAddress.Type() != IPAddressType::kAny)
     351              :     {
     352              : #if defined(IP_PKTINFO) || defined(IPV6_PKTINFO)
     353           66 :         msgHeader.msg_control    = controlData;
     354           66 :         msgHeader.msg_controllen = sizeof(controlData);
     355              : 
     356           66 :         struct cmsghdr * controlHdr      = CMSG_FIRSTHDR(&msgHeader);
     357           66 :         InterfaceId::PlatformType intfId = intf.GetPlatformInterface();
     358              : 
     359              : #if INET_CONFIG_ENABLE_IPV4
     360              : 
     361           66 :         if (mAddrType == IPAddressType::kIPv4)
     362              :         {
     363              : #if defined(IP_PKTINFO)
     364           33 :             controlHdr->cmsg_level = IPPROTO_IP;
     365           33 :             controlHdr->cmsg_type  = IP_PKTINFO;
     366           33 :             controlHdr->cmsg_len   = CMSG_LEN(sizeof(in_pktinfo));
     367              : 
     368           33 :             auto * pktInfo = reinterpret_cast<struct in_pktinfo *> CMSG_DATA(controlHdr);
     369           33 :             if (!CanCastTo<decltype(pktInfo->ipi_ifindex)>(intfId))
     370              :             {
     371            0 :                 return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
     372              :             }
     373              : 
     374           33 :             pktInfo->ipi_ifindex  = static_cast<decltype(pktInfo->ipi_ifindex)>(intfId);
     375           33 :             pktInfo->ipi_spec_dst = aPktInfo->SrcAddress.ToIPv4();
     376              : 
     377           33 :             msgHeader.msg_controllen = CMSG_SPACE(sizeof(in_pktinfo));
     378              : #else  // !defined(IP_PKTINFO)
     379              :             return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
     380              : #endif // !defined(IP_PKTINFO)
     381              :         }
     382              : 
     383              : #endif // INET_CONFIG_ENABLE_IPV4
     384              : 
     385           66 :         if (mAddrType == IPAddressType::kIPv6)
     386              :         {
     387              : #if defined(IPV6_PKTINFO)
     388           33 :             controlHdr->cmsg_level = IPPROTO_IPV6;
     389           33 :             controlHdr->cmsg_type  = IPV6_PKTINFO;
     390           33 :             controlHdr->cmsg_len   = CMSG_LEN(sizeof(in6_pktinfo));
     391              : 
     392           33 :             auto * pktInfo = reinterpret_cast<struct in6_pktinfo *> CMSG_DATA(controlHdr);
     393           33 :             if (!CanCastTo<decltype(pktInfo->ipi6_ifindex)>(intfId))
     394              :             {
     395            0 :                 return CHIP_ERROR_UNEXPECTED_EVENT;
     396              :             }
     397           33 :             pktInfo->ipi6_ifindex = static_cast<decltype(pktInfo->ipi6_ifindex)>(intfId);
     398           33 :             pktInfo->ipi6_addr    = aPktInfo->SrcAddress.ToIPv6();
     399              : 
     400           33 :             msgHeader.msg_controllen = CMSG_SPACE(sizeof(in6_pktinfo));
     401              : #else  // !defined(IPV6_PKTINFO)
     402              :             return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
     403              : #endif // !defined(IPV6_PKTINFO)
     404              :         }
     405              : 
     406              : #else  // !(defined(IP_PKTINFO) && defined(IPV6_PKTINFO))
     407              :         return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
     408              : #endif // !(defined(IP_PKTINFO) && defined(IPV6_PKTINFO))
     409              :     }
     410              : #endif // INET_CONFIG_UDP_SOCKET_PKTINFO
     411              : 
     412              :     // Send IP packet.
     413              :     // NOLINTNEXTLINE(clang-analyzer-unix.StdCLibraryFunctions): GetSocket calls ensure mSocket is valid
     414           70 :     const ssize_t lenSent = sendmsg(mSocket, &msgHeader, 0);
     415           70 :     if (lenSent == -1)
     416              :     {
     417            0 :         return CHIP_ERROR_POSIX(errno);
     418              :     }
     419              : 
     420           70 :     size_t len = static_cast<size_t>(lenSent);
     421              : 
     422           70 :     if (len != msg->DataLength())
     423              :     {
     424            0 :         return CHIP_ERROR_OUTBOUND_MESSAGE_TOO_BIG;
     425              :     }
     426           70 :     return CHIP_NO_ERROR;
     427              : }
     428              : 
     429          117 : void UDPEndPointImplSockets::CloseImpl()
     430              : {
     431          117 :     if (mSocket != kInvalidSocketFd)
     432              :     {
     433          117 :         TEMPORARY_RETURN_IGNORED static_cast<System::LayerSockets *>(&GetSystemLayer())->StopWatchingSocket(&mWatch);
     434          117 :         close(mSocket);
     435          117 :         mSocket = kInvalidSocketFd;
     436              :     }
     437          117 : }
     438              : 
     439          189 : CHIP_ERROR UDPEndPointImplSockets::GetSocket(IPAddressType addressType)
     440              : {
     441          189 :     if (mSocket == kInvalidSocketFd)
     442              :     {
     443          118 :         constexpr int type     = (SOCK_DGRAM | SOCK_CLOEXEC);
     444          118 :         constexpr int protocol = 0;
     445              : 
     446          118 :         int family = PF_UNSPEC;
     447              : 
     448          118 :         switch (addressType)
     449              :         {
     450           59 :         case IPAddressType::kIPv6:
     451           59 :             family = PF_INET6;
     452           59 :             break;
     453              : 
     454              : #if INET_CONFIG_ENABLE_IPV4
     455           58 :         case IPAddressType::kIPv4:
     456           58 :             family = PF_INET;
     457           58 :             break;
     458              : #endif // INET_CONFIG_ENABLE_IPV4
     459              : 
     460            1 :         default:
     461            1 :             return INET_ERROR_WRONG_ADDRESS_TYPE;
     462              :         }
     463              : 
     464          117 :         mSocket = ::socket(family, type, protocol);
     465          117 :         if (mSocket == -1)
     466              :         {
     467            0 :             return CHIP_ERROR_POSIX(errno);
     468              :         }
     469          117 :         CHIP_ERROR err = static_cast<System::LayerSockets *>(&GetSystemLayer())->StartWatchingSocket(mSocket, &mWatch);
     470          234 :         if (err != CHIP_NO_ERROR)
     471              :         {
     472              :             // Our mWatch is not valid; make sure we never use it.
     473            0 :             close(mSocket);
     474            0 :             mSocket = kInvalidSocketFd;
     475            0 :             return err;
     476              :         }
     477              : 
     478          117 :         mAddrType = addressType;
     479              : 
     480              :         // NOTE WELL: the errors returned by setsockopt() here are not
     481              :         // returned as Inet layer CHIP_ERROR_POSIX(errno)
     482              :         // codes because they are normally expected to fail on some
     483              :         // platforms where the socket option code is defined in the
     484              :         // header files but not [yet] implemented. Certainly, there is
     485              :         // room to improve this by connecting the build configuration
     486              :         // logic up to check for implementations of these options and
     487              :         // to provide appropriate HAVE_xxxxx definitions accordingly.
     488              : 
     489          117 :         constexpr int one = 1;
     490          117 :         int res           = setsockopt(mSocket, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
     491              :         static_cast<void>(res);
     492              : 
     493              : #ifdef SO_REUSEPORT
     494          117 :         res = setsockopt(mSocket, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one));
     495          117 :         if (res != 0)
     496              :         {
     497            0 :             ChipLogError(Inet, "SO_REUSEPORT failed: %d", errno);
     498              :         }
     499              : #endif // defined(SO_REUSEPORT)
     500              : 
     501              :         // If creating an IPv6 socket, tell the kernel that it will be
     502              :         // IPv6 only.  This makes it posible to bind two sockets to
     503              :         // the same port, one for IPv4 and one for IPv6.
     504              : 
     505              : #ifdef IPV6_V6ONLY
     506          117 :         if (addressType == IPAddressType::kIPv6)
     507              :         {
     508           59 :             res = setsockopt(mSocket, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one));
     509           59 :             if (res != 0)
     510              :             {
     511            0 :                 ChipLogError(Inet, "IPV6_V6ONLY failed: %d", errno);
     512              :             }
     513              :         }
     514              : #endif // defined(IPV6_V6ONLY)
     515              : 
     516              : #if INET_CONFIG_ENABLE_IPV4
     517              : #ifdef IP_PKTINFO
     518          117 :         if (addressType == IPAddressType::kIPv4)
     519              :         {
     520           58 :             res = setsockopt(mSocket, IPPROTO_IP, IP_PKTINFO, &one, sizeof(one));
     521           58 :             if (res != 0)
     522              :             {
     523            0 :                 ChipLogError(Inet, "IP_PKTINFO failed: %d", errno);
     524              :             }
     525              :         }
     526              : #endif // defined(IP_PKTINFO)
     527              : #endif // INET_CONFIG_ENABLE_IPV4
     528              : 
     529              : #ifdef IPV6_RECVPKTINFO
     530          117 :         if (addressType == IPAddressType::kIPv6)
     531              :         {
     532           59 :             res = setsockopt(mSocket, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one));
     533           59 :             if (res != 0)
     534              :             {
     535            0 :                 ChipLogError(Inet, "IPV6_PKTINFO failed: %d", errno);
     536              :             }
     537              :         }
     538              : #endif // defined(IPV6_RECVPKTINFO)
     539              : 
     540              :         // On systems that support it, disable the delivery of SIGPIPE
     541              :         // signals when writing to a closed socket.  This is mostly
     542              :         // needed on iOS which has the peculiar habit of sending
     543              :         // SIGPIPEs on unconnected UDP sockets.
     544              : #ifdef SO_NOSIGPIPE
     545              :         {
     546              :             res = setsockopt(mSocket, SOL_SOCKET, SO_NOSIGPIPE, &one, sizeof(one));
     547              :             if (res != 0)
     548              :             {
     549              :                 ChipLogError(Inet, "SO_NOSIGPIPE failed: %d", errno);
     550              :             }
     551              :         }
     552              : #endif // defined(SO_NOSIGPIPE)
     553              :     }
     554           71 :     else if (mAddrType != addressType)
     555              :     {
     556            0 :         return CHIP_ERROR_INCORRECT_STATE;
     557              :     }
     558              : 
     559          188 :     return CHIP_NO_ERROR;
     560              : }
     561              : 
     562              : // static
     563           16 : void UDPEndPointImplSockets::HandlePendingIO(System::SocketEvents events, intptr_t data)
     564              : {
     565           16 :     auto * endPoint = reinterpret_cast<UDPEndPointImplSockets *>(data);
     566           16 :     VerifyOrReturn(endPoint != nullptr);
     567           16 :     endPoint->HandlePendingIO(events);
     568              : }
     569              : 
     570           16 : void UDPEndPointImplSockets::HandlePendingIO(System::SocketEvents events)
     571              : {
     572           16 :     if (mState != State::kListening || OnMessageReceived == nullptr || !events.Has(System::SocketEventFlags::kRead))
     573              :     {
     574            0 :         return;
     575              :     }
     576              : 
     577              :     // Prevent the endpoint from being freed while in the middle of a callback.
     578           16 :     UDPEndPointHandle ref(this);
     579           16 :     CHIP_ERROR lStatus = CHIP_NO_ERROR;
     580           16 :     IPPacketInfo lPacketInfo;
     581           16 :     System::PacketBufferHandle lBuffer;
     582              : 
     583           16 :     lPacketInfo.Clear();
     584           16 :     lPacketInfo.DestPort  = mBoundPort;
     585           16 :     lPacketInfo.Interface = mBoundIntfId;
     586              : 
     587           16 :     lBuffer = System::PacketBufferHandle::New(System::PacketBuffer::kMaxSizeWithoutReserve, 0);
     588              : 
     589           16 :     if (!lBuffer.IsNull())
     590              :     {
     591              :         struct iovec msgIOV;
     592              :         SockAddr lPeerSockAddr;
     593              :         uint8_t controlData[256];
     594              :         struct msghdr msgHeader;
     595              : 
     596           16 :         msgIOV.iov_base = lBuffer->Start();
     597           16 :         msgIOV.iov_len  = lBuffer->AvailableDataLength();
     598              : 
     599           16 :         memset(&lPeerSockAddr, 0, sizeof(lPeerSockAddr));
     600           16 :         memset(controlData, 0, sizeof(controlData));
     601           16 :         memset(&msgHeader, 0, sizeof(msgHeader));
     602              : 
     603           16 :         msgHeader.msg_name       = &lPeerSockAddr;
     604           16 :         msgHeader.msg_namelen    = sizeof(lPeerSockAddr);
     605           16 :         msgHeader.msg_iov        = &msgIOV;
     606           16 :         msgHeader.msg_iovlen     = 1;
     607           16 :         msgHeader.msg_control    = controlData;
     608           16 :         msgHeader.msg_controllen = sizeof(controlData);
     609              : 
     610           16 :         ssize_t rcvLen = recvmsg(mSocket, &msgHeader, MSG_DONTWAIT);
     611              : 
     612           16 :         if (rcvLen == -1)
     613              :         {
     614            2 :             lStatus = CHIP_ERROR_POSIX(errno);
     615              :         }
     616           14 :         else if (lBuffer->AvailableDataLength() < static_cast<size_t>(rcvLen))
     617              :         {
     618            0 :             lStatus = CHIP_ERROR_INBOUND_MESSAGE_TOO_BIG;
     619              :         }
     620              :         else
     621              :         {
     622           14 :             lBuffer->SetDataLength(static_cast<uint16_t>(rcvLen));
     623              : 
     624           14 :             if (lPeerSockAddr.any.sa_family == AF_INET6)
     625              :             {
     626            7 :                 lPacketInfo.SrcAddress = IPAddress(lPeerSockAddr.in6.sin6_addr);
     627            7 :                 lPacketInfo.SrcPort    = ntohs(lPeerSockAddr.in6.sin6_port);
     628              :             }
     629              : #if INET_CONFIG_ENABLE_IPV4
     630            7 :             else if (lPeerSockAddr.any.sa_family == AF_INET)
     631              :             {
     632            7 :                 lPacketInfo.SrcAddress = IPAddress(lPeerSockAddr.in.sin_addr);
     633            7 :                 lPacketInfo.SrcPort    = ntohs(lPeerSockAddr.in.sin_port);
     634              :             }
     635              : #endif // INET_CONFIG_ENABLE_IPV4
     636              :             else
     637              :             {
     638            0 :                 lStatus = CHIP_ERROR_INCORRECT_STATE;
     639              :             }
     640              :         }
     641              : 
     642           32 :         if (lStatus == CHIP_NO_ERROR)
     643              :         {
     644           28 :             for (struct cmsghdr * controlHdr = CMSG_FIRSTHDR(&msgHeader); controlHdr != nullptr;
     645           14 :                  controlHdr                  = CMSG_NXTHDR(&msgHeader, controlHdr))
     646              :             {
     647              : #if INET_CONFIG_ENABLE_IPV4
     648              : #ifdef IP_PKTINFO
     649           14 :                 if (controlHdr->cmsg_level == IPPROTO_IP && controlHdr->cmsg_type == IP_PKTINFO)
     650              :                 {
     651            7 :                     auto * inPktInfo = reinterpret_cast<struct in_pktinfo *> CMSG_DATA(controlHdr);
     652            7 :                     if (!CanCastTo<InterfaceId::PlatformType>(inPktInfo->ipi_ifindex))
     653              :                     {
     654            0 :                         lStatus = CHIP_ERROR_INCORRECT_STATE;
     655            0 :                         break;
     656              :                     }
     657            7 :                     lPacketInfo.Interface   = InterfaceId(static_cast<InterfaceId::PlatformType>(inPktInfo->ipi_ifindex));
     658            7 :                     lPacketInfo.DestAddress = IPAddress(inPktInfo->ipi_addr);
     659            7 :                     continue;
     660            7 :                 }
     661              : #endif // defined(IP_PKTINFO)
     662              : #endif // INET_CONFIG_ENABLE_IPV4
     663              : 
     664              : #ifdef IPV6_PKTINFO
     665            7 :                 if (controlHdr->cmsg_level == IPPROTO_IPV6 && controlHdr->cmsg_type == IPV6_PKTINFO)
     666              :                 {
     667            7 :                     auto * in6PktInfo = reinterpret_cast<struct in6_pktinfo *> CMSG_DATA(controlHdr);
     668            7 :                     if (!CanCastTo<InterfaceId::PlatformType>(in6PktInfo->ipi6_ifindex))
     669              :                     {
     670            0 :                         lStatus = CHIP_ERROR_INCORRECT_STATE;
     671            0 :                         break;
     672              :                     }
     673            7 :                     lPacketInfo.Interface   = InterfaceId(static_cast<InterfaceId::PlatformType>(in6PktInfo->ipi6_ifindex));
     674            7 :                     lPacketInfo.DestAddress = IPAddress(in6PktInfo->ipi6_addr);
     675            7 :                     continue;
     676            7 :                 }
     677              : #endif // defined(IPV6_PKTINFO)
     678              :             }
     679              :         }
     680              :     }
     681              :     else
     682              :     {
     683            0 :         lStatus = CHIP_ERROR_NO_MEMORY;
     684              :     }
     685              : 
     686           32 :     if (lStatus == CHIP_NO_ERROR)
     687              :     {
     688           14 :         lBuffer.RightSize();
     689           14 :         OnMessageReceived(this, std::move(lBuffer), &lPacketInfo);
     690              :     }
     691              :     else
     692              :     {
     693            2 :         if (OnReceiveError != nullptr && lStatus != CHIP_ERROR_POSIX(EAGAIN))
     694              :         {
     695            0 :             OnReceiveError(this, lStatus, nullptr);
     696              :         }
     697              :     }
     698           16 : }
     699              : 
     700              : #ifdef IPV6_MULTICAST_LOOP
     701            0 : static CHIP_ERROR SocketsSetMulticastLoopback(int aSocket, bool aLoopback, int aProtocol, int aOption)
     702              : {
     703            0 :     const unsigned int lValue = static_cast<unsigned int>(aLoopback);
     704            0 :     if (setsockopt(aSocket, aProtocol, aOption, &lValue, sizeof(lValue)) != 0)
     705              :     {
     706            0 :         return CHIP_ERROR_POSIX(errno);
     707              :     }
     708              : 
     709            0 :     return CHIP_NO_ERROR;
     710              : }
     711              : #endif // IPV6_MULTICAST_LOOP
     712              : 
     713            0 : static CHIP_ERROR SocketsSetMulticastLoopback(int aSocket, IPVersion aIPVersion, bool aLoopback)
     714              : {
     715              : #ifdef IPV6_MULTICAST_LOOP
     716              :     CHIP_ERROR lRetval;
     717              : 
     718            0 :     switch (aIPVersion)
     719              :     {
     720              : 
     721            0 :     case kIPVersion_6:
     722            0 :         lRetval = SocketsSetMulticastLoopback(aSocket, aLoopback, IPPROTO_IPV6, IPV6_MULTICAST_LOOP);
     723            0 :         break;
     724              : 
     725              : #if INET_CONFIG_ENABLE_IPV4 && defined(IP_MULTICAST_LOOP)
     726            0 :     case kIPVersion_4:
     727            0 :         lRetval = SocketsSetMulticastLoopback(aSocket, aLoopback, IPPROTO_IP, IP_MULTICAST_LOOP);
     728            0 :         break;
     729              : #endif // INET_CONFIG_ENABLE_IPV4 && defined(IP_MULTICAST_LOOP)
     730              : 
     731            0 :     default:
     732            0 :         lRetval = INET_ERROR_WRONG_ADDRESS_TYPE;
     733            0 :         break;
     734              :     }
     735              : 
     736            0 :     return (lRetval);
     737              : #else  // IPV6_MULTICAST_LOOP
     738              :     return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
     739              : #endif // IPV6_MULTICAST_LOOP
     740              : }
     741              : 
     742            0 : CHIP_ERROR UDPEndPointImplSockets::SetMulticastLoopback(IPVersion aIPVersion, bool aLoopback)
     743              : {
     744            0 :     CHIP_ERROR lRetval = CHIP_ERROR_NOT_IMPLEMENTED;
     745              : 
     746            0 :     lRetval = SocketsSetMulticastLoopback(mSocket, aIPVersion, aLoopback);
     747            0 :     SuccessOrExit(lRetval);
     748              : 
     749            0 : exit:
     750            0 :     return (lRetval);
     751              : }
     752              : 
     753              : #if INET_CONFIG_ENABLE_IPV4
     754              : 
     755           27 : CHIP_ERROR UDPEndPointImplSockets::IPv4JoinLeaveMulticastGroupImpl(InterfaceId aInterfaceId, const IPAddress & aAddress, bool join)
     756              : {
     757              :     in_addr interfaceAddr;
     758              : 
     759           27 :     if (aInterfaceId.IsPresent())
     760              :     {
     761              :         IPAddress lInterfaceAddress;
     762           27 :         bool lInterfaceAddressFound = false;
     763              : 
     764           54 :         for (InterfaceAddressIterator lAddressIterator; lAddressIterator.HasCurrent(); lAddressIterator.Next())
     765              :         {
     766              :             IPAddress lCurrentAddress;
     767           81 :             if ((lAddressIterator.GetInterfaceId() == aInterfaceId) &&
     768          108 :                 (lAddressIterator.GetAddress(lCurrentAddress) == CHIP_NO_ERROR))
     769              :             {
     770           27 :                 if (lCurrentAddress.IsIPv4())
     771              :                 {
     772           27 :                     lInterfaceAddressFound = true;
     773           27 :                     lInterfaceAddress      = lCurrentAddress;
     774           27 :                     break;
     775              :                 }
     776              :             }
     777           27 :         }
     778           27 :         VerifyOrReturnError(lInterfaceAddressFound, INET_ERROR_ADDRESS_NOT_FOUND);
     779              : 
     780           27 :         interfaceAddr = lInterfaceAddress.ToIPv4();
     781              :     }
     782              :     else
     783              :     {
     784            0 :         interfaceAddr.s_addr = htonl(INADDR_ANY);
     785              :     }
     786              : 
     787              : #if INET_CONFIG_UDP_SOCKET_MREQN
     788              :     struct ip_mreqn lMulticastRequest;
     789              :     memset(&lMulticastRequest, 0, sizeof(lMulticastRequest));
     790              :     lMulticastRequest.imr_ifindex   = aInterfaceId.GetPlatformInterface(); /* Network interface index */
     791              :     lMulticastRequest.imr_address   = interfaceAddr;                       /* IP address of local interface */
     792              :     lMulticastRequest.imr_multiaddr = aAddress.ToIPv4();                   /* IP multicast group address*/
     793              : 
     794              : #else
     795              : 
     796              :     struct ip_mreq lMulticastRequest;
     797           27 :     memset(&lMulticastRequest, 0, sizeof(lMulticastRequest));
     798           27 :     lMulticastRequest.imr_interface = interfaceAddr;
     799           27 :     lMulticastRequest.imr_multiaddr = aAddress.ToIPv4();
     800              : 
     801              : #endif
     802              : 
     803           27 :     const int command = join ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP;
     804           27 :     if (setsockopt(mSocket, IPPROTO_IP, command, &lMulticastRequest, sizeof(lMulticastRequest)) != 0)
     805              :     {
     806            0 :         return CHIP_ERROR_POSIX(errno);
     807              :     }
     808           27 :     return CHIP_NO_ERROR;
     809              : }
     810              : 
     811              : #endif // INET_CONFIG_ENABLE_IPV4
     812              : 
     813           27 : CHIP_ERROR UDPEndPointImplSockets::IPv6JoinLeaveMulticastGroupImpl(InterfaceId aInterfaceId, const IPAddress & aAddress, bool join)
     814              : {
     815              : #if CHIP_SYSTEM_CONFIG_USE_PLATFORM_MULTICAST_API
     816              :     if (sMulticastGroupHandler != nullptr)
     817              :     {
     818              :         return sMulticastGroupHandler(aInterfaceId, aAddress, join ? MulticastOperation::kJoin : MulticastOperation::kLeave);
     819              :     }
     820              : #endif // CHIP_SYSTEM_CONFIG_USE_PLATFORM_MULTICAST_API
     821              : 
     822              : #ifdef IPV6_MULTICAST_IMPLEMENTED
     823           27 :     if (!aInterfaceId.IsPresent())
     824              :     {
     825              :         // Do it on all the viable interfaces.
     826            0 :         bool interfaceFound = false;
     827              : 
     828            0 :         InterfaceIterator interfaceIt;
     829            0 :         while (interfaceIt.Next())
     830              :         {
     831            0 :             if (!interfaceIt.SupportsMulticast() || !interfaceIt.IsUp())
     832              :             {
     833            0 :                 continue;
     834              :             }
     835              : 
     836            0 :             InterfaceId interfaceId = interfaceIt.GetInterfaceId();
     837              : 
     838              :             IPAddress ifAddr;
     839            0 :             if (interfaceId.GetLinkLocalAddr(&ifAddr) != CHIP_NO_ERROR)
     840              :             {
     841            0 :                 continue;
     842              :             }
     843              : 
     844            0 :             if (ifAddr.Type() != IPAddressType::kIPv6)
     845              :             {
     846              :                 // Not the right sort of interface.
     847            0 :                 continue;
     848              :             }
     849              : 
     850            0 :             interfaceFound = true;
     851              : 
     852              :             char ifName[InterfaceId::kMaxIfNameLength];
     853            0 :             TEMPORARY_RETURN_IGNORED interfaceIt.GetInterfaceName(ifName, sizeof(ifName));
     854              : 
     855              :             // Ignore errors here, except for logging, because we expect some of
     856              :             // these interfaces to not work, and some (e.g. loopback) to always
     857              :             // work.
     858            0 :             CHIP_ERROR err = IPv6JoinLeaveMulticastGroupImpl(interfaceId, aAddress, join);
     859            0 :             if (err == CHIP_NO_ERROR)
     860              :             {
     861            0 :                 ChipLogDetail(Inet, "  %s multicast group on interface %s", (join ? "Joined" : "Left"), ifName);
     862              :             }
     863              :             else
     864              :             {
     865            0 :                 ChipLogError(Inet, "  Failed to %s multicast group on interface %s", (join ? "join" : "leave"), ifName);
     866              :             }
     867              :         }
     868              : 
     869            0 :         if (interfaceFound)
     870              :         {
     871              :             // Assume we're good.
     872            0 :             return CHIP_NO_ERROR;
     873              :         }
     874              : 
     875              :         // Else go ahead and try to work with the default interface.
     876            0 :         ChipLogError(Inet, "No valid IPv6 multicast interface found");
     877            0 :     }
     878              : 
     879           27 :     const InterfaceId::PlatformType lIfIndex = aInterfaceId.GetPlatformInterface();
     880              : 
     881              :     struct ipv6_mreq lMulticastRequest;
     882           27 :     memset(&lMulticastRequest, 0, sizeof(lMulticastRequest));
     883           27 :     VerifyOrReturnError(CanCastTo<decltype(lMulticastRequest.ipv6mr_interface)>(lIfIndex), CHIP_ERROR_UNEXPECTED_EVENT);
     884              : 
     885           27 :     lMulticastRequest.ipv6mr_interface = static_cast<decltype(lMulticastRequest.ipv6mr_interface)>(lIfIndex);
     886           27 :     lMulticastRequest.ipv6mr_multiaddr = aAddress.ToIPv6();
     887              : 
     888           27 :     const int command = join ? INET_IPV6_ADD_MEMBERSHIP : INET_IPV6_DROP_MEMBERSHIP;
     889           27 :     if (setsockopt(mSocket, IPPROTO_IPV6, command, &lMulticastRequest, sizeof(lMulticastRequest)) != 0)
     890              :     {
     891            0 :         return CHIP_ERROR_POSIX(errno);
     892              :     }
     893           27 :     return CHIP_NO_ERROR;
     894              : #else
     895              :     return CHIP_ERROR_NOT_IMPLEMENTED;
     896              : #endif
     897              : }
     898              : 
     899              : } // namespace Inet
     900              : } // namespace chip
        

Generated by: LCOV version 2.0-1