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