Matter SDK Coverage Report
Current view: top level - inet - UDPEndPointImplSockets.cpp (source / functions) Coverage Total Hit
Test: SHA:f84fe08d06f240e801b5d923f8a938a9938ca110 Lines: 76.0 % 321 244
Test Date: 2025-02-22 08:08:07 Functions: 83.3 % 18 15

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

Generated by: LCOV version 2.0-1