Matter SDK Coverage Report
Current view: top level - inet - UDPEndPointImplSockets.cpp (source / functions) Coverage Total Hit
Test: SHA:2a48c1efeab1c0f76f3adb3a0940b0f7de706453 Lines: 76.4 % 318 243
Test Date: 2026-01-31 08:14:20 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           49 : CHIP_ERROR IPv6Bind(int socket, const IPAddress & address, uint16_t port, InterfaceId interface)
      91              : {
      92              :     struct sockaddr_in6 sa;
      93           49 :     memset(&sa, 0, sizeof(sa));
      94           49 :     sa.sin6_family                        = AF_INET6;
      95           49 :     sa.sin6_port                          = htons(port);
      96           49 :     sa.sin6_addr                          = address.ToIPv6();
      97           49 :     InterfaceId::PlatformType interfaceId = interface.GetPlatformInterface();
      98           49 :     if (!CanCastTo<decltype(sa.sin6_scope_id)>(interfaceId))
      99              :     {
     100            0 :         return CHIP_ERROR_INCORRECT_STATE;
     101              :     }
     102           49 :     sa.sin6_scope_id = static_cast<decltype(sa.sin6_scope_id)>(interfaceId);
     103              : 
     104           49 :     CHIP_ERROR status = CHIP_NO_ERROR;
     105              : 
     106              :     // NOLINTNEXTLINE(clang-analyzer-unix.StdCLibraryFunctions): Function called only with valid socket after GetSocket
     107           49 :     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           49 :         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           49 :     int hops = INET_CONFIG_IP_MULTICAST_HOP_LIMIT;
     124           49 :     setsockopt(socket, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hops, sizeof(hops));
     125              : #endif // defined(IPV6_MULTICAST_HOPS)
     126              : 
     127           49 :     return status;
     128              : }
     129              : 
     130              : #if INET_CONFIG_ENABLE_IPV4
     131           48 : CHIP_ERROR IPv4Bind(int socket, const IPAddress & address, uint16_t port)
     132              : {
     133              :     struct sockaddr_in sa;
     134           48 :     memset(&sa, 0, sizeof(sa));
     135           48 :     sa.sin_family = AF_INET;
     136           48 :     sa.sin_port   = htons(port);
     137           48 :     sa.sin_addr   = address.ToIPv4();
     138              : 
     139           48 :     CHIP_ERROR status = CHIP_NO_ERROR;
     140              : 
     141              :     // NOLINTNEXTLINE(clang-analyzer-unix.StdCLibraryFunctions): Function called only with valid socket after GetSocket
     142           48 :     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           47 :         constexpr int enable = 1;
     150           47 :         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           47 :         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           48 :     constexpr int ttl = INET_CONFIG_IP_MULTICAST_HOP_LIMIT;
     163           48 :     setsockopt(socket, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl));
     164              : #endif // defined(IP_MULTICAST_TTL)
     165              : 
     166           48 :     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           98 : 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           98 :     ReturnErrorOnFailure(GetSocket(addressType));
     180              : 
     181           97 :     if (addressType == IPAddressType::kIPv6)
     182              :     {
     183           49 :         ReturnErrorOnFailure(IPv6Bind(mSocket, addr, port, interface));
     184              :     }
     185              : #if INET_CONFIG_ENABLE_IPV4
     186           48 :     else if (addressType == IPAddressType::kIPv4)
     187              :     {
     188           48 :         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           96 :     mBoundPort   = port;
     197           96 :     mBoundIntfId = interface;
     198              : 
     199              :     // If an ephemeral port was requested, retrieve the actual bound port.
     200           96 :     if (port == 0)
     201              :     {
     202              :         SockAddr boundAddr;
     203           50 :         socklen_t boundAddrLen = sizeof(boundAddr);
     204              : 
     205           50 :         if (getsockname(mSocket, &boundAddr.any, &boundAddrLen) == 0)
     206              :         {
     207           50 :             if (boundAddr.any.sa_family == AF_INET)
     208              :             {
     209           25 :                 mBoundPort = ntohs(boundAddr.in.sin_port);
     210              :             }
     211           25 :             else if (boundAddr.any.sa_family == AF_INET6)
     212              :             {
     213           25 :                 mBoundPort = ntohs(boundAddr.in6.sin6_port);
     214              :             }
     215              :         }
     216              :     }
     217              : 
     218           96 :     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           55 : InterfaceId UDPEndPointImplSockets::GetBoundInterface() const
     263              : {
     264           55 :     return mBoundIntfId;
     265              : }
     266              : 
     267           11 : uint16_t UDPEndPointImplSockets::GetBoundPort() const
     268              : {
     269           11 :     return mBoundPort;
     270              : }
     271              : 
     272           96 : CHIP_ERROR UDPEndPointImplSockets::ListenImpl()
     273              : {
     274              :     // Wait for ability to read on this endpoint.
     275           96 :     auto * layer = static_cast<System::LayerSockets *>(&GetSystemLayer());
     276           96 :     ReturnErrorOnFailure(layer->SetCallback(mWatch, HandlePendingIO, reinterpret_cast<intptr_t>(this)));
     277           96 :     return layer->RequestCallbackOnPendingRead(mWatch);
     278              : }
     279              : 
     280           58 : CHIP_ERROR UDPEndPointImplSockets::SendMsgImpl(const IPPacketInfo * aPktInfo, System::PacketBufferHandle && msg)
     281              : {
     282              :     // Ensure packet buffer is not null
     283           58 :     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           58 :     ReturnErrorOnFailure(GetSocket(aPktInfo->DestAddress.Type()));
     288              : 
     289              :     // Ensure the destination address type is compatible with the endpoint address type.
     290           58 :     VerifyOrReturnError(mAddrType == aPktInfo->DestAddress.Type(), CHIP_ERROR_INVALID_ARGUMENT);
     291              : 
     292              :     // For now the entire message must fit within a single buffer.
     293           58 :     VerifyOrReturnError(!msg->HasChainedBuffer(), CHIP_ERROR_MESSAGE_TOO_LONG);
     294              : 
     295              :     struct iovec msgIOV;
     296           58 :     msgIOV.iov_base = msg->Start();
     297           58 :     msgIOV.iov_len  = msg->DataLength();
     298              : 
     299              : #if defined(IP_PKTINFO) || defined(IPV6_PKTINFO)
     300              :     uint8_t controlData[256];
     301           58 :     memset(controlData, 0, sizeof(controlData));
     302              : #endif // defined(IP_PKTINFO) || defined(IPV6_PKTINFO)
     303              : 
     304              :     struct msghdr msgHeader;
     305           58 :     memset(&msgHeader, 0, sizeof(msgHeader));
     306           58 :     msgHeader.msg_iov    = &msgIOV;
     307           58 :     msgHeader.msg_iovlen = 1;
     308              : 
     309              :     // Construct a sockaddr_in/sockaddr_in6 structure containing the destination information.
     310              :     SockAddr peerSockAddr;
     311           58 :     memset(&peerSockAddr, 0, sizeof(peerSockAddr));
     312           58 :     msgHeader.msg_name = &peerSockAddr;
     313           58 :     if (mAddrType == IPAddressType::kIPv6)
     314              :     {
     315           29 :         peerSockAddr.in6.sin6_family     = AF_INET6;
     316           29 :         peerSockAddr.in6.sin6_port       = htons(aPktInfo->DestPort);
     317           29 :         peerSockAddr.in6.sin6_addr       = aPktInfo->DestAddress.ToIPv6();
     318           29 :         InterfaceId::PlatformType intfId = aPktInfo->Interface.GetPlatformInterface();
     319           29 :         VerifyOrReturnError(CanCastTo<decltype(peerSockAddr.in6.sin6_scope_id)>(intfId), CHIP_ERROR_INCORRECT_STATE);
     320           29 :         peerSockAddr.in6.sin6_scope_id = static_cast<decltype(peerSockAddr.in6.sin6_scope_id)>(intfId);
     321           29 :         msgHeader.msg_namelen          = sizeof(sockaddr_in6);
     322              :     }
     323              : #if INET_CONFIG_ENABLE_IPV4
     324              :     else
     325              :     {
     326           29 :         peerSockAddr.in.sin_family = AF_INET;
     327           29 :         peerSockAddr.in.sin_port   = htons(aPktInfo->DestPort);
     328           29 :         peerSockAddr.in.sin_addr   = aPktInfo->DestAddress.ToIPv4();
     329           29 :         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           58 :     InterfaceId intf = aPktInfo->Interface;
     340           58 :     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           58 :     if (intf.IsPresent() || aPktInfo->SrcAddress.Type() != IPAddressType::kAny)
     351              :     {
     352              : #if defined(IP_PKTINFO) || defined(IPV6_PKTINFO)
     353           54 :         msgHeader.msg_control    = controlData;
     354           54 :         msgHeader.msg_controllen = sizeof(controlData);
     355              : 
     356           54 :         struct cmsghdr * controlHdr      = CMSG_FIRSTHDR(&msgHeader);
     357           54 :         InterfaceId::PlatformType intfId = intf.GetPlatformInterface();
     358              : 
     359              : #if INET_CONFIG_ENABLE_IPV4
     360              : 
     361           54 :         if (mAddrType == IPAddressType::kIPv4)
     362              :         {
     363              : #if defined(IP_PKTINFO)
     364           27 :             controlHdr->cmsg_level = IPPROTO_IP;
     365           27 :             controlHdr->cmsg_type  = IP_PKTINFO;
     366           27 :             controlHdr->cmsg_len   = CMSG_LEN(sizeof(in_pktinfo));
     367              : 
     368           27 :             auto * pktInfo = reinterpret_cast<struct in_pktinfo *> CMSG_DATA(controlHdr);
     369           27 :             if (!CanCastTo<decltype(pktInfo->ipi_ifindex)>(intfId))
     370              :             {
     371            0 :                 return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
     372              :             }
     373              : 
     374           27 :             pktInfo->ipi_ifindex  = static_cast<decltype(pktInfo->ipi_ifindex)>(intfId);
     375           27 :             pktInfo->ipi_spec_dst = aPktInfo->SrcAddress.ToIPv4();
     376              : 
     377           27 :             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           54 :         if (mAddrType == IPAddressType::kIPv6)
     386              :         {
     387              : #if defined(IPV6_PKTINFO)
     388           27 :             controlHdr->cmsg_level = IPPROTO_IPV6;
     389           27 :             controlHdr->cmsg_type  = IPV6_PKTINFO;
     390           27 :             controlHdr->cmsg_len   = CMSG_LEN(sizeof(in6_pktinfo));
     391              : 
     392           27 :             auto * pktInfo = reinterpret_cast<struct in6_pktinfo *> CMSG_DATA(controlHdr);
     393           27 :             if (!CanCastTo<decltype(pktInfo->ipi6_ifindex)>(intfId))
     394              :             {
     395            0 :                 return CHIP_ERROR_UNEXPECTED_EVENT;
     396              :             }
     397           27 :             pktInfo->ipi6_ifindex = static_cast<decltype(pktInfo->ipi6_ifindex)>(intfId);
     398           27 :             pktInfo->ipi6_addr    = aPktInfo->SrcAddress.ToIPv6();
     399              : 
     400           27 :             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           58 :     const ssize_t lenSent = sendmsg(mSocket, &msgHeader, 0);
     415           58 :     if (lenSent == -1)
     416              :     {
     417            0 :         return CHIP_ERROR_POSIX(errno);
     418              :     }
     419              : 
     420           58 :     size_t len = static_cast<size_t>(lenSent);
     421              : 
     422           58 :     if (len != msg->DataLength())
     423              :     {
     424            0 :         return CHIP_ERROR_OUTBOUND_MESSAGE_TOO_BIG;
     425              :     }
     426           58 :     return CHIP_NO_ERROR;
     427              : }
     428              : 
     429           97 : void UDPEndPointImplSockets::CloseImpl()
     430              : {
     431           97 :     if (mSocket != kInvalidSocketFd)
     432              :     {
     433           97 :         TEMPORARY_RETURN_IGNORED static_cast<System::LayerSockets *>(&GetSystemLayer())->StopWatchingSocket(&mWatch);
     434           97 :         close(mSocket);
     435           97 :         mSocket = kInvalidSocketFd;
     436              :     }
     437           97 : }
     438              : 
     439          157 : CHIP_ERROR UDPEndPointImplSockets::GetSocket(IPAddressType addressType)
     440              : {
     441          157 :     if (mSocket == kInvalidSocketFd)
     442              :     {
     443           98 :         constexpr int type     = (SOCK_DGRAM | SOCK_CLOEXEC);
     444           98 :         constexpr int protocol = 0;
     445              : 
     446           98 :         int family = PF_UNSPEC;
     447              : 
     448           98 :         switch (addressType)
     449              :         {
     450           49 :         case IPAddressType::kIPv6:
     451           49 :             family = PF_INET6;
     452           49 :             break;
     453              : 
     454              : #if INET_CONFIG_ENABLE_IPV4
     455           48 :         case IPAddressType::kIPv4:
     456           48 :             family = PF_INET;
     457           48 :             break;
     458              : #endif // INET_CONFIG_ENABLE_IPV4
     459              : 
     460            1 :         default:
     461            1 :             return INET_ERROR_WRONG_ADDRESS_TYPE;
     462              :         }
     463              : 
     464           97 :         mSocket = ::socket(family, type, protocol);
     465           97 :         if (mSocket == -1)
     466              :         {
     467            0 :             return CHIP_ERROR_POSIX(errno);
     468              :         }
     469           97 :         CHIP_ERROR err = static_cast<System::LayerSockets *>(&GetSystemLayer())->StartWatchingSocket(mSocket, &mWatch);
     470          194 :         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           97 :         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           97 :         constexpr int one = 1;
     490           97 :         int res           = setsockopt(mSocket, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
     491              :         static_cast<void>(res);
     492              : 
     493              : #ifdef SO_REUSEPORT
     494           97 :         res = setsockopt(mSocket, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one));
     495           97 :         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           97 :         if (addressType == IPAddressType::kIPv6)
     507              :         {
     508           49 :             res = setsockopt(mSocket, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one));
     509           49 :             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           97 :         if (addressType == IPAddressType::kIPv4)
     519              :         {
     520           48 :             res = setsockopt(mSocket, IPPROTO_IP, IP_PKTINFO, &one, sizeof(one));
     521           48 :             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           97 :         if (addressType == IPAddressType::kIPv6)
     531              :         {
     532           49 :             res = setsockopt(mSocket, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one));
     533           49 :             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           59 :     else if (mAddrType != addressType)
     555              :     {
     556            0 :         return CHIP_ERROR_INCORRECT_STATE;
     557              :     }
     558              : 
     559          156 :     return CHIP_NO_ERROR;
     560              : }
     561              : 
     562              : // static
     563           16 : void UDPEndPointImplSockets::HandlePendingIO(System::SocketEvents events, intptr_t data)
     564              : {
     565           16 :     reinterpret_cast<UDPEndPointImplSockets *>(data)->HandlePendingIO(events);
     566           16 : }
     567              : 
     568           16 : void UDPEndPointImplSockets::HandlePendingIO(System::SocketEvents events)
     569              : {
     570           16 :     if (mState != State::kListening || OnMessageReceived == nullptr || !events.Has(System::SocketEventFlags::kRead))
     571              :     {
     572            0 :         return;
     573              :     }
     574              : 
     575              :     // Prevent the endpoint from being freed while in the middle of a callback.
     576           16 :     UDPEndPointHandle ref(this);
     577           16 :     CHIP_ERROR lStatus = CHIP_NO_ERROR;
     578           16 :     IPPacketInfo lPacketInfo;
     579           16 :     System::PacketBufferHandle lBuffer;
     580              : 
     581           16 :     lPacketInfo.Clear();
     582           16 :     lPacketInfo.DestPort  = mBoundPort;
     583           16 :     lPacketInfo.Interface = mBoundIntfId;
     584              : 
     585           16 :     lBuffer = System::PacketBufferHandle::New(System::PacketBuffer::kMaxSizeWithoutReserve, 0);
     586              : 
     587           16 :     if (!lBuffer.IsNull())
     588              :     {
     589              :         struct iovec msgIOV;
     590              :         SockAddr lPeerSockAddr;
     591              :         uint8_t controlData[256];
     592              :         struct msghdr msgHeader;
     593              : 
     594           16 :         msgIOV.iov_base = lBuffer->Start();
     595           16 :         msgIOV.iov_len  = lBuffer->AvailableDataLength();
     596              : 
     597           16 :         memset(&lPeerSockAddr, 0, sizeof(lPeerSockAddr));
     598              : 
     599           16 :         memset(&msgHeader, 0, sizeof(msgHeader));
     600              : 
     601           16 :         msgHeader.msg_name       = &lPeerSockAddr;
     602           16 :         msgHeader.msg_namelen    = sizeof(lPeerSockAddr);
     603           16 :         msgHeader.msg_iov        = &msgIOV;
     604           16 :         msgHeader.msg_iovlen     = 1;
     605           16 :         msgHeader.msg_control    = controlData;
     606           16 :         msgHeader.msg_controllen = sizeof(controlData);
     607              : 
     608           16 :         ssize_t rcvLen = recvmsg(mSocket, &msgHeader, MSG_DONTWAIT);
     609              : 
     610           16 :         if (rcvLen == -1)
     611              :         {
     612            2 :             lStatus = CHIP_ERROR_POSIX(errno);
     613              :         }
     614           14 :         else if (lBuffer->AvailableDataLength() < static_cast<size_t>(rcvLen))
     615              :         {
     616            0 :             lStatus = CHIP_ERROR_INBOUND_MESSAGE_TOO_BIG;
     617              :         }
     618              :         else
     619              :         {
     620           14 :             lBuffer->SetDataLength(static_cast<uint16_t>(rcvLen));
     621              : 
     622           14 :             if (lPeerSockAddr.any.sa_family == AF_INET6)
     623              :             {
     624            7 :                 lPacketInfo.SrcAddress = IPAddress(lPeerSockAddr.in6.sin6_addr);
     625            7 :                 lPacketInfo.SrcPort    = ntohs(lPeerSockAddr.in6.sin6_port);
     626              :             }
     627              : #if INET_CONFIG_ENABLE_IPV4
     628            7 :             else if (lPeerSockAddr.any.sa_family == AF_INET)
     629              :             {
     630            7 :                 lPacketInfo.SrcAddress = IPAddress(lPeerSockAddr.in.sin_addr);
     631            7 :                 lPacketInfo.SrcPort    = ntohs(lPeerSockAddr.in.sin_port);
     632              :             }
     633              : #endif // INET_CONFIG_ENABLE_IPV4
     634              :             else
     635              :             {
     636            0 :                 lStatus = CHIP_ERROR_INCORRECT_STATE;
     637              :             }
     638              :         }
     639              : 
     640           32 :         if (lStatus == CHIP_NO_ERROR)
     641              :         {
     642           28 :             for (struct cmsghdr * controlHdr = CMSG_FIRSTHDR(&msgHeader); controlHdr != nullptr;
     643           14 :                  controlHdr                  = CMSG_NXTHDR(&msgHeader, controlHdr))
     644              :             {
     645              : #if INET_CONFIG_ENABLE_IPV4
     646              : #ifdef IP_PKTINFO
     647           14 :                 if (controlHdr->cmsg_level == IPPROTO_IP && controlHdr->cmsg_type == IP_PKTINFO)
     648              :                 {
     649            7 :                     auto * inPktInfo = reinterpret_cast<struct in_pktinfo *> CMSG_DATA(controlHdr);
     650            7 :                     if (!CanCastTo<InterfaceId::PlatformType>(inPktInfo->ipi_ifindex))
     651              :                     {
     652            0 :                         lStatus = CHIP_ERROR_INCORRECT_STATE;
     653            0 :                         break;
     654              :                     }
     655            7 :                     lPacketInfo.Interface   = InterfaceId(static_cast<InterfaceId::PlatformType>(inPktInfo->ipi_ifindex));
     656            7 :                     lPacketInfo.DestAddress = IPAddress(inPktInfo->ipi_addr);
     657            7 :                     continue;
     658            7 :                 }
     659              : #endif // defined(IP_PKTINFO)
     660              : #endif // INET_CONFIG_ENABLE_IPV4
     661              : 
     662              : #ifdef IPV6_PKTINFO
     663            7 :                 if (controlHdr->cmsg_level == IPPROTO_IPV6 && controlHdr->cmsg_type == IPV6_PKTINFO)
     664              :                 {
     665            7 :                     auto * in6PktInfo = reinterpret_cast<struct in6_pktinfo *> CMSG_DATA(controlHdr);
     666            7 :                     if (!CanCastTo<InterfaceId::PlatformType>(in6PktInfo->ipi6_ifindex))
     667              :                     {
     668            0 :                         lStatus = CHIP_ERROR_INCORRECT_STATE;
     669            0 :                         break;
     670              :                     }
     671            7 :                     lPacketInfo.Interface   = InterfaceId(static_cast<InterfaceId::PlatformType>(in6PktInfo->ipi6_ifindex));
     672            7 :                     lPacketInfo.DestAddress = IPAddress(in6PktInfo->ipi6_addr);
     673            7 :                     continue;
     674            7 :                 }
     675              : #endif // defined(IPV6_PKTINFO)
     676              :             }
     677              :         }
     678              :     }
     679              :     else
     680              :     {
     681            0 :         lStatus = CHIP_ERROR_NO_MEMORY;
     682              :     }
     683              : 
     684           32 :     if (lStatus == CHIP_NO_ERROR)
     685              :     {
     686           14 :         lBuffer.RightSize();
     687           14 :         OnMessageReceived(this, std::move(lBuffer), &lPacketInfo);
     688              :     }
     689              :     else
     690              :     {
     691            2 :         if (OnReceiveError != nullptr && lStatus != CHIP_ERROR_POSIX(EAGAIN))
     692              :         {
     693            0 :             OnReceiveError(this, lStatus, nullptr);
     694              :         }
     695              :     }
     696           16 : }
     697              : 
     698              : #ifdef IPV6_MULTICAST_LOOP
     699            0 : static CHIP_ERROR SocketsSetMulticastLoopback(int aSocket, bool aLoopback, int aProtocol, int aOption)
     700              : {
     701            0 :     const unsigned int lValue = static_cast<unsigned int>(aLoopback);
     702            0 :     if (setsockopt(aSocket, aProtocol, aOption, &lValue, sizeof(lValue)) != 0)
     703              :     {
     704            0 :         return CHIP_ERROR_POSIX(errno);
     705              :     }
     706              : 
     707            0 :     return CHIP_NO_ERROR;
     708              : }
     709              : #endif // IPV6_MULTICAST_LOOP
     710              : 
     711            0 : static CHIP_ERROR SocketsSetMulticastLoopback(int aSocket, IPVersion aIPVersion, bool aLoopback)
     712              : {
     713              : #ifdef IPV6_MULTICAST_LOOP
     714              :     CHIP_ERROR lRetval;
     715              : 
     716            0 :     switch (aIPVersion)
     717              :     {
     718              : 
     719            0 :     case kIPVersion_6:
     720            0 :         lRetval = SocketsSetMulticastLoopback(aSocket, aLoopback, IPPROTO_IPV6, IPV6_MULTICAST_LOOP);
     721            0 :         break;
     722              : 
     723              : #if INET_CONFIG_ENABLE_IPV4 && defined(IP_MULTICAST_LOOP)
     724            0 :     case kIPVersion_4:
     725            0 :         lRetval = SocketsSetMulticastLoopback(aSocket, aLoopback, IPPROTO_IP, IP_MULTICAST_LOOP);
     726            0 :         break;
     727              : #endif // INET_CONFIG_ENABLE_IPV4 && defined(IP_MULTICAST_LOOP)
     728              : 
     729            0 :     default:
     730            0 :         lRetval = INET_ERROR_WRONG_ADDRESS_TYPE;
     731            0 :         break;
     732              :     }
     733              : 
     734            0 :     return (lRetval);
     735              : #else  // IPV6_MULTICAST_LOOP
     736              :     return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
     737              : #endif // IPV6_MULTICAST_LOOP
     738              : }
     739              : 
     740            0 : CHIP_ERROR UDPEndPointImplSockets::SetMulticastLoopback(IPVersion aIPVersion, bool aLoopback)
     741              : {
     742            0 :     CHIP_ERROR lRetval = CHIP_ERROR_NOT_IMPLEMENTED;
     743              : 
     744            0 :     lRetval = SocketsSetMulticastLoopback(mSocket, aIPVersion, aLoopback);
     745            0 :     SuccessOrExit(lRetval);
     746              : 
     747            0 : exit:
     748            0 :     return (lRetval);
     749              : }
     750              : 
     751              : #if INET_CONFIG_ENABLE_IPV4
     752              : 
     753           22 : CHIP_ERROR UDPEndPointImplSockets::IPv4JoinLeaveMulticastGroupImpl(InterfaceId aInterfaceId, const IPAddress & aAddress, bool join)
     754              : {
     755              :     in_addr interfaceAddr;
     756              : 
     757           22 :     if (aInterfaceId.IsPresent())
     758              :     {
     759              :         IPAddress lInterfaceAddress;
     760           22 :         bool lInterfaceAddressFound = false;
     761              : 
     762           44 :         for (InterfaceAddressIterator lAddressIterator; lAddressIterator.HasCurrent(); lAddressIterator.Next())
     763              :         {
     764              :             IPAddress lCurrentAddress;
     765           66 :             if ((lAddressIterator.GetInterfaceId() == aInterfaceId) &&
     766           88 :                 (lAddressIterator.GetAddress(lCurrentAddress) == CHIP_NO_ERROR))
     767              :             {
     768           22 :                 if (lCurrentAddress.IsIPv4())
     769              :                 {
     770           22 :                     lInterfaceAddressFound = true;
     771           22 :                     lInterfaceAddress      = lCurrentAddress;
     772           22 :                     break;
     773              :                 }
     774              :             }
     775           22 :         }
     776           22 :         VerifyOrReturnError(lInterfaceAddressFound, INET_ERROR_ADDRESS_NOT_FOUND);
     777              : 
     778           22 :         interfaceAddr = lInterfaceAddress.ToIPv4();
     779              :     }
     780              :     else
     781              :     {
     782            0 :         interfaceAddr.s_addr = htonl(INADDR_ANY);
     783              :     }
     784              : 
     785              : #if INET_CONFIG_UDP_SOCKET_MREQN
     786              :     struct ip_mreqn lMulticastRequest;
     787              :     memset(&lMulticastRequest, 0, sizeof(lMulticastRequest));
     788              :     lMulticastRequest.imr_ifindex   = aInterfaceId.GetPlatformInterface(); /* Network interface index */
     789              :     lMulticastRequest.imr_address   = interfaceAddr;                       /* IP address of local interface */
     790              :     lMulticastRequest.imr_multiaddr = aAddress.ToIPv4();                   /* IP multicast group address*/
     791              : 
     792              : #else
     793              : 
     794              :     struct ip_mreq lMulticastRequest;
     795           22 :     memset(&lMulticastRequest, 0, sizeof(lMulticastRequest));
     796           22 :     lMulticastRequest.imr_interface = interfaceAddr;
     797           22 :     lMulticastRequest.imr_multiaddr = aAddress.ToIPv4();
     798              : 
     799              : #endif
     800              : 
     801           22 :     const int command = join ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP;
     802           22 :     if (setsockopt(mSocket, IPPROTO_IP, command, &lMulticastRequest, sizeof(lMulticastRequest)) != 0)
     803              :     {
     804            0 :         return CHIP_ERROR_POSIX(errno);
     805              :     }
     806           22 :     return CHIP_NO_ERROR;
     807              : }
     808              : 
     809              : #endif // INET_CONFIG_ENABLE_IPV4
     810              : 
     811           22 : CHIP_ERROR UDPEndPointImplSockets::IPv6JoinLeaveMulticastGroupImpl(InterfaceId aInterfaceId, const IPAddress & aAddress, bool join)
     812              : {
     813              : #if CHIP_SYSTEM_CONFIG_USE_PLATFORM_MULTICAST_API
     814              :     if (sMulticastGroupHandler != nullptr)
     815              :     {
     816              :         return sMulticastGroupHandler(aInterfaceId, aAddress, join ? MulticastOperation::kJoin : MulticastOperation::kLeave);
     817              :     }
     818              : #endif // CHIP_SYSTEM_CONFIG_USE_PLATFORM_MULTICAST_API
     819              : 
     820              : #ifdef IPV6_MULTICAST_IMPLEMENTED
     821           22 :     if (!aInterfaceId.IsPresent())
     822              :     {
     823              :         // Do it on all the viable interfaces.
     824            0 :         bool interfaceFound = false;
     825              : 
     826            0 :         InterfaceIterator interfaceIt;
     827            0 :         while (interfaceIt.Next())
     828              :         {
     829            0 :             if (!interfaceIt.SupportsMulticast() || !interfaceIt.IsUp())
     830              :             {
     831            0 :                 continue;
     832              :             }
     833              : 
     834            0 :             InterfaceId interfaceId = interfaceIt.GetInterfaceId();
     835              : 
     836              :             IPAddress ifAddr;
     837            0 :             if (interfaceId.GetLinkLocalAddr(&ifAddr) != CHIP_NO_ERROR)
     838              :             {
     839            0 :                 continue;
     840              :             }
     841              : 
     842            0 :             if (ifAddr.Type() != IPAddressType::kIPv6)
     843              :             {
     844              :                 // Not the right sort of interface.
     845            0 :                 continue;
     846              :             }
     847              : 
     848            0 :             interfaceFound = true;
     849              : 
     850              :             char ifName[InterfaceId::kMaxIfNameLength];
     851            0 :             TEMPORARY_RETURN_IGNORED interfaceIt.GetInterfaceName(ifName, sizeof(ifName));
     852              : 
     853              :             // Ignore errors here, except for logging, because we expect some of
     854              :             // these interfaces to not work, and some (e.g. loopback) to always
     855              :             // work.
     856            0 :             CHIP_ERROR err = IPv6JoinLeaveMulticastGroupImpl(interfaceId, aAddress, join);
     857            0 :             if (err == CHIP_NO_ERROR)
     858              :             {
     859            0 :                 ChipLogDetail(Inet, "  %s multicast group on interface %s", (join ? "Joined" : "Left"), ifName);
     860              :             }
     861              :             else
     862              :             {
     863            0 :                 ChipLogError(Inet, "  Failed to %s multicast group on interface %s", (join ? "join" : "leave"), ifName);
     864              :             }
     865              :         }
     866              : 
     867            0 :         if (interfaceFound)
     868              :         {
     869              :             // Assume we're good.
     870            0 :             return CHIP_NO_ERROR;
     871              :         }
     872              : 
     873              :         // Else go ahead and try to work with the default interface.
     874            0 :         ChipLogError(Inet, "No valid IPv6 multicast interface found");
     875            0 :     }
     876              : 
     877           22 :     const InterfaceId::PlatformType lIfIndex = aInterfaceId.GetPlatformInterface();
     878              : 
     879              :     struct ipv6_mreq lMulticastRequest;
     880           22 :     memset(&lMulticastRequest, 0, sizeof(lMulticastRequest));
     881           22 :     VerifyOrReturnError(CanCastTo<decltype(lMulticastRequest.ipv6mr_interface)>(lIfIndex), CHIP_ERROR_UNEXPECTED_EVENT);
     882              : 
     883           22 :     lMulticastRequest.ipv6mr_interface = static_cast<decltype(lMulticastRequest.ipv6mr_interface)>(lIfIndex);
     884           22 :     lMulticastRequest.ipv6mr_multiaddr = aAddress.ToIPv6();
     885              : 
     886           22 :     const int command = join ? INET_IPV6_ADD_MEMBERSHIP : INET_IPV6_DROP_MEMBERSHIP;
     887           22 :     if (setsockopt(mSocket, IPPROTO_IPV6, command, &lMulticastRequest, sizeof(lMulticastRequest)) != 0)
     888              :     {
     889            0 :         return CHIP_ERROR_POSIX(errno);
     890              :     }
     891           22 :     return CHIP_NO_ERROR;
     892              : #else
     893              :     return CHIP_ERROR_NOT_IMPLEMENTED;
     894              : #endif
     895              : }
     896              : 
     897              : } // namespace Inet
     898              : } // namespace chip
        

Generated by: LCOV version 2.0-1