| /* |
| * 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" |
| |
| #if OPENTHREAD_CONFIG_SNTP_CLIENT_ENABLE |
| |
| #include <openthread/sntp.h> |
| |
| #include "common/message.hpp" |
| #include "common/non_copyable.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); |
| |
| /** |
| * Defines supported SNTP modes. |
| * |
| */ |
| enum Mode : uint8_t |
| { |
| kModeClient = 3, |
| kModeServer = 4, |
| }; |
| |
| static constexpr uint8_t 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: |
| static constexpr uint8_t kNtpVersion = 4; // Current NTP version. |
| static constexpr uint8_t kLeapOffset = 6; // Leap Indicator field offset. |
| static constexpr uint8_t kLeapMask = 0x03 << kLeapOffset; // Leap Indicator field mask. |
| static constexpr uint8_t kVersionOffset = 3; // Version field offset. |
| static constexpr uint8_t kVersionMask = 0x07 << kVersionOffset; // Version field mask. |
| static constexpr uint8_t kModeOffset = 0; // Mode field offset. |
| static constexpr uint8_t kModeMask = 0x07 << kModeOffset; // Mode filed mask. |
| |
| 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 the system clock was last set or corrected (NTP format). |
| uint32_t mReferenceTimestampFraction; // Fraction part of above value. |
| uint32_t mOriginateTimestampSeconds; // Time at the client when the request departed for the server (NTP format). |
| uint32_t mOriginateTimestampFraction; // Fraction part of above value. |
| uint32_t mReceiveTimestampSeconds; // Time at the server when the request arrived from the client (NTP format). |
| uint32_t mReceiveTimestampFraction; // Fraction part of above value. |
| uint32_t mTransmitTimestampSeconds; // Time at the server when the response left for the client (NTP format). |
| uint32_t mTransmitTimestampFraction; // Fraction part of above value. |
| } OT_TOOL_PACKED_END; |
| |
| /** |
| * This class implements metadata required for SNTP retransmission. |
| * |
| */ |
| class QueryMetadata |
| { |
| friend class Client; |
| |
| public: |
| /** |
| * Default constructor for the object. |
| * |
| */ |
| QueryMetadata(void); |
| |
| /** |
| * 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); |
| |
| /** |
| * This method appends request data to the message. |
| * |
| * @param[in] aMessage A reference to the message. |
| * |
| * @retval kErrorNone Successfully appended the bytes. |
| * @retval kErrorNoBufs Insufficient available buffers to grow the message. |
| * |
| */ |
| Error AppendTo(Message &aMessage) const { return aMessage.Append(*this); } |
| |
| /** |
| * This method reads request data from the message. |
| * |
| * @param[in] aMessage A reference to the message. |
| * |
| */ |
| void ReadFrom(const Message &aMessage) |
| { |
| SuccessOrAssert(aMessage.Read(aMessage.GetLength() - sizeof(*this), *this)); |
| } |
| |
| /** |
| * This method updates request data in the message. |
| * |
| * @param[in] aMessage A reference to the message. |
| * |
| */ |
| void UpdateIn(Message &aMessage) const { aMessage.Write(aMessage.GetLength() - sizeof(*this), *this); } |
| |
| 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. |
| TimeMilli 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. |
| }; |
| |
| /** |
| * This class implements SNTP client. |
| * |
| */ |
| class Client : private NonCopyable |
| { |
| public: |
| /** |
| * This constructor initializes the object. |
| * |
| * @param[in] aInstance A reference to the OpenThread instance. |
| * |
| */ |
| explicit Client(Instance &aInstance); |
| |
| /** |
| * This method starts the SNTP client. |
| * |
| * @retval kErrorNone Successfully started the SNTP client. |
| * @retval kErrorAlready The socket is already open. |
| */ |
| Error Start(void); |
| |
| /** |
| * This method stops the SNTP client. |
| * |
| * @retval kErrorNone Successfully stopped the SNTP client. |
| * |
| */ |
| Error 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 kErrorNone Successfully sent SNTP query. |
| * @retval kErrorNoBufs Failed to allocate retransmission data. |
| * @retval kErrorInvalidArgs Invalid arguments supplied. |
| * |
| */ |
| Error Query(const otSntpQuery *aQuery, otSntpResponseHandler aHandler, void *aContext); |
| |
| private: |
| static constexpr uint32_t kTimeAt1970 = 2208988800UL; // num seconds between 1st Jan 1900 and 1st Jan 1970. |
| |
| static constexpr uint32_t kResponseTimeout = OPENTHREAD_CONFIG_SNTP_CLIENT_RESPONSE_TIMEOUT; |
| static constexpr uint8_t kMaxRetransmit = OPENTHREAD_CONFIG_SNTP_CLIENT_MAX_RETRANSMIT; |
| |
| Message *NewMessage(const Header &aHeader); |
| Message *CopyAndEnqueueMessage(const Message &aMessage, const QueryMetadata &aQueryMetadata); |
| void DequeueMessage(Message &aMessage); |
| Error SendMessage(Message &aMessage, const Ip6::MessageInfo &aMessageInfo); |
| void 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, Error 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::Udp::Socket mSocket; |
| |
| MessageQueue mPendingQueries; |
| TimerMilli mRetransmissionTimer; |
| |
| uint32_t mUnixEra; |
| }; |
| |
| } // namespace Sntp |
| } // namespace ot |
| |
| #endif // OPENTHREAD_CONFIG_SNTP_CLIENT_ENABLE |
| |
| #endif // SNTP_CLIENT_HPP_ |