mirror of
https://github.com/espressif/openthread.git
synced 2026-06-05 21:14:49 +00:00
[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:
committed by
GitHub
parent
86b8bf6de4
commit
64c4124bd1
@@ -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
@@ -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
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user