RFC 1059:Network Time Protocol (Version 1) ...
RFC-Ref

3. Network Time Protocol

   This section consists of a formal definition of the Network Time
   Protocol, including its data formats, entities, state variables,
   events and event-processing procedures.  The specification model is
   based on the implementation model illustrated in Figure 2.1, but it
   is not intended that this model is the only one upon which a
   specification can be based.  In particular, the specification is
   intended to illustrate and clarify the intrinsic operations of NTP
   and serve as a foundation for a more rigorous, comprehensive and
   verifiable specification.

3.1. Data Formats

   All mathematical operations expressed or implied herein are in
   two's-complement arithmetic.  Data are specified as integer or
   fixed-point quantities.  Since various implementations would be
   expected to scale externally derived quantities for internal use,
   neither the precision nor decimal-point placement for fixed-point
   quantities is specified.  Unless specified otherwise, all quantities
   are unsigned and may occupy the full field width, if designated, with
   an implied zero preceding the most significant (leftmost) bit.
   Hardware and software packages designed to work with signed
   quantities will thus yield surprising results when the most
   significant (sign) bit is set.  It is suggested that externally
   derived, unsigned fixed-point quantities such as timestamps be
   shifted right one bit for internal use, since the precision
   represented by the full field width is seldom justified.

   Since NTP timestamps are cherished data and, in fact, represent the
   main product of the protocol, a special timestamp format has been
   established.  NTP timestamps are represented as a 64-bit unsigned
   fixed-point number, in seconds relative to 0000 UT on 1 January 1900.
   The integer part is in the first 32 bits and the fraction part in the
   last 32 bits, as shown in the following diagram.

      0                   1                   2                   3
      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                         Integer Part                          |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                         Fraction Part                         |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

   This format allows convenient multiple-precision arithmetic and
   conversion to Time Protocol representation (seconds), but does
   complicate the conversion to ICMP Timestamp message representation
   (milliseconds).  The precision of this representation is about 0.2

   nanosecond, which should be adequate for even the most exotic
   requirements.

   Timestamps are determined by copying the current value of the logical
   clock to a timestamp variable when some significant event, such as
   the arrival of a message, occurs.  In order to maintain the highest
   accuracy, it is important that this be done as close to the hardware
   or software driver associated with the event as possible.  In
   particular, departure timestamps should be redetermined for each
   link-level retransmission.  In some cases a particular timestamp may
   not be available, such as when the host is rebooted or the protocol
   first starts up.  In these cases the 64-bit field is set to zero,
   indicating the value is invalid or undefined.

   Note that since some time in 1968 the most significant bit (bit 0 of
   the Integer Part) has been set and that the 64-bit field will
   overflow some time in 2036.  Should NTP be in use in 2036, some
   external means will be necessary to qualify time relative to 1900 and
   time relative to 2036 (and other multiples of 136 years).
   Timestamped data requiring such qualification will be so precious
   that appropriate means should be readily available.  There will exist
   an 0.2-nanosecond interval, henceforth ignored, every 136 years when
   the 64-bit field will be zero and thus considered invalid.

3.2. State Variables and Parameters

   Following is a tabular summary of the various state variables and
   parameters used by the protocol.  They are separated into classes of
   system variables, which relate to the operating system environment
   and logical clock mechanism;  peer variables, which are specific to
   each peer operating in symmetric mode or client mode;  packet
   variables, which represent the contents of the NTP message;  and
   parameters, which are fixed in all implementations of the current
   version.  For each class the description of the variable is followed
   by its name and the procedure or value which controls it.  Note that
   variables are in lower case, while parameters are in upper case.

        System Variables                Name            Control
        -------------------------------------------------------
        Logical Clock                   sys.clock       update
        Clock Source                    sys.peer        selection
                                                        algorithm
        Leap Indicator                  sys.leap        update
        Stratum                         sys.stratum     update
        Precision                       sys.precision   system
        Synchronizing Distance          sys.distance    update
        Estimated Drift Rate            sys.drift       system
        Reference Clock Identifier      sys.refid       update
        Reference Timestamp             sys.reftime     update

                        Table 3.1. System Variables

        Peer Variables                  Name            Control
        -------------------------------------------------------
        Peer Address                    peer.srcadr     system
        Peer Port                       peer.srcport    system
        Local Address                   peer.dstadr     system
        Local Port                      peer.dstport    system
        Peer State                      peer.state      receive,
                                                        transmit
        Reachability Register           peer.reach      receive,
                                                        transmit
        Peer Timer                      peer.timer      system
        Timer Threshold                 peer.threshold  system
        Leap Indicator                  peer.leap       receive
        Stratum                         peer.stratum    receive
        Peer Poll Interval              peer.ppoll      receive
        Host Poll Interval              peer.hpoll      receive,
                                                        transmit
        Precision                       peer.precision  receive
        Synchronizing Distance          peer.distance   receive
        Estimated Drift Rate            peer.drift      receive
        Reference Clock Identifier      peer.refid      receive
        Reference Timestamp             peer.reftime    receive
        Originate Timestamp             peer.org        receive
        Receive Timestamp               peer.rec        receive
        Filter Register                 peer.filter     filter
                                                        algorithm
        Delay Estimate                  peer.delay      filter
                                                        algorithm
        Offset Estimate                 peer.offset     filter
                                                        algorithm
        Dispersion Estimate             peer.dispersion filter

                         Table 3.2. Peer Variables

        Packet Variables                Name            Control
        -------------------------------------------------------
        Peer Address                    pkt.srcadr      transmit
        Peer Port                       pkt.srcport     transmit
        Local Address                   pkt.dstadr      transmit
        Local Port                      pkt.dstport     transmit
        Leap Indicator                  pkt.leap        transmit
        Version Number                  pkt.version     transmit
        Stratum                         pkt.stratum     transmit
        Poll                            pkt.poll        transmit
        Precision                       pkt.precision   transmit
        Synchronizing Distance          pkt.distance    transmit
        Estimated Drift Rate            pkt.drift       transmit
        Reference Clock Identifier      pkt.refid       transmit
        Reference Timestamp             pkt.reftime     transmit
        Originate Timestamp             pkt.org         transmit
        Receive Timestamp               pkt.rec         transmit
        Transmit Timestamp              pkt.xmt         transmit

                        Table 3.3. Packet Variables

        Parameters                      Name            Value
        -------------------------------------------------------
        NTP Version                     NTP.VERSION     1
        NTP Port                        NTP.PORT        123
        Minimum Polling Interval        NTP.MINPOLL     6 (64 sec)
        Maximum Polling Interval        NTP.MAXPOLL     10 (1024
                                                        sec)
        Maximum Dispersion              NTP.MAXDISP     65535 ms
        Reachability Register Size      PEER.WINDOW     8
        Shift Register Size             PEER.SHIFT      4/8
        Dispersion Threshold            PEER.THRESHOLD  500 ms
        Filter Weight                   PEER.FILTER     .5
        Select Weight                   PEER.SELECT     .75

                           Table 3.4. Parameters

   Following is a description of the various variables used in the
   protocol.  Additional details on formats and use are presented in
   later sections and appendices.

3.2.1. Common Variables

   The following variables are common to the system, peer and packet
   classes.

   Peer Address (peer.srcadr, pkt.srcadr) Peer Port (peer.srcport,
   pkt.srcport)

      These are the 32-bit Internet address and 16-bit port number of
      the remote host.

   Local Address (peer.dstadr, pkt.dstadr) Local Port (peer.dstport,
   pkt.dstport)

      These are the 32-bit Internet address and 16-bit port number of
      the local host.  They are included among the state variables to
      support multi-homing.

   Leap Indicator (sys.leap, peer.leap, pkt.leap)

      This is a two-bit code warning of an impending leap second to be
      inserted in the NTP time scale.  The bits are set before 23:59 on
      the day of insertion and reset after 00:01 on the following day.
      This causes the number of seconds (rollover interval) in the day
      of insertion to be increased or decreased by one.  In the case of
      primary servers the bits are set by operator intervention, while
      in the case of secondary servers the bits are set by the protocol.
      The two bits are coded as follows:

                   00      no warning (day has 86400 seconds)
                   01      +1 second (day has 86401 seconds)
                           seconds)
                   10      -1 second (day has 86399 seconds)
                           seconds)
                   11      alarm condition (clock not synchronized)

      In all except the alarm condition (11) NTP itself does nothing
      with these bits, except pass them on to the time-conversion
      routines that are not part of NTP.  The alarm condition occurs
      when, for whatever reason, the logical clock is not synchronized,
      such as when first coming up or after an extended period when no
      outside reference source is available.

   Stratum (sys.stratum, peer.stratum, pkt.stratum)

      This is an integer indicating the stratum of the logical clock.  A
      value of zero is interpreted as unspecified, one as a primary
      clock (synchronized by outside means) and remaining values as the
      stratum level (synchronized by NTP).  For comparison purposes a
      value of zero is considered greater than any other value.

   Peer Poll Interval (peer.ppoll, pkt.poll)

      This is a signed integer used only in symmetric mode and
      indicating the minimum interval between messages sent to the peer,
      in seconds as a power of two.  For instance, a value of six

      indicates a minimum interval of 64 seconds.  The value of this
      variable must not be less than NTP.MINPOLL and must not be greater
      than NTP.MAXPOLL.

   Precision (sys.precision, peer.precision, pkt.precision)

      This is a signed integer indicating the precision of the logical
      clock, in seconds to the nearest power of two.  For instance, a
      60-Hz line-frequency clock would be assigned the value -6, while a
      1000-Hz crystal-derived clock would be assigned the value -10.

   Synchronizing Distance (sys.distance, peer.distance, pkt.distance)

      This is a fixed-point number indicating the estimated roundtrip
      delay to the primary clock, in seconds.

   Estimated Drift Rate (sys.drift, peer.drift, pkt.drift)

      This is a fixed-point number indicating the estimated drift rate
      of the local clock, in dimensionless units.

   Reference Clock Identifier (sys.refid, peer.refid, pkt.refid)

      This is a code identifying the particular reference clock or
      server.  The interpretation of the value depends on the stratum.
      For stratum values of zero (unspecified) or one (primary clock),
      the value is an ASCII string identifying the reason or clock,
      respectively.  For stratum values greater than one (synchronized
      by NTP), the value is the 32-bit Internet address of the reference
      server.

   Reference Timestamp (sys.reftime, peer.reftime, pkt.reftime)

      This is the local time, in timestamp format, when the logical
      clock was last updated.  If the logical clock has never been
      synchronized, the value is zero.

3.2.2. System Variables

   The following variables are used by the operating system in order to
   synchronize the logical clock.

   Logical Clock (sys.clock)

      This is the current local time, in timestamp format.  Local time
      is derived from the hardware clock of the particular machine and
      increments at intervals depending on the design used.  An

      appropriate design, including slewing and drift-compensation
      mechanisms, is described in Section 5.

   Clock Source (sys.peer)

      This is a selector identifying the current clock source.  Usually
      this will be a pointer to a structure containing the peer
      variables.

3.2.3. Peer Variables

   Following is a list of state variables used by the peer management
   and measurement functions.  There is one set of these variables for
   every peer operating in client mode or symmetric mode.

   Peer State (peer.state)

      This is a bit-encoded quantity used for various control functions.

   Host Poll Interval (peer.hpoll)

      This is a signed integer used only in symmetric mode and
      indicating the minimum interval between messages expected from the
      peer, in seconds as a power of two.  For instance, a value of six
      indicates a minimum interval of 64 seconds.  The value of this
      variable must not be less than NTP.MINPOLL and must not be greater
      than NTP.MAXPOLL.

   Reachability Register (peer.reach)

      This is a code used to determine the reachability status of the
      peer.  It is used as a shift register, with bits entering from the
      least significant (rightmost) end.  The size of this register is
      specified as PEER.SHIFT bits.

   Peer Timer (peer.timer)

      This is an integer counter used to control the interval between
      transmitted NTP messages.

   Timer Threshold (peer.threshold)

      This is the timer value which, when reached, causes the timeout
      procedure to be executed.

   Originate Timestamp (peer.org, pkt.org)

      This is the local time, in timestamp format, at the peer when its

      latest NTP message was sent.  If the peer becomes unreachable the
      value is set to zero.

   Receive Timestamp (peer.rec, pkt.rec)

      This is the local time, in timestamp format, when the latest NTP
      message from the peer arrived.  If the peer becomes unreachable
      the value is set to zero.

3.2.4. Packet Variables

   Following is a list of variables used in NTP messages in addition to
   the common variables above.

   Version Number (pkt.version)

      This is an integer indicating the version number of the sender.
      NTP messages will always be sent with the current version number
      NTP.VERSION and will always be accepted if the version number
      matches NTP.VERSION.  Exceptions may be advised on a case-by-case
      basis at times when the version number is changed.

   Transmit Timestamp (pkt.xmt)

      This is the local time, in timestamp format, at which the NTP
      message departed the sender.

3.2.5. Clock Filter Variables

   When the filter and selection algorithms suggested in Section 4 are
   used, the following state variables are defined.  There is one set of
   these variables for every peer operating in client mode or symmetric
   mode.

   Filter Register (peer.filter)

      This is a shift register of PEER.WINDOW bits, where each stage is
      a tuple consisting of the measured delay concatenated with the
      measured offset associated with a single observation.
      Delay/offset observations enter from the least significant
      (rightmost) right and are shifted towards the most significant
      (leftmost) end and eventually discarded as new observations
      arrive.  The register is cleared to zeros when (a) the peer
      becomes unreachable or (b) the logical clock has just been reset
      so as to cause a significant discontinuity in local time.

   Delay Estimate (peer.delay)

      This is a signed, fixed-point number indicating the latest delay
      estimate output from the filter, in seconds.  While the number is
      signed, only those values greater than zero represent valid delay
      estimates.

   Offset Estimate (peer.offset)

      This is a signed, fixed-point number indicating the latest offset
      estimate output from the filter, in seconds.

   Dispersion Estimate (peer.dispersion)

      This is a fixed-point number indicating the latest dispersion
      estimate output from the filter, in scrambled units.

3.2.6. Parameters

   Following is a list of parameters assumed for all implementations
   operating in the Internet system.  It is necessary to agree on the
   values for these parameters in order to avoid unnecessary network
   overheads and stable peer associations.

   Version Number (NTP.VERSION)

      This is the NTP version number, currently one (1).

   NTP Port (NTP.PORT)

      This is the port number (123) assigned by the Internet Number Czar
      to NTP.

   Minimum Polling Interval (NTP.MINPOLL)

      This is the minimum polling interval allowed by any peer of the
      Internet system, currently set to 6 (64 seconds).

   Maximum Polling Interval (NTP.MAXPOLL)

      This is the maximum polling interval allowed by any peer of the
      Internet system, currently set to 10 (1024 seconds).

   Maximum Dispersion (NTP.MAXDISP)

      This is the maximum dispersion assumed by the filter algorithms,
      currently set to 65535 milliseconds.

   Reachability Register Size (PEER.WINDOW)

      This is the size of the Reachability Register (peer.reach),
      currently set to eight (8) bits.

   Shift Register Size (PEER.SHIFT)

      When the filter and selection algorithms suggested in Section 4
      are used, this is the size of the Clock Filter (peer.filter) shift
      register, in bits.  For crystal-stabilized oscillators a value of
      eight (8) is suggested, while for mains-frequency oscillators a
      value of four (4) is suggested.  Additional considerations are
      given in Section 5.

   Dispersion Threshold (PEER.THRESHOLD)

      When the filter and selection algorithms suggested in Section 4
      are used, this is the threshold used to discard noisy data.  While
      a value of 500 milliseconds is suggested, the value may be changed
      to suit local conditions on particular peer paths.

   Filter Weight (PEER.FILTER)

      When the filter algorithm suggested in Section 4 is used, this is
      the filter weight used to discard noisy data.  While a value of
      0.5 is suggested, the value may be changed to suit local
      conditions on particular peer paths.

   Select Weight (PEER.SELECT)

      When the selection algorithm suggested in Section 4 is used, this
      is the select weight used to discard outlyers.  data.  While a
      value of 0.75 is suggested, the value may be changed to suit local
      conditions on particular peer paths.

3.3. Modes of Operation

   An NTP host can operate in three modes:  client, server and
   symmetric.  The mode of operation is determined by whether the source
   port (peer.srcport) or destination port (peer.dstport) peer variables
   contain the assigned NTP service port number NTP.PORT (123) as shown
   in the following table.

           peer.srcport    peer.dstport    Mode
           -------------------------------------------
           not NTP.PORT    not NTP.PORT    not possible
           not NTP.PORT    NTP.PORT        server
           NTP.PORT        not NTP.PORT    client
           NTP.PORT        NTP.PORT        symmetric

   A host operating in client mode occasionally sends an NTP message to
   a host operating in server mode.  The server responds by simply
   interchanging addresses and ports, filling in the required
   information and returning the message to the client.  Servers then
   need retain no state information between client requests.  Clients
   are free to manage the intervals between sending NTP messages to suit
   local conditions.

   In symmetric mode the client/server distinction disappears.  Each
   host maintains a table with as many entries as active peers.  Each
   entry includes a code uniquely identifying the peer (e.g.,  Internet
   address and port), together with status information and a copy of the
   timestamps last received.  A host operating in symmetric mode
   periodically sends NTP messages to each peer including the latest
   copy of the timestamps.  The intervals between sending NTP messages
   are managed jointly by the host and each peer using the polling
   variables peer.ppoll and peer.hpoll.

   When a pair of peers operating in symmetric mode exchange NTP
   messages and each determines that the other is reachable, an
   association is formed.  One or both peers must be in active state;
   that is, sending messages to the other regardless of reachability
   status.  A peer not in active state is in passive state.  If a peer
   operating in passive state discovers that the other peer is no longer
   reachable, it ceases sending messages and reclaims the storage and
   timer resources used by the association.  A peer operating in client
   mode is always in active state, while a peer operating in server mode
   is always in passive state.

3.4. Event Processing

   The significant events of interest in NTP occur upon expiration of
   the peer timer, one of which is dedicated to each peer operating in
   symmetric or client modes, and upon arrival of an NTP message from
   the various peers.  An event can also occur as the result of an
   operator command or detected system fault, such as a primary clock
   failure.  This section describes the procedures invoked when these
   events occur.

3.4.1. Timeout Procedure

   The timeout procedure is called in client and symmetric modes when
   the peer timer (peer.timer) reaches the value of the timer threshold
   (peer.threshold) variable.  First, the reachability register
   (peer.reach) is shifted one position to the left and a zero replaces
   the vacated bit.  Then an NTP message is constructed and sent to the
   peer.  If operating in active state or in passive state and
   peer.reach is nonzero (reachable), the peer.timer is reinitialized
   (resumes counting from zero) and the value of peer.threshold is set
   to:

           peer.threshold <- max( min( peer.ppoll, peer.hpoll,
                           NTP.MAXPOLL), NTP.MINPOLL) .

   If operating in active state and peer.reach is zero (unreachable),
   the peer variables are updated as follows:

                   peer.hpoll <- NTP.MINPOLL
                   peer.disp <- NTP.MAXDISP
                   peer.filter <- 0 (cleared)
                   peer.org <- 0
                   peer.rec <- 0

   Then the clock selection algorithm is called, which may result in a
   new clock source (sys.peer).  In other cases the protocol ceases
   operation and the storage and timer resources are reclaimed for
   subsequent use.

   An NTP message is constructed as follows (see Appendices A and B for
   formats).  First, the IP and UDP packet variables are copied from the
   peer variables (note the interchange of source and destination
   addresses and ports):

           pkt.srcadr <- peer.dstadr       pkt.srcport <- peer.dstport
           pkt.dstadr <- peer.srcadr       pkt.dstport <- peer.srcport

   Next, the NTP packet variables are copied (rescaled as necessary)
   from the system and peer variables:

           pkt.leap <- sys.leap            pkt.distance <- sys.distance
           pkt.version <- NTP.VERSION      pkt.drift <- sys.drift
           pkt.stratum <- sys.stratum      pkt.refid <- sys.refid
           pkt.poll <- peer.hpoll          pkt.reftime <- sys.reftime
           pkt.precision <- sys.precision

   Finally, the NTP packet timestamp variables are copied, depending on
   whether the peer is operating in symmetric mode and reachable, in

   symmetric mode and not reachable (but active) or in client mode:

   Symmetric Reachable     Symmetric Active        Client
   - -------------------     -------------------     -------------------
   pkt.org <- peer.org     pkt.org <- 0            pkt.org <- sys.clock
   pkt.rec <- peer.rec     pkt.rec <- 0            pkt.rec <- sys.clock
   pkt.xmt <- sys.clock    pkt.xmt <- sys.clock    pkt.xmt <- sys.clock

   Note that the order of copying should be designed so that the time to
   perform the copy operations themselves does not degrade the
   measurement accuracy, which implies that the sys.clock values should
   be copied last.  The reason for the choice of zeros to fill the
   pkt.org and pkt.rec packet variables in the symmetric unreachable
   case is to avoid the use of old data after a possibly extensive
   period of unreachability.  The reason for the choice of sys.clock to
   fill these variables in the client case is that, if for some reason
   the NTP message is returned by the recipient unaltered, as when
   testing with an Internet-echo server, this convention still allows at
   least the roundtrip time to be accurately determined without special
   handling.

3.4.2. Receive Procedure

   The receive procedure is executed upon arrival of an NTP message.  If
   the version number of the message (pkt.version) does not match the
   current version number (NTP.VERSION), the message is discarded;
   however, exceptions may be advised on a case-by-case basis at times
   when the version number is changed.

   If the clock of the sender is unsynchronized (pkt.leap = 11), or the
   receiver is in server mode or the receiver is in symmetric mode and
   the stratum of the sender is greater than the stratum of the receiver
   (pkt.stratum > sys.stratum), the message is simply returned to the
   sender along with the timestamps.  In this case the addresses and
   ports are interchanged in the IP and UDP headers:

        pkt.srcadr <-> pkt.dstadr       pkt.srcport <-> pkt.dstport

   The following packet variables are updated from the system variables:

        pkt.leap <- sys.leap            pkt.distance <- sys.distance
        pkt.version <- NTP.VERSION      pkt.drift <- sys.drift
        pkt.stratum <- sys.stratum      pkt.refid <- sys.refid
        pkt.precision <- sys.precision  pkt.reftime <- sys.reftime

   Note that the pkt.poll packet variable is unchanged.  The timestamps
   are updated in the order shown:

                        pkt.org <- pkt.xmt
                        pkt.rec <- sys.clock
                        pkt.xmt <- sys.clock

   Finally, the message is forwarded to the sender and the server
   receive procedure terminated at this point.

   If the above is not the case, the source and destination Internet
   addresses and ports in the IP and UDP headers are matched to the
   correct peer.  If there is a match, processing continues at the next
   step below.  If there is no match and symmetric mode is not indicated
   (either pkt.srcport or pkt.dstport not equal to NTP.PORT), the
   message must be a reply to a previously sent message from a client
   which is no longer in operation.  In this case the message is dropped
   and the receive procedure terminated at this point.

   If there is no match and symmetric mode is indicated, (both
   pkt.srcport and pkt.dstport equal to NTP.PORT), an implementation-
   specific instantiation procedure is called to create and initialize a
   new set of peer variables and start the peer timer.  The following
   peer variables are set from the IP and UDP headers:

           peer.srcadr <- pkt.srcadr       peer.srcport <- pkt.srcport
           peer.dstadr <- pkt.dstadr       peer.dstport <- pkt.dstport

   The following peer variables are initialized:

                   peer.state <- symmetric (passive)
                   peer.timer <- 0 (enabled)
                   peer.hpoll <- NTP.MINPOLL
                   peer.disp <- NTP.MAXDISP

   The remaining peer variables are undefined and set to zero.

   Assuming that instantiation is complete and that match occurs, the
   least significant bit of the reachability register (peer.reach) is
   set, indicating the peer is now reachable.  The following peer
   variables are copied (rescaled as necessary) from the NTP packet
   variables and system variables:

           peer.leap <- pkt.leap           peer.distance <- pkt.distance
           peer.stratum <- pkt.stratum     peer.drift <- pkt.drift
           peer.ppoll <- pkt.poll          peer.refid <- pkt.refid
           peer.precision <- pkt.precision peer.reftime <- pkt.reftime
           peer.org <- pkt.xmt             peer.rec <- sys.clock
           peer.threshold <- max( min( peer.ppoll, peer.hpoll,
                           NTP.MAXPOLL), NTP.MINPOLL)

   If either or both the pkt.org or pkt.rec packet variables are zero,
   the sender did not have reliable values for them, so the receive
   procedure is terminated at this point.  If both of these variables
   are nonzero, the roundtrip delay and clock offset relative to the
   peer are calculated as follows.  Number the times of sending and
   receiving NTP messages as shown in Figure 3.1 and let i be an even
   integer.  Then t(i-3), t(i-2) and t(i-1) and t(i) are the contents of
   the pkt.org, pkt.rec, pkt.xmt and peer.rec variables respectively.

                        |                    |
                   t(1) |------------------->| t(2)
                        |                    |
                   t(4) |<-------------------| t(3)
                        |                    |
                   t(5) |------------------->| t(6)
                        |                    |
                   t(8) |<-------------------| t(7)
                        |                    |
                                 ...
                Figure 3.1. Calculating Delay and Offset

   The roundtrip delay d and clock offset c of the receiving peer
   relative to the sending peer is:

                   d = (t(i) - t(i-3)) - (t(i-1) - t(i-2))
                c = [(t(i-2) - t(i-3)) + (t(i-1) - t(i))]/2 .

   This method amounts to a continuously sampled, returnable-time
   system, which is used in some digital telephone networks.  Among the
   advantages are that the order and timing of the messages is
   unimportant and that reliable delivery is not required.  Obviously,
   the accuracies achievable depend upon the statistical properties of
   the outbound and inbound net paths.  Further analysis and
   experimental results bearing on this issue can be found in
   Appendix D.

   The c and d values are then input to the clock filter algorithm to
   produce the delay estimate (peer.delay) and offset estimate
   (peer.offset) for the peer involved.  If d becomes nonpositive due to
   low delays, long polling intervals and high drift rates, it should be

   considered invalid;  however, even under these conditions it may
   still be useful to update the local clock and reduce the drift rate
   to the point that d becomes positive again.  Specification of the
   clock filter algorithm is not an integral part of the NTP
   specification;  however, one found to work well in the Internet
   environment is described in Section 4.

   When a primary clock is connected to the host, it is convenient to
   incorporate its information into the data base as if the clock were
   represented by an ordinary peer.  The clocks are usually polled once
   or twice a minute and the returned timecheck used to produce a new
   update for the logical clock.  The update procedure is then called
   with the following assumed peer variables:

                   peer.offset <- timecheck - sys.clock
                   peer.delay <- as determined
                   peer.dispersion <- 0
                   peer.leap <- selected by operator, ordinarily 00
                   peer.stratum <- 0
                   peer.distance <- 0
                   peer.refid <- ASCII identifier
                   peer.reftime <- timecheck

   In this case the peer.delay and peer.refid can be constants
   reflecting the type and accuracy of the clock.  By convention, the
   value for peer.delay is ten times the expected mean error of the
   clock, for instance, 10 milliseconds for a WWVB clock and 1000
   milliseconds for a less accurate WWV clock, but with a floor of 100
   milliseconds.  Other peer variables such as the peer timer and
   reachability register can be used to control the polling interval and
   to confirm the clock is operating correctly.  In this way the clock
   filter and selection algorithms operate in the usual way and can be
   used to mitigate the clock itself, should it appear to be operating
   correctly, yet deliver bogus time.

3.4.3. Update Procedure

   The update procedure is called when a new delay/offset estimate is
   available.  First, the clock selection algorithm determines the best
   peer on the basis of estimated accuracy and reliability, which may
   result in a new clock source (sys.peer).  If sys.peer points to the
   peer data structure with the just-updated estimates, the state
   variables of that peer are used to update the system state variables

   as follows:

                   sys.leap <- peer.leap
                   sys.stratum <- peer.stratum + 1
                   sys.distance <- peer.distance + peer.delay
                   sys.refid <- peer.srcadr
                   sys.reftime <- peer.rec

   Finally, the logical clock procedure is called with peer.offset as
   argument to update the logical clock (sys.clock) and recompute the
   estimated drift rate (sys.drift).  It may happen that the logical
   clock may be reset, rather than slewed to its final value.  In this
   case the peer variables of all reachable peers are are updated as
   follows:

                   peer.hpoll <- NTP.MINPOLL
                   peer.disp <- NTP.MAXDISP
                   peer.filter <- 0 (cleared)
                   peer.org <- 0
                   peer.rec <- 0

   and the clock selection algorithm is called again, which results in a
   null clock source (sys.peer = 0).  A new selection will occur when
   the filters fill up again and the dispersion settles down.

   Specification of the clock selection algorithm and logical clock
   procedure is not an integral part of the NTP specification.  A clock
   selection algorithm found to work well in the Internet environment is
   described in Section 4, while a logical clock procedure is described
   in Section 5.  The clock selection algorithm described in Section 4
   usually picks the server at the highest stratum and minimum delay
   among all those available, unless that server appears to be a
   falseticker.  The result is that the algorithms all work to build a
   minimum-weight spanning tree relative to the primary servers and thus
   a hierarchical master-slave system similar to those used by some
   digital telephone networks.

3.4.4. Initialization Procedures

   Upon reboot the NTP host initializes all system variables as follows:

                   sys.clock <- best available estimate
                   sys.leap <- 11 (unsynchronized)
                   sys.stratum <- 0 (undefined)
                   sys.precision <- as required
                   sys.distance <- 0 (undefined)
                   sys.drift <- as determined
                   sys.refid <- 0 (undefined)
                   sys.reftime <- 0 (undefined)

   The logical clock sys.clock is presumably undefined at reboot;
   however, in some designs such as the Fuzzball an estimate is
   available from the reboot environment.  The sys.precision variable is
   determined by the intrinsic architecture of the local hardware clock.
   The sys.drift variable is determined as a side effect of subsequent
   logical clock updates, from whatever source.

   Next, an implementation-specific instantiation procedure is called
   repeatedly to establish the set of client peers or symmetric (active)
   peers which will actively probe other servers during regular
   operation.  The mode and addresses of these peers is determined using
   information read during the reboot procedure or as the result of
   operator commands.

Google
Web
RFC-Ref