Page 1 of 3
SNTP is a network protocol for obtaining an accurate time and it is an interesting exercise to build an SNTP client. In this article the language used is C# but it is easy enough to generalise to a language of your choice and extend the ideas to an SNTP server if you need to. The main aim is to describe and show how to implement the basic protocol.
To start at the beginning I'd better tell you what SNTP is all about.
All over the Internet there are servers which transmit the accurate time using different types of clock including some very accurate atomic clocks. In practice it doesn't really matter what type of clock is being used because almost anything is going to be more accurate than your system hardware clock which typically loses minutes every day!
However most modern operating systems do include the ability to synchronise the system clock with an SNTP time server and so your system clock might well be more accurate than its hardware specification would suggest.
The idea is that you can connect to one of these servers and simply request the time be sent to you. The protocol used for the request and the delivery is SNTP, Simple Network Time Protocol, or NTP, Network Time Protocol.
This isn't a complicated protocol but implementing the client described took far longer than you might guess.
The reason is, as always, that the protocol is described in a way that makes good sense to the protocol specification writer but leaves a lot vague and unclear to the implementer.
There are two versions of SNTP, Unicast and Multicast.
The Mulitcast protocol broadcasts time packets that anyone can pick up and is useful for keeping a local network synchronised.
The Unicast protocol is slightly more complicated from the client's point of view in that it has to request a packet but it is the norm on the wider Internet.
To make use of Unicast SNTP we have to use the datagram or UDP protocol as opposed to a TCP connection. The simplest way of working with UDP in .NET is to use the UdpClient class but this is just a customisation of the more fundamental Socket class and you can easily use the Socket class to work with UDP if you want to.
The basic transaction is simple.
- The client sends an SNTP data structure as UDP packet using port 123 to the server.
- The server then sends an SNTP data structure as a UDP packet back using the same port to the client.
The Structure Of Time
Sounds too good to be true, and indeed it is easy, but the complications are hidden in the words "SNTP data structure".
The structure consists of four 32-bit words followed by four 64-bit time stamps. There is also an optional 96-bit authenticator, which can be used to verify the server's identity, but this isn't used by publicly available time servers.
The SNTP time packet
Each of the time stamps uses the same 64-bit format.
The first 32 bits is an unsigned binary integer that gives the number of seconds since 00h on 1 Jan 1900 - the fiducial date.
The next 32 bits is a pure binary fraction giving the fractional part of the seconds since the fiducial date.
Most time standards aren't accurate enough to fill the entire 32 bits and any unused bits are simply set to zero.
Time Stamp format
Interestingly there is a problem contained in this time stamp format that is very similar to the year 2000 problem.
Yes, you've guessed it – roll over!
Currently the high bit of the time stamp is set and it is heading to roll over in 2036 so look out for the Y2036 bug problem.
Ignoring this little problem for the moment, we are still left with a few simple practical difficulties. For example, what time zone does the time stamp represent?
The answer is that it doesn't reflect any time zone, the time stamp is always UT or Universal Time (which is the same as GMT, Greenwich Mean Time)
Our time control is just going to ignore other time zones and will return UT no matter what time zone is in use.
The final problem with the time stamp, and it is the problem with all such specifications, is the byte and bit order of the data.
Although you can be reasonably certain of this using descriptions such as "high order bits to the right" and "Big Endian byte order" you can never be 100% sure that you have understood such a diagram and descriptions until you try it out.
The Time Commands
The first 32-bit word of the packet is an information and command word and from the specification it seems to be the only part of the structure you need to set before sending the request.
The first word
Most of the other fields are for return data.
The first byte is most important. The first two bits carry leap second information and can mostly be ignored.
00 0 no warning
01 1 last minute has 61 seconds
10 2 last minute has 59 seconds)
11 3 alarm condition (clock not synchronized)
The next three bits specify the SNTP version and should be set to 1 by a client so that the request will be processed by almost any server.
The final three bits specify what should happen, i.e. the state or Mode:
1 symmetric active
2 symmetric passive
6 reserved for NTP control message
7 reserved for private use
Mode should be set to 3 for a client request and the server will set it to 4 in the response packet.
The remaining three bytes provide information on the server's time keeper. Stratum gives the level of time precision:
0 unspecified or unavailable
1 primary reference (e.g., radio clock)
2-255 secondary reference (via NTP or SNTP)
Poll gives the minimum time between packets that the server can send.
This is a signed integer giving the power nearest power of 2 in seconds. For example a value of 0 indicates 1 second, a value of 1 indicates 4 seconds, -1 indicates 1/2 second and so on.
Precision is an eight-bit signed integer giving the clock's precision again as a power of 2 in seconds.
The following three words give the root delay, i.e. the round trip delay to the server's primary time source; the root dispersion, i.e. the relative error of the server's time against the primary time source.
Both of these are fixed point signed values with the binary point between bits 15 and 16.
Reference identifier, i.e. a four-byte ASCII code specifying the type of clock used as the standard.
The only problem with the reference identifier is that it isn't specified in the standard but for stratum 1 servers you can look out for
ATOM = atomic clock,
PPS= Precision Pulse Source
GPS= Global Positioning Satellite
and so on.
Radio clocks often quote their radio call sign. For a secondary reference the four bytes are often the TCP/IP address of the primary server.