The transmit procedure is executed when the peer timer decrements to zero for all modes except client mode with a broadcast server and server mode in all cases. In client mode with a broadcast server messages are never sent. In server mode messages are sent only in response to received messages. This procedure is also called by the receive procedure when an NTP message arrives that does not result in a persistent association.
begin transmit procedure
The following initializes the packet buffer and copies the packet variables. The value skew is necessary to account for the skew-error accumulated over the interval since the local clock was last set.
pkt.peeraddr <-- peer.hostaddr; /* copy system and peer variables */ pkt.peerport <-- roman peer.hostport; pkt.hostaddr <-- roman peer.peeraddr; pkt.hostport <-- roman peer.peerport; pkt.leap <-- roman sys.leap; pkt.version <-- roman NTP.VERSION; pkt.mode <-- roman peer.mode; pkt.stratum <-- roman sys.stratum; pkt.poll <-- roman peer.hostpoll; pkt.precision <-- roman sys.precision; pkt.rootdelay <-- roman sys.rootdelay; if (sys.leap = 112 or (sys.clock - sys.reftime) > NTP.MAXAGE) skew <-- NTP.MAXSKEW; else skew <-- phi (sys.clock~-~sys.reftime); pkt.rootdispersion <-- sys.rootdispersion + (1 << sys.precision) +skew; pkt.refid <-- sys.refid; pkt.reftime <-- sys.reftime;
The transmit timestamp pkt.xmt will be used later in order to validate the reply; thus, implementations must save the exact value transmitted. In addition, the order of copying the timestamps should be designed so that the time to format and copy the data does not degrade accuracy.
The call to encrypt is implemented only if authentication is implemented. If authentication is enabled, the delay to encrypt the authenticator may degrade accuracy. Therefore, implementations should include a system state variable (not mentioned elsewhere in this specification) which contains an offset calculated to match the expected encryption delay and correct the transmit timestamp as obtained from the local clock.
#ifdef (authentication implemented) /* see Appendix C */ call encrypt; #endef send packet;
The reachability register is shifted one position to the left, with zero replacing the vacated bit. If all bits of this register are zero, the clear procedure is called to purge the clock filter and reselect the synchronization source, if necessary. If the association was not configured by the initialization procedure, the association is demobilized.
peer.reach <-- peer.reach << 1; /* update reachability */ if (peer.reach = 0 and peer.config = 0) begin demobilize association; exit; endif
If valid data have been shifted into the filter register at least once during the preceding two poll intervals (low-order bit of peer.reach set to one), the valid data counter is incremented. After eight such valid intervals the poll interval is incremented. Otherwise, the valid data counter and poll interval are both decremented and the clock-filter procedure called with zero values for offset and
delay and NTP.MAXDISPERSE for dispersion. The clock-select procedure is called to reselect the synchronization source, if necessary.
if (peer.reach & 6 !=0) /* test two low-order bits (shifted) */ if (peer.valid < NTP.SHIFT) /* valid data received */ peer.valid <-- peer.valid +1; else peer.hostpoll <-- peer.hostpoll + 1; else begin peer.valid <-- peer.valid -1; /* nothing heard */ peer.hostpoll <-- peer.hostpoll -1; call clock-filter(0, 0, NTP.MAXDISPERSE); call clock-select; /* select clock source */ endif call poll-update; end transmit procedure;