LCOV - code coverage report
Current view: top level - inet - UDPEndPointImplSockets.cpp (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 243 320 75.9 %
Date: 2024-02-15 08:20:41 Functions: 15 18 83.3 %

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

Generated by: LCOV version 1.14