blob: e6ff19e044e30f62b83a292cde6e6454dc67ed15 [file] [log] [blame]
/*
*
* Copyright (c) 2020-2021 Project CHIP Authors
* Copyright (c) 2018 Google LLC.
* Copyright (c) 2013-2018 Nest Labs, Inc.
*
* 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 file implements the <tt>Inet::UDPEndPoint</tt>
* class, where the CHIP Inet Layer encapsulates methods for
* interacting with UDP transport endpoints (SOCK_DGRAM sockets
* on Linux and BSD-derived systems) or LwIP UDP protocol
* control blocks, as the system is configured accordingly.
*
*/
#define __APPLE_USE_RFC_3542
#include "UDPEndPoint.h"
#include "InetFaultInjection.h"
#include <inet/InetLayer.h>
#include <lib/support/CodeUtils.h>
#include <lib/support/logging/CHIPLogging.h>
#include <system/SystemFaultInjection.h>
#if CHIP_SYSTEM_CONFIG_USE_LWIP
#include <lwip/ip.h>
#include <lwip/tcpip.h>
#include <lwip/udp.h>
#if CHIP_HAVE_CONFIG_H
#include <lwip/lwip_buildconfig.h> // nogncheck
#endif // CHIP_HAVE_CONFIG_H
#endif // CHIP_SYSTEM_CONFIG_USE_LWIP
#if CHIP_SYSTEM_CONFIG_USE_SOCKETS
#if HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif // HAVE_SYS_SOCKET_H
#include <errno.h>
#include <net/if.h>
#include <netinet/in.h>
#include <unistd.h>
// SOCK_CLOEXEC not defined on all platforms, e.g. iOS/macOS:
#ifndef SOCK_CLOEXEC
#define SOCK_CLOEXEC 0
#endif
#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
#include "arpa-inet-compatibility.h"
#include <string.h>
#include <utility>
namespace chip {
namespace Inet {
chip::System::ObjectPool<UDPEndPoint, INET_CONFIG_NUM_UDP_ENDPOINTS> UDPEndPoint::sPool;
#if CHIP_SYSTEM_CONFIG_USE_LWIP
namespace {
/*
* Note that for LwIP InterfaceId is already defined to be 'struct
* netif'; consequently, some of the checking performed here could
* conceivably be optimized out and the HAVE_LWIP_UDP_BIND_NETIF case
* could simply be:
*
* udp_bind_netif(aUDP, intfId);
*
*/
CHIP_ERROR LwIPBindInterface(struct udp_pcb * aUDP, InterfaceId intfId)
{
CHIP_ERROR res = CHIP_NO_ERROR;
#if HAVE_LWIP_UDP_BIND_NETIF
if (!IsInterfaceIdPresent(intfId))
udp_bind_netif(aUDP, NULL);
else
{
struct netif * netifp = IPEndPointBasis::FindNetifFromInterfaceId(intfId);
if (netifp == NULL)
res = INET_ERROR_UNKNOWN_INTERFACE;
else
udp_bind_netif(aUDP, netifp);
}
#else
if (!IsInterfaceIdPresent(intfId))
aUDP->intf_filter = NULL;
else
{
struct netif * netifp = IPEndPointBasis::FindNetifFromInterfaceId(intfId);
if (netifp == NULL)
res = INET_ERROR_UNKNOWN_INTERFACE;
else
aUDP->intf_filter = netifp;
}
#endif // HAVE_LWIP_UDP_BIND_NETIF
return res;
}
} // anonymous namespace
CHIP_ERROR UDPEndPoint::BindImpl(IPAddressType addrType, const IPAddress & addr, uint16_t port, InterfaceId intfId)
{
// Lock LwIP stack
LOCK_TCPIP_CORE();
// Make sure we have the appropriate type of PCB.
CHIP_ERROR res = GetPCB(addrType);
// Bind the PCB to the specified address/port.
if (res == CHIP_NO_ERROR)
{
#if LWIP_VERSION_MAJOR > 1 || LWIP_VERSION_MINOR >= 5
ip_addr_t ipAddr = addr.ToLwIPAddr();
// TODO: IPAddress ANY has only one constant state, however addrType
// has separate IPV4 and IPV6 'any' settings. This tries to correct
// for this as LWIP default if IPv4 is compiled in is to consider
// 'any == any_v4'
//
// We may want to consider having separate AnyV4 and AnyV6 constants
// inside CHIP to resolve this ambiguity
if ((addr.Type() == IPAddressType::kAny) && (addrType == IPAddressType::kIPv6))
{
ipAddr = *IP6_ADDR_ANY;
}
res = chip::System::MapErrorLwIP(udp_bind(mUDP, &ipAddr, port));
#else // LWIP_VERSION_MAJOR <= 1 && LWIP_VERSION_MINOR < 5
if (addrType == IPAddressType::kIPv6)
{
ip6_addr_t ipv6Addr = addr.ToIPv6();
res = chip::System::MapErrorLwIP(udp_bind_ip6(mUDP, &ipv6Addr, port));
}
#if INET_CONFIG_ENABLE_IPV4
else if (addrType == IPAddressType::kIPv4)
{
ip4_addr_t ipv4Addr = addr.ToIPv4();
res = chip::System::MapErrorLwIP(udp_bind(mUDP, &ipv4Addr, port));
}
#endif // INET_CONFIG_ENABLE_IPV4
else
res = INET_ERROR_WRONG_ADDRESS_TYPE;
#endif // LWIP_VERSION_MAJOR <= 1 || LWIP_VERSION_MINOR >= 5
}
if (res == CHIP_NO_ERROR)
{
res = LwIPBindInterface(mUDP, intfId);
}
// Unlock LwIP stack
UNLOCK_TCPIP_CORE();
return res;
}
CHIP_ERROR UDPEndPoint::BindInterfaceImpl(IPAddressType addrType, InterfaceId intfId)
{
// A lock is required because the LwIP thread may be referring to intf_filter,
// while this code running in the Inet application is potentially modifying it.
// NOTE: this only supports LwIP interfaces whose number is no bigger than 9.
LOCK_TCPIP_CORE();
// Make sure we have the appropriate type of PCB.
CHIP_ERROR err = GetPCB(addrType);
if (err == CHIP_NO_ERROR)
{
err = LwIPBindInterface(mUDP, intfId);
}
UNLOCK_TCPIP_CORE();
return err;
}
InterfaceId UDPEndPoint::GetBoundInterface()
{
#if HAVE_LWIP_UDP_BIND_NETIF
return netif_get_by_index(mUDP->netif_idx);
#else
return mUDP->intf_filter;
#endif
}
uint16_t UDPEndPoint::GetBoundPort()
{
return mUDP->local_port;
}
CHIP_ERROR UDPEndPoint::ListenImpl()
{
// Lock LwIP stack
LOCK_TCPIP_CORE();
#if LWIP_VERSION_MAJOR > 1 || LWIP_VERSION_MINOR >= 5
udp_recv(mUDP, LwIPReceiveUDPMessage, this);
#else // LWIP_VERSION_MAJOR <= 1 && LWIP_VERSION_MINOR < 5
if (PCB_ISIPV6(mUDP))
udp_recv_ip6(mUDP, LwIPReceiveUDPMessage, this);
else
udp_recv(mUDP, LwIPReceiveUDPMessage, this);
#endif // LWIP_VERSION_MAJOR <= 1 || LWIP_VERSION_MINOR >= 5
// Unlock LwIP stack
UNLOCK_TCPIP_CORE();
return CHIP_NO_ERROR;
}
CHIP_ERROR UDPEndPoint::SendMsgImpl(const IPPacketInfo * pktInfo, System::PacketBufferHandle && msg)
{
const IPAddress & destAddr = pktInfo->DestAddress;
if (!msg.HasSoleOwnership())
{
// when retaining a buffer, the caller expects the msg to be unmodified.
// LwIP stack will normally prepend the packet headers as the packet traverses
// the UDP/IP/netif layers, which normally modifies the packet. We need to clone
// msg into a fresh object in this case, and queues that for transmission, leaving
// the original msg available after return.
msg = msg.CloneData();
VerifyOrReturnError(!msg.IsNull(), CHIP_ERROR_NO_MEMORY);
}
// Lock LwIP stack
LOCK_TCPIP_CORE();
// Make sure we have the appropriate type of PCB based on the destination address.
CHIP_ERROR res = GetPCB(destAddr.Type());
if (res != CHIP_NO_ERROR)
{
UNLOCK_TCPIP_CORE();
return res;
}
// Send the message to the specified address/port.
// If an outbound interface has been specified, call a specific version of the UDP sendto()
// function that accepts the target interface.
// If a source address has been specified, temporarily override the local_ip of the PCB.
// This results in LwIP using the given address being as the source address for the generated
// packet, as if the PCB had been bound to that address.
err_t lwipErr = ERR_VAL;
const IPAddress & srcAddr = pktInfo->SrcAddress;
const uint16_t & destPort = pktInfo->DestPort;
const InterfaceId & intfId = pktInfo->Interface;
#if LWIP_VERSION_MAJOR > 1 || LWIP_VERSION_MINOR >= 5
ip_addr_t lwipSrcAddr = srcAddr.ToLwIPAddr();
ip_addr_t lwipDestAddr = destAddr.ToLwIPAddr();
ip_addr_t boundAddr;
ip_addr_copy(boundAddr, mUDP->local_ip);
if (!ip_addr_isany(&lwipSrcAddr))
{
ip_addr_copy(mUDP->local_ip, lwipSrcAddr);
}
if (intfId != INET_NULL_INTERFACEID)
lwipErr = udp_sendto_if(mUDP, System::LwIPPacketBufferView::UnsafeGetLwIPpbuf(msg), &lwipDestAddr, destPort, intfId);
else
lwipErr = udp_sendto(mUDP, System::LwIPPacketBufferView::UnsafeGetLwIPpbuf(msg), &lwipDestAddr, destPort);
ip_addr_copy(mUDP->local_ip, boundAddr);
#else // LWIP_VERSION_MAJOR <= 1 && LWIP_VERSION_MINOR < 5
ipX_addr_t boundAddr;
ipX_addr_copy(boundAddr, mUDP->local_ip);
if (PCB_ISIPV6(mUDP))
{
ip6_addr_t lwipSrcAddr = srcAddr.ToIPv6();
ip6_addr_t lwipDestAddr = destAddr.ToIPv6();
if (!ip6_addr_isany(&lwipSrcAddr))
{
ipX_addr_copy(mUDP->local_ip, *ip6_2_ipX(&lwipSrcAddr));
}
if (intfId != INET_NULL_INTERFACEID)
lwipErr =
udp_sendto_if_ip6(mUDP, System::LwIPPacketBufferView::UnsafeGetLwIPpbuf(msg), &lwipDestAddr, destPort, intfId);
else
lwipErr = udp_sendto_ip6(mUDP, System::LwIPPacketBufferView::UnsafeGetLwIPpbuf(msg), &lwipDestAddr, destPort);
}
#if INET_CONFIG_ENABLE_IPV4
else
{
ip4_addr_t lwipSrcAddr = srcAddr.ToIPv4();
ip4_addr_t lwipDestAddr = destAddr.ToIPv4();
ipX_addr_t boundAddr;
if (!ip_addr_isany(&lwipSrcAddr))
{
ipX_addr_copy(mUDP->local_ip, *ip_2_ipX(&lwipSrcAddr));
}
if (intfId != INET_NULL_INTERFACEID)
lwipErr = udp_sendto_if(mUDP, System::LwIPPacketBufferView::UnsafeGetLwIPpbuf(msg), &lwipDestAddr, destPort, intfId);
else
lwipErr = udp_sendto(mUDP, System::LwIPPacketBufferView::UnsafeGetLwIPpbuf(msg), &lwipDestAddr, destPort);
}
ipX_addr_copy(mUDP->local_ip, boundAddr);
#endif // INET_CONFIG_ENABLE_IPV4
#endif // LWIP_VERSION_MAJOR <= 1 || LWIP_VERSION_MINOR >= 5
// Unlock LwIP stack
UNLOCK_TCPIP_CORE();
if (lwipErr != ERR_OK)
res = chip::System::MapErrorLwIP(lwipErr);
return res;
}
void UDPEndPoint::CloseImpl()
{
// Lock LwIP stack
LOCK_TCPIP_CORE();
// Since UDP PCB is released synchronously here, but UDP endpoint itself might have to wait
// for destruction asynchronously, there could be more allocated UDP endpoints than UDP PCBs.
if (mUDP != NULL)
{
udp_remove(mUDP);
mUDP = NULL;
mLwIPEndPointType = LwIPEndPointType::Unknown;
}
// Unlock LwIP stack
UNLOCK_TCPIP_CORE();
}
void UDPEndPoint::Free()
{
Close();
DeferredFree(kReleaseDeferralErrorTactic_Die);
}
void UDPEndPoint::HandleDataReceived(System::PacketBufferHandle && msg)
{
IPEndPointBasis::HandleDataReceived(std::move(msg));
}
CHIP_ERROR UDPEndPoint::GetPCB(IPAddressType addrType)
{
// IMPORTANT: This method MUST be called with the LwIP stack LOCKED!
// If a PCB hasn't been allocated yet...
if (mUDP == NULL)
{
// Allocate a PCB of the appropriate type.
if (addrType == IPAddressType::kIPv6)
{
#if LWIP_VERSION_MAJOR > 1 || LWIP_VERSION_MINOR >= 5
mUDP = udp_new_ip_type(IPADDR_TYPE_V6);
#else // LWIP_VERSION_MAJOR <= 1 && LWIP_VERSION_MINOR < 5
mUDP = udp_new_ip6();
#endif // LWIP_VERSION_MAJOR <= 1 || LWIP_VERSION_MINOR >= 5
}
#if INET_CONFIG_ENABLE_IPV4
else if (addrType == IPAddressType::kIPv4)
{
#if LWIP_VERSION_MAJOR > 1 || LWIP_VERSION_MINOR >= 5
mUDP = udp_new_ip_type(IPADDR_TYPE_V4);
#else // LWIP_VERSION_MAJOR <= 1 && LWIP_VERSION_MINOR < 5
mUDP = udp_new();
#endif // LWIP_VERSION_MAJOR <= 1 || LWIP_VERSION_MINOR >= 5
}
#endif // INET_CONFIG_ENABLE_IPV4
else
{
return INET_ERROR_WRONG_ADDRESS_TYPE;
}
// Fail if the system has run out of PCBs.
if (mUDP == NULL)
{
ChipLogError(Inet, "Unable to allocate UDP PCB");
return CHIP_ERROR_NO_MEMORY;
}
// Allow multiple bindings to the same port.
ip_set_option(mUDP, SOF_REUSEADDR);
}
// Otherwise, verify that the existing PCB is the correct type...
else
{
IPAddressType pcbAddrType;
// Get the address type of the existing PCB.
#if LWIP_VERSION_MAJOR > 1 || LWIP_VERSION_MINOR >= 5
switch (static_cast<lwip_ip_addr_type>(IP_GET_TYPE(&mUDP->local_ip)))
{
case IPADDR_TYPE_V6:
pcbAddrType = IPAddressType::kIPv6;
break;
#if INET_CONFIG_ENABLE_IPV4
case IPADDR_TYPE_V4:
pcbAddrType = IPAddressType::kIPv4;
break;
#endif // INET_CONFIG_ENABLE_IPV4
default:
return INET_ERROR_WRONG_ADDRESS_TYPE;
}
#else // LWIP_VERSION_MAJOR <= 1 && LWIP_VERSION_MINOR < 5
#if INET_CONFIG_ENABLE_IPV4
pcbAddrType = PCB_ISIPV6(mUDP) ? IPAddressType::kIPv6 : IPAddressType::kIPv4;
#else // !INET_CONFIG_ENABLE_IPV4
pcbAddrType = IPAddressType::kIPv6;
#endif // !INET_CONFIG_ENABLE_IPV4
#endif // LWIP_VERSION_MAJOR <= 1 && LWIP_VERSION_MINOR < 5
// Fail if the existing PCB is not the correct type.
VerifyOrReturnError(addrType == pcbAddrType, INET_ERROR_WRONG_ADDRESS_TYPE);
}
return CHIP_NO_ERROR;
}
#if LWIP_VERSION_MAJOR > 1 || LWIP_VERSION_MINOR >= 5
void UDPEndPoint::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
void UDPEndPoint::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
{
UDPEndPoint * ep = static_cast<UDPEndPoint *>(arg);
System::LayerLwIP * lSystemLayer = static_cast<System::LayerLwIP *>(ep->Layer().SystemLayer());
IPPacketInfo * pktInfo = NULL;
System::PacketBufferHandle buf = System::PacketBufferHandle::Adopt(p);
if (buf->HasChainedBuffer())
{
// Try the simple expedient of flattening in-place.
buf->CompactHead();
}
if (buf->HasChainedBuffer())
{
// Have to allocate a new big-enough buffer and copy.
uint16_t messageSize = buf->TotalLength();
System::PacketBufferHandle copy = System::PacketBufferHandle::New(messageSize, 0);
if (copy.IsNull() || buf->Read(copy->Start(), messageSize) != CHIP_NO_ERROR)
{
ChipLogError(Inet, "No memory to flatten incoming packet buffer chain of size %" PRIu16, buf->TotalLength());
return;
}
buf = std::move(copy);
}
pktInfo = GetPacketInfo(buf);
if (pktInfo != NULL)
{
#if LWIP_VERSION_MAJOR > 1 || LWIP_VERSION_MINOR >= 5
pktInfo->SrcAddress = IPAddress(*addr);
pktInfo->DestAddress = IPAddress(*ip_current_dest_addr());
#else // LWIP_VERSION_MAJOR <= 1
if (PCB_ISIPV6(pcb))
{
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->DestAddress = IPAddress(*ip_current_dest_addr());
}
#endif // INET_CONFIG_ENABLE_IPV4
#endif // LWIP_VERSION_MAJOR <= 1
pktInfo->Interface = ip_current_netif();
pktInfo->SrcPort = port;
pktInfo->DestPort = pcb->local_port;
}
const CHIP_ERROR error =
lSystemLayer->PostEvent(*ep, kInetEvent_UDPDataReceived, (uintptr_t) System::LwIPPacketBufferView::UnsafeGetLwIPpbuf(buf));
if (error == CHIP_NO_ERROR)
{
// If PostEvent() succeeded, it has ownership of the buffer, so we need to release it (without freeing it).
static_cast<void>(std::move(buf).UnsafeRelease());
}
}
#endif // CHIP_SYSTEM_CONFIG_USE_LWIP
#if CHIP_SYSTEM_CONFIG_USE_SOCKETS
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));
mBoundPort = port;
mBoundIntfId = intfId;
// If an ephemeral port was requested, retrieve the actual bound port.
if (port == 0)
{
SockAddr boundAddr;
socklen_t boundAddrLen = sizeof(boundAddr);
if (getsockname(mSocket, &boundAddr.any, &boundAddrLen) == 0)
{
if (boundAddr.any.sa_family == AF_INET)
{
mBoundPort = ntohs(boundAddr.in.sin_port);
}
else if (boundAddr.any.sa_family == AF_INET6)
{
mBoundPort = ntohs(boundAddr.in6.sin6_port);
}
}
}
#if CHIP_SYSTEM_CONFIG_USE_DISPATCH
dispatch_queue_t dispatchQueue = static_cast<System::LayerSocketsLoop *>(Layer().SystemLayer())->GetDispatchQueue();
if (dispatchQueue != nullptr)
{
unsigned long fd = static_cast<unsigned long>(mSocket);
mReadableSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, fd, 0, dispatchQueue);
ReturnErrorCodeIf(mReadableSource == nullptr, CHIP_ERROR_NO_MEMORY);
dispatch_source_set_event_handler(mReadableSource, ^{
this->HandlePendingIO(System::SocketEventFlags::kRead);
});
dispatch_resume(mReadableSource);
}
#endif // CHIP_SYSTEM_CONFIG_USE_DISPATCH
return CHIP_NO_ERROR;
}
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);
}
InterfaceId UDPEndPoint::GetBoundInterface()
{
return mBoundIntfId;
}
uint16_t UDPEndPoint::GetBoundPort()
{
return mBoundPort;
}
CHIP_ERROR UDPEndPoint::ListenImpl()
{
// Wait for ability to read on this endpoint.
auto layer = static_cast<System::LayerSockets *>(Layer().SystemLayer());
ReturnErrorOnFailure(layer->SetCallback(mWatch, HandlePendingIO, reinterpret_cast<intptr_t>(this)));
return layer->RequestCallbackOnPendingRead(mWatch);
}
CHIP_ERROR UDPEndPoint::SendMsgImpl(const IPPacketInfo * pktInfo, System::PacketBufferHandle && msg)
{
// Make sure we have the appropriate type of socket based on the
// destination address.
ReturnErrorOnFailure(GetSocket(pktInfo->DestAddress.Type()));
return IPEndPointBasis::SendMsg(pktInfo, std::move(msg));
}
void UDPEndPoint::CloseImpl()
{
if (mSocket != kInvalidSocketFd)
{
static_cast<System::LayerSockets *>(Layer().SystemLayer())->StopWatchingSocket(&mWatch);
close(mSocket);
mSocket = kInvalidSocketFd;
}
#if CHIP_SYSTEM_CONFIG_USE_DISPATCH
if (mReadableSource)
{
dispatch_source_cancel(mReadableSource);
dispatch_release(mReadableSource);
}
#endif // CHIP_SYSTEM_CONFIG_USE_DISPATCH
}
void UDPEndPoint::Free()
{
Close();
Release();
}
CHIP_ERROR UDPEndPoint::GetSocket(IPAddressType aAddressType)
{
constexpr int lType = (SOCK_DGRAM | SOCK_CLOEXEC);
constexpr int lProtocol = 0;
return IPEndPointBasis::GetSocket(aAddressType, lType, lProtocol);
}
// static
void UDPEndPoint::HandlePendingIO(System::SocketEvents events, intptr_t data)
{
reinterpret_cast<UDPEndPoint *>(data)->HandlePendingIO(events);
}
void UDPEndPoint::HandlePendingIO(System::SocketEvents events)
{
if (mState == State::kListening && OnMessageReceived != nullptr && events.Has(System::SocketEventFlags::kRead))
{
const uint16_t lPort = mBoundPort;
IPEndPointBasis::HandlePendingIO(lPort);
}
}
#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 != INET_NULL_INTERFACEID)
{
return CHIP_ERROR_NOT_IMPLEMENTED;
}
configure_tls = NW_PARAMETERS_DISABLE_PROTOCOL;
parameters = nw_parameters_create_secure_udp(configure_tls, NW_PARAMETERS_DEFAULT_CONFIGURATION);
ReturnErrorOnFailure(IPEndPointBasis::Bind(addrType, addr, port, parameters));
mParameters = parameters;
return CHIP_NO_ERROR;
}
CHIP_ERROR UDPEndPoint::BindInterfaceImpl(IPAddressType addrType, InterfaceId intfId)
{
return INET_ERROR_UNKNOWN_INTERFACE;
}
InterfaceId UDPEndPoint::GetBoundInterface()
{
return INET_NULL_INTERFACEID;
}
uint16_t UDPEndPoint::GetBoundPort()
{
nw_endpoint_t endpoint = nw_parameters_copy_local_endpoint(mParameters);
return nw_endpoint_get_port(endpoint);
}
CHIP_ERROR UDPEndPoint::ListenImpl()
{
return StartListener();
}
CHIP_ERROR UDPEndPoint::SendMsgImpl(const IPPacketInfo * pktInfo, System::PacketBufferHandle && msg)
{
return IPEndPointBasis::SendMsg(pktInfo, std::move(msg));
}
void UDPEndPoint::CloseImpl()
{
IPEndPointBasis::ReleaseAll();
}
void UDPEndPoint::Free()
{
Close();
Release();
}
#endif // CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK
CHIP_ERROR UDPEndPoint::Bind(IPAddressType addrType, const IPAddress & addr, uint16_t port, InterfaceId intfId)
{
if (mState != State::kReady && mState != State::kBound)
{
return CHIP_ERROR_INCORRECT_STATE;
}
if ((addr != IPAddress::Any) && (addr.Type() != IPAddressType::kAny) && (addr.Type() != addrType))
{
return INET_ERROR_WRONG_ADDRESS_TYPE;
}
ReturnErrorOnFailure(BindImpl(addrType, addr, port, intfId));
mState = State::kBound;
return CHIP_NO_ERROR;
}
CHIP_ERROR UDPEndPoint::BindInterface(IPAddressType addrType, InterfaceId intfId)
{
if (mState != State::kReady && mState != State::kBound)
{
return CHIP_ERROR_INCORRECT_STATE;
}
ReturnErrorOnFailure(BindInterfaceImpl(addrType, intfId));
mState = State::kBound;
return CHIP_NO_ERROR;
}
CHIP_ERROR UDPEndPoint::Listen(OnMessageReceivedFunct onMessageReceived, OnReceiveErrorFunct onReceiveError, void * appState)
{
if (mState == State::kListening)
{
return CHIP_NO_ERROR;
}
if (mState != State::kBound)
{
return CHIP_ERROR_INCORRECT_STATE;
}
OnMessageReceived = onMessageReceived;
OnReceiveError = onReceiveError;
AppState = appState;
ReturnErrorOnFailure(ListenImpl());
mState = State::kListening;
return CHIP_NO_ERROR;
}
CHIP_ERROR UDPEndPoint::SendTo(const IPAddress & addr, uint16_t port, chip::System::PacketBufferHandle && msg, InterfaceId intfId)
{
IPPacketInfo pktInfo;
pktInfo.Clear();
pktInfo.DestAddress = addr;
pktInfo.DestPort = port;
pktInfo.Interface = intfId;
return SendMsg(&pktInfo, std::move(msg));
}
CHIP_ERROR UDPEndPoint::SendMsg(const IPPacketInfo * pktInfo, System::PacketBufferHandle && msg)
{
INET_FAULT_INJECT(FaultInjection::kFault_Send, return INET_ERROR_UNKNOWN_INTERFACE;);
INET_FAULT_INJECT(FaultInjection::kFault_SendNonCritical, return CHIP_ERROR_NO_MEMORY;);
ReturnErrorOnFailure(SendMsgImpl(pktInfo, std::move(msg)));
CHIP_SYSTEM_FAULT_INJECT_ASYNC_EVENT();
return CHIP_NO_ERROR;
}
void UDPEndPoint::Close()
{
if (mState != State::kClosed)
{
CloseImpl();
mState = State::kClosed;
}
}
void UDPEndPoint::Init(InetLayer * inetLayer)
{
IPEndPointBasis::Init(inetLayer);
}
} // namespace Inet
} // namespace chip