| /* |
| * Copyright (c) 2018, 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. |
| */ |
| |
| #ifndef SNTP_CLIENT_HPP_ |
| #define SNTP_CLIENT_HPP_ |
| |
| #include "openthread-core-config.h" |
| |
| #include <openthread/sntp.h> |
| |
| #include "common/message.hpp" |
| #include "common/timer.hpp" |
| #include "net/ip6.hpp" |
| #include "net/netif.hpp" |
| |
| /** |
| * @file |
| * This file includes definitions for the SNTP client. |
| */ |
| |
| namespace ot { |
| namespace Sntp { |
| |
| using ot::Encoding::BigEndian::HostSwap32; |
| |
| /** |
| * This class implements SNTP header generation and parsing. |
| * |
| */ |
| OT_TOOL_PACKED_BEGIN |
| class Header |
| { |
| public: |
| /** |
| * Default constructor for SNTP Header. |
| * |
| */ |
| Header(void) |
| { |
| memset(this, 0, sizeof(*this)); |
| |
| // Set default value of flags field. |
| SetFlags(kNtpVersion << kVersionOffset | kModeClient << kModeOffset); |
| } |
| |
| /** |
| * Defines supported SNTP modes. |
| * |
| */ |
| enum Mode |
| { |
| kModeClient = 3, |
| kModeServer = 4, |
| }; |
| |
| /** |
| * Kiss code length. |
| * |
| */ |
| enum |
| { |
| kKissCodeLength = 4, ///< Length of the kiss code in ASCII format |
| }; |
| |
| /** |
| * This method returns the flags field value. |
| * |
| * @returns Value of the flags field (LI, VN and Mode). |
| * |
| */ |
| uint8_t GetFlags(void) const { return mFlags; } |
| |
| /** |
| * This method sets the flags field. |
| * |
| * @param[in] aFlags The value of the flags field. |
| * |
| */ |
| void SetFlags(uint8_t aFlags) { mFlags = aFlags; } |
| |
| /** |
| * This method returns the SNTP operational mode. |
| * |
| * @returns SNTP operational mode. |
| * |
| */ |
| Mode GetMode(void) const { return static_cast<Mode>((mFlags & kModeMask) >> kModeOffset); } |
| |
| /** |
| * This method returns the packet stratum field value. |
| * |
| * @returns Value of the packet stratum. |
| * |
| */ |
| uint8_t GetStratum(void) const { return mStratum; } |
| |
| /** |
| * This method sets the packet stratum field value. |
| * |
| * @param[in] aStratum The value of the packet stratum field. |
| * |
| */ |
| void SetStratum(uint8_t aStratum) { mStratum = aStratum; } |
| |
| /** |
| * This method returns the poll field value. |
| * |
| * @returns Value of the poll field. |
| * |
| */ |
| uint8_t GetPoll(void) const { return mPoll; } |
| |
| /** |
| * This method sets the poll field. |
| * |
| * @param[in] aPoll The value of the poll field. |
| * |
| */ |
| void SetPoll(uint8_t aPoll) { mPoll = aPoll; } |
| |
| /** |
| * This method returns the precision field value. |
| * |
| * @returns Value of the precision field. |
| * |
| */ |
| uint8_t GetPrecision(void) const { return mPrecision; } |
| |
| /** |
| * This method sets the precision field. |
| * |
| * @param[in] aPrecision The value of the precision field. |
| * |
| */ |
| void SetPrecision(uint8_t aPrecision) { mPrecision = aPrecision; } |
| |
| /** |
| * This method returns the root delay field value. |
| * |
| * @returns Value of the root delay field. |
| * |
| */ |
| uint32_t GetRootDelay(void) const { return HostSwap32(mRootDelay); } |
| |
| /** |
| * This method sets the root delay field. |
| * |
| * @param[in] aRootDelay The value of the root delay field. |
| * |
| */ |
| void SetRootDelay(uint32_t aRootDelay) { mRootDelay = HostSwap32(aRootDelay); } |
| |
| /** |
| * This method returns the root dispersion field value. |
| * |
| * @returns Value of the root dispersion field. |
| * |
| */ |
| uint32_t GetRootDispersion(void) const { return HostSwap32(mRootDispersion); } |
| |
| /** |
| * This method sets the root dispersion field. |
| * |
| * @param[in] aRootDispersion The value of the root dispersion field. |
| * |
| */ |
| void SetRootDispersion(uint32_t aRootDispersion) { mRootDispersion = HostSwap32(aRootDispersion); } |
| |
| /** |
| * This method returns the reference identifier field value. |
| * |
| * @returns Value of the reference identifier field. |
| * |
| */ |
| uint32_t GetReferenceId(void) const { return HostSwap32(mReferenceId); } |
| |
| /** |
| * This method sets the reference identifier field. |
| * |
| * @param[in] aReferenceId The value of the reference identifier field. |
| * |
| */ |
| void SetReferenceId(uint32_t aReferenceId) { mReferenceId = HostSwap32(aReferenceId); } |
| |
| /** |
| * This method returns the kiss code in ASCII format. |
| * |
| * @returns Value of the reference identifier field in ASCII format. |
| * |
| */ |
| char *GetKissCode(void) { return reinterpret_cast<char *>(&mReferenceId); } |
| |
| /** |
| * This method returns the reference timestamp seconds field. |
| * |
| * @returns Value of the reference timestamp seconds field. |
| * |
| */ |
| uint32_t GetReferenceTimestampSeconds(void) const { return HostSwap32(mReferenceTimestampSeconds); } |
| |
| /** |
| * This method sets the reference timestamp seconds field. |
| * |
| * @param[in] aReferenceTimestampSeconds Value of the reference timestamp seconds field. |
| * |
| */ |
| void SetReferenceTimestampSeconds(uint32_t aReferenceTimestampSeconds) |
| { |
| mReferenceTimestampSeconds = HostSwap32(aReferenceTimestampSeconds); |
| } |
| |
| /** |
| * This method returns the reference timestamp fraction field. |
| * |
| * @returns Value of the reference timestamp fraction field. |
| * |
| */ |
| uint32_t GetReferenceTimestampFraction(void) const { return HostSwap32(mReferenceTimestampFraction); } |
| |
| /** |
| * This method sets the reference timestamp fraction field. |
| * |
| * @param[in] aReferenceTimestampFraction Value of the reference timestamp fraction field. |
| * |
| */ |
| void SetReferenceTimestampFraction(uint32_t aReferenceTimestampFraction) |
| { |
| mReferenceTimestampFraction = HostSwap32(aReferenceTimestampFraction); |
| } |
| |
| /** |
| * This method returns the originate timestamp seconds field. |
| * |
| * @returns Value of the originate timestamp seconds field. |
| * |
| */ |
| uint32_t GetOriginateTimestampSeconds(void) const { return HostSwap32(mOriginateTimestampSeconds); } |
| |
| /** |
| * This method sets the originate timestamp seconds field. |
| * |
| * @param[in] aOriginateTimestampSeconds Value of the originate timestamp seconds field. |
| * |
| */ |
| void SetOriginateTimestampSeconds(uint32_t aOriginateTimestampSeconds) |
| { |
| mOriginateTimestampSeconds = HostSwap32(aOriginateTimestampSeconds); |
| } |
| |
| /** |
| * This method returns the originate timestamp fraction field. |
| * |
| * @returns Value of the originate timestamp fraction field. |
| * |
| */ |
| uint32_t GetOriginateTimestampFraction(void) const { return HostSwap32(mOriginateTimestampFraction); } |
| |
| /** |
| * This method sets the originate timestamp fraction field. |
| * |
| * @param[in] aOriginateTimestampFraction Value of the originate timestamp fraction field. |
| * |
| */ |
| void SetOriginateTimestampFraction(uint32_t aOriginateTimestampFraction) |
| { |
| mOriginateTimestampFraction = HostSwap32(aOriginateTimestampFraction); |
| } |
| |
| /** |
| * This method returns the receive timestamp seconds field. |
| * |
| * @returns Value of the receive timestamp seconds field. |
| * |
| */ |
| uint32_t GetReceiveTimestampSeconds(void) const { return HostSwap32(mReceiveTimestampSeconds); } |
| |
| /** |
| * This method sets the receive timestamp seconds field. |
| * |
| * @param[in] aReceiveTimestampSeconds Value of the receive timestamp seconds field. |
| * |
| */ |
| void SetReceiveTimestampSeconds(uint32_t aReceiveTimestampSeconds) |
| { |
| mReceiveTimestampSeconds = HostSwap32(aReceiveTimestampSeconds); |
| } |
| |
| /** |
| * This method returns the receive timestamp fraction field. |
| * |
| * @returns Value of the receive timestamp fraction field. |
| * |
| */ |
| uint32_t GetReceiveTimestampFraction(void) const { return HostSwap32(mReceiveTimestampFraction); } |
| |
| /** |
| * This method sets the receive timestamp fraction field. |
| * |
| * @param[in] aReceiveTimestampFraction Value of the receive timestamp fraction field. |
| * |
| */ |
| void SetReceiveTimestampFraction(uint32_t aReceiveTimestampFraction) |
| { |
| mReceiveTimestampFraction = HostSwap32(aReceiveTimestampFraction); |
| } |
| |
| /** |
| * This method returns the transmit timestamp seconds field. |
| * |
| * @returns Value of the transmit timestamp seconds field. |
| * |
| */ |
| uint32_t GetTransmitTimestampSeconds(void) const { return HostSwap32(mTransmitTimestampSeconds); } |
| |
| /** |
| * This method sets the transmit timestamp seconds field. |
| * |
| * @param[in] aTransmitTimestampSeconds Value of the transmit timestamp seconds field. |
| * |
| */ |
| void SetTransmitTimestampSeconds(uint32_t aTransmitTimestampSeconds) |
| { |
| mTransmitTimestampSeconds = HostSwap32(aTransmitTimestampSeconds); |
| } |
| |
| /** |
| * This method returns the transmit timestamp fraction field. |
| * |
| * @returns Value of the transmit timestamp fraction field. |
| * |
| */ |
| uint32_t GetTransmitTimestampFraction(void) const { return HostSwap32(mTransmitTimestampFraction); } |
| |
| /** |
| * This method sets the transmit timestamp fraction field. |
| * |
| * @param[in] aTransmitTimestampFraction Value of the transmit timestamp fraction field. |
| * |
| */ |
| void SetTransmitTimestampFraction(uint32_t aTransmitTimestampFraction) |
| { |
| mTransmitTimestampFraction = HostSwap32(aTransmitTimestampFraction); |
| } |
| |
| private: |
| /** |
| * Protocol Constants (RFC 5905). |
| * |
| */ |
| enum |
| { |
| /** |
| * Current NTP version. |
| * |
| */ |
| kNtpVersion = 4, |
| |
| /** |
| * Flags offsets and masks. |
| * |
| */ |
| kLeapOffset = 6, ///< Leap Indicator field offset. |
| kLeapMask = 0x03 << kLeapOffset, ///< Leap Indicator field mask. |
| kVersionOffset = 3, ///< Version field offset. |
| kVersionMask = 0x07 << kVersionOffset, ///< Version field mask. |
| kModeOffset = 0, ///< Mode field offset. |
| kModeMask = 0x07 << kModeOffset, ///< Mode filed mask. |
| }; |
| |
| /** |
| * SNTP Header fields. |
| * |
| */ |
| uint8_t mFlags; ///< SNTP flags: LI Leap Indicator, VN Version Number and Mode. |
| uint8_t mStratum; ///< Packet Stratum. |
| uint8_t mPoll; ///< Maximum interval between successive messages, in log2 seconds. |
| uint8_t mPrecision; ///< The precision of the system clock, in log2 seconds. |
| uint32_t mRootDelay; ///< Total round-trip delay to the reference clock, in NTP short format. |
| uint32_t mRootDispersion; ///< Total dispersion to the reference clock. |
| uint32_t mReferenceId; ///< ID identifying the particular server or reference clock. |
| uint32_t mReferenceTimestampSeconds; ///< Time when the system clock was last set or corrected, in NTP |
| ///< timestamp format. |
| uint32_t mReferenceTimestampFraction; ///< Fraction part of above value. |
| uint32_t mOriginateTimestampSeconds; ///< Time at the client when the request departed for the server, in NTP |
| ///< timestamp format. |
| uint32_t mOriginateTimestampFraction; ///< Fraction part of above value. |
| uint32_t mReceiveTimestampSeconds; ///< Time at the server when the request arrived from the client, in NTP |
| ///< timestamp format. |
| uint32_t mReceiveTimestampFraction; ///< Fraction part of above value. |
| uint32_t mTransmitTimestampSeconds; ///< Time at the server when the response left for the client, in NTP |
| ///< timestamp format. |
| uint32_t mTransmitTimestampFraction; ///< Fraction part of above value. |
| } OT_TOOL_PACKED_END; |
| |
| /** |
| * This class implements metadata required for SNTP retransmission. |
| * |
| */ |
| OT_TOOL_PACKED_BEGIN |
| class QueryMetadata |
| { |
| friend class Client; |
| |
| public: |
| /** |
| * Default constructor for the object. |
| * |
| */ |
| QueryMetadata(void) { memset(this, 0, sizeof(*this)); } |
| |
| /** |
| * This constructor initializes the object with specific values. |
| * |
| * @param[in] aHandler Pointer to a handler function for the response. |
| * @param[in] aContext Context for the handler function. |
| * |
| */ |
| QueryMetadata(otSntpResponseHandler aHandler, void *aContext) |
| { |
| memset(this, 0, sizeof(*this)); |
| mResponseHandler = aHandler; |
| mResponseContext = aContext; |
| } |
| |
| /** |
| * This method appends request data to the message. |
| * |
| * @param[in] aMessage A reference to the message. |
| * |
| * @retval OT_ERROR_NONE Successfully appended the bytes. |
| * @retval OT_ERROR_NO_BUFS Insufficient available buffers to grow the message. |
| * |
| */ |
| otError AppendTo(Message &aMessage) const { return aMessage.Append(this, sizeof(*this)); } |
| |
| /** |
| * This method reads request data from the message. |
| * |
| * @param[in] aMessage A reference to the message. |
| * |
| */ |
| void ReadFrom(const Message &aMessage) |
| { |
| uint16_t length = aMessage.Read(aMessage.GetLength() - sizeof(*this), sizeof(*this), this); |
| assert(length == sizeof(*this)); |
| OT_UNUSED_VARIABLE(length); |
| } |
| |
| /** |
| * This method updates request data in the message. |
| * |
| * @param[in] aMessage A reference to the message. |
| * |
| * @returns The number of bytes updated. |
| * |
| */ |
| int UpdateIn(Message &aMessage) const |
| { |
| return aMessage.Write(aMessage.GetLength() - sizeof(*this), sizeof(*this), this); |
| } |
| |
| /** |
| * This method checks if the message shall be sent before the given time. |
| * |
| * @param[in] aTime A time to compare. |
| * |
| * @retval TRUE If the message shall be sent before the given time. |
| * @retval FALSE Otherwise. |
| */ |
| bool IsEarlier(uint32_t aTime) const { return (static_cast<int32_t>(aTime - mTransmissionTime) > 0); } |
| |
| /** |
| * This method checks if the message shall be sent after the given time. |
| * |
| * @param[in] aTime A time to compare. |
| * |
| * @retval TRUE If the message shall be sent after the given time. |
| * @retval FALSE Otherwise. |
| */ |
| bool IsLater(uint32_t aTime) const { return (static_cast<int32_t>(aTime - mTransmissionTime) < 0); } |
| |
| private: |
| uint32_t mTransmitTimestamp; ///< Time at the client when the request departed for the server. |
| otSntpResponseHandler mResponseHandler; ///< A function pointer that is called on response reception. |
| void * mResponseContext; ///< A pointer to arbitrary context information. |
| uint32_t mTransmissionTime; ///< Time when the timer should shoot for this message. |
| Ip6::Address mSourceAddress; ///< IPv6 address of the message source. |
| Ip6::Address mDestinationAddress; ///< IPv6 address of the message destination. |
| uint16_t mDestinationPort; ///< UDP port of the message destination. |
| uint8_t mRetransmissionCount; ///< Number of retransmissions. |
| } OT_TOOL_PACKED_END; |
| |
| /** |
| * This class implements SNTP client. |
| * |
| */ |
| class Client |
| { |
| public: |
| /** |
| * This constructor initializes the object. |
| * |
| * @param[in] aNetif A reference to the network interface that SNTP client should be assigned to. |
| * |
| */ |
| explicit Client(Ip6::Netif &aNetif); |
| |
| /** |
| * This method starts the SNTP client. |
| * |
| * @retval OT_ERROR_NONE Successfully started the SNTP client. |
| * @retval OT_ERROR_ALREADY The socket is already open. |
| */ |
| otError Start(void); |
| |
| /** |
| * This method stops the SNTP client. |
| * |
| * @retval OT_ERROR_NONE Successfully stopped the SNTP client. |
| * |
| */ |
| otError Stop(void); |
| |
| /** |
| * This method returns the unix era number. |
| * |
| * @returns The unix era number. |
| * |
| */ |
| uint32_t GetUnixEra(void) const { return mUnixEra; } |
| |
| /** |
| * This method sets the unix era number. |
| * |
| * @param[in] aUnixEra The unix era number. |
| * |
| */ |
| void SetUnixEra(uint32_t aUnixEra) { mUnixEra = aUnixEra; } |
| |
| /** |
| * This method sends an SNTP query. |
| * |
| * @param[in] aQuery A pointer to specify SNTP query parameters. |
| * @param[in] aHandler A function pointer that shall be called on response reception or time-out. |
| * @param[in] aContext A pointer to arbitrary context information. |
| * |
| * @retval OT_ERROR_NONE Successfully sent SNTP query. |
| * @retval OT_ERROR_NO_BUFS Failed to allocate retransmission data. |
| * @retval OT_ERROR_INVALID_ARGS Invalid arguments supplied. |
| * |
| */ |
| otError Query(const otSntpQuery *aQuery, otSntpResponseHandler aHandler, void *aContext); |
| |
| private: |
| /** |
| * Protocol Constants (RFC 5905). |
| * |
| */ |
| enum |
| { |
| /** |
| * Number of seconds between 1st January 1900 and 1st January 1970. |
| * |
| */ |
| kTimeAt1970 = 2208988800UL, |
| }; |
| |
| /** |
| * Retransmission parameters. |
| * |
| */ |
| enum |
| { |
| kResponseTimeout = OPENTHREAD_CONFIG_SNTP_CLIENT_RESPONSE_TIMEOUT, |
| kMaxRetransmit = OPENTHREAD_CONFIG_SNTP_CLIENT_MAX_RETRANSMIT, |
| }; |
| |
| Message *NewMessage(const Header &aHeader); |
| Message *CopyAndEnqueueMessage(const Message &aMessage, const QueryMetadata &aQueryMetadata); |
| void DequeueMessage(Message &aMessage); |
| otError SendMessage(Message &aMessage, const Ip6::MessageInfo &aMessageInfo); |
| otError SendCopy(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo); |
| |
| Message *FindRelatedQuery(const Header &aResponseHeader, QueryMetadata &aQueryMetadata); |
| void FinalizeSntpTransaction(Message &aQuery, const QueryMetadata &aQueryMetadata, uint64_t aTime, otError aResult); |
| |
| static void HandleRetransmissionTimer(Timer &aTimer); |
| void HandleRetransmissionTimer(void); |
| |
| static void HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo); |
| void HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo); |
| |
| Ip6::UdpSocket mSocket; |
| |
| MessageQueue mPendingQueries; |
| TimerMilli mRetransmissionTimer; |
| |
| uint32_t mUnixEra; |
| }; |
| |
| } // namespace Sntp |
| } // namespace ot |
| |
| #endif // SNTP_CLIENT_HPP_ |