/* * 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 UDP6_HPP_ #define UDP6_HPP_ #include "openthread-core-config.h" #include #include #include "common/as_core_type.hpp" #include "common/clearable.hpp" #include "common/linked_list.hpp" #include "common/locator.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 /** * This class implements core UDP message handling. * */ class Udp : public InstanceLocator, private NonCopyable { public: /** * This class implements a UDP/IPv6 socket. * */ class SocketHandle : public otUdpSocket, public LinkedListEntry, public Clearable { friend class Udp; friend class LinkedList; public: /** * This method 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; } /** * This method returns the local socket address. * * @returns A reference to the local socket address. * */ SockAddr &GetSockName(void) { return AsCoreType(&mSockName); } /** * This method returns the local socket address. * * @returns A reference to the local socket address. * */ const SockAddr &GetSockName(void) const { return AsCoreType(&mSockName); } /** * This method returns the peer's socket address. * * @returns A reference to the peer's socket address. * */ SockAddr &GetPeerName(void) { return AsCoreType(&mPeerName); } /** * This method returns the peer's socket address. * * @returns A reference to the peer's socket address. * */ const SockAddr &GetPeerName(void) const { return AsCoreType(&mPeerName); } private: bool Matches(const MessageInfo &aMessageInfo) const; void HandleUdpReceive(Message &aMessage, const MessageInfo &aMessageInfo) { mHandler(mContext, &aMessage, &aMessageInfo); } }; /** * This class implements a UDP/IPv6 socket. * */ class Socket : public InstanceLocator, public SocketHandle { friend class Udp; public: /** * This constructor initializes the object. * * @param[in] aInstance A reference to OpenThread instance. * */ explicit Socket(Instance &aInstance); /** * This method returns a new UDP message with sufficient header space reserved. * * @param[in] aReserved The number of header bytes to reserve after the UDP header. * @param[in] aSettings The message settings (default is used if not provided). * * @returns A pointer to the message or `nullptr` if no buffers are available. * */ Message *NewMessage(uint16_t aReserved, const Message::Settings &aSettings = Message::Settings::GetDefault()); /** * This method opens the UDP socket. * * @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(otUdpReceive aHandler, void *aContext); /** * This method returns if the UDP socket is open. * * @returns If the UDP socket is open. * */ bool IsOpen(void) const; /** * This method binds the UDP socket. * * @param[in] aSockAddr A reference to the socket address. * @param[in] aNetifIdentifier The network interface identifier. * * @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, otNetifIdentifier aNetifIdentifier = OT_NETIF_THREAD); /** * This method binds the UDP socket. * * @param[in] aPort A port number. * @param[in] aNetifIdentifier The network interface identifier. * * @retval kErrorNone Successfully bound the socket. * @retval kErrorFailed Failed to bind UDP Socket. * */ Error Bind(uint16_t aPort, otNetifIdentifier aNetifIdentifier = OT_NETIF_THREAD); /** * This method binds the UDP socket. * * @retval kErrorNone Successfully bound the socket. * @retval kErrorFailed Failed to bind UDP Socket. * */ Error Bind(void) { return Bind(0); } /** * This method 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); /** * This method 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); /** * This method connects the UDP socket. * * @retval kErrorNone Successfully connected the socket. * @retval kErrorFailed Failed to connect UDP Socket. * */ Error Connect(void) { return Connect(0); } /** * This method closes the UDP socket. * * @retval kErrorNone Successfully closed the UDP socket. * @retval kErrorFailed Failed to close UDP Socket. * */ Error Close(void); /** * This method 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 /** * This method configures the UDP socket to join a mutlicast 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(otNetifIdentifier aNetifIdentifier, const Address &aAddress); /** * This method 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(otNetifIdentifier aNetifIdentifier, const Address &aAddress); #endif }; /** * This class implements a UDP receiver. * */ class Receiver : public otUdpReceiver, public LinkedListEntry { friend class Udp; public: /** * This constructor 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); } }; /** * This class implements UDP header generation and parsing. * */ OT_TOOL_PACKED_BEGIN class Header : public Clearable
{ public: static constexpr uint16_t kSourcePortFieldOffset = 0; ///< Byte offset of Source Port field in UDP header. static constexpr uint16_t kDestPortFieldOffset = 2; ///< Byte offset of Destination Port field in UDP header. static constexpr uint16_t kLengthFieldOffset = 4; ///< Byte offset of Length field in UDP header. static constexpr uint16_t kChecksumFieldOffset = 6; ///< Byte offset of Checksum field in UDP header. /** * This method returns the UDP Source Port. * * @returns The UDP Source Port. * */ uint16_t GetSourcePort(void) const { return HostSwap16(mSourcePort); } /** * This method sets the UDP Source Port. * * @param[in] aPort The UDP Source Port. * */ void SetSourcePort(uint16_t aPort) { mSourcePort = HostSwap16(aPort); } /** * This method returns the UDP Destination Port. * * @returns The UDP Destination Port. * */ uint16_t GetDestinationPort(void) const { return HostSwap16(mDestinationPort); } /** * This method sets the UDP Destination Port. * * @param[in] aPort The UDP Destination Port. * */ void SetDestinationPort(uint16_t aPort) { mDestinationPort = HostSwap16(aPort); } /** * This method returns the UDP Length. * * @returns The UDP Length. * */ uint16_t GetLength(void) const { return HostSwap16(mLength); } /** * This method sets the UDP Length. * * @param[in] aLength The UDP Length. * */ void SetLength(uint16_t aLength) { mLength = HostSwap16(aLength); } /** * This method returns the UDP Checksum. * * @returns The UDP Checksum. * */ uint16_t GetChecksum(void) const { return HostSwap16(mChecksum); } /** * This method sets the UDP Checksum. * * @param[in] aChecksum The UDP Checksum. * */ void SetChecksum(uint16_t aChecksum) { mChecksum = HostSwap16(aChecksum); } private: uint16_t mSourcePort; uint16_t mDestinationPort; uint16_t mLength; uint16_t mChecksum; } OT_TOOL_PACKED_END; /** * This constructor initializes the object. * * @param[in] aInstance A reference to OpenThread instance. * */ explicit Udp(Instance &aInstance); /** * This method 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); /** * This method 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); /** * This method opens a UDP socket. * * @param[in] aSocket A reference to the socket. * @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, otUdpReceive aHandler, void *aContext); /** * This method 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); } /** * This method binds a UDP socket. * * @param[in] aSocket A reference to the socket. * @param[in] aSockAddr A reference to the socket address. * @param[in] aNetifIdentifier The network interface identifier. * * @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, otNetifIdentifier aNetifIdentifier); /** * This method 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); /** * This method 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); /** * This method 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); /** * This method returns a new ephemeral port. * * @returns A new ephemeral port. * */ uint16_t GetEphemeralPort(void); /** * This method returns a new UDP message with sufficient header space reserved. * * @param[in] aReserved The number of header bytes to reserve after the UDP header. * @param[in] aSettings The message settings. * * @returns A pointer to the message or `nullptr` if no buffers are available. * */ Message *NewMessage(uint16_t aReserved, const Message::Settings &aSettings = Message::Settings::GetDefault()); /** * This method 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. * @param[in] aIpProto The Internet Protocol value. * * @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, uint8_t aIpProto); /** * This method 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); /** * This method 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); /** * This method 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 /** * This method 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 = aForwarder; mUdpForwarderContext = aContext; } #endif /** * This method 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; /** * This method returns whether a udp port belongs to the platform or the stack. * * @param[in] aPort The udp port * * @retval True when the port belongs to the platform. * @retval False when the port belongs to the stack. * */ bool ShouldUsePlatformUdp(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; static bool IsPortReserved(uint16_t aPort); void AddSocket(SocketHandle &aSocket); void RemoveSocket(SocketHandle &aSocket); #if OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE bool ShouldUsePlatformUdp(const SocketHandle &aSocket) const; #endif #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE void SetBackboneSocket(SocketHandle &aSocket); const SocketHandle *GetBackboneSockets(void) const; bool IsBackboneSocket(const SocketHandle &aSocket) const; #endif uint16_t mEphemeralPort; LinkedList mReceivers; LinkedList mSockets; #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE SocketHandle *mPrevBackboneSockets; #endif #if OPENTHREAD_CONFIG_UDP_FORWARD_ENABLE void * mUdpForwarderContext; otUdpForwarder mUdpForwarder; #endif }; /** * @} * */ } // namespace Ip6 DefineCoreType(otUdpSocket, Ip6::Udp::SocketHandle); DefineCoreType(otUdpReceiver, Ip6::Udp::Receiver); } // namespace ot #endif // UDP6_HPP_