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