[sntp] clean up and improve Sntp::Client (#13114)

This commit refactors and improves the `Sntp::Client` class by
adopting common OpenThread patterns and simplifying the logic.

Key changes:
- Introduced `Sntp::Client::QueryInfo` core class to wrap the
  public `otSntpQuery` structure.
- Added `Timestamp` class to handle SNTP timestamps, simplifying
  the `Header` structure.
- Renamed methods and variables to be more concise and consistent
  (e.g., `FinalizeSntpTransaction` to `Finalize`,
  `mRetransmissionTimer` to `mTimer`).
- Simplified the `HandleUdpReceive` logic by splitting response
  processing into `ProcessResponse`.

This change improves code readability and maintainability of the
SNTP client module.
This commit is contained in:
Abtin Keshavarzian
2026-05-18 13:04:37 -07:00
committed by GitHub
parent 86b8bf6de4
commit 64c4124bd1
4 changed files with 179 additions and 241 deletions
+1 -1
View File
@@ -46,7 +46,7 @@ otError otSntpClientQuery(otInstance *aInstance,
otSntpResponseHandler aHandler,
void *aContext)
{
return AsCoreType(aInstance).Get<Sntp::Client>().Query(aQuery, aHandler, aContext);
return AsCoreType(aInstance).Get<Sntp::Client>().Query(AsCoreType(aQuery), aHandler, aContext);
}
void otSntpClientSetUnixEra(otInstance *aInstance, uint32_t aUnixEra)
+88 -114
View File
@@ -45,7 +45,7 @@ RegisterLogModule("SntpClnt");
Client::Client(Instance &aInstance)
: mSocket(aInstance, *this)
, mRetransmissionTimer(aInstance)
, mTimer(aInstance)
, mUnixEra(0)
{
}
@@ -65,98 +65,80 @@ Error Client::Stop(void)
{
for (Message &message : mPendingQueries)
{
QueryMetadata queryMetadata;
QueryMetadata metadata;
queryMetadata.ReadFrom(message);
FinalizeSntpTransaction(message, queryMetadata, 0, kErrorAbort);
metadata.ReadFrom(message);
Finalize(message, metadata, 0, kErrorAbort);
}
return mSocket.Close();
}
Error Client::Query(const otSntpQuery *aQuery, otSntpResponseHandler aHandler, void *aContext)
Error Client::Query(const QueryInfo &aQuery, ResponseHandler aHandler, void *aContext)
{
Error error;
QueryMetadata queryMetadata;
Message *message = nullptr;
Message *messageCopy = nullptr;
Header header;
const Ip6::MessageInfo *messageInfo;
Error error;
QueryMetadata metadata;
Message *message = nullptr;
Message *messageCopy = nullptr;
Header header;
VerifyOrExit(aQuery->mMessageInfo != nullptr, error = kErrorInvalidArgs);
VerifyOrExit(aQuery.IsValid(), error = kErrorInvalidArgs);
header.Init();
// Originate timestamp is used only as a unique token.
header.SetTransmitTimestampSeconds(TimerMilli::GetNow().GetValue() / 1000 + kTimeAt1970);
header.GetTxTimestamp().SetSeconds(TimerMilli::GetNow().GetValue() / 1000 + kTimeAt1970);
message = mSocket.NewMessage();
VerifyOrExit(message != nullptr, error = kErrorNoBufs);
SuccessOrExit(error = message->Append(header));
messageInfo = AsCoreTypePtr(aQuery->mMessageInfo);
metadata.mResponseCallback.Set(aHandler, aContext);
metadata.mTxTimestamp = header.GetTxTimestamp().GetSeconds();
metadata.mRetxTime = TimerMilli::GetNow() + kResponseTimeout;
metadata.mSourceAddr = aQuery.GetMessageInfo().GetSockAddr();
metadata.mDestPort = aQuery.GetMessageInfo().GetPeerPort();
metadata.mDestAddr = aQuery.GetMessageInfo().GetPeerAddr();
metadata.mRetxCount = 0;
queryMetadata.mResponseHandler.Set(aHandler, aContext);
queryMetadata.mTransmitTimestamp = header.GetTransmitTimestampSeconds();
queryMetadata.mTransmissionTime = TimerMilli::GetNow() + kResponseTimeout;
queryMetadata.mSourceAddress = messageInfo->GetSockAddr();
queryMetadata.mDestinationPort = messageInfo->GetPeerPort();
queryMetadata.mDestinationAddress = messageInfo->GetPeerAddr();
queryMetadata.mRetransmissionCount = 0;
messageCopy = CopyAndEnqueueMessage(*message, metadata);
VerifyOrExit(messageCopy != nullptr, error = kErrorNoBufs);
VerifyOrExit((messageCopy = CopyAndEnqueueMessage(*message, queryMetadata)) != nullptr, error = kErrorNoBufs);
SuccessOrExit(error = SendMessage(*message, *messageInfo));
SuccessOrExit(error = mSocket.SendTo(*message, aQuery.GetMessageInfo()));
mTimer.FireAtIfEarlier(metadata.mRetxTime);
message = nullptr;
messageCopy = nullptr;
exit:
FreeMessage(message);
if (error != kErrorNone)
if (messageCopy != nullptr)
{
FreeMessage(message);
if (messageCopy)
{
DequeueMessage(*messageCopy);
}
mPendingQueries.DequeueAndFree(*messageCopy);
}
return error;
}
Message *Client::CopyAndEnqueueMessage(const Message &aMessage, const QueryMetadata &aQueryMetadata)
Message *Client::CopyAndEnqueueMessage(const Message &aMessage, const QueryMetadata &aMetadata)
{
Error error = kErrorNone;
Message *messageCopy = nullptr;
Error error;
Message *messageCopy;
// Create a message copy for further retransmissions.
VerifyOrExit((messageCopy = aMessage.Clone<kNoReservedHeader>()) != nullptr, error = kErrorNoBufs);
messageCopy = aMessage.Clone<kNoReservedHeader>();
VerifyOrExit(messageCopy != nullptr, error = kErrorNoBufs);
SuccessOrExit(error = aMetadata.AppendTo(*messageCopy));
// Append the copy with retransmission data and add it to the queue.
SuccessOrExit(error = aQueryMetadata.AppendTo(*messageCopy));
mPendingQueries.Enqueue(*messageCopy);
mRetransmissionTimer.FireAtIfEarlier(aQueryMetadata.mTransmissionTime);
exit:
FreeAndNullMessageOnError(messageCopy, error);
return messageCopy;
}
void Client::DequeueMessage(Message &aMessage)
{
if (mRetransmissionTimer.IsRunning() && (mPendingQueries.GetHead() == nullptr))
{
// No more requests pending, stop the timer.
mRetransmissionTimer.Stop();
}
mPendingQueries.DequeueAndFree(aMessage);
}
Error Client::SendMessage(Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
{
return mSocket.SendTo(aMessage, aMessageInfo);
}
void Client::SendCopy(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
{
Error error;
@@ -165,115 +147,114 @@ void Client::SendCopy(const Message &aMessage, const Ip6::MessageInfo &aMessageI
messageCopy = mSocket.CloneMessageWithout<QueryMetadata>(aMessage);
VerifyOrExit(messageCopy != nullptr, error = kErrorNoBufs);
SuccessOrExit(error = SendMessage(*messageCopy, aMessageInfo));
error = mSocket.SendTo(*messageCopy, aMessageInfo);
exit:
if (error != kErrorNone)
{
FreeMessage(messageCopy);
LogWarnOnError(error, "send SNTP request");
}
FreeMessageOnError(messageCopy, error);
}
Message *Client::FindRelatedQuery(const Header &aResponseHeader, QueryMetadata &aQueryMetadata)
Message *Client::FindRelatedQuery(const Header &aResponseHeader, QueryMetadata &aMetadata)
{
Message *matchedMessage = nullptr;
Message *matched = nullptr;
for (Message &message : mPendingQueries)
{
// Read originate timestamp.
aQueryMetadata.ReadFrom(message);
aMetadata.ReadFrom(message);
if (aQueryMetadata.mTransmitTimestamp == aResponseHeader.GetOriginateTimestampSeconds())
if (aMetadata.mTxTimestamp == aResponseHeader.GetOriginateTimestamp().GetSeconds())
{
matchedMessage = &message;
matched = &message;
break;
}
}
return matchedMessage;
return matched;
}
void Client::FinalizeSntpTransaction(Message &aQuery,
const QueryMetadata &aQueryMetadata,
uint64_t aTime,
Error aResult)
void Client::Finalize(Message &aQuery, const QueryMetadata &aMetadata, uint64_t aTime, Error aResult)
{
DequeueMessage(aQuery);
aQueryMetadata.mResponseHandler.InvokeIfSet(aTime, aResult);
mPendingQueries.DequeueAndFree(aQuery);
aMetadata.mResponseCallback.InvokeIfSet(aTime, aResult);
}
void Client::HandleRetransmissionTimer(void)
void Client::HandleTimer(void)
{
NextFireTime nextTime;
QueryMetadata queryMetadata;
QueryMetadata metadata;
Ip6::MessageInfo messageInfo;
for (Message &message : mPendingQueries)
{
queryMetadata.ReadFrom(message);
metadata.ReadFrom(message);
if (nextTime.GetNow() >= queryMetadata.mTransmissionTime)
if (nextTime.GetNow() >= metadata.mRetxTime)
{
if (queryMetadata.mRetransmissionCount >= kMaxRetransmit)
if (metadata.mRetxCount >= kMaxRetransmit)
{
// No expected response.
FinalizeSntpTransaction(message, queryMetadata, 0, kErrorResponseTimeout);
Finalize(message, metadata, 0, kErrorResponseTimeout);
continue;
}
// Increment retransmission counter and timer.
queryMetadata.mRetransmissionCount++;
queryMetadata.mTransmissionTime = nextTime.GetNow() + kResponseTimeout;
queryMetadata.UpdateIn(message);
metadata.mRetxCount++;
metadata.mRetxTime = nextTime.GetNow() + kResponseTimeout;
metadata.UpdateIn(message);
// Retransmit
messageInfo.SetPeerAddr(queryMetadata.mDestinationAddress);
messageInfo.SetPeerPort(queryMetadata.mDestinationPort);
messageInfo.SetSockAddr(queryMetadata.mSourceAddress);
messageInfo.SetPeerAddr(metadata.mDestAddr);
messageInfo.SetPeerPort(metadata.mDestPort);
messageInfo.SetSockAddr(metadata.mSourceAddr);
SendCopy(message, messageInfo);
}
nextTime.UpdateIfEarlier(queryMetadata.mTransmissionTime);
nextTime.UpdateIfEarlier(metadata.mRetxTime);
}
mRetransmissionTimer.FireAt(nextTime);
mTimer.FireAt(nextTime);
}
void Client::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
{
OT_UNUSED_VARIABLE(aMessageInfo);
Error error = kErrorNone;
Header responseHeader;
QueryMetadata queryMetadata;
Message *message = nullptr;
uint64_t unixTime = 0;
Header header;
Message *query;
QueryMetadata metadata;
SuccessOrExit(aMessage.Read(aMessage.GetOffset(), responseHeader));
SuccessOrExit(aMessage.Read(aMessage.GetOffset(), header));
VerifyOrExit((message = FindRelatedQuery(responseHeader, queryMetadata)) != nullptr);
query = FindRelatedQuery(header, metadata);
VerifyOrExit(query != nullptr);
ProcessResponse(*query, metadata, header);
exit:
return;
}
void Client::ProcessResponse(Message &aQuery, const QueryMetadata &aMetadata, Header &aResponseHeader)
{
Error error = kErrorNone;
uint64_t unixTime = 0;
// Check if response came from the server.
VerifyOrExit(responseHeader.GetMode() == Header::kModeServer, error = kErrorFailed);
VerifyOrExit(aResponseHeader.GetMode() == Header::kModeServer, error = kErrorFailed);
// Check the Kiss-o'-death packet.
if (!responseHeader.GetStratum())
if (!aResponseHeader.GetStratum())
{
char kissCode[Header::kKissCodeLength + 1];
memcpy(kissCode, responseHeader.GetKissCode(), Header::kKissCodeLength);
kissCode[Header::kKissCodeLength] = 0;
memcpy(kissCode, aResponseHeader.GetKissCode(), Header::kKissCodeLength);
kissCode[Header::kKissCodeLength] = kNullChar;
LogInfo("SNTP response contains the Kiss-o'-death packet with %s code", kissCode);
ExitNow(error = kErrorBusy);
}
// Check if timestamp has been set.
VerifyOrExit(responseHeader.GetTransmitTimestampSeconds() != 0 &&
responseHeader.GetTransmitTimestampFraction() != 0,
error = kErrorFailed);
VerifyOrExit(!aResponseHeader.GetTxTimestamp().IsZero(), error = kErrorFailed);
// The NTP time starts at 1900 while the unix epoch starts at 1970.
// Due to NTP protocol limitation, this module stops working correctly after around year 2106, if
@@ -281,24 +262,17 @@ void Client::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessag
// obtained using NTP protocol, and client of this module is responsible to set it properly.
unixTime = GetUnixEra() * (1ULL << 32);
if (responseHeader.GetTransmitTimestampSeconds() > kTimeAt1970)
if (aResponseHeader.GetTxTimestamp().GetSeconds() > kTimeAt1970)
{
unixTime += static_cast<uint64_t>(responseHeader.GetTransmitTimestampSeconds()) - kTimeAt1970;
unixTime += static_cast<uint64_t>(aResponseHeader.GetTxTimestamp().GetSeconds()) - kTimeAt1970;
}
else
{
unixTime += static_cast<uint64_t>(responseHeader.GetTransmitTimestampSeconds()) + (1ULL << 32) - kTimeAt1970;
unixTime += static_cast<uint64_t>(aResponseHeader.GetTxTimestamp().GetSeconds()) + (1ULL << 32) - kTimeAt1970;
}
// Return the time since 1970.
FinalizeSntpTransaction(*message, queryMetadata, unixTime, kErrorNone);
exit:
if (message != nullptr && error != kErrorNone)
{
FinalizeSntpTransaction(*message, queryMetadata, 0, error);
}
Finalize(aQuery, aMetadata, unixTime, error);
}
} // namespace Sntp
+88 -126
View File
@@ -35,6 +35,7 @@
#include <openthread/sntp.h>
#include "common/as_core_type.hpp"
#include "common/clearable.hpp"
#include "common/message.hpp"
#include "common/non_copyable.hpp"
@@ -58,6 +59,18 @@ class Client : private NonCopyable
public:
typedef otSntpResponseHandler ResponseHandler; ///< Response handler callback.
/**
* Represents an SNTP Query parameters.
*/
class QueryInfo : public otSntpQuery
{
friend class Client;
private:
bool IsValid(void) const { return mMessageInfo != nullptr; }
const Ip6::MessageInfo &GetMessageInfo(void) const { return AsCoreType(mMessageInfo); }
};
/**
* Initializes the object.
*
@@ -105,7 +118,7 @@ public:
* @retval kErrorNoBufs Failed to allocate retransmission data.
* @retval kErrorInvalidArgs Invalid arguments supplied.
*/
Error Query(const otSntpQuery *aQuery, ResponseHandler aHandler, void *aContext);
Error Query(const QueryInfo &aQuery, ResponseHandler aHandler, void *aContext);
private:
static constexpr uint32_t kTimeAt1970 = 2208988800UL; // num seconds between 1st Jan 1900 and 1st Jan 1970.
@@ -113,102 +126,56 @@ private:
static constexpr uint32_t kResponseTimeout = OPENTHREAD_CONFIG_SNTP_CLIENT_RESPONSE_TIMEOUT;
static constexpr uint8_t kMaxRetransmit = OPENTHREAD_CONFIG_SNTP_CLIENT_MAX_RETRANSMIT;
typedef Callback<ResponseHandler> ResponseCallback;
OT_TOOL_PACKED_BEGIN
class Timestamp : public Clearable<Timestamp>
{
public:
bool IsZero(void) const { return (mSeconds == 0) && (mFraction == 0); }
uint32_t GetSeconds(void) const { return BigEndian::HostSwap32(mSeconds); }
void SetSeconds(uint32_t aSeconds) { mSeconds = BigEndian::HostSwap32(aSeconds); }
uint32_t GetFraction(void) const { return BigEndian::HostSwap32(mFraction); }
void SetFraction(uint32_t aFraction) { mFraction = BigEndian::HostSwap32(aFraction); }
private:
uint32_t mSeconds;
uint32_t mFraction;
} OT_TOOL_PACKED_END;
OT_TOOL_PACKED_BEGIN
class Header : public Clearable<Header>
{
public:
enum Mode : uint8_t
{
kModeClient = 3,
kModeServer = 4,
};
static constexpr uint8_t kModeClient = 3;
static constexpr uint8_t 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);
}
void Init(void) { Clear(), mFlags = (kNtpVersion << kVersionOffset | kModeClient << kModeOffset); }
uint8_t GetFlags(void) const { return mFlags; }
void SetFlags(uint8_t aFlags) { mFlags = aFlags; }
uint8_t GetMode(void) const { return 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 aDelay) { mRootDelay = BigEndian::HostSwap32(aDelay); }
uint32_t GetRootDispersion(void) const { return BigEndian::HostSwap32(mRootDispersion); }
void SetRootDispersion(uint32_t aDisp) { mRootDispersion = BigEndian::HostSwap32(aDisp); }
uint32_t GetReferenceId(void) const { return BigEndian::HostSwap32(mReferenceId); }
void SetReferenceId(uint32_t aId) { mReferenceId = BigEndian::HostSwap32(aId); }
char *GetKissCode(void) { return reinterpret_cast<char *>(&mReferenceId); }
Timestamp &GetReferenceTimestamp(void) { return mReferenceTimestamp; }
Timestamp &GetOriginateTimestamp(void) { return mOriginateTimestamp; }
Timestamp &GetRxTimestamp(void) { return mRxTimestamp; }
Timestamp &GetTxTimestamp(void) { return mTxTimestamp; }
const Timestamp &GetReferenceTimestamp(void) const { return mReferenceTimestamp; }
const Timestamp &GetOriginateTimestamp(void) const { return mOriginateTimestamp; }
const Timestamp &GetRxTimestamp(void) const { return mRxTimestamp; }
const Timestamp &GetTxTimestamp(void) const { return mTxTimestamp; }
private:
static constexpr uint8_t kNtpVersion = 4; // Current NTP version.
@@ -219,56 +186,51 @@ private:
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.
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.
Timestamp mReferenceTimestamp; // Time the system clock was last set or corrected.
Timestamp mOriginateTimestamp; // Time at client when request departed for the server.
Timestamp mRxTimestamp; // Time at server when request arrived from the client.
Timestamp mTxTimestamp; // Time at server when the response left for the client.
} 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
uint32_t mTxTimestamp; // Time at client when request departed for server
ResponseCallback mResponseCallback; // Response handler callback
TimeMilli mRetxTime; // Time to retx the query (`kResponseTimeout` after last tx)
Ip6::Address mSourceAddr; // Source IPv6 address
Ip6::Address mDestAddr; // Destination IPv6 address
uint16_t mDestPort; // Destination UDP port
uint8_t mRetxCount; // Number of retransmissions
};
Message *CopyAndEnqueueMessage(const Message &aMessage, const QueryMetadata &aQueryMetadata);
void DequeueMessage(Message &aMessage);
Error SendMessage(Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
Message *CopyAndEnqueueMessage(const Message &aMessage, const QueryMetadata &aMetadata);
void SendCopy(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
Message *FindRelatedQuery(const Header &aResponseHeader, QueryMetadata &aMetadata);
void Finalize(Message &aQuery, const QueryMetadata &aMetadata, uint64_t aTime, Error aResult);
void HandleTimer(void);
void HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
void ProcessResponse(Message &aQuery, const QueryMetadata &aMetadata, Header &aResponseHeader);
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 RetxTimer = TimerMilliIn<Client, &Client::HandleTimer>;
using ClientSocket = Ip6::Udp::SocketIn<Client, &Client::HandleUdpReceive>;
ClientSocket mSocket;
MessageQueue mPendingQueries;
RetxTimer mRetransmissionTimer;
uint32_t mUnixEra;
RetxTimer mTimer;
uint32_t mUnixEra;
};
} // namespace Sntp
DefineCoreType(otSntpQuery, Sntp::Client::QueryInfo);
} // namespace ot
#endif // OPENTHREAD_CONFIG_SNTP_CLIENT_ENABLE
@@ -199,6 +199,8 @@
#define OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_DEFAULT_MODE 0
#define OPENTHREAD_CONFIG_SNTP_CLIENT_ENABLE 1
#define OPENTHREAD_CONFIG_HISTORY_TRACKER_ENABLE 1
#define OPENTHREAD_CONFIG_DNSSD_SERVER_ENABLE 1