AmendHub

Download

vkoskiv

/

MacNTP

/

main.c

 

(View History)

vkoskiv   Some touchups for initial v0.1 release Latest amendment: 20 on 2024-01-21

1 /*
2 * Copyright (c) 2023 Valtteri Koskivuori <vkoskiv@gmail.com>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 /*
18 TODO:
19 - Display possible errors in cdev
20 */
21
22 #include <SetUpA4.h>
23 #include <GestaltEqu.h>
24 #include "MacNTP.h"
25 #include "ShowInitIcon.h"
26 #include "rsrcid.h"
27
28 // This enables DebugStr() printouts to aid development.
29 // This also disables the system time check, so it tries NTP
30 // on every boot.
31 //#define DEBUGGING
32
33 void dump_error(enum MacNTPError error, OSErr oserror);
34 int TryMacNTP(Str255 ntp1, Str255 ntp2, Str255 utc);
35 int is_number(char c);
36 int validate_utc(Str255 utc_str);
37 int utcstr_to_mins(Str255 utc, long *out);
38
39 #define SECONDS_TO_02_09_1996 2924510400ul
40
41 Handle g_mtcp_init_handle;
42
43 void dump_error(enum MacNTPError error, OSErr oserror) {
44 // Str255 numstr;
45 StringHandle err_str;
46 err_str = GetString(ERR_STR_ID);
47 if (!err_str) {
48 return;
49 }
50 SetHandleSize(err_str, 256);
51 HLock(err_str);
52 // NumToString(oserror, numstr);
53 switch (error) {
54 case Success:
55 SetString(err_str, "\p"); //FIXME: Bit dumb to write this every time?
56 break;
57 case MacTCPInitFailed:
58 SetString(err_str, "\pMacTCP init failed");
59 break;
60 case MacTCPNotFound:
61 SetString(err_str, "\pMacTCP not found");
62 break;
63 case InvalidURL:
64 SetString(err_str, "\pInvalid URL");
65 break;
66 case BadNtpStructSize:
67 SetString(err_str, "\pBad NTP struct size");
68 break;
69 case UDPCreateFailed:
70 SetString(err_str, "\pUDPCreate failed");
71 break;
72 case UDPSendFailed:
73 SetString(err_str, "\pUDPSend failed");
74 break;
75 case UDPRcvFailed:
76 SetString(err_str, "\pUDPRcv failed");
77 break;
78 case InvalidNTPResponse:
79 SetString(err_str, "\pInvalid NTP response");
80 break;
81 case OriginTimestampMismatch:
82 SetString(err_str, "\pOrigin timestamp mismatch");
83 break;
84 case DNSResolveFailed:
85 SetString(err_str, "\pDNS resolve failed");
86 break;
87 case GestaltMissing:
88 SetString(err_str, "\pMissing Gestalt, MacNTP requires >=6.0.8");
89 break;
90 case ClockWriteFailed:
91 SetString(err_str, "\pClock write failed");
92 break;
93 case ClockReadFailed:
94 SetString(err_str, "\pClock read failed");
95 break;
96 case UDPRcvTimedOut:
97 SetString(err_str, "\pUDPRcv timed out");
98 break;
99 case PacketParamNull:
100 SetString(err_str, "\pPacket param null");
101 break;
102 }
103 HUnlock(err_str);
104 ChangedResource(err_str);
105 ReleaseResource(err_str);
106 UpdateResFile(CurResFile());
107 }
108
109 //FIXME: This is duplicated from cdev.c, but I didn't want to
110 //make a library and all the extra build steps just for this.
111 //Maybe we'll just stick it in MacNTPLib and figure out linkage somehow
112 int is_number(char c) {
113 return c >> 4 == 3 && (c & 0x0F) < 0xA;
114 }
115
116 int validate_utc(Str255 utc_str) {
117 // Str255 is a pointer to a pascal string, where
118 // the first byte is the string length.
119 char scratch[6];
120 short strlen;
121 char *str;
122 strlen = utc_str[0];
123 str = (char *)&utc_str[1];
124 if (strlen != 6) return false;
125 if (str[0] != '+' && str[0] != '-') return false;
126 if (!is_number(str[1]) || !is_number(str[2])) return false;
127 if (str[3] != ':') return false;
128 if (!is_number(str[4]) || !is_number(str[5])) return false;
129
130 return true;
131 }
132 int utcstr_to_mins(Str255 utc, long *out) {
133 long minutes;
134 if (!validate_utc(utc)) return false;
135 minutes = 0;
136 minutes += ((utc[2] - 0x30) * 10) * 60;
137 minutes += (utc[3] - 0x30) * 60;
138 minutes += (utc[5] - 0x30) * 10;
139 minutes += (utc[6] - 0x30);
140 if (utc[1] == '-')
141 minutes = -minutes;
142 if (out) *out = minutes;
143 return true;
144 }
145
146 int TryMacNTP(Str255 ntp1, Str255 ntp2, Str255 utc) {
147 struct ntp_packet payload;
148 enum MacNTPError error;
149 OSErr oserr = 0;
150 minutes_t utc_offset;
151
152 if (!utc[0]) return 1;
153 if (!utcstr_to_mins(utc, &utc_offset)) return 1;
154
155 if (!ntp1[0]) return 1;
156 PtoCstr(ntp1);
157 error = MacNTPFetchTime((char *)(ntp1), &payload, &oserr, utc_offset);
158 // If the first lookup fails and we have a fallback, try it.
159 if (error == DNSResolveFailed && ntp2[0]) {
160 PtoCstr(ntp2);
161 error = MacNTPFetchTime((char *)(ntp2), &payload, &oserr, utc_offset);
162 }
163 dump_error(error, oserr);
164 if (error) return 1;
165
166 error = MacNTPSetSystemTime(&payload, utc_offset);
167 dump_error(error, oserr);
168 if (error) return 1;
169 return 0;
170 }
171
172 void main() {
173 Ptr our_init_ptr;
174 unsigned long systime;
175 StringHandle ntp1;
176 StringHandle ntp2;
177 StringHandle utc; // Offset in minutes as pstr
178 long answer;
179 OSErr gestalt_err;
180 asm {
181 move.L A0, our_init_ptr;
182 }
183 RememberA0();
184 SetUpA4();
185 // This is already locked in the resource attrs
186 g_mtcp_init_handle = RecoverHandle(our_init_ptr);
187
188 // First we check if MacTCP is available
189 // This also assumes Gestalt support
190 gestalt_err = Gestalt(gestaltVersion, &answer);
191 if (gestalt_err) {
192 // Gestalt not available, it was introduced in 6.0.4
193 // And MacTCP in 6.0.3, so we're just going to assume
194 // the user has at least 6.0.8
195 ShowInitIcon(MACNTP_ICN_ID_FAILURE, true);
196 dump_error(GestaltMissing, 0);
197 goto skip;
198 }
199
200 if (Gestalt('mtcp', nil)) {
201 // MacTCP not found
202 ShowInitIcon(MACNTP_ICN_ID_FAILURE, true);
203 dump_error(MacTCPNotFound, 0);
204 goto skip;
205 }
206
207 ntp1 = GetString(NTP1_STR_ID);
208 ntp2 = GetString(NTP2_STR_ID);
209 utc = GetString(UTC_STR_ID);
210 if (!ntp1 || !ntp2 || !utc) {
211 #ifdef DEBUGGING
212 DebugStr("\pSTR rsrcs missing");
213 #endif
214 ShowInitIcon(MACNTP_ICN_ID_FAILURE, true);
215 goto skip;
216 }
217 /*if (!*ntp1[0] && !*ntp2[0]) {
218 #ifdef DEBUGGING
219 DebugStr("\pBoth NTP urls empty");
220 #endif
221 ShowInitIcon(MACNTP_ICN_ID_FAILURE, true);
222 goto skip;
223 }*/
224 HLock(ntp1);
225 HLock(ntp2);
226 HLock(utc);
227
228 //TODO: Move this up a bit
229 #ifndef DEBUGGING
230 // We only try to update the clock if we're well into the 20th century
231 ReadDateTime((unsigned long *)&systime);
232 if (systime > SECONDS_TO_02_09_1996) {
233 ShowInitIcon(MACNTP_ICN_ID_SUCCESS, true);
234 goto skip;
235 } else {
236 ShowInitIcon(MACNTP_ICN_ID_PENDING, false);
237 }
238 #else
239 ShowInitIcon(MACNTP_ICN_ID_PENDING, false);
240 #endif
241
242 if (!TryMacNTP(*ntp1, *ntp2, *utc)) {
243 ShowInitIcon(MACNTP_ICN_ID_SUCCESS, true);
244 } else {
245 ShowInitIcon(MACNTP_ICN_ID_FAILURE, true);
246 }
247
248 // I have no idea if unlock is needed here. Maybe not.
249 HUnlock(ntp1);
250 //DisposHandle(ntp1);
251 HUnlock(ntp2);
252 // For whatever reason, System 6 crashes on boot if we
253 // try to dispose this specific handle. Okay.
254 //DisposHandle(ntp2);
255 HUnlock(utc);
256 //DisposHandle(utc);
257 HUnlock(g_mtcp_init_handle);
258 skip:
259 error:
260 RestoreA4();
261 }