AmendHub

Download:

vkoskiv

/

MacNTP

/

amendments

/

13

Small NTP corrections

* Send actual transmit timestamp and verify it matches
* Use server transmit timestamp to set system clock instead of
the reference timestamp
* Clean up debugging gunk

vkoskiv made amendment 13 10 months ago
--- MacNTP.c Thu Sep 7 21:21:54 2023 +++ MacNTP.c Thu Sep 7 23:53:33 2023 @@ -29,24 +29,28 @@ void on_udp_receive(struct UDPiopb *iopb); // We already have this from dnr.h above, but Think C ignores it. OSErr ResolveName(char *name, unsigned long *ipAddress); -enum MacNTPError MacNTPSetSystemTime(struct ntp_packet *ntp, minutes_t utc_offset) { - /* +/* The NTP protocol expresses time as seconds from 01-01-1900. The Macintosh expresses them as seconds from 01-01-1904. This first step converts the two. Seconds between 01-01-1900 and 01-01-1904 (none were leap years): 4 * 365 * 24 * 60 * 60 = 126144000 - */ +*/ +#define NTP_MAC_OFFSET 126144000 + +enum MacNTPError MacNTPSetSystemTime(struct ntp_packet *ntp, minutes_t utc_offset) { //FIXME: We seem to be behind about 10 seconds after update. OSErr err; long mac_seconds; - long old_time; - Str255 date_string; - Str255 time_string; - long ntp_seconds = ntp->reference_timestamp.upper; + + // The Mac clock isn't very precise, and we don't currently even + // measure the precise time we receive the response, so we forgo + // the clock filter computations, and trust that the network latency + // isn't too bad. + //FIXME: Record receive time and compensate for it if delay exceeds 1s + long ntp_seconds = ntp->transmit_timestamp.upper; ntp_seconds += utc_offset * 60; - mac_seconds = ntp_seconds - 126144000; - GetDateTime(&old_time); + mac_seconds = ntp_seconds - NTP_MAC_OFFSET; err = SetDateTime(mac_seconds); if (err) { if (err == -86) { // clkWrErr @@ -89,11 +93,12 @@ void on_udp_receive(struct UDPiopb *iopb) { req->state = GotResponse; } -enum MacNTPError MacNTPFetchTime(char *ntp_url, struct ntp_packet *packet, OSErr *supplemental) { +enum MacNTPError MacNTPFetchTime(char *ntp_url, struct ntp_packet *packet, OSErr *supplemental, minutes_t utc_offset) { struct ntp_request req; OSErr err; UDPIOCompletionProc completion; long i; + unsigned long local_transmit_time; long retries = 40000; // Arbitrary enum MacNTPError current_error = Success; // I tried other values, but they all seem to make UDPCreate fail with @@ -131,16 +136,17 @@ enum MacNTPError MacNTPFetchTime(char *ntp_url, struct current_error = DNSResolveFailed; goto error; } - //req.host_ip = 3639550720; // Set up NTP payload mntp_memset(&req.payload, 0, sizeof(req.payload)); // Set the mode to tell the server we're a client req.payload.li_vn_mode = (4 << 3) | 3; - // TODO: This should be fine, our time is always in 1904 anyway - // Just verify when receiving - mntp_memset(&req.payload.transmit_timestamp, 0x41, sizeof(req.payload.transmit_timestamp)); + GetDateTime(&local_transmit_time); + local_transmit_time += NTP_MAC_OFFSET; + local_transmit_time -= utc_offset * 60; + // Copy and verify this matches the response transmit ts + req.payload.transmit_timestamp.upper = local_transmit_time; // And prepare for sending mntp_memset(&req.udp_wds, 0, sizeof(req.udp_wds)); @@ -189,12 +195,11 @@ enum MacNTPError MacNTPFetchTime(char *ntp_url, struct goto error; } - // Verify received origin_ts is all 0x41s - for (i = 0; i < sizeof(struct ntp_ts); ++i) { - if (((unsigned char *)&req.payload.origin_timestamp)[i] != 0x41) { - current_error = OriginTimestampMismatch; - goto error; - } + // The server copies transmit_timestamp from the packet we sent to + // origin_timestamp in the response. We verify it here. + if (req.payload.origin_timestamp.upper != local_transmit_time) { + current_error = OriginTimestampMismatch; + goto error; } *packet = req.payload; --- MacNTP.h Thu Sep 7 21:22:11 2023 +++ MacNTP.h Thu Sep 7 23:06:56 2023 @@ -36,7 +36,7 @@ enum MacNTPError { }; struct ntp_ts { - unsigned long upper; /* Seconds since 1900-01-01 */ + unsigned long upper; /* Seconds since 1904-01-01 */ unsigned long lower; /* FIXME: These values seem to be wrong */ }; @@ -58,7 +58,7 @@ struct ntp_packet { typedef long minutes_t; -enum MacNTPError MacNTPFetchTime(char *ntp_url, struct ntp_packet *packet, OSErr *supplemental); +enum MacNTPError MacNTPFetchTime(char *ntp_url, struct ntp_packet *packet, OSErr *supplemental, minutes_t utc_offset); // For convenience, you can just pass ntp_packet from above to set the system time // Optionally, you can care about the contents of ntp_packet and do things with it. --- main.c Thu Sep 7 21:21:30 2023 +++ main.c Fri Sep 8 00:03:01 2023 @@ -21,6 +21,8 @@ #include "prefs.h" // This enables DebugStr() printouts to aid development. +// This also disables the system time check, so it tries NTP +// on every boot. //#define DEBUGGING pascal void NewInitGraf(Ptr globalPtr); @@ -98,11 +100,17 @@ int TryMacNTP(void) { struct ntp_packet payload; enum MacNTPError error; OSErr oserr = 0; - long utc_offset_minutes; + minutes_t utc_offset; + if (!g_utc) return 1; + StringToNum(*g_utc, &utc_offset); + HUnlock(g_utc); + DisposHandle(g_utc); + g_utc = nil; + if (!g_url) return 1; PtoCstr(*g_url); - error = MacNTPFetchTime((char *)(*g_url), &payload, &oserr); + error = MacNTPFetchTime((char *)(*g_url), &payload, &oserr, utc_offset); HUnlock(g_url); DisposHandle(g_url); g_url = nil; @@ -114,13 +122,7 @@ int TryMacNTP(void) { return 1; } - if (!g_utc) return 1; - StringToNum(*g_utc, &utc_offset_minutes); - HUnlock(g_utc); - DisposHandle(g_utc); - g_utc = nil; - - error = MacNTPSetSystemTime(&payload, utc_offset_minutes); + error = MacNTPSetSystemTime(&payload, utc_offset); if (error) { #ifdef DEBUGGING dump_error(error, oserr); @@ -136,12 +138,14 @@ pascal void NewInitGraf(Ptr globalPtr) { unsigned long systime; SetUpA4(); if (g_ntp_success || g_ntp_error) goto skip; // Pretend we weren't here! - //ReadDateTime((unsigned long *)&systime); +#ifndef DEBUGGING // We only try to update the clock if we're well into the 20th century - /*if (systime > SECONDS_TO_02_09_1996) { + ReadDateTime((unsigned long *)&systime); + if (systime > SECONDS_TO_02_09_1996) { g_ntp_success = 1; goto skip; - }*/ + } +#endif if (!TryMacNTP()) { g_ntp_success = 1;