Version 2 of Network Time Protocol - NTP

Updated 2002-05-23 13:31:59

Purpose - to discuss what NTP is, and to discuss coding issues relating to this protocol.

[hopefully one of my comrades in crime will fill in the blanks here as to RFC number, point to standard implementations of say an ntp daemon, etc.]

[Here's a start (MNO):-

Firstly, the protocol implemented in the code below is the "daytime" protocol, not NTP. The daytime protocol is described in RFC867 [L1 ].

NTP is a far more sophisticated protocol created by Dave Mills. Version 3 of NTP is described in RFC1305 [L2 ]. More information including links to Dave Mills' ntpd implementation is available at http://www.ntp.org

Documentation and other links are at http://www.eecis.udel.edu/~ntp/documentation.html

NTP is implemented via UDP over port 123, and can operate in broadcast and multicast modes, or by direct queries. NTP can synchronise to multiple time sources, making allowances for the network delays and apparent reliability of the clocks it synchronises to.

]

The following code was recently posted to comp.lang.tcl :

 ##
 ## good-time - for the correct time, ...
 ##
 ## Placed into the public domain by [email protected], January 1999.
 ##
 ## usage: good-time [host [port [timezone]]]
 ##     host - defaults to time.nist.gov.
 ##     port - defaults to 13.
 ##     timezone - defaults to nothing, not necessary for NIST format.
 ##
 ## After wading through a complicated linux time synchronization
 ## package, it turned out that the key was to telnet to time.nist.gov
 ## on port 13.  You can do that in tcl, so here it is.
 ##
 ## It also turns out that a lot of machines return some kind of time
 ## service on port 13, so I recognize a few variations in the format
 ## returned.
 ##
 ## See http://www.boulder.nist.gov/timefreq/ for more information and
 ## links to yet more information.
 ##
 # 23Jan02RT - add -set flag
 set doset 0
 if {$argc >= 1 && [string equal [lindex $argv 0] -set]} {
        incr argc -1
        set argv [lrange $argv 1 end]
        set doset 1
 }

 ##
 ## choose the host
 ##
        # 11Jan02RT TODO use host list
        # numeric values come from "Atomic Clock Sync v2.5" server menu
 set hlist {
        129.6.15.28         
        129.6.15.29         
        132.163.4.101       
        132.163.4.102       
        132.163.4.103       
        128.138.140.44      
        time-nw.nist.gov
        time-a.timefreq.bldrdoc.gov
        time.nist.gov
        allhoststried
 }
 # set host time.nist.gov
 if {$argc > 0} {
     set hlist [concat[lindex $argv 0] $hlist]
 }

 ##
 ## choose the port
 ##
 set port 13
 if {$argc > 1} {
     set port [lindex $argv 1];
 }

 ##
 ## choose the timezone
 ##
 set timezone {}
 if {$argc > 2} {
     set timezone [lindex $argv 2];
 }

 ##
 ## set a time out
 ##
 after [expr 30*1000] {
     close $sock
     puts stderr "timed out";
     if {[info exists lines]} {
        puts stderr "no time found in:\n$lines"
     }
     exit 1;
 }

 ##
 ## open a socket
 ##
 foreach h $hlist {
        if {[catch {socket $h $port} sock]} {
                #puts stderr "socket: $sock"
                #exit 2;
                puts stderr "host $h - FAILED"
                continue
        }
        break
 }

 ##
 ## read what comes back
 ##
 while {[gets $sock line] >= 0} {

     #
     # typical daytime response is unix date format without timezone indication
     #
     #  Mon Sep 16 21:59:22 1996
     #
     set seconds 0
     if {[regexp \
        {^... ([A-Z][a-z][a-z]) ([ \d]\d) (\d\d:\d\d:\d\d) (\d\d\d\d)$} \
         $line all month mday time year]} {
        set seconds [clock scan "$month $mday, $year $time $timezone"]
     }

     #
     # NIST time service format returned by:
     #
     #  time.nist.gov
     #  time-nw.nist.gov
     #  time-a.timefreq.bldrdoc.gov
     #
     # 50343 96-09-17 05:02:07 50 0 0  50.0 UTC(NIST) * 
     #
     if {!$seconds &&
       [regexp \
      {^..... (\d\d)-(\d\d)-(\d\d) (\d\d:\d\d:\d\d) .. . . ..... UTC\(NIST\)} \
      $line all year month day time]} {
        set seconds [clock scan "$month/$day/$year $time UTC"]
     }

     #
     # USNO master clock format returned by:
     #
     #  tick.usno.navy.mil
     #  tock.usno.navy.mil
     #
     # 50343 261 044932 UTC
     #
     if {!$seconds && [regexp {^..... ([ \d][ \d]\d) (\d\d)(\d\d)(\d\d) UTC$} \
             $line all doy hour minute second]} {
        set seconds [clock scan $hour:$minute:$second -gmt true]
     }
     if {$seconds} {
        puts "FETCHED: [clock format $seconds]"
        puts "  LOCAL: [clock format [clock seconds]]"
        if {$doset} {
            set newtime [clock format $seconds -format %H%M.%S]
            exec date.exe $newtime
            puts "set date to $newtime"
        }
        close $sock;
        exit 0;
    }

     #
     # save unrecognized stuff for final error message
     #
     append lines $line\n
 }

 ##
 ## give up
 ##
 close $sock;
 puts stderr "no time found in:\n$lines";
 exit 4

Category Acronym Category Internet Category Application