AmendHub

Download

vkoskiv

/

MacNTP

/

main.c

 

(View History)

vkoskiv   Display MacNTP errors in cdev Latest amendment: 19 on 2023-09-20

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 SysBeep(10);
49 SysBeep(1);
50 return;
51 }
52 SetHandleSize(err_str, 256);
53 HLock(err_str);
54 NumToString(oserror, numstr);
55 switch (error) {
56 case Success:
57 SetString(err_str, "\p"); //FIXME: Bit dumb to write this every time?
58 break;
59 case MacTCPInitFailed:
60 SetString(err_str, "\pMacTCP init failed");
61 break;
62 case InvalidURL:
63 SetString(err_str, "\pInvalid URL");
64 break;
65 case BadNtpStructSize:
66 SetString(err_str, "\pBad NTP struct size");
67 break;
68 case UDPCreateFailed:
69 SetString(err_str, "\pUDPCreate failed");
70 break;
71 case UDPSendFailed:
72 SetString(err_str, "\pUDPSend failed");
73 break;
74 case UDPRcvFailed:
75 SetString(err_str, "\pUDPRcv failed");
76 break;
77 case InvalidNTPResponse:
78 SetString(err_str, "\pInvalid NTP response");
79 break;
80 case OriginTimestampMismatch:
81 SetString(err_str, "\pOrigin timestamp mismatch");
82 break;
83 case DNSResolveFailed:
84 SetString(err_str, "\pDNS resolve failed");
85 break;
86 case ClockWriteFailed:
87 SetString(err_str, "\pClock write failed");
88 break;
89 case ClockReadFailed:
90 SetString(err_str, "\pClock read failed");
91 break;
92 case UDPRcvTimedOut:
93 SetString(err_str, "\pUDPRcv timed out");
94 break;
95 case PacketParamNull:
96 SetString(err_str, "\pPacket param null");
97 break;
98 }
99 HUnlock(err_str);
100 ChangedResource(err_str);
101 ReleaseResource(err_str);
102 UpdateResFile(CurResFile());
103 }
104
105 //FIXME: This is duplicated from cdev.c, but I didn't want to
106 //make a library and all the extra build steps just for this.
107 //Maybe we'll just stick it in MacNTPLib and figure out linkage somehow
108 int is_number(char c) {
109 return c >> 4 == 3 && (c & 0x0F) < 0xA;
110 }
111
112 int validate_utc(Str255 utc_str) {
113 // Str255 is a pointer to a pascal string, where
114 // the first byte is the string length.
115 char scratch[6];
116 short strlen;
117 char *str;
118 strlen = utc_str[0];
119 str = (char *)&utc_str[1];
120 if (strlen != 6) return false;
121 if (str[0] != '+' && str[0] != '-') return false;
122 if (!is_number(str[1]) || !is_number(str[2])) return false;
123 if (str[3] != ':') return false;
124 if (!is_number(str[4]) || !is_number(str[5])) return false;
125
126 return true;
127 }
128 int utcstr_to_mins(Str255 utc, long *out) {
129 long minutes;
130 if (!validate_utc(utc)) return false;
131 minutes = 0;
132 minutes += ((utc[2] - 0x30) * 10) * 60;
133 minutes += (utc[3] - 0x30) * 60;
134 minutes += (utc[5] - 0x30) * 10;
135 minutes += (utc[6] - 0x30);
136 if (utc[1] == '-')
137 minutes = -minutes;
138 if (out) *out = minutes;
139 return true;
140 }
141
142 int TryMacNTP(Str255 ntp1, Str255 ntp2, Str255 utc) {
143 struct ntp_packet payload;
144 enum MacNTPError error;
145 OSErr oserr = 0;
146 minutes_t utc_offset;
147
148 if (!utc[0]) return 1;
149 if (!utcstr_to_mins(utc, &utc_offset)) return 1;
150
151 if (!ntp1[0]) return 1;
152 PtoCstr(ntp1);
153 error = MacNTPFetchTime((char *)(ntp1), &payload, &oserr, utc_offset);
154 if (error == DNSResolveFailed) SysBeep(1);
155 // If the first lookup fails and we have a fallback, try it.
156 if (error == DNSResolveFailed && ntp2[0]) {
157 PtoCstr(ntp2);
158 error = MacNTPFetchTime((char *)(ntp2), &payload, &oserr, utc_offset);
159 }
160 dump_error(error, oserr);
161 if (error) return 1;
162
163 error = MacNTPSetSystemTime(&payload, utc_offset);
164 dump_error(error, oserr);
165 if (error) return 1;
166 return 0;
167 }
168
169 void main() {
170 Ptr our_init_ptr;
171 unsigned long systime;
172 StringHandle ntp1;
173 StringHandle ntp2;
174 StringHandle utc; // Offset in minutes as pstr
175 long answer;
176 OSErr gestalt_err;
177 asm {
178 move.L A0, our_init_ptr;
179 }
180 RememberA0();
181 SetUpA4();
182 // This is already locked in the resource attrs
183 g_mtcp_init_handle = RecoverHandle(our_init_ptr);
184
185 // First we check if MacTCP is available
186 // This also assumes Gestalt support
187 gestalt_err = Gestalt(gestaltVersion, &answer);
188 if (gestalt_err) {
189 // Gestalt not available, it was introduced in 6.0.4
190 // And MacTCP in 6.0.3, so we're just going to assume
191 // the user has at least 6.0.8
192 ShowInitIcon(MACNTP_ICN_ID_FAILURE, true);
193 goto skip;
194 }
195
196 if (Gestalt('mtcp', nil)) {
197 // MacTCP not found
198 ShowInitIcon(MACNTP_ICN_ID_FAILURE, true);
199 goto skip;
200 }
201
202 ntp1 = GetString(NTP1_STR_ID);
203 ntp2 = GetString(NTP2_STR_ID);
204 utc = GetString(UTC_STR_ID);
205 if (!ntp1 || !ntp2 || !utc) {
206 #ifdef DEBUGGING
207 DebugStr("\pSTR rsrcs missing");
208 #endif
209 ShowInitIcon(MACNTP_ICN_ID_FAILURE, true);
210 goto skip;
211 }
212 /*if (!*ntp1[0] && !*ntp2[0]) {
213 #ifdef DEBUGGING
214 DebugStr("\pBoth NTP urls empty");
215 #endif
216 ShowInitIcon(MACNTP_ICN_ID_FAILURE, true);
217 goto skip;
218 }*/
219 HLock(ntp1);
220 HLock(ntp2);
221 HLock(utc);
222
223 //TODO: Move this up a bit
224 #ifndef DEBUGGING
225 // We only try to update the clock if we're well into the 20th century
226 ReadDateTime((unsigned long *)&systime);
227 if (systime > SECONDS_TO_02_09_1996) {
228 ShowInitIcon(MACNTP_ICN_ID_SUCCESS, true);
229 goto skip;
230 } else {
231 ShowInitIcon(MACNTP_ICN_ID_PENDING, false);
232 }
233 #else
234 ShowInitIcon(MACNTP_ICN_ID_PENDING, false);
235 #endif
236
237 if (!TryMacNTP(*ntp1, *ntp2, *utc)) {
238 ShowInitIcon(MACNTP_ICN_ID_SUCCESS, true);
239 } else {
240 ShowInitIcon(MACNTP_ICN_ID_FAILURE, true);
241 }
242
243 // I have no idea if unlock is needed here. Maybe not.
244 HUnlock(ntp1);
245 //DisposHandle(ntp1);
246 HUnlock(ntp2);
247 // For whatever reason, System 6 crashes on boot if we
248 // try to dispose this specific handle. Okay.
249 //DisposHandle(ntp2);
250 HUnlock(utc);
251 //DisposHandle(utc);
252 HUnlock(g_mtcp_init_handle);
253 skip:
254 error:
255 RestoreA4();
256 }