blob: b2ecc923a898bf9b5081c8fa75717cbceff4ed86 [file]
/*
* Copyright (c) 2016, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* This file includes definitions for UDP/IPv6 sockets.
*/
#ifndef OT_CORE_NET_UDP6_HPP_
#define OT_CORE_NET_UDP6_HPP_
#include "openthread-core-config.h"
#include <openthread/udp.h>
#include <openthread/platform/udp.h>
#include "common/as_core_type.hpp"
#include "common/callback.hpp"
#include "common/clearable.hpp"
#include "common/linked_list.hpp"
#include "common/locator.hpp"
#include "common/message_allocator.hpp"
#include "common/non_copyable.hpp"
#include "net/ip6_headers.hpp"
namespace ot {
namespace Ip6 {
class Udp;
/**
* @addtogroup core-udp
*
* @brief
* This module includes definitions for UDP/IPv6 sockets.
*
* @{
*/
#if OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE && OPENTHREAD_CONFIG_UDP_FORWARD_ENABLE
#error "OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE and OPENTHREAD_CONFIG_UDP_FORWARD_ENABLE must not both be set."
#endif
/**
* Defines the network interface identifiers.
*/
enum NetifIdentifier : uint8_t
{
kNetifUnspecified = OT_NETIF_UNSPECIFIED, ///< Unspecified network interface.
kNetifThreadHost = OT_NETIF_THREAD_HOST, ///< The host Thread interface - allow use of platform UDP.
kNetifThreadInternal = OT_NETIF_THREAD_INTERNAL, ///< The internal Thread interface - do not use platform UDP.
kNetifBackbone = OT_NETIF_BACKBONE, ///< The Backbone interface.
};
/**
* Implements core UDP message handling.
*/
class Udp : public InstanceLocator, public MessageAllocator<Udp, ReservedHeaderSize::kUdpMessage>, private NonCopyable
{
public:
typedef UdpHeader Header; ///< UDP header.
typedef otUdpReceive ReceiveHandler; ///< Receive handler callback.
/**
* Implements a UDP/IPv6 socket.
*/
class SocketHandle : public otUdpSocket, public LinkedListEntry<SocketHandle>, public Clearable<SocketHandle>
{
friend class Udp;
friend class LinkedList<SocketHandle>;
public:
/**
* Indicates whether or not the socket is bound.
*
* @retval TRUE if the socket is bound (i.e. source port is non-zero).
* @retval FALSE if the socket is not bound (source port is zero).
*/
bool IsBound(void) const { return mSockName.mPort != 0; }
/**
* Returns the local socket address.
*
* @returns A reference to the local socket address.
*/
SockAddr &GetSockName(void) { return AsCoreType(&mSockName); }
/**
* Returns the local socket address.
*
* @returns A reference to the local socket address.
*/
const SockAddr &GetSockName(void) const { return AsCoreType(&mSockName); }
/**
* Returns the peer's socket address.
*
* @returns A reference to the peer's socket address.
*/
SockAddr &GetPeerName(void) { return AsCoreType(&mPeerName); }
/**
* Returns the peer's socket address.
*
* @returns A reference to the peer's socket address.
*/
const SockAddr &GetPeerName(void) const { return AsCoreType(&mPeerName); }
/**
* Returns the network interface identifier.
*
* @returns The network interface identifier.
*/
NetifIdentifier GetNetifId(void) const { return static_cast<NetifIdentifier>(mNetifId); }
/**
* Sets the network interface identifier.
*
* @param[in] aNetifId The network interface identifier.
*/
void SetNetifId(NetifIdentifier aNetifId) { mNetifId = static_cast<otNetifIdentifier>(aNetifId); }
/**
* Indicates whether or not the socket can use platform UDP.
*
* @retval TRUE This socket should use platform UDP.
* @retval FALSE This socket is associated with the internal Thread interface and should not use platform UDP.
*/
bool ShouldUsePlatformUdp(void) const { return GetNetifId() != kNetifThreadInternal; }
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
/**
* Indicate whether or not the socket is bound to the backbone network interface.
*
* @retval TRUE This is a backbone socket.
* @retval FALSE This is not a backbone socket.
*/
bool IsBackbone(void) const { return (GetNetifId() == kNetifBackbone); }
#endif
private:
bool Matches(uint16_t aSockPort) const { return GetSockName().GetPort() == aSockPort; }
bool Matches(const MessageInfo &aMessageInfo) const;
void HandleUdpReceive(Message &aMessage, const MessageInfo &aMessageInfo)
{
mHandler(mContext, &aMessage, &aMessageInfo);
}
};
/**
* Implements a UDP/IPv6 socket.
*/
class Socket : public InstanceLocator,
public SocketHandle,
public MessageAllocator<Socket, ReservedHeaderSize::kUdpMessage>
{
friend class Udp;
public:
/**
* Initializes the object.
*
* @param[in] aInstance A reference to OpenThread instance.
* @param[in] aHandler A pointer to a function that is called when receiving UDP messages.
* @param[in] aContext A pointer to arbitrary context information.
*/
Socket(Instance &aInstance, ReceiveHandler aHandler, void *aContext);
/**
* Opens the UDP socket.
*
* @param[in] aNetifId The network interface identifier.
*
* @retval kErrorNone Successfully opened the socket.
* @retval kErrorFailed Failed to open the socket.
*/
Error Open(NetifIdentifier aNetifId);
/**
* Returns if the UDP socket is open.
*
* @returns If the UDP socket is open.
*/
bool IsOpen(void) const;
/**
* Binds the UDP socket.
*
* @param[in] aSockAddr A reference to the socket address.
*
* @retval kErrorNone Successfully bound the socket.
* @retval kErrorInvalidArgs Unable to bind to Thread network interface with the given address.
* @retval kErrorFailed Failed to bind UDP Socket.
*/
Error Bind(const SockAddr &aSockAddr);
/**
* Binds the UDP socket.
*
* @param[in] aPort A port number.
*
* @retval kErrorNone Successfully bound the socket.
* @retval kErrorFailed Failed to bind UDP Socket.
*/
Error Bind(uint16_t aPort);
/**
* Binds the UDP socket.
*
* @retval kErrorNone Successfully bound the socket.
* @retval kErrorFailed Failed to bind UDP Socket.
*/
Error Bind(void) { return Bind(0); }
/**
* Connects the UDP socket.
*
* @param[in] aSockAddr A reference to the socket address.
*
* @retval kErrorNone Successfully connected the socket.
* @retval kErrorFailed Failed to connect UDP Socket.
*/
Error Connect(const SockAddr &aSockAddr);
/**
* Connects the UDP socket.
*
* @param[in] aPort A port number.
*
* @retval kErrorNone Successfully connected the socket.
* @retval kErrorFailed Failed to connect UDP Socket.
*/
Error Connect(uint16_t aPort);
/**
* Connects the UDP socket.
*
* @retval kErrorNone Successfully connected the socket.
* @retval kErrorFailed Failed to connect UDP Socket.
*/
Error Connect(void) { return Connect(0); }
/**
* Closes the UDP socket.
*
* @retval kErrorNone Successfully closed the UDP socket.
* @retval kErrorFailed Failed to close UDP Socket.
*/
Error Close(void);
/**
* Sends a UDP message.
*
* @param[in] aMessage The message to send.
* @param[in] aMessageInfo The message info associated with @p aMessage.
*
* @retval kErrorNone Successfully sent the UDP message.
* @retval kErrorInvalidArgs If no peer is specified in @p aMessageInfo or by Connect().
* @retval kErrorNoBufs Insufficient available buffer to add the UDP and IPv6 headers.
*/
Error SendTo(Message &aMessage, const MessageInfo &aMessageInfo);
#if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
/**
* Configures the UDP socket to join a multicast group on a Host network interface.
*
* @param[in] aNetifIdentifier The network interface identifier.
* @param[in] aAddress The multicast group address.
*
* @retval kErrorNone Successfully joined the multicast group.
* @retval kErrorFailed Failed to join the multicast group.
*/
Error JoinNetifMulticastGroup(NetifIdentifier aNetifIdentifier, const Address &aAddress);
/**
* Configures the UDP socket to leave a multicast group on a Host network interface.
*
* @param[in] aNetifIdentifier The network interface identifier.
* @param[in] aAddress The multicast group address.
*
* @retval kErrorNone Successfully left the multicast group.
* @retval kErrorFailed Failed to leave the multicast group.
*/
Error LeaveNetifMulticastGroup(NetifIdentifier aNetifIdentifier, const Address &aAddress);
#endif
};
/**
* A socket owned by a specific type with a given owner type as the callback.
*
* @tparam Owner The type of the owner of this socket.
* @tparam HandleUdpReceivePtr A pointer to a non-static member method of `Owner` to handle received messages.
*/
template <typename Owner, void (Owner::*HandleUdpReceivePtr)(Message &aMessage, const MessageInfo &aMessageInfo)>
class SocketIn : public Socket
{
public:
/**
* Initializes the socket.
*
* @param[in] aInstance The OpenThread instance.
* @param[in] aOnwer The owner of the socket, providing the `HandleUdpReceivePtr` callback.
*/
explicit SocketIn(Instance &aInstance, Owner &aOwner)
: Socket(aInstance, HandleUdpReceive, &aOwner)
{
}
private:
static void HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo)
{
(reinterpret_cast<Owner *>(aContext)->*HandleUdpReceivePtr)(AsCoreType(aMessage), AsCoreType(aMessageInfo));
}
};
/**
* Implements a UDP receiver.
*/
class Receiver : public otUdpReceiver, public LinkedListEntry<Receiver>
{
friend class Udp;
public:
/**
* Initializes the UDP receiver.
*
* @param[in] aHandler A pointer to the function to handle UDP message.
* @param[in] aContext A pointer to arbitrary context information.
*/
Receiver(otUdpHandler aHandler, void *aContext)
{
mNext = nullptr;
mHandler = aHandler;
mContext = aContext;
}
private:
bool HandleMessage(Message &aMessage, const MessageInfo &aMessageInfo)
{
return mHandler(mContext, &aMessage, &aMessageInfo);
}
};
/**
* Initializes the object.
*
* @param[in] aInstance A reference to OpenThread instance.
*/
explicit Udp(Instance &aInstance);
/**
* Adds a UDP receiver.
*
* @param[in] aReceiver A reference to the UDP receiver.
*
* @retval kErrorNone Successfully added the UDP receiver.
* @retval kErrorAlready The UDP receiver was already added.
*/
Error AddReceiver(Receiver &aReceiver);
/**
* Removes a UDP receiver.
*
* @param[in] aReceiver A reference to the UDP receiver.
*
* @retval kErrorNone Successfully removed the UDP receiver.
* @retval kErrorNotFound The UDP receiver was not added.
*/
Error RemoveReceiver(Receiver &aReceiver);
/**
* Opens a UDP socket.
*
* @param[in] aSocket A reference to the socket.
* @param[in] aNetifId A network interface identifier.
* @param[in] aHandler A pointer to a function that is called when receiving UDP messages.
* @param[in] aContext A pointer to arbitrary context information.
*
* @retval kErrorNone Successfully opened the socket.
* @retval kErrorFailed Failed to open the socket.
*/
Error Open(SocketHandle &aSocket, NetifIdentifier aNetifId, ReceiveHandler aHandler, void *aContext);
/**
* Returns if a UDP socket is open.
*
* @param[in] aSocket A reference to the socket.
*
* @returns If the UDP socket is open.
*/
bool IsOpen(const SocketHandle &aSocket) const { return mSockets.Contains(aSocket); }
/**
* Binds a UDP socket.
*
* @param[in] aSocket A reference to the socket.
* @param[in] aSockAddr A reference to the socket address.
*
* @retval kErrorNone Successfully bound the socket.
* @retval kErrorInvalidArgs Unable to bind to Thread network interface with the given address.
* @retval kErrorFailed Failed to bind UDP Socket.
*/
Error Bind(SocketHandle &aSocket, const SockAddr &aSockAddr);
/**
* Connects a UDP socket.
*
* @param[in] aSocket A reference to the socket.
* @param[in] aSockAddr A reference to the socket address.
*
* @retval kErrorNone Successfully connected the socket.
* @retval kErrorFailed Failed to connect UDP Socket.
*/
Error Connect(SocketHandle &aSocket, const SockAddr &aSockAddr);
/**
* Closes the UDP socket.
*
* @param[in] aSocket A reference to the socket.
*
* @retval kErrorNone Successfully closed the UDP socket.
* @retval kErrorFailed Failed to close UDP Socket.
*/
Error Close(SocketHandle &aSocket);
/**
* Sends a UDP message using a socket.
*
* @param[in] aSocket A reference to the socket.
* @param[in] aMessage The message to send.
* @param[in] aMessageInfo The message info associated with @p aMessage.
*
* @retval kErrorNone Successfully sent the UDP message.
* @retval kErrorInvalidArgs If no peer is specified in @p aMessageInfo or by Connect().
* @retval kErrorNoBufs Insufficient available buffer to add the UDP and IPv6 headers.
*/
Error SendTo(SocketHandle &aSocket, Message &aMessage, const MessageInfo &aMessageInfo);
/**
* Returns a new ephemeral port.
*
* @returns A new ephemeral port.
*/
uint16_t GetEphemeralPort(void);
/**
* Sends an IPv6 datagram.
*
* @param[in] aMessage A reference to the message.
* @param[in] aMessageInfo A reference to the message info associated with @p aMessage.
*
* @retval kErrorNone Successfully enqueued the message into an output interface.
* @retval kErrorNoBufs Insufficient available buffer to add the IPv6 headers.
*/
Error SendDatagram(Message &aMessage, MessageInfo &aMessageInfo);
/**
* Handles a received UDP message.
*
* @param[in] aMessage A reference to the UDP message to process.
* @param[in] aMessageInfo A reference to the message info associated with @p aMessage.
*
* @retval kErrorNone Successfully processed the UDP message.
* @retval kErrorDrop Could not fully process the UDP message.
*/
Error HandleMessage(Message &aMessage, MessageInfo &aMessageInfo);
/**
* Handles a received UDP message with offset set to the payload.
*
* @param[in] aMessage A reference to the UDP message to process.
* @param[in] aMessageInfo A reference to the message info associated with @p aMessage.
*/
void HandlePayload(Message &aMessage, MessageInfo &aMessageInfo);
/**
* Returns the head of UDP Sockets list.
*
* @returns A pointer to the head of UDP Socket linked list.
*/
SocketHandle *GetUdpSockets(void) { return mSockets.GetHead(); }
#if OPENTHREAD_CONFIG_UDP_FORWARD_ENABLE
/**
* Sets the forward sender.
*
* @param[in] aForwarder A function pointer to forward UDP packets.
* @param[in] aContext A pointer to arbitrary context information.
*/
void SetUdpForwarder(otUdpForwarder aForwarder, void *aContext) { mUdpForwarder.Set(aForwarder, aContext); }
#endif
/**
* Returns whether a udp port is being used by OpenThread or any of it's optional
* features, e.g. CoAP API.
*
* @param[in] aPort The udp port
*
* @retval True when port is used by the OpenThread.
* @retval False when the port is not used by OpenThread.
*/
bool IsPortInUse(uint16_t aPort) const;
private:
static constexpr uint16_t kDynamicPortMin = 49152; // Service Name and Transport Protocol Port Number Registry
static constexpr uint16_t kDynamicPortMax = 65535; // Service Name and Transport Protocol Port Number Registry
// Reserved range for use by SRP server
static constexpr uint16_t kSrpServerPortMin = OPENTHREAD_CONFIG_SRP_SERVER_UDP_PORT_MIN;
static constexpr uint16_t kSrpServerPortMax = OPENTHREAD_CONFIG_SRP_SERVER_UDP_PORT_MAX;
#if OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE
struct Plat
{
static Error Open(SocketHandle &aSocket);
static Error Close(SocketHandle &aSocket);
static Error Bind(SocketHandle &aSocket);
static Error BindToNetif(SocketHandle &aSocket);
static Error Connect(SocketHandle &aSocket);
static Error Send(SocketHandle &aSocket, Message &aMessage, const MessageInfo &aMessageInfo);
static Error JoinMulticastGroup(SocketHandle &aSocket, NetifIdentifier aNetifId, const Address &aAddress);
static Error LeaveMulticastGroup(SocketHandle &aSocket, NetifIdentifier aNetifId, const Address &aAddress);
};
#endif
static bool IsPortReserved(uint16_t aPort);
void AddSocket(SocketHandle &aSocket);
void RemoveSocket(SocketHandle &aSocket);
uint16_t mEphemeralPort;
LinkedList<Receiver> mReceivers;
LinkedList<SocketHandle> mSockets;
#if OPENTHREAD_CONFIG_UDP_FORWARD_ENABLE
Callback<otUdpForwarder> mUdpForwarder;
#endif
};
/**
* @}
*/
} // namespace Ip6
DefineCoreType(otUdpSocket, Ip6::Udp::SocketHandle);
DefineCoreType(otUdpReceiver, Ip6::Udp::Receiver);
DefineMapEnum(otNetifIdentifier, Ip6::NetifIdentifier);
} // namespace ot
#endif // OT_CORE_NET_UDP6_HPP_