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

Generated by: LCOV version 2.0-1