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 about 1 year 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;