blob: 071eda602c117c3782e85367942113d77847bf75 [file]
/*
* 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 OT_CORE_NET_SNTP_CLIENT_HPP_
#define OT_CORE_NET_SNTP_CLIENT_HPP_
#include "openthread-core-config.h"
#if OPENTHREAD_CONFIG_SNTP_CLIENT_ENABLE
#include <openthread/sntp.h>
#include "common/clearable.hpp"
#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 {
/**
* Implements SNTP client.
*/
class Client : private NonCopyable
{
public:
typedef otSntpResponseHandler ResponseHandler; ///< Response handler callback.
/**
* Initializes the object.
*
* @param[in] aInstance A reference to the OpenThread instance.
*/
explicit Client(Instance &aInstance);
/**
* Starts the SNTP client.
*
* @retval kErrorNone Successfully started the SNTP client.
* @retval kErrorAlready The socket is already open.
*/
Error Start(void);
/**
* Stops the SNTP client.
*
* @retval kErrorNone Successfully stopped the SNTP client.
*/
Error Stop(void);
/**
* Returns the unix era number.
*
* @returns The unix era number.
*/
uint32_t GetUnixEra(void) const { return mUnixEra; }
/**
* Sets the unix era number.
*
* @param[in] aUnixEra The unix era number.
*/
void SetUnixEra(uint32_t aUnixEra) { mUnixEra = aUnixEra; }
/**
* 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, ResponseHandler 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;
OT_TOOL_PACKED_BEGIN
class Header : public Clearable<Header>
{
public:
enum Mode : uint8_t
{
kModeClient = 3,
kModeServer = 4,
};
static constexpr uint8_t kKissCodeLength = 4;
void Init(void)
{
Clear();
mFlags = (kNtpVersion << kVersionOffset | kModeClient << kModeOffset);
}
uint8_t GetFlags(void) const { return mFlags; }
void SetFlags(uint8_t aFlags) { mFlags = aFlags; }
Mode GetMode(void) const { return static_cast<Mode>(ReadBits<uint8_t, kModeMask>(mFlags)); }
uint8_t GetStratum(void) const { return mStratum; }
void SetStratum(uint8_t aStratum) { mStratum = aStratum; }
uint8_t GetPoll(void) const { return mPoll; }
void SetPoll(uint8_t aPoll) { mPoll = aPoll; }
uint8_t GetPrecision(void) const { return mPrecision; }
void SetPrecision(uint8_t aPrecision) { mPrecision = aPrecision; }
uint32_t GetRootDelay(void) const { return BigEndian::HostSwap32(mRootDelay); }
void SetRootDelay(uint32_t aRootDelay) { mRootDelay = BigEndian::HostSwap32(aRootDelay); }
uint32_t GetRootDispersion(void) const { return BigEndian::HostSwap32(mRootDispersion); }
void SetRootDispersion(uint32_t aRootDispersion) { mRootDispersion = BigEndian::HostSwap32(aRootDispersion); }
uint32_t GetReferenceId(void) const { return BigEndian::HostSwap32(mReferenceId); }
void SetReferenceId(uint32_t aReferenceId) { mReferenceId = BigEndian::HostSwap32(aReferenceId); }
char *GetKissCode(void) { return reinterpret_cast<char *>(&mReferenceId); }
uint32_t GetReferenceTimestampSeconds(void) const { return BigEndian::HostSwap32(mReferenceTimestampSeconds); }
void SetReferenceTimestampSeconds(uint32_t aTimestamp)
{
mReferenceTimestampSeconds = BigEndian::HostSwap32(aTimestamp);
}
uint32_t GetReferenceTimestampFraction(void) const
{
return BigEndian::HostSwap32(mReferenceTimestampFraction);
}
void SetReferenceTimestampFraction(uint32_t aFraction)
{
mReferenceTimestampFraction = BigEndian::HostSwap32(aFraction);
}
uint32_t GetOriginateTimestampSeconds(void) const { return BigEndian::HostSwap32(mOriginateTimestampSeconds); }
void SetOriginateTimestampSeconds(uint32_t aTimestamp)
{
mOriginateTimestampSeconds = BigEndian::HostSwap32(aTimestamp);
}
uint32_t GetOriginateTimestampFraction(void) const
{
return BigEndian::HostSwap32(mOriginateTimestampFraction);
}
void SetOriginateTimestampFraction(uint32_t aFraction)
{
mOriginateTimestampFraction = BigEndian::HostSwap32(aFraction);
}
uint32_t GetReceiveTimestampSeconds(void) const { return BigEndian::HostSwap32(mReceiveTimestampSeconds); }
void SetReceiveTimestampSeconds(uint32_t aTimestamp)
{
mReceiveTimestampSeconds = BigEndian::HostSwap32(aTimestamp);
}
uint32_t GetReceiveTimestampFraction(void) const { return BigEndian::HostSwap32(mReceiveTimestampFraction); }
void SetReceiveTimestampFraction(uint32_t aFraction)
{
mReceiveTimestampFraction = BigEndian::HostSwap32(aFraction);
}
uint32_t GetTransmitTimestampSeconds(void) const { return BigEndian::HostSwap32(mTransmitTimestampSeconds); }
void SetTransmitTimestampSeconds(uint32_t aTimestamp)
{
mTransmitTimestampSeconds = BigEndian::HostSwap32(aTimestamp);
}
uint32_t GetTransmitTimestampFraction(void) const { return BigEndian::HostSwap32(mTransmitTimestampFraction); }
void SetTransmitTimestampFraction(uint32_t aFraction)
{
mTransmitTimestampFraction = BigEndian::HostSwap32(aFraction);
}
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 client when request departed for the server (NTP format).
uint32_t mOriginateTimestampFraction; // Fraction part of above value.
uint32_t mReceiveTimestampSeconds; // Time at server when request arrived from the client (NTP format).
uint32_t mReceiveTimestampFraction; // Fraction part of above value.
uint32_t mTransmitTimestampSeconds; // Time at server when the response left for the client (NTP format).
uint32_t mTransmitTimestampFraction; // Fraction part of above value.
} OT_TOOL_PACKED_END;
struct QueryMetadata : public Message::FooterData<QueryMetadata>
{
uint32_t mTransmitTimestamp; // Time at client when request departed for server
Callback<ResponseHandler> mResponseHandler; // Response handler callback
TimeMilli mTransmissionTime; // Time when the timer should shoot for this message
Ip6::Address mSourceAddress; // Source IPv6 address
Ip6::Address mDestinationAddress; // Destination IPv6 address
uint16_t mDestinationPort; // Destination UDP port
uint8_t mRetransmissionCount; // Number of retransmissions
};
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);
void HandleRetransmissionTimer(void);
void HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
using RetxTimer = TimerMilliIn<Client, &Client::HandleRetransmissionTimer>;
using ClientSocket = Ip6::Udp::SocketIn<Client, &Client::HandleUdpReceive>;
ClientSocket mSocket;
MessageQueue mPendingQueries;
RetxTimer mRetransmissionTimer;
uint32_t mUnixEra;
};
} // namespace Sntp
} // namespace ot
#endif // OPENTHREAD_CONFIG_SNTP_CLIENT_ENABLE
#endif // OT_CORE_NET_SNTP_CLIENT_HPP_