coreSNTP  v1.0.0
Client library for synchronizing device time with internet time using Simple Network Time Protocol (SNTP)
core_sntp_client.c File Reference

Implementation of the client API of the coreSNTP library. More...

#include <assert.h>
#include <string.h>
#include "core_sntp_client.h"

Macros

#define FRACTIONS_TO_MS(fractions)    ( fractions / ( SNTP_FRACTION_VALUE_PER_MICROSECOND * 1000U ) )
 Utility to convert fractions part of SNTP timestamp to milliseconds. More...
 

Functions

SntpStatus_t Sntp_Init (SntpContext_t *pContext, const SntpServerInfo_t *pTimeServers, size_t numOfServers, uint32_t serverResponseTimeoutMs, uint8_t *pNetworkBuffer, size_t bufferSize, SntpResolveDns_t resolveDnsFunc, SntpGetTime_t getSystemTimeFunc, SntpSetTime_t setSystemTimeFunc, const UdpTransportInterface_t *pTransportIntf, const SntpAuthenticationInterface_t *pAuthIntf)
 Initializes a context for SNTP client communication with SNTP/NTP servers. More...
 
static uint64_t calculateElapsedTimeMs (const SntpTimestamp_t *pCurrentTime, const SntpTimestamp_t *pOlderTime)
 Utility to calculate the difference in milliseconds between 2 SNTP timestamps. More...
 
static SntpStatus_t validateContext (const SntpContext_t *pContext)
 Validates the content of the SNTP context passed to the APIs to check whether it represents an initialized context. More...
 
static SntpStatus_t sendSntpPacket (const UdpTransportInterface_t *pNetworkIntf, uint32_t timeServer, uint16_t serverPort, SntpGetTime_t getTimeFunc, const uint8_t *pPacket, uint16_t packetSize, uint32_t timeoutMs)
 Sends SNTP request packet to the passed server over the network using transport interface's send function. More...
 
static SntpStatus_t addClientAuthentication (SntpContext_t *pContext)
 Adds client authentication data to SNTP request packet by calling the authentication interface. More...
 
SntpStatus_t Sntp_SendTimeRequest (SntpContext_t *pContext, uint32_t randomNumber, uint32_t blockTimeMs)
 Sends a request for time from the currently configured server (in the context). If the user has provided an authentication interface, the client authentication code is appended to the request before sending over the network by calling the SntpGenerateAuthCode_t function of the SntpAuthenticationInterface_t. More...
 
static void rotateServerForNextTimeQuery (SntpContext_t *pContext)
 Utility to update the SNTP context to rotate the server of use for subsequent time request(s). More...
 
static SntpStatus_t receiveSntpResponse (const UdpTransportInterface_t *pTransportIntf, uint32_t timeServer, uint16_t serverPort, uint8_t *pBuffer, uint16_t responseSize)
 This function attempts to receive the SNTP response packet from a server. More...
 
static SntpStatus_t processServerResponse (SntpContext_t *pContext, const SntpTimestamp_t *pResponseRxTime)
 Processes the response from a server by de-serializing the SNTP packet to validate the server (if an authentication interface has been configured), determine whether server has accepted or rejected the time request, and update the system clock if the server responded positively with time. More...
 
static bool decideAboutReadRetry (const SntpTimestamp_t *pCurrentTime, const SntpTimestamp_t *pReadStartTime, const SntpTimestamp_t *pRequestTime, uint32_t responseTimeoutMs, uint32_t blockTimeMs, bool *pHasResponseTimedOut)
 Determines whether a retry attempt should be made to receive server response packet from the network depending on the timing constraints of server response timeout, responseTimeoutMs, and the block time period, blockTimeMs, passed. If neither of the time windows have expired, the function determines that the read operation can be re-tried. More...
 
SntpStatus_t Sntp_ReceiveTimeResponse (SntpContext_t *pContext, uint32_t blockTimeMs)
 Receives a time response from the server that has been requested for time with the Sntp_SendTimeRequest API function. Once an accepted response containing time from server is received, this function calls the user-defined SntpSetTime_t function to update the system time. More...
 
const char * Sntp_StatusToStr (SntpStatus_t status)
 Converts SntpStatus_t to its equivalent string. More...
 

Detailed Description

Implementation of the client API of the coreSNTP library.

Macro Definition Documentation

◆ FRACTIONS_TO_MS

#define FRACTIONS_TO_MS (   fractions)     ( fractions / ( SNTP_FRACTION_VALUE_PER_MICROSECOND * 1000U ) )

Utility to convert fractions part of SNTP timestamp to milliseconds.

Parameters
[in]fractionsThe fractions value in an SNTP timestamp.

Function Documentation

◆ Sntp_Init()

SntpStatus_t Sntp_Init ( SntpContext_t pContext,
const SntpServerInfo_t pTimeServers,
size_t  numOfServers,
uint32_t  serverResponseTimeoutMs,
uint8_t *  pNetworkBuffer,
size_t  bufferSize,
SntpResolveDns_t  resolveDnsFunc,
SntpGetTime_t  getSystemTimeFunc,
SntpSetTime_t  setSystemTimeFunc,
const UdpTransportInterface_t pTransportIntf,
const SntpAuthenticationInterface_t pAuthIntf 
)

Initializes a context for SNTP client communication with SNTP/NTP servers.

Parameters
[out]pContextThe user-supplied memory for the context that will be initialized to represent an SNTP client.
[in]pTimeServersThe list of decreasing order of priority of time servers that should be used by the SNTP client. This list MUST stay in scope for all the time of use of the context.
[in]numOfServersThe number of servers in the list, pTimeServers.
[in]serverResponseTimeoutMsThe timeout duration (in milliseconds) for receiving server response for time requests. The same timeout value is used for each server in the pTimeServers list.
[in]pNetworkBufferThe user-supplied memory that will be used for storing network data for SNTP client-server communication. The buffer MUST stay in scope for all the time of use of the context.
[in]bufferSizeThe size of the passed buffer pNetworkBuffer. The buffer SHOULD be appropriately sized for storing an entire SNTP packet which includes both SNTP_PACKET_BASE_SIZE bytes of standard SNTP packet size, and space for authentication data, if security mechanism is used to communicate with any of the time servers configured for use.
[in]resolveDnsFuncThe user-defined function for DNS resolution of time server.
[in]getSystemTimeFuncThe user-defined function for querying system time.
[in]setSystemTimeFuncThe user-defined function for correcting system time for every successful time response received from a server.
[in]pTransportIntfThe user-defined function for performing network send/recv operations over UDP.
[in]pAuthIntfThe user-defined interface for generating client authentication in SNTP requests and authenticating servers in SNTP responses, if security mechanism is used in SNTP communication with server(s). If security mechanism is not used in communication with any of the configured servers (in pTimeServers), then the SntpAuthenticationInterface_t does not need to be defined and this parameter can be NULL.
Returns
This function returns one of the following:

◆ calculateElapsedTimeMs()

static uint64_t calculateElapsedTimeMs ( const SntpTimestamp_t pCurrentTime,
const SntpTimestamp_t pOlderTime 
)
static

Utility to calculate the difference in milliseconds between 2 SNTP timestamps.

Parameters
[in]pCurrentTimeThe more recent timestamp.
[in]pOlderTimeThe older timestamp.
Note
This functions supports the edge case of SNTP timestamp overflow when pCurrentTime represents time in NTP era 1 (i.e. time since 7 Feb 2036) and the OlderTime represents time in NTP era 0 (i.e. time since 1st Jan 1900).
Returns
Returns the calculated time duration between the two timestamps.
Note
This function returns the calculated time difference as unsigned 64 bit to avoid integer overflow when converting time difference between the seconds part of the timestamps, which are 32 bits wide, to milliseconds.

◆ validateContext()

static SntpStatus_t validateContext ( const SntpContext_t pContext)
static

Validates the content of the SNTP context passed to the APIs to check whether it represents an initialized context.

Parameters
[in]pContextThe SNTP context to validate.
Returns
Returns one of the following:

◆ sendSntpPacket()

static SntpStatus_t sendSntpPacket ( const UdpTransportInterface_t pNetworkIntf,
uint32_t  timeServer,
uint16_t  serverPort,
SntpGetTime_t  getTimeFunc,
const uint8_t *  pPacket,
uint16_t  packetSize,
uint32_t  timeoutMs 
)
static

Sends SNTP request packet to the passed server over the network using transport interface's send function.

Note
For the case of zero byte transmissions over the network, this function repeatedly retries the send operation by calling the transport interface until either:
  1. The requested number of bytes packetSize have been sent. OR
  2. There is an error in sending data over the network.
This function treats partial data transmissions as error as UDP transport protocol does not support partial sends.
Parameters
[in]pNetworkIntfThe UDP transport interface to use for sending data over the network.
[in]timeServerThe IPv4 address of the server to send the SNTP request packet to.
[in]serverPortThe port of the timeServer to send the request to.
[in]getTimeFuncThe function to query system time for tracking retry time period of no data transmissions.
[in]pPacketThe buffer containing the SNTP packet data to send over the network.
[in]packetSizeThe size of data in the SNTP request packet.
[in]timeoutMsThe timeout period for retry attempts of sending SNTP request packet over the network.
Returns
Returns SntpSuccess on successful transmission of the entire SNTP request packet over the network; SntpErrorNetworkFailure to indicate failure from transport interface; SntpErrorSendTimeout if time request could not be sent over the network within the timeoutMs duration.

◆ addClientAuthentication()

static SntpStatus_t addClientAuthentication ( SntpContext_t pContext)
static

Adds client authentication data to SNTP request packet by calling the authentication interface.

Parameters
[in]pContextThe SNTP context.
Returns
Returns one of the following:
  • SntpSuccess if the interface function successfully appends client authentication data.
  • SntpErrorAuthFailure when the interface returns either an error OR an incorrect size of the client authentication data.

◆ Sntp_SendTimeRequest()

SntpStatus_t Sntp_SendTimeRequest ( SntpContext_t pContext,
uint32_t  randomNumber,
uint32_t  blockTimeMs 
)

Sends a request for time from the currently configured server (in the context). If the user has provided an authentication interface, the client authentication code is appended to the request before sending over the network by calling the SntpGenerateAuthCode_t function of the SntpAuthenticationInterface_t.

Note
This function will ONLY send a request if there is a server available in the configured list that has not rejected an earlier request for time. This adheres to the Best Practice functionality specified in Section 10 Point 8 of SNTPv4 specification.
Parameters
[in]pContextThe context representing an SNTPv4 client.
[in]randomNumberA random number serializing the SNTP request packet to protect against spoofing attacks by attackers that are off the network path of the SNTP client-server communication. This mechanism is suggested by SNTPv4 specification in RFC 4330 Section 3.
[in]blockTimeMsThe maximum duration of time (in milliseconds) the function will block on attempting to send time request to the server over the network. If a zero block time value is provided, then the function will attempt to send the packet ONLY once.
Note
It is RECOMMENDED that a True Random Number Generator is used to generate the random number by using a hardware module, like Hardware Security Module (HSM), Secure Element, etc, as the entropy source.
Returns
The API function returns one of the following:
  • SntpSuccess if a time request is successfully sent to the currently configured time server in the context.
  • SntpErrorBadParameter if an invalid context is passed to the function.
  • SntpErrorContextNotInitialized if an uninitialized or invalid context is passed to the function.
  • SntpErrorDnsFailure if there is failure in the user-defined function for DNS resolution of the time server.
  • SntpErrorNetworkFailure if the SNTP request could not be sent over the network through the user-defined transport interface.
  • SntpErrorAuthFailure if there was a failure in generating the client authentication code in the user-defined authentication interface.
  • SntpErrorSendTimeout if the time request packet could not be sent over the network for the entire blockTimeMs duration.

◆ rotateServerForNextTimeQuery()

static void rotateServerForNextTimeQuery ( SntpContext_t pContext)
static

Utility to update the SNTP context to rotate the server of use for subsequent time request(s).

Note
If there is no next server remaining, after the current server's index, in the list of configured servers, the server rotation algorithm wraps around to the first server in the list. The wrap around is done so that an application using the library for a long-running SNTP client functionality (like a daemon task) does not become dysfunctional after all configured time servers have been used up. Time synchronization can be a critical functionality for a system and the wrap around logic ensures that the SNTP client continues to function in such a case.
Server rotation is performed ONLY when either of:
  • The current server responds with a rejection for time request. OR
  • The current server response wait has timed out.

◆ receiveSntpResponse()

static SntpStatus_t receiveSntpResponse ( const UdpTransportInterface_t pTransportIntf,
uint32_t  timeServer,
uint16_t  serverPort,
uint8_t *  pBuffer,
uint16_t  responseSize 
)
static

This function attempts to receive the SNTP response packet from a server.

Note
This function treats reads of data sizes less than the expected server response packet, as an error as UDP does not support partial reads. Such a scenario can exist either due:
  • An error in the server sending its response with smaller packet size than the request packet OR
  • A malicious attacker spoofing or modifying server response OR
  • An error in the UDP transport interface implementation for read operation.
Parameters
[in]pTransportIntfThe UDP transport interface to use for receiving data from the network.
[in]timeServerThe server to read the response from the network.
[in]serverPortThe port of the server to read the response from.
[in,out]pBufferThis will be filled with the server response read from the network.
[in]responseSizeThe size of server response to read from the network.
Returns
It returns one of the following:

◆ processServerResponse()

static SntpStatus_t processServerResponse ( SntpContext_t pContext,
const SntpTimestamp_t pResponseRxTime 
)
static

Processes the response from a server by de-serializing the SNTP packet to validate the server (if an authentication interface has been configured), determine whether server has accepted or rejected the time request, and update the system clock if the server responded positively with time.

Parameters
[in]pContextThe SNTP context representing the SNTP client.
[in]pResponseRxTimeThe time of receiving the server response from the network.
Returns
It returns one of the following:

◆ decideAboutReadRetry()

static bool decideAboutReadRetry ( const SntpTimestamp_t pCurrentTime,
const SntpTimestamp_t pReadStartTime,
const SntpTimestamp_t pRequestTime,
uint32_t  responseTimeoutMs,
uint32_t  blockTimeMs,
bool *  pHasResponseTimedOut 
)
static

Determines whether a retry attempt should be made to receive server response packet from the network depending on the timing constraints of server response timeout, responseTimeoutMs, and the block time period, blockTimeMs, passed. If neither of the time windows have expired, the function determines that the read operation can be re-tried.

Parameters
[in]pCurrentTimeThe current time in the system used for calculating elapsed time windows.
[in]pReadStartTimeThe time of the first read attempt in the current set of read tries occurring from the Sntp_ReceiveTimeRequest API call by the application. This time is used for calculating the elapsed time to determine whether the block time has expired.
[in]pRequestTimeThe time of sending the SNTP request to the server for which the response is awaited. This time is used for calculating total elapsed elapsed time of waiting for server response to determine if a server response timeout has occurred.
[in]responseTimeoutMsThe server response timeout configuration.
[in]blockTimeMsThe maximum block time of waiting for server response across read tries in the current call made by application to Sntp_ReceiveTimeResponse API.
[out]pHasResponseTimedOutThis will be populated with state to indicate whether the wait for server response has timed out.
Returns
Returns true for retrying read operation of server response; false on either server response timeout OR completion of block time window.

◆ Sntp_ReceiveTimeResponse()

SntpStatus_t Sntp_ReceiveTimeResponse ( SntpContext_t pContext,
uint32_t  blockTimeMs 
)

Receives a time response from the server that has been requested for time with the Sntp_SendTimeRequest API function. Once an accepted response containing time from server is received, this function calls the user-defined SntpSetTime_t function to update the system time.

Note
If the user has provided an authentication interface to the client (through Sntp_Init), the server response is authenticated by calling the SntpValidateServerAuth_t function of the SntpAuthenticationInterface_t interface.
On receiving a successful server response containing server time, this API calculates the clock offset value of the system clock relative to the server before calling the user-defined SntpSetTime_t function for updating the system time.
For correct calculation of clock-offset, the server and client times MUST be within ~68 years (or 2^31 seconds) of each other. In the special case when the server and client times are exactly 2^31 seconds apart, the library ASSUMES that the server time is ahead of the client time, and returns the positive clock-offset value of INT32_MAX seconds.
This API will rotate the server of use in the library for the next time request (through the Sntp_SendTimeRequest) if either of following events occur:
  • The server has responded with a rejection for the time request. OR
  • The server response wait has timed out. If all the servers configured in the context have been used, the API will rotate server for time query back to the first server in the list which will be used in next time request.
Parameters
[in]pContextThe context representing an SNTPv4 client.
[in]blockTimeMsThe maximum duration of time (in milliseconds) the function will block on receiving a response from the server unless either the response is received OR a response timeout occurs.
Note
This function can be called multiple times with zero or small blocking times to poll whether server response is received until either the response response is received from the server OR a response timeout has occurred.
Returns
This API functions returns one of the following:

◆ Sntp_StatusToStr()

const char* Sntp_StatusToStr ( SntpStatus_t  status)

Converts SntpStatus_t to its equivalent string.

Note
The returned string MUST NOT be modified.
Parameters
[in]statusThe status to convert to a string.
Returns
The string representation of the status code.