Chapter 192. The SNTP Client

192.1. Starting the SNTP client

The sntp client is implemented as a thread which listens for NTP broadcasts and IPv6 multicasts, and optionally sends SNTP unicast requests to specific NTP servers. This thread may be automatically started by the system if it receives a list of (S)NTP servers from the DHCP server and unicast mode is enabled. Otherwise it must be started by the user application. The header file cyg/sntp/sntp.h declares the function to be called. The thread is then started by calling the function:

void cyg_sntp_start(void);

It is safe to call this function multiple times. Once started, the thread will run forever.

192.2. What it does

The SNTP client listens for NTP IPv4 broadcasts from any NTP servers, or IPv6 multicasts using the address fe0x:0X::101, where X can be 2 (Link Local), 5 (Site-Local) or 0xe (Global). Such packets contain a timestamp indicating the current time. The packet also contains information about where the server is in the hierarchy of time servers. A server at the root of the time server tree normally has an atomic clock. Such a server is said to be at stratum 0. A time server which is synchronised to a stratum 0 server is said to be at stratum 1 etc. The client will accept any NTP packets from servers using version 3 or 4 of the protocol. When receiving packets from multiple servers, it will use the packets from the server with the lowest stratum. However, if there are no packets from this server for 10 minutes and another server is sending packets, the client will change servers.

If SNTP unicast mode is enabled via the CYGPKG_NET_SNTP_UNICAST option, the SNTP client can additionally be configured with a list of specific NTP servers to query. The general algorithm is as follows: if the system clock has not yet been set via an NTP time update, then the client will send out NTP requests every 30 seconds to all configured NTP servers. Once an NTP time update has been received, the client will send out additional NTP requests every 30 minutes in order to update the system clock. These requests are resent every 30 seconds until a response is received.

The system clock in eCos is accurate to 1 second. The SNTP client will change the system clock when the time difference with the received timestamp is greater than 2 seconds. The change is made as a step.

192.3. Configuring the unicast list of NTP servers

If SNTP unicast mode is enabled via the CYGPKG_NET_SNTP_UNICAST option, the SNTP client can be configured with a list of NTP servers to contact for time updates.

By default, this list is configured with NTP server information received from DHCP. The number of NTP servers that are extracted from DHCP can be configured with the CYGOPT_NET_SNTP_UNICAST_MAXDHCP option. This option can also be used to disable DHCP usage entirely.

The list of NTP servers can be manually configured with the following API function. Note that manual configuration will override any servers that were automatically configured by DHCP. But later reconfigurations by DHCP will override manual configurations. Hence it is not recommended to manually configure servers when CYGOPT_NET_SNTP_UNICAST is enabled.

#include <cyg/sntp/sntp.h>

void cyg_sntp_set_servers(struct sockaddr *server_list, cyg_uint32 num_servers);

This function takes an array of sockaddr structures specifying the IP address and UDP port of each NTP server to query. Currently, both IPv4 and IPv6 sockaddr structures are supported. The num_servers argument specifies how many sockaddr's are contained in the array. The server_list array must be maintained by the caller. Once the array is registered with this function, it must not be modified by the caller until it is replaced or unregistered by another call to this function.

Calling this function with a server_list of NULL and a num_servers value of 0 unregisters any previously configured server_list array.

Finally, note that if this function is called with a non-empty server list, it will implicitly start the SNTP client if it has not already been started (i.e. it will call cyg_sntp_start()).

192.4. Warning: timestamp wrap around

The timestamp in the NTP packet is a 32bit integer which represents the number of seconds after 00:00 01/01/1970. This 32bit number will wrap around at 06:28:16 Feb 7 2036. At this point in time, the eCos time will jump back to around 00:00:00 Jan 1 1970 when the next NTP packet is received.


192.5. The SNTP test program

The SNTP package contains a simple test program. Testing an SNTP client is not easy, so the test program should be considered as more a proof of concept. It shows that an NTP packet has been received, and is accurate to within a few days.

The test program starts the network interfaces using the standard call. It then starts the SNTP thread. A loop is then entered printing the current system time every second for two minutes. When the client receives an NTP packet the time will jump from 1970 to hopefully the present day. Once the two minutes have expired, two simple tests are made. If the time is still less than 5 minutes since 00:00:00 01/01/1970 the test fails. This indicates no NTP messages have been received. Check that the server is actually sending packet, using the correct port (123), correct IPv6 multicast address, and at a sufficiently frequent rate that the target has a chance to receive a message within the 2 minute interval. If all this is correct, assume the target is broken.

The second test is that the current system time is compared with the build time as reported by the CPP macro __DATE__. If the build date is in the future relative to the system time, the test fails. If the build date is more than 90 days in the past relative to the system time the test also fails. If such failures are seen, use wallclock time to verify the time printed during the test. If this seems correct check the build date for the test. This is printed at startup. If all else fails check that the computer used to build the test has the correct time.

If SNTP unicast mode is enabled, the above tests are run twice. The first time, the SNTP client is configured with NTP server addresses from DHCP. The second time, unicast mode is disabled and only multicasts are listened for. Note that the unicast test is partially bogus in the sense that any multicast packet received will also make the unicast test pass. To reduce the chance of this happening the test will wait for a shorter time for replies. This is not ideal, but it is the best that can be done with an automated test.