From 3583338c65610eaae9667bbdee032debfe18b625 Mon Sep 17 00:00:00 2001 From: Kevin Schoedel <67607049+kpschoedel@users.noreply.github.com> Date: Thu, 28 Oct 2021 13:59:25 -0400 Subject: [PATCH] Collapse IPEndPointBasis into UDPEndPoint (#11135) * Collapse IPEndPointBasis into UDPEndPoint #### Problem For historical reasons, Inet EndPoints have an unnecessarily deep class hierarchy: InetLayerBasis EndPointBasis TCPEndPoint IPEndPointBasis UDPEndPoint #### Change overview This change moves the contents of IPEndPointBasis into UDPEndPoint. InetLayerBasis EndPointBasis TCPEndPoint UDPEndPoint Since comparing moved code in diff format is difficult, this change explicitly does NOT make any changes to moved code; a future change will remove redundancies. Transitionally, methods that would have duplicate names have are prefixed with `Ip` here. This is a step toward #7715 _Virtualize System and Inet interfaces_. #### Testing CI; no changes to functionality. * Restyled by clang-format Co-authored-by: Restyled.io --- src/inet/BUILD.gn | 2 - src/inet/IPEndPointBasis.cpp | 1447 ---------------- src/inet/IPEndPointBasis.h | 229 --- src/inet/InetLayer.h | 2 +- src/inet/UDPEndPoint.cpp | 1460 ++++++++++++++++- src/inet/UDPEndPoint.h | 180 +- src/inet/tests/TestInetLayer.cpp | 4 +- src/inet/tests/TestInetLayerCommon.cpp | 10 +- src/inet/tests/TestInetLayerCommon.hpp | 5 +- src/inet/tests/TestInetLayerMulticast.cpp | 8 +- src/lib/dnssd/minimal_mdns/Server.cpp | 2 +- src/lib/dnssd/minimal_mdns/Server.h | 2 +- .../Zephyr/ThreadStackManagerImpl.cpp | 6 +- src/system/SystemPacketBuffer.h | 2 - src/transport/SessionManager.h | 1 - src/transport/raw/TCP.h | 1 - src/transport/raw/UDP.cpp | 2 +- src/transport/raw/UDP.h | 4 +- 18 files changed, 1611 insertions(+), 1756 deletions(-) delete mode 100644 src/inet/IPEndPointBasis.cpp delete mode 100644 src/inet/IPEndPointBasis.h diff --git a/src/inet/BUILD.gn b/src/inet/BUILD.gn index 3e17783ca8da3d..8bbbea0d69526a 100644 --- a/src/inet/BUILD.gn +++ b/src/inet/BUILD.gn @@ -72,8 +72,6 @@ static_library("inet") { "IPAddress-StringFuncts.cpp", "IPAddress.cpp", "IPAddress.h", - "IPEndPointBasis.cpp", - "IPEndPointBasis.h", "IPPrefix.cpp", "IPPrefix.h", "Inet.h", diff --git a/src/inet/IPEndPointBasis.cpp b/src/inet/IPEndPointBasis.cpp deleted file mode 100644 index 8ea3c07b3acf98..00000000000000 --- a/src/inet/IPEndPointBasis.cpp +++ /dev/null @@ -1,1447 +0,0 @@ -/* - * - * Copyright (c) 2020-2021 Project CHIP Authors - * Copyright (c) 2018 Google LLC. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @file - * This header file implements the Inet::IPEndPointBasis - * class, an intermediate, non-instantiable basis class - * supporting other IP-based end points. - * - */ - -// define to ensure we have the IPV6_PKTINFO -#define __APPLE_USE_RFC_3542 - -#include "IPEndPointBasis.h" - -#include -#include - -#include -#include -#include - -#include -#include - -#if CHIP_SYSTEM_CONFIG_USE_LWIP -#if INET_CONFIG_ENABLE_IPV4 -#include -#endif // INET_CONFIG_ENABLE_IPV4 -#include -#include -#include -#include -#include -#include - -#if !defined(RAW_FLAGS_MULTICAST_LOOP) || !defined(UDP_FLAGS_MULTICAST_LOOP) || !defined(raw_clear_flags) || \ - !defined(raw_set_flags) || !defined(udp_clear_flags) || !defined(udp_set_flags) -#define HAVE_LWIP_MULTICAST_LOOP 0 -#else -#define HAVE_LWIP_MULTICAST_LOOP 1 -#endif // !defined(RAW_FLAGS_MULTICAST_LOOP) || !defined(UDP_FLAGS_MULTICAST_LOOP) || !defined(raw_clear_flags) || - // !defined(raw_set_flags) || !defined(udp_clear_flags) || !defined(udp_set_flags) - -// unusual define check for LWIP_IPV6_ND is because espressif fork -// of LWIP does not define the _ND constant. -#if LWIP_IPV6_MLD && (!defined(LWIP_IPV6_ND) || LWIP_IPV6_ND) && LWIP_IPV6 -#define HAVE_IPV6_MULTICAST -#else -// Within Project CHIP multicast support is highly desirable: used for mDNS -// as well as group communication. -#undef HAVE_IPV6_MULTICAST -#endif -#endif // CHIP_SYSTEM_CONFIG_USE_LWIP - -#if CHIP_SYSTEM_CONFIG_USE_SOCKETS -#include -#include -#include -#include -#include -#include -#if HAVE_SYS_SOCKET_H -#include -#endif // HAVE_SYS_SOCKET_H - -/* - * Some systems define both IPV6_{ADD,DROP}_MEMBERSHIP and - * IPV6_{JOIN,LEAVE}_GROUP while others only define - * IPV6_{JOIN,LEAVE}_GROUP. Prefer the "_MEMBERSHIP" flavor for - * parallelism with IPv4 and create the alias to the availabile - * definitions. - */ -#if defined(IPV6_ADD_MEMBERSHIP) -#define INET_IPV6_ADD_MEMBERSHIP IPV6_ADD_MEMBERSHIP -#elif defined(IPV6_JOIN_GROUP) -#define INET_IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP -#elif !__ZEPHYR__ -#error \ - "Neither IPV6_ADD_MEMBERSHIP nor IPV6_JOIN_GROUP are defined which are required for generalized IPv6 multicast group support." -#endif // IPV6_ADD_MEMBERSHIP - -#if defined(IPV6_DROP_MEMBERSHIP) -#define INET_IPV6_DROP_MEMBERSHIP IPV6_DROP_MEMBERSHIP -#elif defined(IPV6_LEAVE_GROUP) -#define INET_IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP -#elif !__ZEPHYR__ -#error \ - "Neither IPV6_DROP_MEMBERSHIP nor IPV6_LEAVE_GROUP are defined which are required for generalized IPv6 multicast group support." -#endif // IPV6_DROP_MEMBERSHIP - -#if CHIP_SYSTEM_CONFIG_USE_ZEPHYR_SOCKET_EXTENSIONS -#include "ZephyrSocket.h" -#endif // CHIP_SYSTEM_CONFIG_USE_ZEPHYR_SOCKET_EXTENSIONS -#endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS - -#if CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK -#define INET_PORTSTRLEN 6 -#endif // CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK - -namespace chip { -namespace Inet { - -#if CHIP_SYSTEM_CONFIG_USE_LWIP || CHIP_SYSTEM_CONFIG_USE_SOCKETS - -static CHIP_ERROR CheckMulticastGroupArgs(InterfaceId aInterfaceId, const IPAddress & aAddress) -{ - VerifyOrReturnError(aInterfaceId.IsPresent(), INET_ERROR_UNKNOWN_INTERFACE); - VerifyOrReturnError(aAddress.IsMulticast(), INET_ERROR_WRONG_ADDRESS_TYPE); - return CHIP_NO_ERROR; -} -#endif // CHIP_SYSTEM_CONFIG_USE_LWIP || CHIP_SYSTEM_CONFIG_USE_SOCKETS - -#if CHIP_SYSTEM_CONFIG_USE_LWIP - -CHIP_ERROR IPEndPointBasis::SetMulticastLoopback(IPVersion aIPVersion, bool aLoopback) -{ - CHIP_ERROR lRetval = CHIP_ERROR_NOT_IMPLEMENTED; - -#if !HAVE_LWIP_MULTICAST_LOOP - lRetval = CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; -#else - if (aLoopback) - { - switch (mLwIPEndPointType) - { - -#if INET_CONFIG_ENABLE_UDP_ENDPOINT - case LwIPEndPointType::UDP: - udp_set_flags(mUDP, UDP_FLAGS_MULTICAST_LOOP); - break; -#endif // INET_CONFIG_ENABLE_UDP_ENDPOINT - - default: - lRetval = CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; - break; - } - } - else - { - switch (mLwIPEndPointType) - { - -#if INET_CONFIG_ENABLE_UDP_ENDPOINT - case LwIPEndPointType::UDP: - udp_clear_flags(mUDP, UDP_FLAGS_MULTICAST_LOOP); - break; -#endif // INET_CONFIG_ENABLE_UDP_ENDPOINT - - default: - lRetval = CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; - break; - } - } - - lRetval = CHIP_NO_ERROR; -#endif // !HAVE_LWIP_MULTICAST_LOOP - return (lRetval); -} - -void IPEndPointBasis::InitImpl() {} - -#if INET_CONFIG_ENABLE_IPV4 -#if LWIP_IPV4 && LWIP_IGMP -static CHIP_ERROR LwIPIPv4JoinLeaveMulticastGroup(InterfaceId aInterfaceId, const IPAddress & aAddress, - err_t (*aMethod)(struct netif *, const ip4_addr_t *)) -{ - struct netif * const lNetif = IPEndPointBasis::FindNetifFromInterfaceId(aInterfaceId); - VerifyOrReturnError(lNetif != nullptr, INET_ERROR_UNKNOWN_INTERFACE); - - const ip4_addr_t lIPv4Address = aAddress.ToIPv4(); - const err_t lStatus = aMethod(lNetif, &lIPv4Address); - - if (lStatus == ERR_MEM) - { - return CHIP_ERROR_NO_MEMORY; - } - return chip::System::MapErrorLwIP(lStatus); -} -#endif // LWIP_IPV4 && LWIP_IGMP -#endif // INET_CONFIG_ENABLE_IPV4 - -#ifdef HAVE_IPV6_MULTICAST -static CHIP_ERROR LwIPIPv6JoinLeaveMulticastGroup(InterfaceId aInterfaceId, const IPAddress & aAddress, - err_t (*aMethod)(struct netif *, const ip6_addr_t *)) -{ - struct netif * const lNetif = IPEndPointBasis::FindNetifFromInterfaceId(aInterfaceId); - VerifyOrReturnError(lNetif != nullptr, INET_ERROR_UNKNOWN_INTERFACE); - - const ip6_addr_t lIPv6Address = aAddress.ToIPv6(); - const err_t lStatus = aMethod(lNetif, &lIPv6Address); - - if (lStatus == ERR_MEM) - { - return CHIP_ERROR_NO_MEMORY; - } - return chip::System::MapErrorLwIP(lStatus); -} -#endif // LWIP_IPV6_MLD && LWIP_IPV6_ND && LWIP_IPV6 - -#if INET_CONFIG_ENABLE_IPV4 -CHIP_ERROR IPEndPointBasis::IPv4JoinLeaveMulticastGroupImpl(InterfaceId aInterfaceId, const IPAddress & aAddress, bool join) -{ -#if LWIP_IPV4 && LWIP_IGMP - const auto method = join ? igmp_joingroup_netif : igmp_leavegroup_netif; - return LwIPIPv4JoinLeaveMulticastGroup(aInterfaceId, aAddress, method); -#else // LWIP_IPV4 && LWIP_IGMP - return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; -#endif // LWIP_IPV4 && LWIP_IGMP -} -#endif // INET_CONFIG_ENABLE_IPV4 - -CHIP_ERROR IPEndPointBasis::IPv6JoinLeaveMulticastGroupImpl(InterfaceId aInterfaceId, const IPAddress & aAddress, bool join) -{ -#ifdef HAVE_IPV6_MULTICAST - const auto method = join ? mld6_joingroup_netif : mld6_leavegroup_netif; - return LwIPIPv6JoinLeaveMulticastGroup(aInterfaceId, aAddress, method); -#else // HAVE_IPV6_MULTICAST - return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; -#endif // HAVE_IPV6_MULTICAST -} - -struct netif * IPEndPointBasis::FindNetifFromInterfaceId(InterfaceId aInterfaceId) -{ - struct netif * lRetval = NULL; - -#if LWIP_VERSION_MAJOR >= 2 && LWIP_VERSION_MINOR >= 0 && defined(NETIF_FOREACH) - NETIF_FOREACH(lRetval) - { - if (lRetval == aInterfaceId.GetPlatformInterface()) - break; - } -#else // LWIP_VERSION_MAJOR < 2 || !defined(NETIF_FOREACH) - for (lRetval = netif_list; lRetval != NULL && lRetval != aInterfaceId.GetPlatformInterface(); lRetval = lRetval->next) - ; -#endif // LWIP_VERSION_MAJOR >= 2 && LWIP_VERSION_MINOR >= 0 && defined(NETIF_FOREACH) - - return (lRetval); -} - -void IPEndPointBasis::HandleDataReceived(System::PacketBufferHandle && aBuffer) -{ - if ((mState == State::kListening) && (OnMessageReceived != NULL)) - { - const IPPacketInfo * pktInfo = GetPacketInfo(aBuffer); - - if (pktInfo != NULL) - { - const IPPacketInfo pktInfoCopy = *pktInfo; // copy the address info so that the app can free the - // PacketBuffer without affecting access to address info. - OnMessageReceived(this, std::move(aBuffer), &pktInfoCopy); - } - else - { - if (OnReceiveError != NULL) - OnReceiveError(this, CHIP_ERROR_INBOUND_MESSAGE_TOO_BIG, NULL); - } - } -} - -IPPacketInfo * IPEndPointBasis::GetPacketInfo(const System::PacketBufferHandle & aBuffer) -{ - uintptr_t lStart; - uintptr_t lPacketInfoStart; - IPPacketInfo * lPacketInfo = NULL; - - if (!aBuffer->EnsureReservedSize(sizeof(IPPacketInfo) + 3)) - goto done; - - lStart = (uintptr_t) aBuffer->Start(); - lPacketInfoStart = lStart - sizeof(IPPacketInfo); - - // Align to a 4-byte boundary - - lPacketInfo = reinterpret_cast(lPacketInfoStart & ~(sizeof(uint32_t) - 1)); - -done: - return (lPacketInfo); -} - -#endif // CHIP_SYSTEM_CONFIG_USE_LWIP - -#if CHIP_SYSTEM_CONFIG_USE_SOCKETS - -#if CHIP_SYSTEM_CONFIG_USE_PLATFORM_MULTICAST_API -IPEndPointBasis::MulticastGroupHandler IPEndPointBasis::sJoinMulticastGroupHandler; -IPEndPointBasis::MulticastGroupHandler IPEndPointBasis::sLeaveMulticastGroupHandler; -#endif // CHIP_SYSTEM_CONFIG_USE_PLATFORM_MULTICAST_API - -#if IP_MULTICAST_LOOP || IPV6_MULTICAST_LOOP -static CHIP_ERROR SocketsSetMulticastLoopback(int aSocket, bool aLoopback, int aProtocol, int aOption) -{ - const unsigned int lValue = aLoopback; - if (setsockopt(aSocket, aProtocol, aOption, &lValue, sizeof(lValue)) != 0) - { - return CHIP_ERROR_POSIX(errno); - } - - return CHIP_NO_ERROR; -} -#endif // IP_MULTICAST_LOOP || IPV6_MULTICAST_LOOP - -static CHIP_ERROR SocketsSetMulticastLoopback(int aSocket, IPVersion aIPVersion, bool aLoopback) -{ -#ifdef IPV6_MULTICAST_LOOP - CHIP_ERROR lRetval; - - switch (aIPVersion) - { - - case kIPVersion_6: - lRetval = SocketsSetMulticastLoopback(aSocket, aLoopback, IPPROTO_IPV6, IPV6_MULTICAST_LOOP); - break; - -#if INET_CONFIG_ENABLE_IPV4 - case kIPVersion_4: - lRetval = SocketsSetMulticastLoopback(aSocket, aLoopback, IPPROTO_IP, IP_MULTICAST_LOOP); - break; -#endif // INET_CONFIG_ENABLE_IPV4 - - default: - lRetval = INET_ERROR_WRONG_ADDRESS_TYPE; - break; - } - - return (lRetval); -#else // IPV6_MULTICAST_LOOP - return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; -#endif // IPV6_MULTICAST_LOOP -} - -CHIP_ERROR IPEndPointBasis::SetMulticastLoopback(IPVersion aIPVersion, bool aLoopback) -{ - CHIP_ERROR lRetval = CHIP_ERROR_NOT_IMPLEMENTED; - - lRetval = SocketsSetMulticastLoopback(mSocket, aIPVersion, aLoopback); - SuccessOrExit(lRetval); - -exit: - return (lRetval); -} - -void IPEndPointBasis::InitImpl() -{ - mBoundIntfId = InterfaceId::Null(); -} - -#if INET_CONFIG_ENABLE_IPV4 - -static CHIP_ERROR SocketsIPv4JoinLeaveMulticastGroup(int aSocket, InterfaceId aInterfaceId, const IPAddress & aAddress, - int aCommand) -{ - IPAddress lInterfaceAddress; - bool lInterfaceAddressFound = false; - - for (InterfaceAddressIterator lAddressIterator; lAddressIterator.HasCurrent(); lAddressIterator.Next()) - { - const IPAddress lCurrentAddress = lAddressIterator.GetAddress(); - - if (lAddressIterator.GetInterfaceId() == aInterfaceId) - { - if (lCurrentAddress.IsIPv4()) - { - lInterfaceAddressFound = true; - lInterfaceAddress = lCurrentAddress; - break; - } - } - } - - VerifyOrReturnError(lInterfaceAddressFound, INET_ERROR_ADDRESS_NOT_FOUND); - - struct ip_mreq lMulticastRequest; - memset(&lMulticastRequest, 0, sizeof(lMulticastRequest)); - lMulticastRequest.imr_interface = lInterfaceAddress.ToIPv4(); - lMulticastRequest.imr_multiaddr = aAddress.ToIPv4(); - - if (setsockopt(aSocket, IPPROTO_IP, aCommand, &lMulticastRequest, sizeof(lMulticastRequest)) != 0) - { - return CHIP_ERROR_POSIX(errno); - } - return CHIP_NO_ERROR; -} - -CHIP_ERROR IPEndPointBasis::IPv4JoinLeaveMulticastGroupImpl(InterfaceId aInterfaceId, const IPAddress & aAddress, bool join) -{ - return SocketsIPv4JoinLeaveMulticastGroup(mSocket, aInterfaceId, aAddress, join ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP); -} - -#endif // INET_CONFIG_ENABLE_IPV4 - -#if INET_IPV6_ADD_MEMBERSHIP || INET_IPV6_DROP_MEMBERSHIP -static CHIP_ERROR SocketsIPv6JoinLeaveMulticastGroup(int aSocket, InterfaceId aInterfaceId, const IPAddress & aAddress, - int aCommand) -{ - const InterfaceId::PlatformType lIfIndex = aInterfaceId.GetPlatformInterface(); - - struct ipv6_mreq lMulticastRequest; - memset(&lMulticastRequest, 0, sizeof(lMulticastRequest)); - VerifyOrReturnError(CanCastTo(lIfIndex), CHIP_ERROR_UNEXPECTED_EVENT); - - lMulticastRequest.ipv6mr_interface = static_cast(lIfIndex); - lMulticastRequest.ipv6mr_multiaddr = aAddress.ToIPv6(); - - if (setsockopt(aSocket, IPPROTO_IPV6, aCommand, &lMulticastRequest, sizeof(lMulticastRequest)) != 0) - { - return CHIP_ERROR_POSIX(errno); - } - return CHIP_NO_ERROR; -} -#endif // INET_IPV6_ADD_MEMBERSHIP || INET_IPV6_DROP_MEMBERSHIP - -CHIP_ERROR IPEndPointBasis::IPv6JoinLeaveMulticastGroupImpl(InterfaceId aInterfaceId, const IPAddress & aAddress, bool join) -{ -#if CHIP_SYSTEM_CONFIG_USE_PLATFORM_MULTICAST_API - MulticastGroupHandler handler = join ? sJoinMulticastGroupHandler : sLeaveMulticastGroupHandler; - if (handler != nullptr) - { - return handler(aInterfaceId, aAddress); - } -#endif // CHIP_SYSTEM_CONFIG_USE_PLATFORM_MULTICAST_API -#if defined(INET_IPV6_ADD_MEMBERSHIP) && defined(INET_IPV6_DROP_MEMBERSHIP) - return SocketsIPv6JoinLeaveMulticastGroup(mSocket, aInterfaceId, aAddress, - join ? INET_IPV6_ADD_MEMBERSHIP : INET_IPV6_DROP_MEMBERSHIP); -#else // defined(INET_IPV6_ADD_MEMBERSHIP) && defined(INET_IPV6_DROP_MEMBERSHIP) - return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; -#endif // defined(INET_IPV6_ADD_MEMBERSHIP) && defined(INET_IPV6_DROP_MEMBERSHIP) -} - -CHIP_ERROR IPEndPointBasis::Bind(IPAddressType aAddressType, const IPAddress & aAddress, uint16_t aPort, InterfaceId aInterfaceId) -{ - CHIP_ERROR lRetval = CHIP_NO_ERROR; - - if (aAddressType == IPAddressType::kIPv6) - { - struct sockaddr_in6 sa; - - memset(&sa, 0, sizeof(sa)); - - sa.sin6_family = AF_INET6; - sa.sin6_port = htons(aPort); - sa.sin6_addr = aAddress.ToIPv6(); - InterfaceId::PlatformType interfaceId = aInterfaceId.GetPlatformInterface(); - if (!CanCastTo(interfaceId)) - { - return CHIP_ERROR_INCORRECT_STATE; - } - sa.sin6_scope_id = static_cast(interfaceId); - - if (bind(mSocket, reinterpret_cast(&sa), static_cast(sizeof(sa))) != 0) - lRetval = CHIP_ERROR_POSIX(errno); - - // Instruct the kernel that any messages to multicast destinations should be - // sent down the interface specified by the caller. -#ifdef IPV6_MULTICAST_IF - if (lRetval == CHIP_NO_ERROR) - setsockopt(mSocket, IPPROTO_IPV6, IPV6_MULTICAST_IF, &aInterfaceId, sizeof(aInterfaceId)); -#endif // defined(IPV6_MULTICAST_IF) - - // Instruct the kernel that any messages to multicast destinations should be - // set with the configured hop limit value. -#ifdef IPV6_MULTICAST_HOPS - int hops = INET_CONFIG_IP_MULTICAST_HOP_LIMIT; - setsockopt(mSocket, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hops, sizeof(hops)); -#endif // defined(IPV6_MULTICAST_HOPS) - } -#if INET_CONFIG_ENABLE_IPV4 - else if (aAddressType == IPAddressType::kIPv4) - { - struct sockaddr_in sa; - int enable = 1; - - memset(&sa, 0, sizeof(sa)); - - sa.sin_family = AF_INET; - sa.sin_port = htons(aPort); - sa.sin_addr = aAddress.ToIPv4(); - - if (bind(mSocket, reinterpret_cast(&sa), static_cast(sizeof(sa))) != 0) - lRetval = CHIP_ERROR_POSIX(errno); - - // Instruct the kernel that any messages to multicast destinations should be - // sent down the interface to which the specified IPv4 address is bound. -#ifdef IP_MULTICAST_IF - if (lRetval == CHIP_NO_ERROR) - setsockopt(mSocket, IPPROTO_IP, IP_MULTICAST_IF, &sa, sizeof(sa)); -#endif // defined(IP_MULTICAST_IF) - - // Instruct the kernel that any messages to multicast destinations should be - // set with the configured hop limit value. -#ifdef IP_MULTICAST_TTL - int ttl = INET_CONFIG_IP_MULTICAST_HOP_LIMIT; - setsockopt(mSocket, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)); -#endif // defined(IP_MULTICAST_TTL) - - // Allow socket transmitting broadcast packets. - if (lRetval == CHIP_NO_ERROR) - setsockopt(mSocket, SOL_SOCKET, SO_BROADCAST, &enable, sizeof(enable)); - } -#endif // INET_CONFIG_ENABLE_IPV4 - else - lRetval = INET_ERROR_WRONG_ADDRESS_TYPE; - - return (lRetval); -} - -CHIP_ERROR IPEndPointBasis::BindInterface(IPAddressType aAddressType, InterfaceId aInterfaceId) -{ - CHIP_ERROR lRetval = CHIP_NO_ERROR; - -#if HAVE_SO_BINDTODEVICE - if (!aInterfaceId.IsPresent()) - { - // Stop interface-based filtering. - if (setsockopt(mSocket, SOL_SOCKET, SO_BINDTODEVICE, "", 0) == -1) - { - lRetval = CHIP_ERROR_POSIX(errno); - } - } - else - { - // Start filtering on the passed interface. - char lInterfaceName[IF_NAMESIZE]; - - if (if_indextoname(aInterfaceId.GetPlatformInterface(), lInterfaceName) == NULL) - { - lRetval = CHIP_ERROR_POSIX(errno); - } - - if (lRetval == CHIP_NO_ERROR && - setsockopt(mSocket, SOL_SOCKET, SO_BINDTODEVICE, lInterfaceName, socklen_t(strlen(lInterfaceName))) == -1) - { - lRetval = CHIP_ERROR_POSIX(errno); - } - } - - if (lRetval == CHIP_NO_ERROR) - mBoundIntfId = aInterfaceId; - -#else // !HAVE_SO_BINDTODEVICE - lRetval = CHIP_ERROR_NOT_IMPLEMENTED; -#endif // HAVE_SO_BINDTODEVICE - - return (lRetval); -} - -CHIP_ERROR IPEndPointBasis::SendMsg(const IPPacketInfo * aPktInfo, chip::System::PacketBufferHandle && aBuffer) -{ - // Ensure the destination address type is compatible with the endpoint address type. - VerifyOrReturnError(mAddrType == aPktInfo->DestAddress.Type(), CHIP_ERROR_INVALID_ARGUMENT); - - // For now the entire message must fit within a single buffer. - VerifyOrReturnError(!aBuffer->HasChainedBuffer(), CHIP_ERROR_MESSAGE_TOO_LONG); - - struct iovec msgIOV; - msgIOV.iov_base = aBuffer->Start(); - msgIOV.iov_len = aBuffer->DataLength(); - -#if defined(IP_PKTINFO) || defined(IPV6_PKTINFO) - uint8_t controlData[256]; - memset(controlData, 0, sizeof(controlData)); -#endif // defined(IP_PKTINFO) || defined(IPV6_PKTINFO) - - struct msghdr msgHeader; - memset(&msgHeader, 0, sizeof(msgHeader)); - msgHeader.msg_iov = &msgIOV; - msgHeader.msg_iovlen = 1; - - // Construct a sockaddr_in/sockaddr_in6 structure containing the destination information. - SockAddr peerSockAddr; - memset(&peerSockAddr, 0, sizeof(peerSockAddr)); - msgHeader.msg_name = &peerSockAddr; - if (mAddrType == IPAddressType::kIPv6) - { - peerSockAddr.in6.sin6_family = AF_INET6; - peerSockAddr.in6.sin6_port = htons(aPktInfo->DestPort); - peerSockAddr.in6.sin6_addr = aPktInfo->DestAddress.ToIPv6(); - InterfaceId::PlatformType intfId = aPktInfo->Interface.GetPlatformInterface(); - VerifyOrReturnError(CanCastTo(intfId), CHIP_ERROR_INCORRECT_STATE); - peerSockAddr.in6.sin6_scope_id = static_cast(intfId); - msgHeader.msg_namelen = sizeof(sockaddr_in6); - } -#if INET_CONFIG_ENABLE_IPV4 - else - { - peerSockAddr.in.sin_family = AF_INET; - peerSockAddr.in.sin_port = htons(aPktInfo->DestPort); - peerSockAddr.in.sin_addr = aPktInfo->DestAddress.ToIPv4(); - msgHeader.msg_namelen = sizeof(sockaddr_in); - } -#endif // INET_CONFIG_ENABLE_IPV4 - - // If the endpoint has been bound to a particular interface, - // and the caller didn't supply a specific interface to send - // on, use the bound interface. This appears to be necessary - // for messages to multicast addresses, which under Linux - // don't seem to get sent out the correct interface, despite - // the socket being bound. - InterfaceId intf = aPktInfo->Interface; - if (!intf.IsPresent()) - intf = mBoundIntfId; - - // If the packet should be sent over a specific interface, or with a specific source - // address, construct an IP_PKTINFO/IPV6_PKTINFO "control message" to that effect - // add add it to the message header. If the local OS doesn't support IP_PKTINFO/IPV6_PKTINFO - // fail with an error. - if (intf.IsPresent() || aPktInfo->SrcAddress.Type() != IPAddressType::kAny) - { -#if defined(IP_PKTINFO) || defined(IPV6_PKTINFO) - msgHeader.msg_control = controlData; - msgHeader.msg_controllen = sizeof(controlData); - - struct cmsghdr * controlHdr = CMSG_FIRSTHDR(&msgHeader); - InterfaceId::PlatformType intfId = intf.GetPlatformInterface(); - -#if INET_CONFIG_ENABLE_IPV4 - - if (mAddrType == IPAddressType::kIPv4) - { -#if defined(IP_PKTINFO) - controlHdr->cmsg_level = IPPROTO_IP; - controlHdr->cmsg_type = IP_PKTINFO; - controlHdr->cmsg_len = CMSG_LEN(sizeof(in_pktinfo)); - - struct in_pktinfo * pktInfo = reinterpret_cast CMSG_DATA(controlHdr); - if (!CanCastToipi_ifindex)>(intfId)) - { - return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; - } - - pktInfo->ipi_ifindex = static_castipi_ifindex)>(intfId); - pktInfo->ipi_spec_dst = aPktInfo->SrcAddress.ToIPv4(); - - msgHeader.msg_controllen = CMSG_SPACE(sizeof(in_pktinfo)); -#else // !defined(IP_PKTINFO) - return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; -#endif // !defined(IP_PKTINFO) - } - -#endif // INET_CONFIG_ENABLE_IPV4 - - if (mAddrType == IPAddressType::kIPv6) - { -#if defined(IPV6_PKTINFO) - controlHdr->cmsg_level = IPPROTO_IPV6; - controlHdr->cmsg_type = IPV6_PKTINFO; - controlHdr->cmsg_len = CMSG_LEN(sizeof(in6_pktinfo)); - - struct in6_pktinfo * pktInfo = reinterpret_cast CMSG_DATA(controlHdr); - if (!CanCastToipi6_ifindex)>(intfId)) - { - return CHIP_ERROR_UNEXPECTED_EVENT; - } - pktInfo->ipi6_ifindex = static_castipi6_ifindex)>(intfId); - pktInfo->ipi6_addr = aPktInfo->SrcAddress.ToIPv6(); - - msgHeader.msg_controllen = CMSG_SPACE(sizeof(in6_pktinfo)); -#else // !defined(IPV6_PKTINFO) - return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; -#endif // !defined(IPV6_PKTINFO) - } - -#else // !(defined(IP_PKTINFO) && defined(IPV6_PKTINFO)) - return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; -#endif // !(defined(IP_PKTINFO) && defined(IPV6_PKTINFO)) - } - - // Send IP packet. - const ssize_t lenSent = sendmsg(mSocket, &msgHeader, 0); - if (lenSent == -1) - return CHIP_ERROR_POSIX(errno); - if (lenSent != aBuffer->DataLength()) - return CHIP_ERROR_OUTBOUND_MESSAGE_TOO_BIG; - return CHIP_NO_ERROR; -} - -CHIP_ERROR IPEndPointBasis::GetSocket(IPAddressType aAddressType, int aType, int aProtocol) -{ - if (mSocket == kInvalidSocketFd) - { - const int one = 1; - int family; - - switch (aAddressType) - { - case IPAddressType::kIPv6: - family = PF_INET6; - break; - -#if INET_CONFIG_ENABLE_IPV4 - case IPAddressType::kIPv4: - family = PF_INET; - break; -#endif // INET_CONFIG_ENABLE_IPV4 - - default: - return INET_ERROR_WRONG_ADDRESS_TYPE; - } - - mSocket = ::socket(family, aType, aProtocol); - if (mSocket == -1) - return CHIP_ERROR_POSIX(errno); - ReturnErrorOnFailure(static_cast(Layer().SystemLayer())->StartWatchingSocket(mSocket, &mWatch)); - - mAddrType = aAddressType; - - // NOTE WELL: the errors returned by setsockopt() here are not - // returned as Inet layer CHIP_ERROR_POSIX(errno) - // codes because they are normally expected to fail on some - // platforms where the socket option code is defined in the - // header files but not [yet] implemented. Certainly, there is - // room to improve this by connecting the build configuration - // logic up to check for implementations of these options and - // to provide appropriate HAVE_xxxxx definitions accordingly. - - int res = setsockopt(mSocket, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); - static_cast(res); - -#ifdef SO_REUSEPORT - res = setsockopt(mSocket, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)); - if (res != 0) - { - ChipLogError(Inet, "SO_REUSEPORT failed: %d", errno); - } -#endif // defined(SO_REUSEPORT) - - // If creating an IPv6 socket, tell the kernel that it will be - // IPv6 only. This makes it posible to bind two sockets to - // the same port, one for IPv4 and one for IPv6. - -#ifdef IPV6_V6ONLY - if (aAddressType == IPAddressType::kIPv6) - { - res = setsockopt(mSocket, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)); - if (res != 0) - { - ChipLogError(Inet, "IPV6_V6ONLY failed: %d", errno); - } - } -#endif // defined(IPV6_V6ONLY) - -#if INET_CONFIG_ENABLE_IPV4 -#ifdef IP_PKTINFO - if (aAddressType == IPAddressType::kIPv4) - { - res = setsockopt(mSocket, IPPROTO_IP, IP_PKTINFO, &one, sizeof(one)); - if (res != 0) - { - ChipLogError(Inet, "IP_PKTINFO failed: %d", errno); - } - } -#endif // defined(IP_PKTINFO) -#endif // INET_CONFIG_ENABLE_IPV4 - -#ifdef IPV6_RECVPKTINFO - if (aAddressType == IPAddressType::kIPv6) - { - res = setsockopt(mSocket, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one)); - if (res != 0) - { - ChipLogError(Inet, "IPV6_PKTINFO failed: %d", errno); - } - } -#endif // defined(IPV6_RECVPKTINFO) - - // On systems that support it, disable the delivery of SIGPIPE - // signals when writing to a closed socket. This is mostly - // needed on iOS which has the peculiar habit of sending - // SIGPIPEs on unconnected UDP sockets. -#ifdef SO_NOSIGPIPE - { - res = setsockopt(mSocket, SOL_SOCKET, SO_NOSIGPIPE, &one, sizeof(one)); - if (res != 0) - { - ChipLogError(Inet, "SO_NOSIGPIPE failed: %d", errno); - } - } -#endif // defined(SO_NOSIGPIPE) - } - else if (mAddrType != aAddressType) - { - return CHIP_ERROR_INCORRECT_STATE; - } - - return CHIP_NO_ERROR; -} - -void IPEndPointBasis::HandlePendingIO(uint16_t aPort) -{ - CHIP_ERROR lStatus = CHIP_NO_ERROR; - IPPacketInfo lPacketInfo; - System::PacketBufferHandle lBuffer; - - lPacketInfo.Clear(); - lPacketInfo.DestPort = aPort; - - lBuffer = System::PacketBufferHandle::New(System::PacketBuffer::kMaxSizeWithoutReserve, 0); - - if (!lBuffer.IsNull()) - { - struct iovec msgIOV; - SockAddr lPeerSockAddr; - uint8_t controlData[256]; - struct msghdr msgHeader; - - msgIOV.iov_base = lBuffer->Start(); - msgIOV.iov_len = lBuffer->AvailableDataLength(); - - memset(&lPeerSockAddr, 0, sizeof(lPeerSockAddr)); - - memset(&msgHeader, 0, sizeof(msgHeader)); - - msgHeader.msg_name = &lPeerSockAddr; - msgHeader.msg_namelen = sizeof(lPeerSockAddr); - msgHeader.msg_iov = &msgIOV; - msgHeader.msg_iovlen = 1; - msgHeader.msg_control = controlData; - msgHeader.msg_controllen = sizeof(controlData); - - ssize_t rcvLen = recvmsg(mSocket, &msgHeader, MSG_DONTWAIT); - - if (rcvLen < 0) - { - lStatus = CHIP_ERROR_POSIX(errno); - } - else if (rcvLen > lBuffer->AvailableDataLength()) - { - lStatus = CHIP_ERROR_INBOUND_MESSAGE_TOO_BIG; - } - else - { - lBuffer->SetDataLength(static_cast(rcvLen)); - - if (lPeerSockAddr.any.sa_family == AF_INET6) - { - lPacketInfo.SrcAddress = IPAddress(lPeerSockAddr.in6.sin6_addr); - lPacketInfo.SrcPort = ntohs(lPeerSockAddr.in6.sin6_port); - } -#if INET_CONFIG_ENABLE_IPV4 - else if (lPeerSockAddr.any.sa_family == AF_INET) - { - lPacketInfo.SrcAddress = IPAddress(lPeerSockAddr.in.sin_addr); - lPacketInfo.SrcPort = ntohs(lPeerSockAddr.in.sin_port); - } -#endif // INET_CONFIG_ENABLE_IPV4 - else - { - lStatus = CHIP_ERROR_INCORRECT_STATE; - } - } - - if (lStatus == CHIP_NO_ERROR) - { - for (struct cmsghdr * controlHdr = CMSG_FIRSTHDR(&msgHeader); controlHdr != nullptr; - controlHdr = CMSG_NXTHDR(&msgHeader, controlHdr)) - { -#if INET_CONFIG_ENABLE_IPV4 -#ifdef IP_PKTINFO - if (controlHdr->cmsg_level == IPPROTO_IP && controlHdr->cmsg_type == IP_PKTINFO) - { - struct in_pktinfo * inPktInfo = reinterpret_cast CMSG_DATA(controlHdr); - if (!CanCastTo(inPktInfo->ipi_ifindex)) - { - lStatus = CHIP_ERROR_INCORRECT_STATE; - break; - } - lPacketInfo.Interface = InterfaceId(static_cast(inPktInfo->ipi_ifindex)); - lPacketInfo.DestAddress = IPAddress(inPktInfo->ipi_addr); - continue; - } -#endif // defined(IP_PKTINFO) -#endif // INET_CONFIG_ENABLE_IPV4 - -#ifdef IPV6_PKTINFO - if (controlHdr->cmsg_level == IPPROTO_IPV6 && controlHdr->cmsg_type == IPV6_PKTINFO) - { - struct in6_pktinfo * in6PktInfo = reinterpret_cast CMSG_DATA(controlHdr); - if (!CanCastTo(in6PktInfo->ipi6_ifindex)) - { - lStatus = CHIP_ERROR_INCORRECT_STATE; - break; - } - lPacketInfo.Interface = InterfaceId(static_cast(in6PktInfo->ipi6_ifindex)); - lPacketInfo.DestAddress = IPAddress(in6PktInfo->ipi6_addr); - continue; - } -#endif // defined(IPV6_PKTINFO) - } - } - } - else - { - lStatus = CHIP_ERROR_NO_MEMORY; - } - - if (lStatus == CHIP_NO_ERROR) - { - lBuffer.RightSize(); - OnMessageReceived(this, std::move(lBuffer), &lPacketInfo); - } - else - { - if (OnReceiveError != nullptr && lStatus != CHIP_ERROR_POSIX(EAGAIN)) - { - OnReceiveError(this, lStatus, nullptr); - } - } -} - -#endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS - -#if CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK - -CHIP_ERROR IPEndPointBasis::SetMulticastLoopback(IPVersion aIPVersion, bool aLoopback) -{ - CHIP_ERROR lRetval = CHIP_ERROR_NOT_IMPLEMENTED; - return (lRetval); -} - -void IPEndPointBasis::InitImpl() {} - -#if INET_CONFIG_ENABLE_IPV4 -CHIP_ERROR IPEndPointBasis::IPv4JoinLeaveMulticastGroupImpl(InterfaceId aInterfaceId, const IPAddress & aAddress, bool join) -{ - return CHIP_ERROR_NOT_IMPLEMENTED; -} -#endif // INET_CONFIG_ENABLE_IPV4 - -CHIP_ERROR IPEndPointBasis::IPv6JoinLeaveMulticastGroupImpl(InterfaceId aInterfaceId, const IPAddress & aAddress, bool join) -{ - return CHIP_ERROR_NOT_IMPLEMENTED; -} - -CHIP_ERROR IPEndPointBasis::Bind(IPAddressType aAddressType, const IPAddress & aAddress, uint16_t aPort, - const nw_parameters_t & aParameters) -{ - nw_endpoint_t endpoint = nullptr; - - VerifyOrReturnError(aParameters != NULL, CHIP_ERROR_INVALID_ARGUMENT); - - ReturnErrorOnFailure(ConfigureProtocol(aAddressType, aParameters)); - - CHIP_ERROR res = GetEndPoint(endpoint, aAddressType, aAddress, aPort); - nw_parameters_set_local_endpoint(aParameters, endpoint); - nw_release(endpoint); - ReturnErrorOnFailure(res); - - mDispatchQueue = dispatch_queue_create("inet_dispatch_global", DISPATCH_QUEUE_CONCURRENT); - VerifyOrReturnError(mDispatchQueue != NULL, CHIP_ERROR_NO_MEMORY); - dispatch_retain(mDispatchQueue); - - mConnectionSemaphore = dispatch_semaphore_create(0); - VerifyOrReturnError(mConnectionSemaphore != NULL, CHIP_ERROR_NO_MEMORY); - dispatch_retain(mConnectionSemaphore); - - mSendSemaphore = dispatch_semaphore_create(0); - VerifyOrReturnError(mSendSemaphore != NULL, CHIP_ERROR_NO_MEMORY); - dispatch_retain(mSendSemaphore); - - mAddrType = aAddressType; - mConnection = NULL; - - return CHIP_NO_ERROR; -} - -CHIP_ERROR IPEndPointBasis::SendMsg(const IPPacketInfo * aPktInfo, chip::System::PacketBufferHandle && aBuffer) -{ - dispatch_data_t content; - - // Ensure the destination address type is compatible with the endpoint address type. - VerifyOrReturnError(mAddrType == aPktInfo->DestAddress.Type(), CHIP_ERROR_INVALID_ARGUMENT); - - // For now the entire message must fit within a single buffer. - VerifyOrReturnError(aBuffer->Next() == NULL, CHIP_ERROR_MESSAGE_TOO_LONG); - - ReturnErrorOnFailure(GetConnection(aPktInfo)); - - // Send a message, and wait for it to be dispatched. - content = dispatch_data_create(aBuffer->Start(), aBuffer->DataLength(), mDispatchQueue, DISPATCH_DATA_DESTRUCTOR_DEFAULT); - - // If there is a current message pending and the state of the network connection change (e.g switch to a - // different network) the connection will enter a nw_connection_state_failed state and the completion handler - // will never be called. In such cases a signal is sent from the connection state change handler to release - // the semaphore. In this case the CHIP_ERROR will not update with the result of the completion handler. - // To make sure caller knows that sending a message has failed the following code consider there is an error - // _unless_ the completion handler says otherwise. - __block CHIP_ERROR res = CHIP_ERROR_UNEXPECTED_EVENT; - nw_connection_send(mConnection, content, NW_CONNECTION_DEFAULT_MESSAGE_CONTEXT, true, ^(nw_error_t error) { - if (error) - { - res = CHIP_ERROR_POSIX(nw_error_get_error_code(error)); - } - else - { - res = CHIP_NO_ERROR; - } - dispatch_semaphore_signal(mSendSemaphore); - }); - dispatch_release(content); - - dispatch_semaphore_wait(mSendSemaphore, DISPATCH_TIME_FOREVER); - - return res; -} - -CHIP_ERROR IPEndPointBasis::ConfigureProtocol(IPAddressType aAddressType, const nw_parameters_t & aParameters) -{ - CHIP_ERROR res = CHIP_NO_ERROR; - - nw_protocol_stack_t protocolStack = nw_parameters_copy_default_protocol_stack(aParameters); - nw_protocol_options_t ipOptions = nw_protocol_stack_copy_internet_protocol(protocolStack); - - switch (aAddressType) - { - - case IPAddressType::kIPv6: - nw_ip_options_set_version(ipOptions, nw_ip_version_6); - break; - -#if INET_CONFIG_ENABLE_IPV4 - case IPAddressType::kIPv4: - nw_ip_options_set_version(ipOptions, nw_ip_version_4); - break; -#endif // INET_CONFIG_ENABLE_IPV4 - - default: - res = INET_ERROR_WRONG_ADDRESS_TYPE; - break; - } - nw_release(ipOptions); - nw_release(protocolStack); - - return res; -} - -void IPEndPointBasis::HandleDataReceived(const nw_connection_t & aConnection) -{ - - nw_connection_receive_completion_t handler = - ^(dispatch_data_t content, nw_content_context_t context, bool is_complete, nw_error_t receive_error) { - dispatch_block_t schedule_next_receive = ^{ - if (receive_error == NULL) - { - HandleDataReceived(aConnection); - } - else if (OnReceiveError != NULL) - { - nw_error_domain_t error_domain = nw_error_get_error_domain(receive_error); - errno = nw_error_get_error_code(receive_error); - if (!(error_domain == nw_error_domain_posix && errno == ECANCELED)) - { - CHIP_ERROR error = CHIP_ERROR_POSIX(errno); - IPPacketInfo packetInfo; - GetPacketInfo(aConnection, packetInfo); - dispatch_async(mDispatchQueue, ^{ - OnReceiveError((IPEndPointBasis *) this, error, &packetInfo); - }); - } - } - }; - - if (content != NULL && OnMessageReceived != NULL) - { - size_t count = dispatch_data_get_size(content); - System::PacketBufferHandle * packetBuffer = System::PacketBufferHandle::New(count); - dispatch_data_apply(content, ^(dispatch_data_t data, size_t offset, const void * buffer, size_t size) { - memmove(packetBuffer->Start() + offset, buffer, size); - return true; - }); - packetBuffer->SetDataLength(count); - - IPPacketInfo packetInfo; - GetPacketInfo(aConnection, packetInfo); - dispatch_async(mDispatchQueue, ^{ - OnMessageReceived((IPEndPointBasis *) this, packetBuffer, &packetInfo); - }); - } - - schedule_next_receive(); - }; - - nw_connection_receive_message(aConnection, handler); -} - -void IPEndPointBasis::GetPacketInfo(const nw_connection_t & aConnection, IPPacketInfo & aPacketInfo) -{ - nw_path_t path = nw_connection_copy_current_path(aConnection); - nw_endpoint_t dest_endpoint = nw_path_copy_effective_local_endpoint(path); - nw_endpoint_t src_endpoint = nw_path_copy_effective_remote_endpoint(path); - - aPacketInfo.Clear(); - aPacketInfo.SrcAddress = IPAddress::FromSockAddr(*nw_endpoint_get_address(src_endpoint)); - aPacketInfo.DestAddress = IPAddress::FromSockAddr(*nw_endpoint_get_address(dest_endpoint)); - aPacketInfo.SrcPort = nw_endpoint_get_port(src_endpoint); - aPacketInfo.DestPort = nw_endpoint_get_port(dest_endpoint); -} - -CHIP_ERROR IPEndPointBasis::GetEndPoint(nw_endpoint_t & aEndPoint, const IPAddressType aAddressType, const IPAddress & aAddress, - uint16_t aPort) -{ - char addrStr[INET6_ADDRSTRLEN]; - char portStr[INET_PORTSTRLEN]; - - // Note: aAddress.ToString will return the IPv6 Any address if the address type is Any, but that's not what - // we want if the locale endpoint is IPv4. - if (aAddressType == IPAddressType::kIPv4 && aAddress.Type() == IPAddressType::kAny) - { - const IPAddress anyAddr = IPAddress(aAddress.ToIPv4()); - anyAddr.ToString(addrStr, sizeof(addrStr)); - } - else - { - aAddress.ToString(addrStr, sizeof(addrStr)); - } - - snprintf(portStr, sizeof(portStr), "%u", aPort); - - aEndPoint = nw_endpoint_create_host(addrStr, portStr); - VerifyOrReturnError(aEndPoint != NULL, CHIP_ERROR_INVALID_ARGUMENT); - - return CHIP_NO_ERROR; -} - -CHIP_ERROR IPEndPointBasis::GetConnection(const IPPacketInfo * aPktInfo) -{ - VerifyOrReturnError(mParameters != NULL, CHIP_ERROR_INCORRECT_STATE); - - nw_endpoint_t endpoint = NULL; - nw_connection_t connection = NULL; - - if (mConnection) - { - nw_path_t path = nw_connection_copy_current_path(mConnection); - nw_endpoint_t remote_endpoint = nw_path_copy_effective_remote_endpoint(path); - const IPAddress remote_address = IPAddress::FromSockAddr(*nw_endpoint_get_address(remote_endpoint)); - const uint16_t remote_port = nw_endpoint_get_port(remote_endpoint); - const bool isDifferentEndPoint = aPktInfo->DestPort != remote_port || aPktInfo->DestAddress != remote_address; - VerifyOrReturnError(isDifferentEndPoint, CHIP_NO_ERROR); - - ReturnErrorOnFailure(ReleaseConnection()); - } - - ReturnErrorOnFailure(GetEndPoint(endpoint, mAddrType, aPktInfo->DestAddress, aPktInfo->DestPort)); - - connection = nw_connection_create(endpoint, mParameters); - nw_release(endpoint); - - VerifyOrReturnError(connection != NULL, CHIP_ERROR_INCORRECT_STATE); - - return StartConnection(connection); -} - -CHIP_ERROR IPEndPointBasis::StartListener() -{ - __block CHIP_ERROR res = CHIP_NO_ERROR; - nw_listener_t listener; - - VerifyOrReturnError(mListener == NULL, CHIP_ERROR_INCORRECT_STATE); - VerifyOrReturnError(mListenerSemaphore == NULL, CHIP_ERROR_INCORRECT_STATE); - VerifyOrReturnError(mListenerQueue == NULL, CHIP_ERROR_INCORRECT_STATE); - - listener = nw_listener_create(mParameters); - VerifyOrReturnError(listener != NULL, CHIP_ERROR_INCORRECT_STATE); - - mListenerSemaphore = dispatch_semaphore_create(0); - VerifyOrReturnError(mListenerSemaphore != NULL, CHIP_ERROR_NO_MEMORY); - dispatch_retain(mListenerSemaphore); - - mListenerQueue = dispatch_queue_create("inet_dispatch_listener", DISPATCH_QUEUE_CONCURRENT); - VerifyOrReturnError(mListenerQueue != NULL, CHIP_ERROR_NO_MEMORY); - dispatch_retain(mListenerQueue); - - nw_listener_set_queue(listener, mListenerQueue); - - nw_listener_set_new_connection_handler(listener, ^(nw_connection_t connection) { - ReleaseConnection(); - StartConnection(connection); - }); - - nw_listener_set_state_changed_handler(listener, ^(nw_listener_state_t state, nw_error_t error) { - switch (state) - { - - case nw_listener_state_invalid: - ChipLogDetail(Inet, "Listener: Invalid"); - res = CHIP_ERROR_INCORRECT_STATE; - nw_listener_cancel(listener); - break; - - case nw_listener_state_waiting: - ChipLogDetail(Inet, "Listener: Waiting"); - break; - - case nw_listener_state_failed: - ChipLogDetail(Inet, "Listener: Failed"); - res = CHIP_ERROR_POSIX(nw_error_get_error_code(error)); - break; - - case nw_listener_state_ready: - ChipLogDetail(Inet, "Listener: Ready"); - res = CHIP_NO_ERROR; - dispatch_semaphore_signal(mListenerSemaphore); - break; - - case nw_listener_state_cancelled: - ChipLogDetail(Inet, "Listener: Cancelled"); - if (res == CHIP_NO_ERROR) - res = CHIP_ERROR_CONNECTION_ABORTED; - - dispatch_semaphore_signal(mListenerSemaphore); - break; - } - }); - - nw_listener_start(listener); - dispatch_semaphore_wait(mListenerSemaphore, DISPATCH_TIME_FOREVER); - ReturnErrorOnFailure(res); - - mListener = listener; - nw_retain(mListener); - return res; -} - -CHIP_ERROR IPEndPointBasis::StartConnection(nw_connection_t & aConnection) -{ - __block CHIP_ERROR res = CHIP_NO_ERROR; - - nw_connection_set_queue(aConnection, mDispatchQueue); - - nw_connection_set_state_changed_handler(aConnection, ^(nw_connection_state_t state, nw_error_t error) { - switch (state) - { - - case nw_connection_state_invalid: - ChipLogDetail(Inet, "Connection: Invalid"); - res = CHIP_ERROR_INCORRECT_STATE; - nw_connection_cancel(aConnection); - break; - - case nw_connection_state_preparing: - ChipLogDetail(Inet, "Connection: Preparing"); - res = CHIP_ERROR_INCORRECT_STATE; - break; - - case nw_connection_state_waiting: - ChipLogDetail(Inet, "Connection: Waiting"); - nw_connection_cancel(aConnection); - break; - - case nw_connection_state_failed: - ChipLogDetail(Inet, "Connection: Failed"); - res = CHIP_ERROR_POSIX(nw_error_get_error_code(error)); - break; - - case nw_connection_state_ready: - ChipLogDetail(Inet, "Connection: Ready"); - res = CHIP_NO_ERROR; - dispatch_semaphore_signal(mConnectionSemaphore); - break; - - case nw_connection_state_cancelled: - ChipLogDetail(Inet, "Connection: Cancelled"); - if (res == CHIP_NO_ERROR) - res = CHIP_ERROR_CONNECTION_ABORTED; - - dispatch_semaphore_signal(mConnectionSemaphore); - break; - } - }); - - nw_connection_start(aConnection); - dispatch_semaphore_wait(mConnectionSemaphore, DISPATCH_TIME_FOREVER); - SuccessOrExit(res); - - mConnection = aConnection; - nw_retain(mConnection); - HandleDataReceived(mConnection); - - return res; -} - -void IPEndPointBasis::ReleaseAll() -{ - - OnMessageReceived = NULL; - OnReceiveError = NULL; - - ReleaseConnection(); - ReleaseListener(); - - if (mParameters) - { - nw_release(mParameters); - mParameters = NULL; - } - - if (mDispatchQueue) - { - dispatch_suspend(mDispatchQueue); - dispatch_release(mDispatchQueue); - mDispatchQueue = NULL; - } - - if (mConnectionSemaphore) - { - dispatch_release(mConnectionSemaphore); - mConnectionSemaphore = NULL; - } - - if (mListenerQueue) - { - dispatch_suspend(mListenerQueue); - dispatch_release(mListenerQueue); - mListenerQueue = NULL; - } - - if (mListenerSemaphore) - { - dispatch_release(mListenerSemaphore); - mListenerSemaphore = NULL; - } - - if (mSendSemaphore) - { - dispatch_release(mSendSemaphore); - mSendSemaphore = NULL; - } -} - -CHIP_ERROR IPEndPointBasis::ReleaseListener() -{ - VerifyOrReturnError(mListener, CHIP_ERROR_INCORRECT_STATE); - VerifyOrReturnError(mDispatchQueue, CHIP_ERROR_INCORRECT_STATE); - VerifyOrReturnError(mConnectionSemaphore, CHIP_ERROR_INCORRECT_STATE); - - nw_listener_cancel(mListener); - dispatch_semaphore_wait(mListenerSemaphore, DISPATCH_TIME_FOREVER); - nw_release(mListener); - mListener = NULL; - - return CHIP_NO_ERROR; -} - -CHIP_ERROR IPEndPointBasis::ReleaseConnection() -{ - VerifyOrReturnError(mConnection, CHIP_ERROR_INCORRECT_STATE); - VerifyOrReturnError(mDispatchQueue, CHIP_ERROR_INCORRECT_STATE); - VerifyOrReturnError(mConnectionSemaphore, CHIP_ERROR_INCORRECT_STATE); - - nw_connection_cancel(mConnection); - dispatch_semaphore_wait(mConnectionSemaphore, DISPATCH_TIME_FOREVER); - nw_release(mConnection); - mConnection = NULL; - - return CHIP_NO_ERROR; -} - -#endif // CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK - -CHIP_ERROR IPEndPointBasis::JoinMulticastGroup(InterfaceId aInterfaceId, const IPAddress & aAddress) -{ - CHIP_ERROR lRetval = CHIP_ERROR_NOT_IMPLEMENTED; - - const IPAddressType lAddrType = aAddress.Type(); - lRetval = CheckMulticastGroupArgs(aInterfaceId, aAddress); - SuccessOrExit(lRetval); - - switch (lAddrType) - { - -#if INET_CONFIG_ENABLE_IPV4 - case IPAddressType::kIPv4: { - return IPv4JoinLeaveMulticastGroupImpl(aInterfaceId, aAddress, true); - } - break; -#endif // INET_CONFIG_ENABLE_IPV4 - - case IPAddressType::kIPv6: { - return IPv6JoinLeaveMulticastGroupImpl(aInterfaceId, aAddress, true); - } - break; - - default: - lRetval = INET_ERROR_WRONG_ADDRESS_TYPE; - break; - } - -exit: - return (lRetval); -} - -CHIP_ERROR IPEndPointBasis::LeaveMulticastGroup(InterfaceId aInterfaceId, const IPAddress & aAddress) -{ - CHIP_ERROR lRetval = CHIP_ERROR_NOT_IMPLEMENTED; - - const IPAddressType lAddrType = aAddress.Type(); - lRetval = CheckMulticastGroupArgs(aInterfaceId, aAddress); - SuccessOrExit(lRetval); - - switch (lAddrType) - { - -#if INET_CONFIG_ENABLE_IPV4 - case IPAddressType::kIPv4: { - return IPv4JoinLeaveMulticastGroupImpl(aInterfaceId, aAddress, false); - } - break; -#endif // INET_CONFIG_ENABLE_IPV4 - - case IPAddressType::kIPv6: { - return IPv6JoinLeaveMulticastGroupImpl(aInterfaceId, aAddress, false); - } - break; - - default: - lRetval = INET_ERROR_WRONG_ADDRESS_TYPE; - break; - } - -exit: - return (lRetval); -} - -void IPEndPointBasis::Init(InetLayer * aInetLayer) -{ - InitEndPointBasis(*aInetLayer); - InitImpl(); -} - -} // namespace Inet -} // namespace chip diff --git a/src/inet/IPEndPointBasis.h b/src/inet/IPEndPointBasis.h deleted file mode 100644 index 1b3a408ec06e2e..00000000000000 --- a/src/inet/IPEndPointBasis.h +++ /dev/null @@ -1,229 +0,0 @@ -/* - * - * Copyright (c) 2020 Project CHIP Authors - * Copyright (c) 2018 Google LLC. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @file - * This header file defines the Inet::IPEndPointBasis - * class, an intermediate, non-instantiable basis class - * supporting other IP-based end points. - * - */ - -#pragma once - -#include - -#include -#include -#include - -#if CHIP_SYSTEM_CONFIG_USE_LWIP -#include -#include -#endif // CHIP_SYSTEM_CONFIG_USE_LWIP - -namespace chip { -namespace Inet { - -class InetLayer; -class IPPacketInfo; - -/** - * @class IPEndPointBasis - * - * @brief Objects of this class represent non-instantiable IP protocol - * endpoints. - * - */ -class DLL_EXPORT IPEndPointBasis : public EndPointBasis -{ -public: - /** - * @brief Type of message text reception event handling function. - * - * @param[in] endPoint The endpoint associated with the event. - * @param[in] msg The message text received. - * @param[in] pktInfo The packet's IP information. - * - * @details - * Provide a function of this type to the \c OnMessageReceived delegate - * member to process message text reception events on \c endPoint where - * \c msg is the message text received from the sender at \c senderAddr. - */ - typedef void (*OnMessageReceivedFunct)(IPEndPointBasis * endPoint, chip::System::PacketBufferHandle && msg, - const IPPacketInfo * pktInfo); - - /** - * @brief Type of reception error event handling function. - * - * @param[in] endPoint The endpoint associated with the event. - * @param[in] err The reason for the error. - * - * @details - * Provide a function of this type to the \c OnReceiveError delegate - * member to process reception error events on \c endPoint. The \c err - * argument provides specific detail about the type of the error. - */ - typedef void (*OnReceiveErrorFunct)(IPEndPointBasis * endPoint, CHIP_ERROR err, const IPPacketInfo * pktInfo); - - IPEndPointBasis() = default; - - /** - * Set whether IP multicast traffic should be looped back. - */ - CHIP_ERROR SetMulticastLoopback(IPVersion aIPVersion, bool aLoopback); - - /** - * Join an IP multicast group. - * - * @param[in] aInterfaceId The indicator of the network interface to add to the multicast group. - * @param[in] aAddress The multicast group to add the interface to. - * - * @retval CHIP_NO_ERROR Success: multicast group removed. - * @retval INET_ERROR_UNKNOWN_INTERFACE Unknown network interface, \c aInterfaceId. - * @retval INET_ERROR_WRONG_ADDRESS_TYPE \c aAddress is not \c kIPv4 or \c kIPv6 or is not multicast. - * @retval other Another system or platform error. - */ - CHIP_ERROR JoinMulticastGroup(InterfaceId aInterfaceId, const IPAddress & aAddress); - - /** - * Leave an IP multicast group. - * - * @param[in] aInterfaceId The indicator of the network interface to remove from the multicast group. - * @param[in] aAddress The multicast group to remove the interface from. - * - * @retval CHIP_NO_ERROR Success: multicast group removed - * @retval INET_ERROR_UNKNOWN_INTERFACE Unknown network interface, \c aInterfaceId - * @retval INET_ERROR_WRONG_ADDRESS_TYPE \c aAddress is not \c kIPv4 or \c kIPv6 or is not multicast. - * @retval other Another system or platform error - */ - CHIP_ERROR LeaveMulticastGroup(InterfaceId aInterfaceId, const IPAddress & aAddress); - -protected: - friend class InetLayer; - - /** - * Basic dynamic state of the underlying endpoint. - * - * Objects are initialized in the "ready" state, proceed to the "bound" - * state after binding to a local interface address, then proceed to the - * "listening" state when they have continuations registered for handling - * events for reception of ICMP messages. - */ - enum class State : uint8_t - { - kReady = 0, /**< Endpoint initialized, but not open. */ - kBound = 1, /**< Endpoint bound, but not listening. */ - kListening = 2, /**< Endpoint receiving datagrams. */ - kClosed = 3 /**< Endpoint closed, ready for release. */ - } mState; - - void Init(InetLayer * aInetLayer); - - /** The endpoint's message reception event handling function delegate. */ - OnMessageReceivedFunct OnMessageReceived; - - /** The endpoint's receive error event handling function delegate. */ - OnReceiveErrorFunct OnReceiveError; - -private: - IPEndPointBasis(const IPEndPointBasis &) = delete; - - void InitImpl(); - CHIP_ERROR IPv4JoinLeaveMulticastGroupImpl(InterfaceId aInterfaceId, const IPAddress & aAddress, bool join); - CHIP_ERROR IPv6JoinLeaveMulticastGroupImpl(InterfaceId aInterfaceId, const IPAddress & aAddress, bool join); - -#if CHIP_SYSTEM_CONFIG_USE_LWIP -public: - static struct netif * FindNetifFromInterfaceId(InterfaceId aInterfaceId); - -protected: - void HandleDataReceived(chip::System::PacketBufferHandle && aBuffer); - - /** - * Get LwIP IP layer source and destination addressing information. - * - * @param[in] aBuffer The packet buffer containing the IP message. - * - * @returns a pointer to the address information on success; otherwise, - * nullptr if there is insufficient space in the packet for - * the address information. - * - * When using LwIP information about the packet is 'hidden' in the reserved space before the start of the - * data in the packet buffer. This is necessary because the system layer events only have two arguments, - * which in this case are used to convey the pointer to the end point and the pointer to the buffer. - * - * In most cases this trick of storing information before the data works because the first buffer in an - * LwIP IP message contains the space that was used for the Ethernet/IP/UDP headers. However, given the - * current size of the IPPacketInfo structure (40 bytes), it is possible for there to not be enough room - * to store the structure along with the payload in a single packet buffer. In practice, this should only - * happen for extremely large IPv4 packets that arrive without an Ethernet header. - */ - static IPPacketInfo * GetPacketInfo(const chip::System::PacketBufferHandle & aBuffer); -#endif // CHIP_SYSTEM_CONFIG_USE_LWIP - -#if CHIP_SYSTEM_CONFIG_USE_SOCKETS -protected: - InterfaceId mBoundIntfId; - - CHIP_ERROR Bind(IPAddressType aAddressType, const IPAddress & aAddress, uint16_t aPort, InterfaceId aInterfaceId); - CHIP_ERROR BindInterface(IPAddressType aAddressType, InterfaceId aInterfaceId); - CHIP_ERROR SendMsg(const IPPacketInfo * aPktInfo, chip::System::PacketBufferHandle && aBuffer); - CHIP_ERROR GetSocket(IPAddressType aAddressType, int aType, int aProtocol); - void HandlePendingIO(uint16_t aPort); - -#if CHIP_SYSTEM_CONFIG_USE_PLATFORM_MULTICAST_API -public: - using MulticastGroupHandler = CHIP_ERROR (*)(InterfaceId, const IPAddress &); - static void SetJoinMulticastGroupHandler(MulticastGroupHandler handler) { sJoinMulticastGroupHandler = handler; } - static void SetLeaveMulticastGroupHandler(MulticastGroupHandler handler) { sLeaveMulticastGroupHandler = handler; } - -private: - static MulticastGroupHandler sJoinMulticastGroupHandler; - static MulticastGroupHandler sLeaveMulticastGroupHandler; -#endif // CHIP_SYSTEM_CONFIG_USE_PLATFORM_MULTICAST_API - -#endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS - -#if CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK -protected: - nw_listener_t mListener; - dispatch_semaphore_t mListenerSemaphore; - dispatch_queue_t mListenerQueue; - nw_connection_t mConnection; - dispatch_semaphore_t mConnectionSemaphore; - dispatch_queue_t mDispatchQueue; - dispatch_semaphore_t mSendSemaphore; - - CHIP_ERROR Bind(IPAddressType aAddressType, const IPAddress & aAddress, uint16_t aPort, const nw_parameters_t & aParameters); - CHIP_ERROR ConfigureProtocol(IPAddressType aAddressType, const nw_parameters_t & aParameters); - CHIP_ERROR SendMsg(const IPPacketInfo * aPktInfo, chip::System::PacketBufferHandle && aBuffer); - CHIP_ERROR StartListener(); - CHIP_ERROR GetConnection(const IPPacketInfo * aPktInfo); - CHIP_ERROR GetEndPoint(nw_endpoint_t & aEndpoint, const IPAddressType aAddressType, const IPAddress & aAddress, uint16_t aPort); - CHIP_ERROR StartConnection(nw_connection_t & aConnection); - void GetPacketInfo(const nw_connection_t & aConnection, IPPacketInfo & aPacketInfo); - void HandleDataReceived(const nw_connection_t & aConnection); - CHIP_ERROR ReleaseListener(); - CHIP_ERROR ReleaseConnection(); - void ReleaseAll(); -#endif // CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK -}; - -} // namespace Inet -} // namespace chip diff --git a/src/inet/InetLayer.h b/src/inet/InetLayer.h index 052353b532d677..d87917bd9efa0a 100644 --- a/src/inet/InetLayer.h +++ b/src/inet/InetLayer.h @@ -231,7 +231,7 @@ class DLL_EXPORT InetLayer * * @warning * Do not alter the contents of this class without first reading and understanding - * the code/comments in IPEndPointBasis::GetPacketInfo(). + * the code/comments in UDPEndPoint::GetPacketInfo(). */ class IPPacketInfo { diff --git a/src/inet/UDPEndPoint.cpp b/src/inet/UDPEndPoint.cpp index 39c3d947b13104..7fe265f8d6a51c 100644 --- a/src/inet/UDPEndPoint.cpp +++ b/src/inet/UDPEndPoint.cpp @@ -34,25 +34,55 @@ #include #include +#include #include #include #if CHIP_SYSTEM_CONFIG_USE_LWIP -#include -#include -#include #if CHIP_HAVE_CONFIG_H #include // nogncheck #endif // CHIP_HAVE_CONFIG_H -#endif // CHIP_SYSTEM_CONFIG_USE_LWIP + +#if INET_CONFIG_ENABLE_IPV4 +#include +#endif // INET_CONFIG_ENABLE_IPV4 + +#include +#include +#include +#include +#include +#include +#include + +#if !defined(RAW_FLAGS_MULTICAST_LOOP) || !defined(UDP_FLAGS_MULTICAST_LOOP) || !defined(raw_clear_flags) || \ + !defined(raw_set_flags) || !defined(udp_clear_flags) || !defined(udp_set_flags) +#define HAVE_LWIP_MULTICAST_LOOP 0 +#else +#define HAVE_LWIP_MULTICAST_LOOP 1 +#endif // !defined(RAW_FLAGS_MULTICAST_LOOP) || !defined(UDP_FLAGS_MULTICAST_LOOP) || !defined(raw_clear_flags) || + // !defined(raw_set_flags) || !defined(udp_clear_flags) || !defined(udp_set_flags) + +// unusual define check for LWIP_IPV6_ND is because espressif fork +// of LWIP does not define the _ND constant. +#if LWIP_IPV6_MLD && (!defined(LWIP_IPV6_ND) || LWIP_IPV6_ND) && LWIP_IPV6 +#define HAVE_IPV6_MULTICAST +#else +// Within Project CHIP multicast support is highly desirable: used for mDNS +// as well as group communication. +#undef HAVE_IPV6_MULTICAST +#endif +#endif // CHIP_SYSTEM_CONFIG_USE_LWIP #if CHIP_SYSTEM_CONFIG_USE_SOCKETS #if HAVE_SYS_SOCKET_H #include #endif // HAVE_SYS_SOCKET_H + #include #include #include +#include #include // SOCK_CLOEXEC not defined on all platforms, e.g. iOS/macOS: @@ -63,8 +93,37 @@ #if CHIP_SYSTEM_CONFIG_USE_ZEPHYR_SOCKET_EXTENSIONS #include "ZephyrSocket.h" #endif // CHIP_SYSTEM_CONFIG_USE_ZEPHYR_SOCKET_EXTENSIONS + +/* + * Some systems define both IPV6_{ADD,DROP}_MEMBERSHIP and + * IPV6_{JOIN,LEAVE}_GROUP while others only define + * IPV6_{JOIN,LEAVE}_GROUP. Prefer the "_MEMBERSHIP" flavor for + * parallelism with IPv4 and create the alias to the availabile + * definitions. + */ +#if defined(IPV6_ADD_MEMBERSHIP) +#define INET_IPV6_ADD_MEMBERSHIP IPV6_ADD_MEMBERSHIP +#elif defined(IPV6_JOIN_GROUP) +#define INET_IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP +#elif !__ZEPHYR__ +#error \ + "Neither IPV6_ADD_MEMBERSHIP nor IPV6_JOIN_GROUP are defined which are required for generalized IPv6 multicast group support." +#endif // IPV6_ADD_MEMBERSHIP + +#if defined(IPV6_DROP_MEMBERSHIP) +#define INET_IPV6_DROP_MEMBERSHIP IPV6_DROP_MEMBERSHIP +#elif defined(IPV6_LEAVE_GROUP) +#define INET_IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP +#elif !__ZEPHYR__ +#error \ + "Neither IPV6_DROP_MEMBERSHIP nor IPV6_LEAVE_GROUP are defined which are required for generalized IPv6 multicast group support." +#endif // IPV6_DROP_MEMBERSHIP #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS +#if CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK +#define INET_PORTSTRLEN 6 +#endif // CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK + #include "arpa-inet-compatibility.h" #include @@ -75,6 +134,16 @@ namespace Inet { chip::System::ObjectPool UDPEndPoint::sPool; +#if CHIP_SYSTEM_CONFIG_USE_LWIP || CHIP_SYSTEM_CONFIG_USE_SOCKETS + +static CHIP_ERROR CheckMulticastGroupArgs(InterfaceId aInterfaceId, const IPAddress & aAddress) +{ + VerifyOrReturnError(aInterfaceId.IsPresent(), INET_ERROR_UNKNOWN_INTERFACE); + VerifyOrReturnError(aAddress.IsMulticast(), INET_ERROR_WRONG_ADDRESS_TYPE); + return CHIP_NO_ERROR; +} +#endif // CHIP_SYSTEM_CONFIG_USE_LWIP || CHIP_SYSTEM_CONFIG_USE_SOCKETS + #if CHIP_SYSTEM_CONFIG_USE_LWIP namespace { @@ -97,7 +166,7 @@ CHIP_ERROR LwIPBindInterface(struct udp_pcb * aUDP, InterfaceId intfId) udp_bind_netif(aUDP, NULL); else { - struct netif * netifp = IPEndPointBasis::FindNetifFromInterfaceId(intfId); + struct netif * netifp = UDPEndPoint::FindNetifFromInterfaceId(intfId); if (netifp == NULL) res = INET_ERROR_UNKNOWN_INTERFACE; @@ -109,7 +178,7 @@ CHIP_ERROR LwIPBindInterface(struct udp_pcb * aUDP, InterfaceId intfId) aUDP->intf_filter = NULL; else { - struct netif * netifp = IPEndPointBasis::FindNetifFromInterfaceId(intfId); + struct netif * netifp = FindNetifFromInterfaceId(intfId); if (netifp == NULL) res = INET_ERROR_UNKNOWN_INTERFACE; @@ -373,7 +442,27 @@ void UDPEndPoint::Free() void UDPEndPoint::HandleDataReceived(System::PacketBufferHandle && msg) { - IPEndPointBasis::HandleDataReceived(std::move(msg)); + IpHandleDataReceived(std::move(msg)); +} + +void UDPEndPoint::IpHandleDataReceived(System::PacketBufferHandle && aBuffer) +{ + if ((mState == State::kListening) && (OnMessageReceived != NULL)) + { + const IPPacketInfo * pktInfo = GetPacketInfo(aBuffer); + + if (pktInfo != NULL) + { + const IPPacketInfo pktInfoCopy = *pktInfo; // copy the address info so that the app can free the + // PacketBuffer without affecting access to address info. + OnMessageReceived(this, std::move(aBuffer), &pktInfoCopy); + } + else + { + if (OnReceiveError != NULL) + OnReceiveError(this, CHIP_ERROR_INBOUND_MESSAGE_TOO_BIG, NULL); + } + } } CHIP_ERROR UDPEndPoint::GetPCB(IPAddressType addrType) @@ -491,13 +580,13 @@ void UDPEndPoint::LwIPReceiveUDPMessage(void * arg, struct udp_pcb * pcb, struct #else // LWIP_VERSION_MAJOR <= 1 if (PCB_ISIPV6(pcb)) { - pktInfo->SrcAddress = IPAddress(*(ip6_addr_t *) addr); + pktInfo->SrcAddress = IPAddress(*(ip6_addr_t *) addr); pktInfo->DestAddress = IPAddress(*ip6_current_dest_addr()); } #if INET_CONFIG_ENABLE_IPV4 else { - pktInfo->SrcAddress = IPAddress(*addr); + pktInfo->SrcAddress = IPAddress(*addr); pktInfo->DestAddress = IPAddress(*ip_current_dest_addr()); } #endif // INET_CONFIG_ENABLE_IPV4 @@ -517,15 +606,165 @@ void UDPEndPoint::LwIPReceiveUDPMessage(void * arg, struct udp_pcb * pcb, struct } } +CHIP_ERROR UDPEndPoint::SetMulticastLoopback(IPVersion aIPVersion, bool aLoopback) +{ + CHIP_ERROR lRetval = CHIP_ERROR_NOT_IMPLEMENTED; + +#if !HAVE_LWIP_MULTICAST_LOOP + lRetval = CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +#else + if (aLoopback) + { + switch (mLwIPEndPointType) + { + +#if INET_CONFIG_ENABLE_UDP_ENDPOINT + case LwIPEndPointType::UDP: + udp_set_flags(mUDP, UDP_FLAGS_MULTICAST_LOOP); + break; +#endif // INET_CONFIG_ENABLE_UDP_ENDPOINT + + default: + lRetval = CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; + break; + } + } + else + { + switch (mLwIPEndPointType) + { + +#if INET_CONFIG_ENABLE_UDP_ENDPOINT + case LwIPEndPointType::UDP: + udp_clear_flags(mUDP, UDP_FLAGS_MULTICAST_LOOP); + break; +#endif // INET_CONFIG_ENABLE_UDP_ENDPOINT + + default: + lRetval = CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; + break; + } + } + + lRetval = CHIP_NO_ERROR; +#endif // !HAVE_LWIP_MULTICAST_LOOP + return (lRetval); +} + +void UDPEndPoint::InitImpl() {} + +#if INET_CONFIG_ENABLE_IPV4 +#if LWIP_IPV4 && LWIP_IGMP +static CHIP_ERROR LwIPIPv4JoinLeaveMulticastGroup(InterfaceId aInterfaceId, const IPAddress & aAddress, + err_t (*aMethod)(struct netif *, const ip4_addr_t *)) +{ + struct netif * const lNetif = UDPEndPoint::FindNetifFromInterfaceId(aInterfaceId); + VerifyOrReturnError(lNetif != nullptr, INET_ERROR_UNKNOWN_INTERFACE); + + const ip4_addr_t lIPv4Address = aAddress.ToIPv4(); + const err_t lStatus = aMethod(lNetif, &lIPv4Address); + + if (lStatus == ERR_MEM) + { + return CHIP_ERROR_NO_MEMORY; + } + return chip::System::MapErrorLwIP(lStatus); +} +#endif // LWIP_IPV4 && LWIP_IGMP +#endif // INET_CONFIG_ENABLE_IPV4 + +#ifdef HAVE_IPV6_MULTICAST +static CHIP_ERROR LwIPIPv6JoinLeaveMulticastGroup(InterfaceId aInterfaceId, const IPAddress & aAddress, + err_t (*aMethod)(struct netif *, const ip6_addr_t *)) +{ + struct netif * const lNetif = UDPEndPoint::FindNetifFromInterfaceId(aInterfaceId); + VerifyOrReturnError(lNetif != nullptr, INET_ERROR_UNKNOWN_INTERFACE); + + const ip6_addr_t lIPv6Address = aAddress.ToIPv6(); + const err_t lStatus = aMethod(lNetif, &lIPv6Address); + + if (lStatus == ERR_MEM) + { + return CHIP_ERROR_NO_MEMORY; + } + return chip::System::MapErrorLwIP(lStatus); +} +#endif // LWIP_IPV6_MLD && LWIP_IPV6_ND && LWIP_IPV6 + +#if INET_CONFIG_ENABLE_IPV4 +CHIP_ERROR UDPEndPoint::IPv4JoinLeaveMulticastGroupImpl(InterfaceId aInterfaceId, const IPAddress & aAddress, bool join) +{ +#if LWIP_IPV4 && LWIP_IGMP + const auto method = join ? igmp_joingroup_netif : igmp_leavegroup_netif; + return LwIPIPv4JoinLeaveMulticastGroup(aInterfaceId, aAddress, method); +#else // LWIP_IPV4 && LWIP_IGMP + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +#endif // LWIP_IPV4 && LWIP_IGMP +} +#endif // INET_CONFIG_ENABLE_IPV4 + +CHIP_ERROR UDPEndPoint::IPv6JoinLeaveMulticastGroupImpl(InterfaceId aInterfaceId, const IPAddress & aAddress, bool join) +{ +#ifdef HAVE_IPV6_MULTICAST + const auto method = join ? mld6_joingroup_netif : mld6_leavegroup_netif; + return LwIPIPv6JoinLeaveMulticastGroup(aInterfaceId, aAddress, method); +#else // HAVE_IPV6_MULTICAST + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +#endif // HAVE_IPV6_MULTICAST +} + +struct netif * UDPEndPoint::FindNetifFromInterfaceId(InterfaceId aInterfaceId) +{ + struct netif * lRetval = NULL; + +#if LWIP_VERSION_MAJOR >= 2 && LWIP_VERSION_MINOR >= 0 && defined(NETIF_FOREACH) + NETIF_FOREACH(lRetval) + { + if (lRetval == aInterfaceId.GetPlatformInterface()) + break; + } +#else // LWIP_VERSION_MAJOR < 2 || !defined(NETIF_FOREACH) + for (lRetval = netif_list; lRetval != NULL && lRetval != aInterfaceId.GetPlatformInterface(); lRetval = lRetval->next) + ; +#endif // LWIP_VERSION_MAJOR >= 2 && LWIP_VERSION_MINOR >= 0 && defined(NETIF_FOREACH) + + return (lRetval); +} + +IPPacketInfo * UDPEndPoint::GetPacketInfo(const System::PacketBufferHandle & aBuffer) +{ + uintptr_t lStart; + uintptr_t lPacketInfoStart; + IPPacketInfo * lPacketInfo = NULL; + + if (!aBuffer->EnsureReservedSize(sizeof(IPPacketInfo) + 3)) + goto done; + + lStart = (uintptr_t) aBuffer->Start(); + lPacketInfoStart = lStart - sizeof(IPPacketInfo); + + // Align to a 4-byte boundary + + lPacketInfo = reinterpret_cast(lPacketInfoStart & ~(sizeof(uint32_t) - 1)); + +done: + return (lPacketInfo); +} + #endif // CHIP_SYSTEM_CONFIG_USE_LWIP #if CHIP_SYSTEM_CONFIG_USE_SOCKETS +#if CHIP_SYSTEM_CONFIG_USE_PLATFORM_MULTICAST_API +UDPEndPoint::MulticastGroupHandler UDPEndPoint::sJoinMulticastGroupHandler; +UDPEndPoint::MulticastGroupHandler UDPEndPoint::sLeaveMulticastGroupHandler; +#endif // CHIP_SYSTEM_CONFIG_USE_PLATFORM_MULTICAST_API + CHIP_ERROR UDPEndPoint::BindImpl(IPAddressType addrType, const IPAddress & addr, uint16_t port, InterfaceId intfId) { // Make sure we have the appropriate type of socket. ReturnErrorOnFailure(GetSocket(addrType)); - ReturnErrorOnFailure(IPEndPointBasis::Bind(addrType, addr, port, intfId)); + ReturnErrorOnFailure(IpBind(addrType, addr, port, intfId)); mBoundPort = port; mBoundIntfId = intfId; @@ -568,11 +807,128 @@ CHIP_ERROR UDPEndPoint::BindImpl(IPAddressType addrType, const IPAddress & addr, return CHIP_NO_ERROR; } +CHIP_ERROR UDPEndPoint::IpBind(IPAddressType aAddressType, const IPAddress & aAddress, uint16_t aPort, InterfaceId aInterfaceId) +{ + CHIP_ERROR lRetval = CHIP_NO_ERROR; + + if (aAddressType == IPAddressType::kIPv6) + { + struct sockaddr_in6 sa; + + memset(&sa, 0, sizeof(sa)); + + sa.sin6_family = AF_INET6; + sa.sin6_port = htons(aPort); + sa.sin6_addr = aAddress.ToIPv6(); + InterfaceId::PlatformType interfaceId = aInterfaceId.GetPlatformInterface(); + if (!CanCastTo(interfaceId)) + { + return CHIP_ERROR_INCORRECT_STATE; + } + sa.sin6_scope_id = static_cast(interfaceId); + + if (bind(mSocket, reinterpret_cast(&sa), static_cast(sizeof(sa))) != 0) + lRetval = CHIP_ERROR_POSIX(errno); + + // Instruct the kernel that any messages to multicast destinations should be + // sent down the interface specified by the caller. +#ifdef IPV6_MULTICAST_IF + if (lRetval == CHIP_NO_ERROR) + setsockopt(mSocket, IPPROTO_IPV6, IPV6_MULTICAST_IF, &aInterfaceId, sizeof(aInterfaceId)); +#endif // defined(IPV6_MULTICAST_IF) + + // Instruct the kernel that any messages to multicast destinations should be + // set with the configured hop limit value. +#ifdef IPV6_MULTICAST_HOPS + int hops = INET_CONFIG_IP_MULTICAST_HOP_LIMIT; + setsockopt(mSocket, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hops, sizeof(hops)); +#endif // defined(IPV6_MULTICAST_HOPS) + } +#if INET_CONFIG_ENABLE_IPV4 + else if (aAddressType == IPAddressType::kIPv4) + { + struct sockaddr_in sa; + int enable = 1; + + memset(&sa, 0, sizeof(sa)); + + sa.sin_family = AF_INET; + sa.sin_port = htons(aPort); + sa.sin_addr = aAddress.ToIPv4(); + + if (bind(mSocket, reinterpret_cast(&sa), static_cast(sizeof(sa))) != 0) + lRetval = CHIP_ERROR_POSIX(errno); + + // Instruct the kernel that any messages to multicast destinations should be + // sent down the interface to which the specified IPv4 address is bound. +#ifdef IP_MULTICAST_IF + if (lRetval == CHIP_NO_ERROR) + setsockopt(mSocket, IPPROTO_IP, IP_MULTICAST_IF, &sa, sizeof(sa)); +#endif // defined(IP_MULTICAST_IF) + + // Instruct the kernel that any messages to multicast destinations should be + // set with the configured hop limit value. +#ifdef IP_MULTICAST_TTL + int ttl = INET_CONFIG_IP_MULTICAST_HOP_LIMIT; + setsockopt(mSocket, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)); +#endif // defined(IP_MULTICAST_TTL) + + // Allow socket transmitting broadcast packets. + if (lRetval == CHIP_NO_ERROR) + setsockopt(mSocket, SOL_SOCKET, SO_BROADCAST, &enable, sizeof(enable)); + } +#endif // INET_CONFIG_ENABLE_IPV4 + else + lRetval = INET_ERROR_WRONG_ADDRESS_TYPE; + + return (lRetval); +} + CHIP_ERROR UDPEndPoint::BindInterfaceImpl(IPAddressType addrType, InterfaceId intfId) { // Make sure we have the appropriate type of socket. ReturnErrorOnFailure(GetSocket(addrType)); - return IPEndPointBasis::BindInterface(addrType, intfId); + return IpBindInterface(addrType, intfId); +} + +CHIP_ERROR UDPEndPoint::IpBindInterface(IPAddressType aAddressType, InterfaceId aInterfaceId) +{ + CHIP_ERROR lRetval = CHIP_NO_ERROR; + +#if HAVE_SO_BINDTODEVICE + if (!aInterfaceId.IsPresent()) + { + // Stop interface-based filtering. + if (setsockopt(mSocket, SOL_SOCKET, SO_BINDTODEVICE, "", 0) == -1) + { + lRetval = CHIP_ERROR_POSIX(errno); + } + } + else + { + // Start filtering on the passed interface. + char lInterfaceName[IF_NAMESIZE]; + + if (if_indextoname(aInterfaceId.GetPlatformInterface(), lInterfaceName) == NULL) + { + lRetval = CHIP_ERROR_POSIX(errno); + } + + if (lRetval == CHIP_NO_ERROR && + setsockopt(mSocket, SOL_SOCKET, SO_BINDTODEVICE, lInterfaceName, socklen_t(strlen(lInterfaceName))) == -1) + { + lRetval = CHIP_ERROR_POSIX(errno); + } + } + + if (lRetval == CHIP_NO_ERROR) + mBoundIntfId = aInterfaceId; + +#else // !HAVE_SO_BINDTODEVICE + lRetval = CHIP_ERROR_NOT_IMPLEMENTED; +#endif // HAVE_SO_BINDTODEVICE + + return (lRetval); } InterfaceId UDPEndPoint::GetBoundInterface() @@ -599,7 +955,137 @@ CHIP_ERROR UDPEndPoint::SendMsgImpl(const IPPacketInfo * pktInfo, System::Packet // destination address. ReturnErrorOnFailure(GetSocket(pktInfo->DestAddress.Type())); - return IPEndPointBasis::SendMsg(pktInfo, std::move(msg)); + return IpSendMsg(pktInfo, std::move(msg)); +} + +CHIP_ERROR UDPEndPoint::IpSendMsg(const IPPacketInfo * aPktInfo, chip::System::PacketBufferHandle && aBuffer) +{ + // Ensure the destination address type is compatible with the endpoint address type. + VerifyOrReturnError(mAddrType == aPktInfo->DestAddress.Type(), CHIP_ERROR_INVALID_ARGUMENT); + + // For now the entire message must fit within a single buffer. + VerifyOrReturnError(!aBuffer->HasChainedBuffer(), CHIP_ERROR_MESSAGE_TOO_LONG); + + struct iovec msgIOV; + msgIOV.iov_base = aBuffer->Start(); + msgIOV.iov_len = aBuffer->DataLength(); + +#if defined(IP_PKTINFO) || defined(IPV6_PKTINFO) + uint8_t controlData[256]; + memset(controlData, 0, sizeof(controlData)); +#endif // defined(IP_PKTINFO) || defined(IPV6_PKTINFO) + + struct msghdr msgHeader; + memset(&msgHeader, 0, sizeof(msgHeader)); + msgHeader.msg_iov = &msgIOV; + msgHeader.msg_iovlen = 1; + + // Construct a sockaddr_in/sockaddr_in6 structure containing the destination information. + SockAddr peerSockAddr; + memset(&peerSockAddr, 0, sizeof(peerSockAddr)); + msgHeader.msg_name = &peerSockAddr; + if (mAddrType == IPAddressType::kIPv6) + { + peerSockAddr.in6.sin6_family = AF_INET6; + peerSockAddr.in6.sin6_port = htons(aPktInfo->DestPort); + peerSockAddr.in6.sin6_addr = aPktInfo->DestAddress.ToIPv6(); + InterfaceId::PlatformType intfId = aPktInfo->Interface.GetPlatformInterface(); + VerifyOrReturnError(CanCastTo(intfId), CHIP_ERROR_INCORRECT_STATE); + peerSockAddr.in6.sin6_scope_id = static_cast(intfId); + msgHeader.msg_namelen = sizeof(sockaddr_in6); + } +#if INET_CONFIG_ENABLE_IPV4 + else + { + peerSockAddr.in.sin_family = AF_INET; + peerSockAddr.in.sin_port = htons(aPktInfo->DestPort); + peerSockAddr.in.sin_addr = aPktInfo->DestAddress.ToIPv4(); + msgHeader.msg_namelen = sizeof(sockaddr_in); + } +#endif // INET_CONFIG_ENABLE_IPV4 + + // If the endpoint has been bound to a particular interface, + // and the caller didn't supply a specific interface to send + // on, use the bound interface. This appears to be necessary + // for messages to multicast addresses, which under Linux + // don't seem to get sent out the correct interface, despite + // the socket being bound. + InterfaceId intf = aPktInfo->Interface; + if (!intf.IsPresent()) + intf = mBoundIntfId; + + // If the packet should be sent over a specific interface, or with a specific source + // address, construct an IP_PKTINFO/IPV6_PKTINFO "control message" to that effect + // add add it to the message header. If the local OS doesn't support IP_PKTINFO/IPV6_PKTINFO + // fail with an error. + if (intf.IsPresent() || aPktInfo->SrcAddress.Type() != IPAddressType::kAny) + { +#if defined(IP_PKTINFO) || defined(IPV6_PKTINFO) + msgHeader.msg_control = controlData; + msgHeader.msg_controllen = sizeof(controlData); + + struct cmsghdr * controlHdr = CMSG_FIRSTHDR(&msgHeader); + InterfaceId::PlatformType intfId = intf.GetPlatformInterface(); + +#if INET_CONFIG_ENABLE_IPV4 + + if (mAddrType == IPAddressType::kIPv4) + { +#if defined(IP_PKTINFO) + controlHdr->cmsg_level = IPPROTO_IP; + controlHdr->cmsg_type = IP_PKTINFO; + controlHdr->cmsg_len = CMSG_LEN(sizeof(in_pktinfo)); + + struct in_pktinfo * pktInfo = reinterpret_cast CMSG_DATA(controlHdr); + if (!CanCastToipi_ifindex)>(intfId)) + { + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; + } + + pktInfo->ipi_ifindex = static_castipi_ifindex)>(intfId); + pktInfo->ipi_spec_dst = aPktInfo->SrcAddress.ToIPv4(); + + msgHeader.msg_controllen = CMSG_SPACE(sizeof(in_pktinfo)); +#else // !defined(IP_PKTINFO) + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +#endif // !defined(IP_PKTINFO) + } + +#endif // INET_CONFIG_ENABLE_IPV4 + + if (mAddrType == IPAddressType::kIPv6) + { +#if defined(IPV6_PKTINFO) + controlHdr->cmsg_level = IPPROTO_IPV6; + controlHdr->cmsg_type = IPV6_PKTINFO; + controlHdr->cmsg_len = CMSG_LEN(sizeof(in6_pktinfo)); + + struct in6_pktinfo * pktInfo = reinterpret_cast CMSG_DATA(controlHdr); + if (!CanCastToipi6_ifindex)>(intfId)) + { + return CHIP_ERROR_UNEXPECTED_EVENT; + } + pktInfo->ipi6_ifindex = static_castipi6_ifindex)>(intfId); + pktInfo->ipi6_addr = aPktInfo->SrcAddress.ToIPv6(); + + msgHeader.msg_controllen = CMSG_SPACE(sizeof(in6_pktinfo)); +#else // !defined(IPV6_PKTINFO) + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +#endif // !defined(IPV6_PKTINFO) + } + +#else // !(defined(IP_PKTINFO) && defined(IPV6_PKTINFO)) + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +#endif // !(defined(IP_PKTINFO) && defined(IPV6_PKTINFO)) + } + + // Send IP packet. + const ssize_t lenSent = sendmsg(mSocket, &msgHeader, 0); + if (lenSent == -1) + return CHIP_ERROR_POSIX(errno); + if (lenSent != aBuffer->DataLength()) + return CHIP_ERROR_OUTBOUND_MESSAGE_TOO_BIG; + return CHIP_NO_ERROR; } void UDPEndPoint::CloseImpl() @@ -631,7 +1117,118 @@ CHIP_ERROR UDPEndPoint::GetSocket(IPAddressType aAddressType) constexpr int lType = (SOCK_DGRAM | SOCK_CLOEXEC); constexpr int lProtocol = 0; - return IPEndPointBasis::GetSocket(aAddressType, lType, lProtocol); + return IpGetSocket(aAddressType, lType, lProtocol); +} + +CHIP_ERROR UDPEndPoint::IpGetSocket(IPAddressType aAddressType, int aType, int aProtocol) +{ + if (mSocket == kInvalidSocketFd) + { + const int one = 1; + int family; + + switch (aAddressType) + { + case IPAddressType::kIPv6: + family = PF_INET6; + break; + +#if INET_CONFIG_ENABLE_IPV4 + case IPAddressType::kIPv4: + family = PF_INET; + break; +#endif // INET_CONFIG_ENABLE_IPV4 + + default: + return INET_ERROR_WRONG_ADDRESS_TYPE; + } + + mSocket = ::socket(family, aType, aProtocol); + if (mSocket == -1) + return CHIP_ERROR_POSIX(errno); + ReturnErrorOnFailure(static_cast(Layer().SystemLayer())->StartWatchingSocket(mSocket, &mWatch)); + + mAddrType = aAddressType; + + // NOTE WELL: the errors returned by setsockopt() here are not + // returned as Inet layer CHIP_ERROR_POSIX(errno) + // codes because they are normally expected to fail on some + // platforms where the socket option code is defined in the + // header files but not [yet] implemented. Certainly, there is + // room to improve this by connecting the build configuration + // logic up to check for implementations of these options and + // to provide appropriate HAVE_xxxxx definitions accordingly. + + int res = setsockopt(mSocket, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); + static_cast(res); + +#ifdef SO_REUSEPORT + res = setsockopt(mSocket, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)); + if (res != 0) + { + ChipLogError(Inet, "SO_REUSEPORT failed: %d", errno); + } +#endif // defined(SO_REUSEPORT) + + // If creating an IPv6 socket, tell the kernel that it will be + // IPv6 only. This makes it posible to bind two sockets to + // the same port, one for IPv4 and one for IPv6. + +#ifdef IPV6_V6ONLY + if (aAddressType == IPAddressType::kIPv6) + { + res = setsockopt(mSocket, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)); + if (res != 0) + { + ChipLogError(Inet, "IPV6_V6ONLY failed: %d", errno); + } + } +#endif // defined(IPV6_V6ONLY) + +#if INET_CONFIG_ENABLE_IPV4 +#ifdef IP_PKTINFO + if (aAddressType == IPAddressType::kIPv4) + { + res = setsockopt(mSocket, IPPROTO_IP, IP_PKTINFO, &one, sizeof(one)); + if (res != 0) + { + ChipLogError(Inet, "IP_PKTINFO failed: %d", errno); + } + } +#endif // defined(IP_PKTINFO) +#endif // INET_CONFIG_ENABLE_IPV4 + +#ifdef IPV6_RECVPKTINFO + if (aAddressType == IPAddressType::kIPv6) + { + res = setsockopt(mSocket, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one)); + if (res != 0) + { + ChipLogError(Inet, "IPV6_PKTINFO failed: %d", errno); + } + } +#endif // defined(IPV6_RECVPKTINFO) + + // On systems that support it, disable the delivery of SIGPIPE + // signals when writing to a closed socket. This is mostly + // needed on iOS which has the peculiar habit of sending + // SIGPIPEs on unconnected UDP sockets. +#ifdef SO_NOSIGPIPE + { + res = setsockopt(mSocket, SOL_SOCKET, SO_NOSIGPIPE, &one, sizeof(one)); + if (res != 0) + { + ChipLogError(Inet, "SO_NOSIGPIPE failed: %d", errno); + } + } +#endif // defined(SO_NOSIGPIPE) + } + else if (mAddrType != aAddressType) + { + return CHIP_ERROR_INCORRECT_STATE; + } + + return CHIP_NO_ERROR; } // static @@ -646,48 +1243,342 @@ void UDPEndPoint::HandlePendingIO(System::SocketEvents events) { const uint16_t lPort = mBoundPort; - IPEndPointBasis::HandlePendingIO(lPort); + IpHandlePendingIO(lPort); } } -#endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS +void UDPEndPoint::IpHandlePendingIO(uint16_t aPort) +{ + CHIP_ERROR lStatus = CHIP_NO_ERROR; + IPPacketInfo lPacketInfo; + System::PacketBufferHandle lBuffer; -#if CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK + lPacketInfo.Clear(); + lPacketInfo.DestPort = aPort; -CHIP_ERROR UDPEndPoint::BindImpl(IPAddressType addrType, const IPAddress & addr, uint16_t port, InterfaceId intfId) -{ - nw_parameters_configure_protocol_block_t configure_tls; - nw_parameters_t parameters; + lBuffer = System::PacketBufferHandle::New(System::PacketBuffer::kMaxSizeWithoutReserve, 0); - if (intfId.IsPresent()) + if (!lBuffer.IsNull()) { - return CHIP_ERROR_NOT_IMPLEMENTED; - } + struct iovec msgIOV; + SockAddr lPeerSockAddr; + uint8_t controlData[256]; + struct msghdr msgHeader; - configure_tls = NW_PARAMETERS_DISABLE_PROTOCOL; - parameters = nw_parameters_create_secure_udp(configure_tls, NW_PARAMETERS_DEFAULT_CONFIGURATION); + msgIOV.iov_base = lBuffer->Start(); + msgIOV.iov_len = lBuffer->AvailableDataLength(); - ReturnErrorOnFailure(IPEndPointBasis::Bind(addrType, addr, port, parameters)); + memset(&lPeerSockAddr, 0, sizeof(lPeerSockAddr)); - mParameters = parameters; - return CHIP_NO_ERROR; -} + memset(&msgHeader, 0, sizeof(msgHeader)); -CHIP_ERROR UDPEndPoint::BindInterfaceImpl(IPAddressType addrType, InterfaceId intfId) -{ - return INET_ERROR_UNKNOWN_INTERFACE; -} + msgHeader.msg_name = &lPeerSockAddr; + msgHeader.msg_namelen = sizeof(lPeerSockAddr); + msgHeader.msg_iov = &msgIOV; + msgHeader.msg_iovlen = 1; + msgHeader.msg_control = controlData; + msgHeader.msg_controllen = sizeof(controlData); -InterfaceId UDPEndPoint::GetBoundInterface() -{ - return InterfaceId::Null(); -} + ssize_t rcvLen = recvmsg(mSocket, &msgHeader, MSG_DONTWAIT); -uint16_t UDPEndPoint::GetBoundPort() -{ - nw_endpoint_t endpoint = nw_parameters_copy_local_endpoint(mParameters); - return nw_endpoint_get_port(endpoint); -} + if (rcvLen < 0) + { + lStatus = CHIP_ERROR_POSIX(errno); + } + else if (rcvLen > lBuffer->AvailableDataLength()) + { + lStatus = CHIP_ERROR_INBOUND_MESSAGE_TOO_BIG; + } + else + { + lBuffer->SetDataLength(static_cast(rcvLen)); + + if (lPeerSockAddr.any.sa_family == AF_INET6) + { + lPacketInfo.SrcAddress = IPAddress(lPeerSockAddr.in6.sin6_addr); + lPacketInfo.SrcPort = ntohs(lPeerSockAddr.in6.sin6_port); + } +#if INET_CONFIG_ENABLE_IPV4 + else if (lPeerSockAddr.any.sa_family == AF_INET) + { + lPacketInfo.SrcAddress = IPAddress(lPeerSockAddr.in.sin_addr); + lPacketInfo.SrcPort = ntohs(lPeerSockAddr.in.sin_port); + } +#endif // INET_CONFIG_ENABLE_IPV4 + else + { + lStatus = CHIP_ERROR_INCORRECT_STATE; + } + } + + if (lStatus == CHIP_NO_ERROR) + { + for (struct cmsghdr * controlHdr = CMSG_FIRSTHDR(&msgHeader); controlHdr != nullptr; + controlHdr = CMSG_NXTHDR(&msgHeader, controlHdr)) + { +#if INET_CONFIG_ENABLE_IPV4 +#ifdef IP_PKTINFO + if (controlHdr->cmsg_level == IPPROTO_IP && controlHdr->cmsg_type == IP_PKTINFO) + { + struct in_pktinfo * inPktInfo = reinterpret_cast CMSG_DATA(controlHdr); + if (!CanCastTo(inPktInfo->ipi_ifindex)) + { + lStatus = CHIP_ERROR_INCORRECT_STATE; + break; + } + lPacketInfo.Interface = InterfaceId(static_cast(inPktInfo->ipi_ifindex)); + lPacketInfo.DestAddress = IPAddress(inPktInfo->ipi_addr); + continue; + } +#endif // defined(IP_PKTINFO) +#endif // INET_CONFIG_ENABLE_IPV4 + +#ifdef IPV6_PKTINFO + if (controlHdr->cmsg_level == IPPROTO_IPV6 && controlHdr->cmsg_type == IPV6_PKTINFO) + { + struct in6_pktinfo * in6PktInfo = reinterpret_cast CMSG_DATA(controlHdr); + if (!CanCastTo(in6PktInfo->ipi6_ifindex)) + { + lStatus = CHIP_ERROR_INCORRECT_STATE; + break; + } + lPacketInfo.Interface = InterfaceId(static_cast(in6PktInfo->ipi6_ifindex)); + lPacketInfo.DestAddress = IPAddress(in6PktInfo->ipi6_addr); + continue; + } +#endif // defined(IPV6_PKTINFO) + } + } + } + else + { + lStatus = CHIP_ERROR_NO_MEMORY; + } + + if (lStatus == CHIP_NO_ERROR) + { + lBuffer.RightSize(); + OnMessageReceived(this, std::move(lBuffer), &lPacketInfo); + } + else + { + if (OnReceiveError != nullptr && lStatus != CHIP_ERROR_POSIX(EAGAIN)) + { + OnReceiveError(this, lStatus, nullptr); + } + } +} + +#if IP_MULTICAST_LOOP || IPV6_MULTICAST_LOOP +static CHIP_ERROR SocketsSetMulticastLoopback(int aSocket, bool aLoopback, int aProtocol, int aOption) +{ + const unsigned int lValue = aLoopback; + if (setsockopt(aSocket, aProtocol, aOption, &lValue, sizeof(lValue)) != 0) + { + return CHIP_ERROR_POSIX(errno); + } + + return CHIP_NO_ERROR; +} +#endif // IP_MULTICAST_LOOP || IPV6_MULTICAST_LOOP + +static CHIP_ERROR SocketsSetMulticastLoopback(int aSocket, IPVersion aIPVersion, bool aLoopback) +{ +#ifdef IPV6_MULTICAST_LOOP + CHIP_ERROR lRetval; + + switch (aIPVersion) + { + + case kIPVersion_6: + lRetval = SocketsSetMulticastLoopback(aSocket, aLoopback, IPPROTO_IPV6, IPV6_MULTICAST_LOOP); + break; + +#if INET_CONFIG_ENABLE_IPV4 + case kIPVersion_4: + lRetval = SocketsSetMulticastLoopback(aSocket, aLoopback, IPPROTO_IP, IP_MULTICAST_LOOP); + break; +#endif // INET_CONFIG_ENABLE_IPV4 + + default: + lRetval = INET_ERROR_WRONG_ADDRESS_TYPE; + break; + } + + return (lRetval); +#else // IPV6_MULTICAST_LOOP + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +#endif // IPV6_MULTICAST_LOOP +} + +CHIP_ERROR UDPEndPoint::SetMulticastLoopback(IPVersion aIPVersion, bool aLoopback) +{ + CHIP_ERROR lRetval = CHIP_ERROR_NOT_IMPLEMENTED; + + lRetval = SocketsSetMulticastLoopback(mSocket, aIPVersion, aLoopback); + SuccessOrExit(lRetval); + +exit: + return (lRetval); +} + +void UDPEndPoint::InitImpl() +{ + mBoundIntfId = InterfaceId::Null(); +} + +#if INET_CONFIG_ENABLE_IPV4 + +static CHIP_ERROR SocketsIPv4JoinLeaveMulticastGroup(int aSocket, InterfaceId aInterfaceId, const IPAddress & aAddress, + int aCommand) +{ + IPAddress lInterfaceAddress; + bool lInterfaceAddressFound = false; + + for (InterfaceAddressIterator lAddressIterator; lAddressIterator.HasCurrent(); lAddressIterator.Next()) + { + const IPAddress lCurrentAddress = lAddressIterator.GetAddress(); + + if (lAddressIterator.GetInterfaceId() == aInterfaceId) + { + if (lCurrentAddress.IsIPv4()) + { + lInterfaceAddressFound = true; + lInterfaceAddress = lCurrentAddress; + break; + } + } + } + + VerifyOrReturnError(lInterfaceAddressFound, INET_ERROR_ADDRESS_NOT_FOUND); + + struct ip_mreq lMulticastRequest; + memset(&lMulticastRequest, 0, sizeof(lMulticastRequest)); + lMulticastRequest.imr_interface = lInterfaceAddress.ToIPv4(); + lMulticastRequest.imr_multiaddr = aAddress.ToIPv4(); + + if (setsockopt(aSocket, IPPROTO_IP, aCommand, &lMulticastRequest, sizeof(lMulticastRequest)) != 0) + { + return CHIP_ERROR_POSIX(errno); + } + return CHIP_NO_ERROR; +} + +CHIP_ERROR UDPEndPoint::IPv4JoinLeaveMulticastGroupImpl(InterfaceId aInterfaceId, const IPAddress & aAddress, bool join) +{ + return SocketsIPv4JoinLeaveMulticastGroup(mSocket, aInterfaceId, aAddress, join ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP); +} + +#endif // INET_CONFIG_ENABLE_IPV4 + +#if INET_IPV6_ADD_MEMBERSHIP || INET_IPV6_DROP_MEMBERSHIP +static CHIP_ERROR SocketsIPv6JoinLeaveMulticastGroup(int aSocket, InterfaceId aInterfaceId, const IPAddress & aAddress, + int aCommand) +{ + const InterfaceId::PlatformType lIfIndex = aInterfaceId.GetPlatformInterface(); + + struct ipv6_mreq lMulticastRequest; + memset(&lMulticastRequest, 0, sizeof(lMulticastRequest)); + VerifyOrReturnError(CanCastTo(lIfIndex), CHIP_ERROR_UNEXPECTED_EVENT); + + lMulticastRequest.ipv6mr_interface = static_cast(lIfIndex); + lMulticastRequest.ipv6mr_multiaddr = aAddress.ToIPv6(); + + if (setsockopt(aSocket, IPPROTO_IPV6, aCommand, &lMulticastRequest, sizeof(lMulticastRequest)) != 0) + { + return CHIP_ERROR_POSIX(errno); + } + return CHIP_NO_ERROR; +} +#endif // INET_IPV6_ADD_MEMBERSHIP || INET_IPV6_DROP_MEMBERSHIP + +CHIP_ERROR UDPEndPoint::IPv6JoinLeaveMulticastGroupImpl(InterfaceId aInterfaceId, const IPAddress & aAddress, bool join) +{ +#if CHIP_SYSTEM_CONFIG_USE_PLATFORM_MULTICAST_API + MulticastGroupHandler handler = join ? sJoinMulticastGroupHandler : sLeaveMulticastGroupHandler; + if (handler != nullptr) + { + return handler(aInterfaceId, aAddress); + } +#endif // CHIP_SYSTEM_CONFIG_USE_PLATFORM_MULTICAST_API +#if defined(INET_IPV6_ADD_MEMBERSHIP) && defined(INET_IPV6_DROP_MEMBERSHIP) + return SocketsIPv6JoinLeaveMulticastGroup(mSocket, aInterfaceId, aAddress, + join ? INET_IPV6_ADD_MEMBERSHIP : INET_IPV6_DROP_MEMBERSHIP); +#else // defined(INET_IPV6_ADD_MEMBERSHIP) && defined(INET_IPV6_DROP_MEMBERSHIP) + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +#endif // defined(INET_IPV6_ADD_MEMBERSHIP) && defined(INET_IPV6_DROP_MEMBERSHIP) +} + +#endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS + +#if CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK + +CHIP_ERROR UDPEndPoint::BindImpl(IPAddressType addrType, const IPAddress & addr, uint16_t port, InterfaceId intfId) +{ + nw_parameters_configure_protocol_block_t configure_tls; + nw_parameters_t parameters; + + if (intfId.IsPresent()) + { + return CHIP_ERROR_NOT_IMPLEMENTED; + } + + configure_tls = NW_PARAMETERS_DISABLE_PROTOCOL; + parameters = nw_parameters_create_secure_udp(configure_tls, NW_PARAMETERS_DEFAULT_CONFIGURATION); + + ReturnErrorOnFailure(IpBind(addrType, addr, port, parameters)); + + mParameters = parameters; + return CHIP_NO_ERROR; +} + +CHIP_ERROR UDPEndPoint::IpBind(IPAddressType aAddressType, const IPAddress & aAddress, uint16_t aPort, + const nw_parameters_t & aParameters) +{ + nw_endpoint_t endpoint = nullptr; + + VerifyOrReturnError(aParameters != NULL, CHIP_ERROR_INVALID_ARGUMENT); + + ReturnErrorOnFailure(ConfigureProtocol(aAddressType, aParameters)); + + CHIP_ERROR res = GetEndPoint(endpoint, aAddressType, aAddress, aPort); + nw_parameters_set_local_endpoint(aParameters, endpoint); + nw_release(endpoint); + ReturnErrorOnFailure(res); + + mDispatchQueue = dispatch_queue_create("inet_dispatch_global", DISPATCH_QUEUE_CONCURRENT); + VerifyOrReturnError(mDispatchQueue != NULL, CHIP_ERROR_NO_MEMORY); + dispatch_retain(mDispatchQueue); + + mConnectionSemaphore = dispatch_semaphore_create(0); + VerifyOrReturnError(mConnectionSemaphore != NULL, CHIP_ERROR_NO_MEMORY); + dispatch_retain(mConnectionSemaphore); + + mSendSemaphore = dispatch_semaphore_create(0); + VerifyOrReturnError(mSendSemaphore != NULL, CHIP_ERROR_NO_MEMORY); + dispatch_retain(mSendSemaphore); + + mAddrType = aAddressType; + mConnection = NULL; + + return CHIP_NO_ERROR; +} + +CHIP_ERROR UDPEndPoint::BindInterfaceImpl(IPAddressType addrType, InterfaceId intfId) +{ + return INET_ERROR_UNKNOWN_INTERFACE; +} + +InterfaceId UDPEndPoint::GetBoundInterface() +{ + return InterfaceId::Null(); +} + +uint16_t UDPEndPoint::GetBoundPort() +{ + nw_endpoint_t endpoint = nw_parameters_copy_local_endpoint(mParameters); + return nw_endpoint_get_port(endpoint); +} CHIP_ERROR UDPEndPoint::ListenImpl() { @@ -696,12 +1587,100 @@ CHIP_ERROR UDPEndPoint::ListenImpl() CHIP_ERROR UDPEndPoint::SendMsgImpl(const IPPacketInfo * pktInfo, System::PacketBufferHandle && msg) { - return IPEndPointBasis::SendMsg(pktInfo, std::move(msg)); + return IpSendMsg(pktInfo, std::move(msg)); +} + +CHIP_ERROR UDPEndPoint::IpSendMsg(const IPPacketInfo * aPktInfo, chip::System::PacketBufferHandle && aBuffer) +{ + dispatch_data_t content; + + // Ensure the destination address type is compatible with the endpoint address type. + VerifyOrReturnError(mAddrType == aPktInfo->DestAddress.Type(), CHIP_ERROR_INVALID_ARGUMENT); + + // For now the entire message must fit within a single buffer. + VerifyOrReturnError(aBuffer->Next() == NULL, CHIP_ERROR_MESSAGE_TOO_LONG); + + ReturnErrorOnFailure(GetConnection(aPktInfo)); + + // Send a message, and wait for it to be dispatched. + content = dispatch_data_create(aBuffer->Start(), aBuffer->DataLength(), mDispatchQueue, DISPATCH_DATA_DESTRUCTOR_DEFAULT); + + // If there is a current message pending and the state of the network connection change (e.g switch to a + // different network) the connection will enter a nw_connection_state_failed state and the completion handler + // will never be called. In such cases a signal is sent from the connection state change handler to release + // the semaphore. In this case the CHIP_ERROR will not update with the result of the completion handler. + // To make sure caller knows that sending a message has failed the following code consider there is an error + // _unless_ the completion handler says otherwise. + __block CHIP_ERROR res = CHIP_ERROR_UNEXPECTED_EVENT; + nw_connection_send(mConnection, content, NW_CONNECTION_DEFAULT_MESSAGE_CONTEXT, true, ^(nw_error_t error) { + if (error) + { + res = CHIP_ERROR_POSIX(nw_error_get_error_code(error)); + } + else + { + res = CHIP_NO_ERROR; + } + dispatch_semaphore_signal(mSendSemaphore); + }); + dispatch_release(content); + + dispatch_semaphore_wait(mSendSemaphore, DISPATCH_TIME_FOREVER); + + return res; } void UDPEndPoint::CloseImpl() { - IPEndPointBasis::ReleaseAll(); + ReleaseAll(); +} + +void UDPEndPoint::ReleaseAll() +{ + + OnMessageReceived = NULL; + OnReceiveError = NULL; + + ReleaseConnection(); + ReleaseListener(); + + if (mParameters) + { + nw_release(mParameters); + mParameters = NULL; + } + + if (mDispatchQueue) + { + dispatch_suspend(mDispatchQueue); + dispatch_release(mDispatchQueue); + mDispatchQueue = NULL; + } + + if (mConnectionSemaphore) + { + dispatch_release(mConnectionSemaphore); + mConnectionSemaphore = NULL; + } + + if (mListenerQueue) + { + dispatch_suspend(mListenerQueue); + dispatch_release(mListenerQueue); + mListenerQueue = NULL; + } + + if (mListenerSemaphore) + { + dispatch_release(mListenerSemaphore); + mListenerSemaphore = NULL; + } + + if (mSendSemaphore) + { + dispatch_release(mSendSemaphore); + mSendSemaphore = NULL; + } } void UDPEndPoint::Free() @@ -710,6 +1689,327 @@ void UDPEndPoint::Free() Release(); } +CHIP_ERROR UDPEndPoint::SetMulticastLoopback(IPVersion aIPVersion, bool aLoopback) +{ + CHIP_ERROR lRetval = CHIP_ERROR_NOT_IMPLEMENTED; + return (lRetval); +} + +#if INET_CONFIG_ENABLE_IPV4 +CHIP_ERROR UDPEndPoint::IPv4JoinLeaveMulticastGroupImpl(InterfaceId aInterfaceId, const IPAddress & aAddress, bool join) +{ + return CHIP_ERROR_NOT_IMPLEMENTED; +} +#endif // INET_CONFIG_ENABLE_IPV4 + +CHIP_ERROR UDPEndPoint::IPv6JoinLeaveMulticastGroupImpl(InterfaceId aInterfaceId, const IPAddress & aAddress, bool join) +{ + return CHIP_ERROR_NOT_IMPLEMENTED; +} + +CHIP_ERROR UDPEndPoint::ConfigureProtocol(IPAddressType aAddressType, const nw_parameters_t & aParameters) +{ + CHIP_ERROR res = CHIP_NO_ERROR; + + nw_protocol_stack_t protocolStack = nw_parameters_copy_default_protocol_stack(aParameters); + nw_protocol_options_t ipOptions = nw_protocol_stack_copy_internet_protocol(protocolStack); + + switch (aAddressType) + { + + case IPAddressType::kIPv6: + nw_ip_options_set_version(ipOptions, nw_ip_version_6); + break; + +#if INET_CONFIG_ENABLE_IPV4 + case IPAddressType::kIPv4: + nw_ip_options_set_version(ipOptions, nw_ip_version_4); + break; +#endif // INET_CONFIG_ENABLE_IPV4 + + default: + res = INET_ERROR_WRONG_ADDRESS_TYPE; + break; + } + nw_release(ipOptions); + nw_release(protocolStack); + + return res; +} + +void UDPEndPoint::GetPacketInfo(const nw_connection_t & aConnection, IPPacketInfo & aPacketInfo) +{ + nw_path_t path = nw_connection_copy_current_path(aConnection); + nw_endpoint_t dest_endpoint = nw_path_copy_effective_local_endpoint(path); + nw_endpoint_t src_endpoint = nw_path_copy_effective_remote_endpoint(path); + + aPacketInfo.Clear(); + aPacketInfo.SrcAddress = IPAddress::FromSockAddr(*nw_endpoint_get_address(src_endpoint)); + aPacketInfo.DestAddress = IPAddress::FromSockAddr(*nw_endpoint_get_address(dest_endpoint)); + aPacketInfo.SrcPort = nw_endpoint_get_port(src_endpoint); + aPacketInfo.DestPort = nw_endpoint_get_port(dest_endpoint); +} + +CHIP_ERROR UDPEndPoint::GetEndPoint(nw_endpoint_t & aEndPoint, const IPAddressType aAddressType, const IPAddress & aAddress, + uint16_t aPort) +{ + char addrStr[INET6_ADDRSTRLEN]; + char portStr[INET_PORTSTRLEN]; + + // Note: aAddress.ToString will return the IPv6 Any address if the address type is Any, but that's not what + // we want if the locale endpoint is IPv4. + if (aAddressType == IPAddressType::kIPv4 && aAddress.Type() == IPAddressType::kAny) + { + const IPAddress anyAddr = IPAddress(aAddress.ToIPv4()); + anyAddr.ToString(addrStr, sizeof(addrStr)); + } + else + { + aAddress.ToString(addrStr, sizeof(addrStr)); + } + + snprintf(portStr, sizeof(portStr), "%u", aPort); + + aEndPoint = nw_endpoint_create_host(addrStr, portStr); + VerifyOrReturnError(aEndPoint != NULL, CHIP_ERROR_INVALID_ARGUMENT); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR UDPEndPoint::GetConnection(const IPPacketInfo * aPktInfo) +{ + VerifyOrReturnError(mParameters != NULL, CHIP_ERROR_INCORRECT_STATE); + + nw_endpoint_t endpoint = NULL; + nw_connection_t connection = NULL; + + if (mConnection) + { + nw_path_t path = nw_connection_copy_current_path(mConnection); + nw_endpoint_t remote_endpoint = nw_path_copy_effective_remote_endpoint(path); + const IPAddress remote_address = IPAddress::FromSockAddr(*nw_endpoint_get_address(remote_endpoint)); + const uint16_t remote_port = nw_endpoint_get_port(remote_endpoint); + const bool isDifferentEndPoint = aPktInfo->DestPort != remote_port || aPktInfo->DestAddress != remote_address; + VerifyOrReturnError(isDifferentEndPoint, CHIP_NO_ERROR); + + ReturnErrorOnFailure(ReleaseConnection()); + } + + ReturnErrorOnFailure(GetEndPoint(endpoint, mAddrType, aPktInfo->DestAddress, aPktInfo->DestPort)); + + connection = nw_connection_create(endpoint, mParameters); + nw_release(endpoint); + + VerifyOrReturnError(connection != NULL, CHIP_ERROR_INCORRECT_STATE); + + return StartConnection(connection); +} + +CHIP_ERROR UDPEndPoint::StartListener() +{ + __block CHIP_ERROR res = CHIP_NO_ERROR; + nw_listener_t listener; + + VerifyOrReturnError(mListener == NULL, CHIP_ERROR_INCORRECT_STATE); + VerifyOrReturnError(mListenerSemaphore == NULL, CHIP_ERROR_INCORRECT_STATE); + VerifyOrReturnError(mListenerQueue == NULL, CHIP_ERROR_INCORRECT_STATE); + + listener = nw_listener_create(mParameters); + VerifyOrReturnError(listener != NULL, CHIP_ERROR_INCORRECT_STATE); + + mListenerSemaphore = dispatch_semaphore_create(0); + VerifyOrReturnError(mListenerSemaphore != NULL, CHIP_ERROR_NO_MEMORY); + dispatch_retain(mListenerSemaphore); + + mListenerQueue = dispatch_queue_create("inet_dispatch_listener", DISPATCH_QUEUE_CONCURRENT); + VerifyOrReturnError(mListenerQueue != NULL, CHIP_ERROR_NO_MEMORY); + dispatch_retain(mListenerQueue); + + nw_listener_set_queue(listener, mListenerQueue); + + nw_listener_set_new_connection_handler(listener, ^(nw_connection_t connection) { + ReleaseConnection(); + StartConnection(connection); + }); + + nw_listener_set_state_changed_handler(listener, ^(nw_listener_state_t state, nw_error_t error) { + switch (state) + { + + case nw_listener_state_invalid: + ChipLogDetail(Inet, "Listener: Invalid"); + res = CHIP_ERROR_INCORRECT_STATE; + nw_listener_cancel(listener); + break; + + case nw_listener_state_waiting: + ChipLogDetail(Inet, "Listener: Waiting"); + break; + + case nw_listener_state_failed: + ChipLogDetail(Inet, "Listener: Failed"); + res = CHIP_ERROR_POSIX(nw_error_get_error_code(error)); + break; + + case nw_listener_state_ready: + ChipLogDetail(Inet, "Listener: Ready"); + res = CHIP_NO_ERROR; + dispatch_semaphore_signal(mListenerSemaphore); + break; + + case nw_listener_state_cancelled: + ChipLogDetail(Inet, "Listener: Cancelled"); + if (res == CHIP_NO_ERROR) + res = CHIP_ERROR_CONNECTION_ABORTED; + + dispatch_semaphore_signal(mListenerSemaphore); + break; + } + }); + + nw_listener_start(listener); + dispatch_semaphore_wait(mListenerSemaphore, DISPATCH_TIME_FOREVER); + ReturnErrorOnFailure(res); + + mListener = listener; + nw_retain(mListener); + return res; +} + +CHIP_ERROR UDPEndPoint::StartConnection(nw_connection_t & aConnection) +{ + __block CHIP_ERROR res = CHIP_NO_ERROR; + + nw_connection_set_queue(aConnection, mDispatchQueue); + + nw_connection_set_state_changed_handler(aConnection, ^(nw_connection_state_t state, nw_error_t error) { + switch (state) + { + + case nw_connection_state_invalid: + ChipLogDetail(Inet, "Connection: Invalid"); + res = CHIP_ERROR_INCORRECT_STATE; + nw_connection_cancel(aConnection); + break; + + case nw_connection_state_preparing: + ChipLogDetail(Inet, "Connection: Preparing"); + res = CHIP_ERROR_INCORRECT_STATE; + break; + + case nw_connection_state_waiting: + ChipLogDetail(Inet, "Connection: Waiting"); + nw_connection_cancel(aConnection); + break; + + case nw_connection_state_failed: + ChipLogDetail(Inet, "Connection: Failed"); + res = CHIP_ERROR_POSIX(nw_error_get_error_code(error)); + break; + + case nw_connection_state_ready: + ChipLogDetail(Inet, "Connection: Ready"); + res = CHIP_NO_ERROR; + dispatch_semaphore_signal(mConnectionSemaphore); + break; + + case nw_connection_state_cancelled: + ChipLogDetail(Inet, "Connection: Cancelled"); + if (res == CHIP_NO_ERROR) + res = CHIP_ERROR_CONNECTION_ABORTED; + + dispatch_semaphore_signal(mConnectionSemaphore); + break; + } + }); + + nw_connection_start(aConnection); + dispatch_semaphore_wait(mConnectionSemaphore, DISPATCH_TIME_FOREVER); + SuccessOrExit(res); + + mConnection = aConnection; + nw_retain(mConnection); + IpHandleDataReceived(mConnection); + + return res; +} + +void UDPEndPoint::IpHandleDataReceived(const nw_connection_t & aConnection) +{ + nw_connection_receive_completion_t handler = + ^(dispatch_data_t content, nw_content_context_t context, bool is_complete, nw_error_t receive_error) { + dispatch_block_t schedule_next_receive = ^{ + if (receive_error == NULL) + { + IpHandleDataReceived(aConnection); + } + else if (OnReceiveError != NULL) + { + nw_error_domain_t error_domain = nw_error_get_error_domain(receive_error); + errno = nw_error_get_error_code(receive_error); + if (!(error_domain == nw_error_domain_posix && errno == ECANCELED)) + { + CHIP_ERROR error = CHIP_ERROR_POSIX(errno); + IPPacketInfo packetInfo; + GetPacketInfo(aConnection, packetInfo); + dispatch_async(mDispatchQueue, ^{ + OnReceiveError((UDPEndPoint *) this, error, &packetInfo); + }); + } + } + }; + + if (content != NULL && OnMessageReceived != NULL) + { + size_t count = dispatch_data_get_size(content); + System::PacketBufferHandle * packetBuffer = System::PacketBufferHandle::New(count); + dispatch_data_apply(content, ^(dispatch_data_t data, size_t offset, const void * buffer, size_t size) { + memmove(packetBuffer->Start() + offset, buffer, size); + return true; + }); + packetBuffer->SetDataLength(count); + + IPPacketInfo packetInfo; + GetPacketInfo(aConnection, packetInfo); + dispatch_async(mDispatchQueue, ^{ + OnMessageReceived((UDPEndPoint *) this, packetBuffer, &packetInfo); + }); + } + + schedule_next_receive(); + }; + + nw_connection_receive_message(aConnection, handler); +} + +CHIP_ERROR UDPEndPoint::ReleaseListener() +{ + VerifyOrReturnError(mListener, CHIP_ERROR_INCORRECT_STATE); + VerifyOrReturnError(mDispatchQueue, CHIP_ERROR_INCORRECT_STATE); + VerifyOrReturnError(mConnectionSemaphore, CHIP_ERROR_INCORRECT_STATE); + + nw_listener_cancel(mListener); + dispatch_semaphore_wait(mListenerSemaphore, DISPATCH_TIME_FOREVER); + nw_release(mListener); + mListener = NULL; + + return CHIP_NO_ERROR; +} + +CHIP_ERROR UDPEndPoint::ReleaseConnection() +{ + VerifyOrReturnError(mConnection, CHIP_ERROR_INCORRECT_STATE); + VerifyOrReturnError(mDispatchQueue, CHIP_ERROR_INCORRECT_STATE); + VerifyOrReturnError(mConnectionSemaphore, CHIP_ERROR_INCORRECT_STATE); + + nw_connection_cancel(mConnection); + dispatch_semaphore_wait(mConnectionSemaphore, DISPATCH_TIME_FOREVER); + nw_release(mConnection); + mConnection = NULL; + + return CHIP_NO_ERROR; +} + #endif // CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK CHIP_ERROR UDPEndPoint::Bind(IPAddressType addrType, const IPAddress & addr, uint16_t port, InterfaceId intfId) @@ -801,7 +2101,77 @@ void UDPEndPoint::Close() void UDPEndPoint::Init(InetLayer * inetLayer) { - IPEndPointBasis::Init(inetLayer); + IpInit(inetLayer); +} + +void UDPEndPoint::IpInit(InetLayer * aInetLayer) +{ + InitEndPointBasis(*aInetLayer); + InitImpl(); +} + +CHIP_ERROR UDPEndPoint::JoinMulticastGroup(InterfaceId aInterfaceId, const IPAddress & aAddress) +{ + CHIP_ERROR lRetval = CHIP_ERROR_NOT_IMPLEMENTED; + + const IPAddressType lAddrType = aAddress.Type(); + lRetval = CheckMulticastGroupArgs(aInterfaceId, aAddress); + SuccessOrExit(lRetval); + + switch (lAddrType) + { + +#if INET_CONFIG_ENABLE_IPV4 + case IPAddressType::kIPv4: { + return IPv4JoinLeaveMulticastGroupImpl(aInterfaceId, aAddress, true); + } + break; +#endif // INET_CONFIG_ENABLE_IPV4 + + case IPAddressType::kIPv6: { + return IPv6JoinLeaveMulticastGroupImpl(aInterfaceId, aAddress, true); + } + break; + + default: + lRetval = INET_ERROR_WRONG_ADDRESS_TYPE; + break; + } + +exit: + return (lRetval); +} + +CHIP_ERROR UDPEndPoint::LeaveMulticastGroup(InterfaceId aInterfaceId, const IPAddress & aAddress) +{ + CHIP_ERROR lRetval = CHIP_ERROR_NOT_IMPLEMENTED; + + const IPAddressType lAddrType = aAddress.Type(); + lRetval = CheckMulticastGroupArgs(aInterfaceId, aAddress); + SuccessOrExit(lRetval); + + switch (lAddrType) + { + +#if INET_CONFIG_ENABLE_IPV4 + case IPAddressType::kIPv4: { + return IPv4JoinLeaveMulticastGroupImpl(aInterfaceId, aAddress, false); + } + break; +#endif // INET_CONFIG_ENABLE_IPV4 + + case IPAddressType::kIPv6: { + return IPv6JoinLeaveMulticastGroupImpl(aInterfaceId, aAddress, false); + } + break; + + default: + lRetval = INET_ERROR_WRONG_ADDRESS_TYPE; + break; + } + +exit: + return (lRetval); } } // namespace Inet diff --git a/src/inet/UDPEndPoint.h b/src/inet/UDPEndPoint.h index a19a05b4bf6c04..0c96aabe330867 100644 --- a/src/inet/UDPEndPoint.h +++ b/src/inet/UDPEndPoint.h @@ -28,8 +28,9 @@ #pragma once -#include "inet/IPEndPointBasis.h" +#include #include +#include #include @@ -51,13 +52,70 @@ class IPPacketInfo; * endpoints (SOCK_DGRAM sockets on Linux and BSD-derived systems) or LwIP * UDP protocol control blocks, as the system is configured accordingly. */ -class DLL_EXPORT UDPEndPoint : public IPEndPointBasis +class DLL_EXPORT UDPEndPoint : public EndPointBasis { - friend class InetLayer; - public: UDPEndPoint() = default; + /** + * @brief Type of message text reception event handling function. + * + * @param[in] endPoint The endpoint associated with the event. + * @param[in] msg The message text received. + * @param[in] pktInfo The packet's IP information. + * + * @details + * Provide a function of this type to the \c OnMessageReceived delegate + * member to process message text reception events on \c endPoint where + * \c msg is the message text received from the sender at \c senderAddr. + */ + typedef void (*OnMessageReceivedFunct)(UDPEndPoint * endPoint, chip::System::PacketBufferHandle && msg, + const IPPacketInfo * pktInfo); + + /** + * @brief Type of reception error event handling function. + * + * @param[in] endPoint The endpoint associated with the event. + * @param[in] err The reason for the error. + * + * @details + * Provide a function of this type to the \c OnReceiveError delegate + * member to process reception error events on \c endPoint. The \c err + * argument provides specific detail about the type of the error. + */ + typedef void (*OnReceiveErrorFunct)(UDPEndPoint * endPoint, CHIP_ERROR err, const IPPacketInfo * pktInfo); + + /** + * Set whether IP multicast traffic should be looped back. + */ + CHIP_ERROR SetMulticastLoopback(IPVersion aIPVersion, bool aLoopback); + + /** + * Join an IP multicast group. + * + * @param[in] aInterfaceId The indicator of the network interface to add to the multicast group. + * @param[in] aAddress The multicast group to add the interface to. + * + * @retval CHIP_NO_ERROR Success: multicast group removed. + * @retval INET_ERROR_UNKNOWN_INTERFACE Unknown network interface, \c aInterfaceId. + * @retval INET_ERROR_WRONG_ADDRESS_TYPE \c aAddress is not \c kIPv4 or \c kIPv6 or is not multicast. + * @retval other Another system or platform error. + */ + CHIP_ERROR JoinMulticastGroup(InterfaceId aInterfaceId, const IPAddress & aAddress); + + /** + * Leave an IP multicast group. + * + * @param[in] aInterfaceId The indicator of the network interface to remove from the multicast group. + * @param[in] aAddress The multicast group to remove the interface from. + * + * @retval CHIP_NO_ERROR Success: multicast group removed + * @retval INET_ERROR_UNKNOWN_INTERFACE Unknown network interface, \c aInterfaceId + * @retval INET_ERROR_WRONG_ADDRESS_TYPE \c aAddress is not \c kIPv4 or \c kIPv6 or is not multicast. + * @retval other Another system or platform error + */ + CHIP_ERROR LeaveMulticastGroup(InterfaceId aInterfaceId, const IPAddress & aAddress); + /** * Bind the endpoint to an interface IP address. * @@ -189,6 +247,40 @@ class DLL_EXPORT UDPEndPoint : public IPEndPointBasis void Free(); private: + friend class InetLayer; + + // XXX Temporary: start of import from IPEndPointBasis + + /** + * Basic dynamic state of the underlying endpoint. + * + * Objects are initialized in the "ready" state, proceed to the "bound" + * state after binding to a local interface address, then proceed to the + * "listening" state when they have continuations registered for handling + * events for reception of ICMP messages. + */ + enum class State : uint8_t + { + kReady = 0, /**< Endpoint initialized, but not open. */ + kBound = 1, /**< Endpoint bound, but not listening. */ + kListening = 2, /**< Endpoint receiving datagrams. */ + kClosed = 3 /**< Endpoint closed, ready for release. */ + } mState; + + void IpInit(InetLayer * aInetLayer); + + /** The endpoint's message reception event handling function delegate. */ + OnMessageReceivedFunct OnMessageReceived; + + /** The endpoint's receive error event handling function delegate. */ + OnReceiveErrorFunct OnReceiveError; + + void InitImpl(); + CHIP_ERROR IPv4JoinLeaveMulticastGroupImpl(InterfaceId aInterfaceId, const IPAddress & aAddress, bool join); + CHIP_ERROR IPv6JoinLeaveMulticastGroupImpl(InterfaceId aInterfaceId, const IPAddress & aAddress, bool join); + + // XXX Temporary: end of import from IPEndPointBasis + UDPEndPoint(const UDPEndPoint &) = delete; static chip::System::ObjectPool sPool; @@ -202,16 +294,69 @@ class DLL_EXPORT UDPEndPoint : public IPEndPointBasis void Init(InetLayer * inetLayer); #if CHIP_SYSTEM_CONFIG_USE_LWIP - void HandleDataReceived(chip::System::PacketBufferHandle && msg); + + // XXX Temporary: start of import from IPEndPointBasis +public: + static struct netif * FindNetifFromInterfaceId(InterfaceId aInterfaceId); + +private: + void HandleDataReceived(chip::System::PacketBufferHandle && aBuffer); + + /** + * Get LwIP IP layer source and destination addressing information. + * + * @param[in] aBuffer The packet buffer containing the IP message. + * + * @returns a pointer to the address information on success; otherwise, + * nullptr if there is insufficient space in the packet for + * the address information. + * + * When using LwIP information about the packet is 'hidden' in the reserved space before the start of the + * data in the packet buffer. This is necessary because the system layer events only have two arguments, + * which in this case are used to convey the pointer to the end point and the pointer to the buffer. + * + * In most cases this trick of storing information before the data works because the first buffer in an + * LwIP IP message contains the space that was used for the Ethernet/IP/UDP headers. However, given the + * current size of the IPPacketInfo structure (40 bytes), it is possible for there to not be enough room + * to store the structure along with the payload in a single packet buffer. In practice, this should only + * happen for extremely large IPv4 packets that arrive without an Ethernet header. + */ + static IPPacketInfo * GetPacketInfo(const chip::System::PacketBufferHandle & aBuffer); + // XXX Temporary: end of import from IPEndPointBasis + + void IpHandleDataReceived(chip::System::PacketBufferHandle && msg); CHIP_ERROR GetPCB(IPAddressType addrType4); #if LWIP_VERSION_MAJOR > 1 || LWIP_VERSION_MINOR >= 5 static void LwIPReceiveUDPMessage(void * arg, struct udp_pcb * pcb, struct pbuf * p, const ip_addr_t * addr, u16_t port); #else // LWIP_VERSION_MAJOR <= 1 && LWIP_VERSION_MINOR < 5 static void LwIPReceiveUDPMessage(void * arg, struct udp_pcb * pcb, struct pbuf * p, ip_addr_t * addr, u16_t port); #endif // LWIP_VERSION_MAJOR > 1 || LWIP_VERSION_MINOR >= 5 + #endif // CHIP_SYSTEM_CONFIG_USE_LWIP #if CHIP_SYSTEM_CONFIG_USE_SOCKETS + // XXX Temporary: start of import from IPEndPointBasis + InterfaceId mBoundIntfId; + + CHIP_ERROR IpBind(IPAddressType aAddressType, const IPAddress & aAddress, uint16_t aPort, InterfaceId aInterfaceId); + CHIP_ERROR IpBindInterface(IPAddressType aAddressType, InterfaceId aInterfaceId); + CHIP_ERROR IpSendMsg(const IPPacketInfo * aPktInfo, chip::System::PacketBufferHandle && aBuffer); + CHIP_ERROR IpGetSocket(IPAddressType aAddressType, int aType, int aProtocol); + void IpHandlePendingIO(uint16_t aPort); + +#if CHIP_SYSTEM_CONFIG_USE_PLATFORM_MULTICAST_API +public: + using MulticastGroupHandler = CHIP_ERROR (*)(InterfaceId, const IPAddress &); + static void SetJoinMulticastGroupHandler(MulticastGroupHandler handler) { sJoinMulticastGroupHandler = handler; } + static void SetLeaveMulticastGroupHandler(MulticastGroupHandler handler) { sLeaveMulticastGroupHandler = handler; } + +private: + static MulticastGroupHandler sJoinMulticastGroupHandler; + static MulticastGroupHandler sLeaveMulticastGroupHandler; +#endif // CHIP_SYSTEM_CONFIG_USE_PLATFORM_MULTICAST_API + + // XXX Temporary: end of import from IPEndPointBasis + uint16_t mBoundPort; CHIP_ERROR GetSocket(IPAddressType addrType); @@ -222,6 +367,31 @@ class DLL_EXPORT UDPEndPoint : public IPEndPointBasis dispatch_source_t mReadableSource = nullptr; #endif // CHIP_SYSTEM_CONFIG_USE_DISPATCH #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS + +#if CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK + // XXX Temporary: start of import from IPEndPointBasis + nw_listener_t mListener; + dispatch_semaphore_t mListenerSemaphore; + dispatch_queue_t mListenerQueue; + nw_connection_t mConnection; + dispatch_semaphore_t mConnectionSemaphore; + dispatch_queue_t mDispatchQueue; + dispatch_semaphore_t mSendSemaphore; + + CHIP_ERROR IpBind(IPAddressType aAddressType, const IPAddress & aAddress, uint16_t aPort, const nw_parameters_t & aParameters); + CHIP_ERROR ConfigureProtocol(IPAddressType aAddressType, const nw_parameters_t & aParameters); + CHIP_ERROR IpSendMsg(const IPPacketInfo * aPktInfo, chip::System::PacketBufferHandle && aBuffer); + CHIP_ERROR StartListener(); + CHIP_ERROR GetConnection(const IPPacketInfo * aPktInfo); + CHIP_ERROR GetEndPoint(nw_endpoint_t & aEndpoint, const IPAddressType aAddressType, const IPAddress & aAddress, uint16_t aPort); + CHIP_ERROR StartConnection(nw_connection_t & aConnection); + void GetPacketInfo(const nw_connection_t & aConnection, IPPacketInfo & aPacketInfo); + void IpHandleDataReceived(const nw_connection_t & aConnection); + CHIP_ERROR ReleaseListener(); + CHIP_ERROR ReleaseConnection(); + void ReleaseAll(); + // XXX Temporary: end of import from IPEndPointBasis +#endif // CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK }; } // namespace Inet diff --git a/src/inet/tests/TestInetLayer.cpp b/src/inet/tests/TestInetLayer.cpp index 5a2ca21237d8ca..c57a2ee11f8e5a 100644 --- a/src/inet/tests/TestInetLayer.cpp +++ b/src/inet/tests/TestInetLayer.cpp @@ -641,7 +641,7 @@ static void HandleTCPConnectionReceived(TCPEndPoint * aListenEndPoint, TCPEndPoi // UDP Endpoint Callbacks -static void HandleUDPMessageReceived(IPEndPointBasis * aEndPoint, PacketBufferHandle && aBuffer, const IPPacketInfo * aPacketInfo) +static void HandleUDPMessageReceived(UDPEndPoint * aEndPoint, PacketBufferHandle && aBuffer, const IPPacketInfo * aPacketInfo) { const bool lCheckBuffer = true; bool lStatus; @@ -661,7 +661,7 @@ static void HandleUDPMessageReceived(IPEndPointBasis * aEndPoint, PacketBufferHa } } -static void HandleUDPReceiveError(IPEndPointBasis * aEndPoint, CHIP_ERROR aError, const IPPacketInfo * aPacketInfo) +static void HandleUDPReceiveError(UDPEndPoint * aEndPoint, CHIP_ERROR aError, const IPPacketInfo * aPacketInfo) { Common::HandleUDPReceiveError(aEndPoint, aError, aPacketInfo); diff --git a/src/inet/tests/TestInetLayerCommon.cpp b/src/inet/tests/TestInetLayerCommon.cpp index 609acf9f14ee50..a81916dfc60829 100644 --- a/src/inet/tests/TestInetLayerCommon.cpp +++ b/src/inet/tests/TestInetLayerCommon.cpp @@ -349,8 +349,7 @@ void HandleSendTimerComplete(System::Layer * aSystemLayer, void * aAppState) // Raw Endpoint Callback Handlers -void HandleRawMessageReceived(const IPEndPointBasis * aEndPoint, const PacketBufferHandle & aBuffer, - const IPPacketInfo * aPacketInfo) +void HandleRawMessageReceived(const UDPEndPoint * aEndPoint, const PacketBufferHandle & aBuffer, const IPPacketInfo * aPacketInfo) { char lSourceAddressBuffer[INET6_ADDRSTRLEN]; char lDestinationAddressBuffer[INET6_ADDRSTRLEN]; @@ -362,7 +361,7 @@ void HandleRawMessageReceived(const IPEndPointBasis * aEndPoint, const PacketBuf static_cast(aBuffer->DataLength())); } -void HandleRawReceiveError(const IPEndPointBasis * aEndPoint, const CHIP_ERROR & aError, const IPPacketInfo * aPacketInfo) +void HandleRawReceiveError(const UDPEndPoint * aEndPoint, const CHIP_ERROR & aError, const IPPacketInfo * aPacketInfo) { char lAddressBuffer[INET6_ADDRSTRLEN]; @@ -380,8 +379,7 @@ void HandleRawReceiveError(const IPEndPointBasis * aEndPoint, const CHIP_ERROR & // UDP Endpoint Callback Handlers -void HandleUDPMessageReceived(const IPEndPointBasis * aEndPoint, const PacketBufferHandle & aBuffer, - const IPPacketInfo * aPacketInfo) +void HandleUDPMessageReceived(const UDPEndPoint * aEndPoint, const PacketBufferHandle & aBuffer, const IPPacketInfo * aPacketInfo) { char lSourceAddressBuffer[INET6_ADDRSTRLEN]; char lDestinationAddressBuffer[INET6_ADDRSTRLEN]; @@ -393,7 +391,7 @@ void HandleUDPMessageReceived(const IPEndPointBasis * aEndPoint, const PacketBuf lDestinationAddressBuffer, aPacketInfo->DestPort, static_cast(aBuffer->DataLength())); } -void HandleUDPReceiveError(const IPEndPointBasis * aEndPoint, const CHIP_ERROR & aError, const IPPacketInfo * aPacketInfo) +void HandleUDPReceiveError(const UDPEndPoint * aEndPoint, const CHIP_ERROR & aError, const IPPacketInfo * aPacketInfo) { char lAddressBuffer[INET6_ADDRSTRLEN]; uint16_t lSourcePort; diff --git a/src/inet/tests/TestInetLayerCommon.hpp b/src/inet/tests/TestInetLayerCommon.hpp index b90aa0bd6400f8..0d649ed4904832 100644 --- a/src/inet/tests/TestInetLayerCommon.hpp +++ b/src/inet/tests/TestInetLayerCommon.hpp @@ -146,10 +146,9 @@ extern void HandleSendTimerComplete(chip::System::Layer * aSystemLayer, void * a // UDP Endpoint Callback Handlers -extern void HandleUDPMessageReceived(const chip::Inet::IPEndPointBasis * aEndPoint, - const chip::System::PacketBufferHandle & aBuffer, +extern void HandleUDPMessageReceived(const chip::Inet::UDPEndPoint * aEndPoint, const chip::System::PacketBufferHandle & aBuffer, const chip::Inet::IPPacketInfo * aPacketInfo); -extern void HandleUDPReceiveError(const chip::Inet::IPEndPointBasis * aEndPoint, const CHIP_ERROR & aError, +extern void HandleUDPReceiveError(const chip::Inet::UDPEndPoint * aEndPoint, const CHIP_ERROR & aError, const chip::Inet::IPPacketInfo * aPacketInfo); } // namespace Common diff --git a/src/inet/tests/TestInetLayerMulticast.cpp b/src/inet/tests/TestInetLayerMulticast.cpp index eaaf6b429db143..cbde782f5b4a7f 100644 --- a/src/inet/tests/TestInetLayerMulticast.cpp +++ b/src/inet/tests/TestInetLayerMulticast.cpp @@ -589,7 +589,7 @@ static bool HandleDataReceived(const PacketBufferHandle & aBuffer, const IPPacke // UDP Endpoint Callbacks -static void HandleUDPMessageReceived(IPEndPointBasis * aEndPoint, PacketBufferHandle && aBuffer, const IPPacketInfo * aPacketInfo) +static void HandleUDPMessageReceived(UDPEndPoint * aEndPoint, PacketBufferHandle && aBuffer, const IPPacketInfo * aPacketInfo) { const bool lCheckBuffer = true; bool lStatus; @@ -609,7 +609,7 @@ static void HandleUDPMessageReceived(IPEndPointBasis * aEndPoint, PacketBufferHa } } -static void HandleUDPReceiveError(IPEndPointBasis * aEndPoint, CHIP_ERROR aError, const IPPacketInfo * aPacketInfo) +static void HandleUDPReceiveError(UDPEndPoint * aEndPoint, CHIP_ERROR aError, const IPPacketInfo * aPacketInfo) { Common::HandleUDPReceiveError(aEndPoint, aError, aPacketInfo); @@ -719,7 +719,7 @@ static void StartTest() IPAddressType lIPAddressType = IPAddressType::kIPv6; IPVersion lIPVersion = kIPVersion_6; IPAddress lAddress = IPAddress::Any; - IPEndPointBasis * lEndPoint = nullptr; + UDPEndPoint * lEndPoint = nullptr; const bool lUseLoopback = ((gOptFlags & kOptFlagNoLoopback) == 0); CHIP_ERROR lStatus; @@ -803,7 +803,7 @@ static void StartTest() static void CleanupTest() { - IPEndPointBasis * lEndPoint = nullptr; + UDPEndPoint * lEndPoint = nullptr; CHIP_ERROR lStatus; gSendIntervalExpired = false; diff --git a/src/lib/dnssd/minimal_mdns/Server.cpp b/src/lib/dnssd/minimal_mdns/Server.cpp index 8e95b604eb81c5..9800240ea30ca1 100644 --- a/src/lib/dnssd/minimal_mdns/Server.cpp +++ b/src/lib/dnssd/minimal_mdns/Server.cpp @@ -340,7 +340,7 @@ CHIP_ERROR ServerBase::BroadcastSend(chip::System::PacketBufferHandle && data, u return CHIP_NO_ERROR; } -void ServerBase::OnUdpPacketReceived(chip::Inet::IPEndPointBasis * endPoint, chip::System::PacketBufferHandle && buffer, +void ServerBase::OnUdpPacketReceived(chip::Inet::UDPEndPoint * endPoint, chip::System::PacketBufferHandle && buffer, const chip::Inet::IPPacketInfo * info) { ServerBase * srv = static_cast(endPoint->AppState); diff --git a/src/lib/dnssd/minimal_mdns/Server.h b/src/lib/dnssd/minimal_mdns/Server.h index 3c5200d7b29799..c1d07c5ba6f6aa 100644 --- a/src/lib/dnssd/minimal_mdns/Server.h +++ b/src/lib/dnssd/minimal_mdns/Server.h @@ -139,7 +139,7 @@ class ServerBase bool IsListening() const; private: - static void OnUdpPacketReceived(chip::Inet::IPEndPointBasis * endPoint, chip::System::PacketBufferHandle && buffer, + static void OnUdpPacketReceived(chip::Inet::UDPEndPoint * endPoint, chip::System::PacketBufferHandle && buffer, const chip::Inet::IPPacketInfo * info); EndpointInfo * mEndpoints; // possible endpoints, to listen on multiple interfaces diff --git a/src/platform/Zephyr/ThreadStackManagerImpl.cpp b/src/platform/Zephyr/ThreadStackManagerImpl.cpp index 5e37e32da7cbd9..7718ce9c2a68eb 100644 --- a/src/platform/Zephyr/ThreadStackManagerImpl.cpp +++ b/src/platform/Zephyr/ThreadStackManagerImpl.cpp @@ -27,7 +27,7 @@ #include #include -#include +#include #include #include #include @@ -46,13 +46,13 @@ CHIP_ERROR ThreadStackManagerImpl::_InitThreadStack() ReturnErrorOnFailure(GenericThreadStackManagerImpl_OpenThread::DoInit(instance)); - IPEndPointBasis::SetJoinMulticastGroupHandler([](InterfaceId, const IPAddress & address) { + UDPEndPoint::SetJoinMulticastGroupHandler([](InterfaceId, const IPAddress & address) { const otIp6Address otAddress = ToOpenThreadIP6Address(address); const auto otError = otIp6SubscribeMulticastAddress(openthread_get_default_instance(), &otAddress); return MapOpenThreadError(otError); }); - IPEndPointBasis::SetLeaveMulticastGroupHandler([](InterfaceId, const IPAddress & address) { + UDPEndPoint::SetLeaveMulticastGroupHandler([](InterfaceId, const IPAddress & address) { const otIp6Address otAddress = ToOpenThreadIP6Address(address); const auto otError = otIp6UnsubscribeMulticastAddress(openthread_get_default_instance(), &otAddress); return MapOpenThreadError(otError); diff --git a/src/system/SystemPacketBuffer.h b/src/system/SystemPacketBuffer.h index e59e00cba17729..9280e56a43bf0a 100644 --- a/src/system/SystemPacketBuffer.h +++ b/src/system/SystemPacketBuffer.h @@ -845,7 +845,6 @@ namespace chip { namespace Inet { class UDPEndPoint; -class IPEndPointBasis; } // namespace Inet namespace System { @@ -865,7 +864,6 @@ class LwIPPacketBufferView : public PacketBufferHandle */ static struct pbuf * UnsafeGetLwIPpbuf(const PacketBufferHandle & handle) { return PacketBufferHandle::GetLwIPpbuf(handle); } friend class Inet::UDPEndPoint; - friend class Inet::IPEndPointBasis; }; } // namespace System diff --git a/src/transport/SessionManager.h b/src/transport/SessionManager.h index dd76f6ebe8d1c0..5fe4cbd7797ccb 100644 --- a/src/transport/SessionManager.h +++ b/src/transport/SessionManager.h @@ -28,7 +28,6 @@ #include #include -#include #include #include #include diff --git a/src/transport/raw/TCP.h b/src/transport/raw/TCP.h index 3b48aaf4f851d3..75b526c65ffe73 100644 --- a/src/transport/raw/TCP.h +++ b/src/transport/raw/TCP.h @@ -29,7 +29,6 @@ #include #include -#include #include #include #include diff --git a/src/transport/raw/UDP.cpp b/src/transport/raw/UDP.cpp index cfef98cf48b429..88f7546ab642cb 100644 --- a/src/transport/raw/UDP.cpp +++ b/src/transport/raw/UDP.cpp @@ -111,7 +111,7 @@ CHIP_ERROR UDP::SendMessage(const Transport::PeerAddress & address, System::Pack return mUDPEndPoint->SendMsg(&addrInfo, std::move(msgBuf)); } -void UDP::OnUdpReceive(Inet::IPEndPointBasis * endPoint, System::PacketBufferHandle && buffer, const Inet::IPPacketInfo * pktInfo) +void UDP::OnUdpReceive(Inet::UDPEndPoint * endPoint, System::PacketBufferHandle && buffer, const Inet::IPPacketInfo * pktInfo) { CHIP_ERROR err = CHIP_NO_ERROR; UDP * udp = reinterpret_cast(endPoint->AppState); diff --git a/src/transport/raw/UDP.h b/src/transport/raw/UDP.h index e4ed2fb8e2670a..5cc04166b29d9a 100644 --- a/src/transport/raw/UDP.h +++ b/src/transport/raw/UDP.h @@ -28,8 +28,8 @@ #include #include -#include #include +#include #include #include @@ -122,7 +122,7 @@ class DLL_EXPORT UDP : public Base private: // UDP message receive handler. - static void OnUdpReceive(Inet::IPEndPointBasis * endPoint, System::PacketBufferHandle && buffer, + static void OnUdpReceive(Inet::UDPEndPoint * endPoint, System::PacketBufferHandle && buffer, const Inet::IPPacketInfo * pktInfo); Inet::UDPEndPoint * mUDPEndPoint = nullptr; ///< UDP socket used by the transport