]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOS9/mDNSMacOS9.c
mDNSResponder-320.5.tar.gz
[apple/mdnsresponder.git] / mDNSMacOS9 / mDNSMacOS9.c
1 /* -*- Mode: C; tab-width: 4 -*-
2 *
3 * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 #include <stdio.h>
19 #include <stdarg.h> // For va_list support
20
21 #include <LowMem.h> // For LMGetCurApName()
22 #include <TextUtils.h> // For smSystemScript
23 #include <UnicodeConverter.h> // For ConvertFromPStringToUnicode()
24
25 #include "mDNSEmbeddedAPI.h" // Defines the interface provided to the client layer above
26
27 #include "mDNSMacOS9.h" // Defines the specific types needed to run mDNS on this platform
28
29 // ***************************************************************************
30 // Constants
31
32 static const TSetBooleanOption kReusePortOption =
33 { kOTBooleanOptionSize, INET_IP, IP_REUSEPORT, 0, true };
34
35 // IP_RCVDSTADDR with TSetByteOption/kOTOneByteOptionSize works on OS 9, OS X Classic, and OS 9 Carbon,
36 // but gives error #-3151 (kOTBadOptionErr) on OS X Carbon.
37 // If we instead use TSetBooleanOption/kOTBooleanOptionSize then OTOptionManagement on OS X Carbon
38 // no longer returns -3151 but it still doesn't actually work -- no destination addresses
39 // are delivered by OTRcvUData. I think it's just a bug in OS X Carbon.
40 static const TSetByteOption kRcvDestAddrOption =
41 { kOTOneByteOptionSize, INET_IP, IP_RCVDSTADDR, 0, true };
42 //static const TSetBooleanOption kRcvDestAddrOption =
43 // { kOTBooleanOptionSize, INET_IP, IP_RCVDSTADDR, 0, true };
44
45 static const TSetByteOption kSetUnicastTTLOption =
46 { kOTOneByteOptionSize, INET_IP, IP_TTL, 0, 255 };
47
48 static const TSetByteOption kSetMulticastTTLOption =
49 { kOTOneByteOptionSize, INET_IP, IP_MULTICAST_TTL, 0, 255 };
50
51 static const TIPAddMulticastOption kAddLinkMulticastOption =
52 { sizeof(TIPAddMulticastOption), INET_IP, IP_ADD_MEMBERSHIP, 0, { 224, 0, 0,251 }, { 0,0,0,0 } };
53
54 //static const TIPAddMulticastOption kAddAdminMulticastOption =
55 // { sizeof(TIPAddMulticastOption), INET_IP, IP_ADD_MEMBERSHIP, 0, { 239,255,255,251 }, { 0,0,0,0 } };
56
57 // Bind endpoint to port number. Don't specify any specific IP address --
58 // we want to receive unicasts on all interfaces, as well as multicasts.
59 typedef struct { OTAddressType fAddressType; mDNSIPPort fPort; mDNSv4Addr fHost; UInt8 fUnused[8]; } mDNSInetAddress;
60 //static const mDNSInetAddress mDNSPortInetAddress = { AF_INET, { 0,0 }, { 0,0,0,0 } }; // For testing legacy client support
61 #define MulticastDNSPortAsNumber 5353
62 static const mDNSInetAddress mDNSPortInetAddress = { AF_INET, { MulticastDNSPortAsNumber >> 8, MulticastDNSPortAsNumber & 0xFF }, { 0,0,0,0 } };
63 static const TBind mDNSbindReq = { sizeof(mDNSPortInetAddress), sizeof(mDNSPortInetAddress), (UInt8*)&mDNSPortInetAddress, 0 };
64
65 static const TNetbuf zeroTNetbuf = { 0 };
66
67 // ***************************************************************************
68 // Functions
69
70 mDNSlocal void SafeDebugStr(unsigned char *buffer)
71 {
72 int i;
73 // Don't want semicolons in MacsBug messages -- they signify commands to execute
74 for (i=1; i<= buffer[0]; i++) if (buffer[i] == ';') buffer[i] = '.';
75 DebugStr(buffer);
76 }
77
78 #if MDNS_DEBUGMSGS
79 mDNSexport void debugf_(const char *format, ...)
80 {
81 unsigned char buffer[256];
82 va_list ptr;
83 va_start(ptr,format);
84 buffer[0] = (unsigned char)mDNS_vsnprintf((char*)buffer+1, 255, format, ptr);
85 va_end(ptr);
86 #if MDNS_ONLYSYSTEMTASK
87 buffer[1+buffer[0]] = 0;
88 fprintf(stderr, "%s\n", buffer+1);
89 fflush(stderr);
90 #else
91 SafeDebugStr(buffer);
92 #endif
93 }
94 #endif
95
96 #if MDNS_BUILDINGSHAREDLIBRARY >= 2
97 // When building the non-debug version of the Extension, intended to go on end-user systems, we don't want
98 // MacsBug breaks for *anything*, not even for the serious LogMsg messages that on OS X would be written to syslog
99 mDNSexport void LogMsg(const char *format, ...) { (void)format; }
100 #else
101 mDNSexport void LogMsg(const char *format, ...)
102 {
103 unsigned char buffer[256];
104 va_list ptr;
105 va_start(ptr,format);
106 buffer[0] = (unsigned char)mDNS_vsnprintf((char*)buffer+1, 255, format, ptr);
107 va_end(ptr);
108 #if MDNS_ONLYSYSTEMTASK
109 buffer[1+buffer[0]] = 0;
110 fprintf(stderr, "%s\n", buffer+1);
111 fflush(stderr);
112 #else
113 SafeDebugStr(buffer);
114 #endif
115 }
116 #endif
117
118 mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const msg, const mDNSu8 *const end,
119 mDNSInterfaceID InterfaceID, const mDNSAddr *dst, mDNSIPPort dstPort)
120 {
121 // Note: If we did multi-homing, we'd have to use the InterfaceID parameter to specify from which interface to send this response
122 #pragma unused(InterfaceID)
123
124 InetAddress InetDest;
125 TUnitData senddata;
126
127 if (dst->type != mDNSAddrType_IPv4) return(mStatus_NoError);
128
129 InetDest.fAddressType = AF_INET;
130 InetDest.fPort = dstPort.NotAnInteger;
131 InetDest.fHost = dst->ip.v4.NotAnInteger;
132
133 senddata.addr .maxlen = sizeof(InetDest);
134 senddata.addr .len = sizeof(InetDest);
135 senddata.addr .buf = (UInt8*)&InetDest;
136 senddata.opt = zeroTNetbuf;
137 senddata.udata.maxlen = (UInt32)((UInt8*)end - (UInt8*)msg);
138 senddata.udata.len = (UInt32)((UInt8*)end - (UInt8*)msg);
139 senddata.udata.buf = (UInt8*)msg;
140
141 return(OTSndUData(m->p->ep, &senddata));
142 }
143
144 mDNSlocal OSStatus readpacket(mDNS *m)
145 {
146 mDNSAddr senderaddr, destaddr;
147 mDNSInterfaceID interface;
148 mDNSIPPort senderport;
149 InetAddress sender;
150 char options[256];
151 DNSMessage packet;
152 TUnitData recvdata;
153 OTFlags flags = 0;
154 OSStatus err;
155
156 recvdata.addr .maxlen = sizeof(sender);
157 recvdata.addr .len = 0;
158 recvdata.addr .buf = (UInt8*)&sender;
159 recvdata.opt .maxlen = sizeof(options);
160 recvdata.opt .len = 0;
161 recvdata.opt .buf = (UInt8*)&options;
162 recvdata.udata.maxlen = sizeof(packet);
163 recvdata.udata.len = 0;
164 recvdata.udata.buf = (UInt8*)&packet;
165
166 err = OTRcvUData(m->p->ep, &recvdata, &flags);
167 if (err && err != kOTNoDataErr) debugf("OTRcvUData error %d", err);
168
169 if (err) return(err);
170
171 senderaddr.type = mDNSAddrType_IPv4;
172 senderaddr.ip.v4.NotAnInteger = sender.fHost;
173 senderport.NotAnInteger = sender.fPort;
174
175 destaddr.type = mDNSAddrType_IPv4;
176 destaddr.ip.v4 = zerov4Addr;
177
178 #if OTCARBONAPPLICATION
179 // IP_RCVDSTADDR is known to fail on OS X Carbon, so we'll just assume the packet was probably multicast
180 destaddr.ip.v4 = AllDNSLinkGroup_v4.ip.v4;
181 #endif
182
183 if (recvdata.opt.len)
184 {
185 TOption *c = nil;
186 while (1)
187 {
188 err = OTNextOption(recvdata.opt.buf, recvdata.opt.len, &c);
189 if (err || !c) break;
190 if (c->level == INET_IP && c->name == IP_RCVDSTADDR && c->len - kOTOptionHeaderSize == sizeof(destaddr.ip.v4))
191 mDNSPlatformMemCopy(&destaddr.ip.v4, c->value, sizeof(destaddr.ip.v4));
192 }
193 }
194
195 interface = m->HostInterfaces->InterfaceID;
196
197 if (flags & T_MORE) debugf("ERROR: OTRcvUData() buffer too small (T_MORE set)");
198 else if (recvdata.addr.len < sizeof(InetAddress)) debugf("ERROR: recvdata.addr.len (%d) too short", recvdata.addr.len);
199 else mDNSCoreReceive(m, &packet, recvdata.udata.buf + recvdata.udata.len, &senderaddr, senderport, &destaddr, MulticastDNSPort, interface);
200
201 return(err);
202 }
203
204 mDNSexport TCPSocket *mDNSPlatformTCPSocket(mDNS * const m, TCPSocketFlags flags, mDNSIPPort * port)
205 {
206 (void)m; // Unused
207 (void)flags; // Unused
208 (void)port; // Unused
209 return NULL;
210 }
211
212 mDNSexport TCPSocket *mDNSPlatformTCPAccept(TCPSocketFlags flags, int sd)
213 {
214 (void)flags; // Unused
215 (void)sd; // Unused
216 return NULL;
217 }
218
219 mDNSexport int mDNSPlatformTCPGetFD(TCPSocket *sock)
220 {
221 (void)sock; // Unused
222 return -1;
223 }
224
225 mDNSexport mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr * dst, mDNSOpaque16 dstport, mDNSInterfaceID InterfaceID,
226 TCPConnectionCallback callback, void * context)
227 {
228 (void)sock; // Unused
229 (void)dst; // Unused
230 (void)dstport; // Unused
231 (void)InterfaceID; // Unused
232 (void)callback; // Unused
233 (void)context; // Unused
234 return(mStatus_UnsupportedErr);
235 }
236
237 mDNSexport void mDNSPlatformTCPCloseConnection(TCPSocket *sd)
238 {
239 (void)sd; // Unused
240 }
241
242 mDNSexport long mDNSPlatformReadTCP(TCPSocket *sock, void *buf, unsigned long buflen, mDNSBool *closed)
243 {
244 (void)sock; // Unused
245 (void)buf; // Unused
246 (void)buflen; // Unused
247 (void)closed; // Unused
248 return(0);
249 }
250
251 mDNSexport long mDNSPlatformWriteTCP(TCPSocket *sock, const char *msg, unsigned long len)
252 {
253 (void)sock; // Unused
254 (void)msg; // Unused
255 (void)len; // Unused
256 return(0);
257 }
258
259 mDNSexport UDPSocket *mDNSPlatformUDPSocket(mDNS * const m, mDNSIPPort port)
260 {
261 (void)m; // Unused
262 (void)port; // Unused
263 return NULL;
264 }
265
266 mDNSexport void mDNSPlatformUDPClose(UDPSocket *sock)
267 {
268 (void)sock; // Unused
269 }
270
271 mDNSlocal void mDNSOptionManagement(mDNS *const m)
272 {
273 OSStatus err;
274
275 // Make sure the length in the TNetbuf agrees with the length in the TOptionHeader
276 m->p->optReq.opt.len = m->p->optBlock.h.len;
277 m->p->optReq.opt.maxlen = m->p->optBlock.h.len;
278 if (m->p->optReq.opt.maxlen < 4)
279 m->p->optReq.opt.maxlen = 4;
280
281 err = OTOptionManagement(m->p->ep, &m->p->optReq, NULL);
282 if (err) LogMsg("OTOptionManagement failed %d", err);
283 }
284
285 mDNSlocal void mDNSinitComplete(mDNS *const m, mStatus result)
286 {
287 m->mDNSPlatformStatus = result;
288 mDNSCoreInitComplete(m, mStatus_NoError);
289 }
290
291 mDNSlocal pascal void mDNSNotifier(void *contextPtr, OTEventCode code, OTResult result, void *cookie)
292 {
293 mDNS *const m = (mDNS *const)contextPtr;
294 if (!m) debugf("mDNSNotifier FATAL ERROR! No context");
295 switch (code)
296 {
297 case T_OPENCOMPLETE:
298 {
299 OSStatus err;
300 InetInterfaceInfo interfaceinfo;
301 if (result) { LogMsg("T_OPENCOMPLETE failed %d", result); mDNSinitComplete(m, result); return; }
302 //debugf("T_OPENCOMPLETE");
303 m->p->ep = (EndpointRef)cookie;
304 //debugf("OTInetGetInterfaceInfo");
305 // (In future may want to loop over all interfaces instead of just using kDefaultInetInterface)
306 err = OTInetGetInterfaceInfo(&interfaceinfo, kDefaultInetInterface);
307 if (err) { LogMsg("OTInetGetInterfaceInfo failed %d", err); mDNSinitComplete(m, err); return; }
308
309 // Make our basic standard host resource records (address, PTR, etc.)
310 m->p->interface.InterfaceID = (mDNSInterfaceID)&m->p->interface;
311 m->p->interface.ip .type = mDNSAddrType_IPv4;
312 m->p->interface.ip .ip.v4.NotAnInteger = interfaceinfo.fAddress;
313 m->p->interface.mask.type = mDNSAddrType_IPv4;
314 m->p->interface.mask.ip.v4.NotAnInteger = interfaceinfo.fNetmask;
315 m->p->interface.ifname[0] = 0;
316 m->p->interface.Advertise = m->AdvertiseLocalAddresses;
317 m->p->interface.McastTxRx = mDNStrue;
318 }
319
320 case T_OPTMGMTCOMPLETE:
321 case T_BINDCOMPLETE:
322 // IP_RCVDSTADDR is known to fail on OS X Carbon, so we don't want to abort for that error
323 // (see comment above at the definition of kRcvDestAddrOption)
324 #if OTCARBONAPPLICATION
325 if (result && m->p->mOTstate == mOT_RcvDestAddr)
326 LogMsg("Carbon IP_RCVDSTADDR option failed %d; continuing anyway", result);
327 else
328 #endif
329 if (result) { LogMsg("T_OPTMGMTCOMPLETE/T_BINDCOMPLETE %d failed %d", m->p->mOTstate, result); mDNSinitComplete(m, result); return; }
330 //LogMsg("T_OPTMGMTCOMPLETE/T_BINDCOMPLETE %d", m->p->mOTstate);
331 switch (++m->p->mOTstate)
332 {
333 case mOT_ReusePort: m->p->optBlock.b = kReusePortOption; mDNSOptionManagement(m); break;
334 case mOT_RcvDestAddr: m->p->optBlock.i = kRcvDestAddrOption; mDNSOptionManagement(m); break;
335 case mOT_SetUTTL: m->p->optBlock.i = kSetUnicastTTLOption; mDNSOptionManagement(m); break;
336 case mOT_SetMTTL: m->p->optBlock.i = kSetMulticastTTLOption; mDNSOptionManagement(m); break;
337 case mOT_LLScope: m->p->optBlock.m = kAddLinkMulticastOption; mDNSOptionManagement(m); break;
338 // case mOT_AdminScope: m->p->optBlock.m = kAddAdminMulticastOption; mDNSOptionManagement(m); break;
339 case mOT_Bind: OTBind(m->p->ep, (TBind*)&mDNSbindReq, NULL); break;
340 case mOT_Ready: mDNSinitComplete(m, mStatus_NoError);
341 // Can't do mDNS_RegisterInterface until *after* mDNSinitComplete has set m->mDNSPlatformStatus to mStatus_NoError
342 mDNS_RegisterInterface(m, &m->p->interface, mDNSfalse);
343 break;
344 default: LogMsg("Unexpected m->p->mOTstate %d", m->p->mOTstate-1);
345 }
346 break;
347
348 case T_DATA:
349 //debugf("T_DATA");
350 while (readpacket(m) == kOTNoError) continue; // Read packets until we run out
351 break;
352
353 case kOTProviderWillClose: LogMsg("kOTProviderWillClose"); break;
354 case kOTProviderIsClosed: // Machine is going to sleep, shutting down, or reconfiguring IP
355 LogMsg("kOTProviderIsClosed");
356 if (m->p->mOTstate == mOT_Ready)
357 {
358 m->p->mOTstate = mOT_Closed;
359 mDNS_DeregisterInterface(m, &m->p->interface, mDNSfalse);
360 }
361 if (m->p->ep) { OTCloseProvider(m->p->ep); m->p->ep = NULL; }
362 break; // Do we need to do anything?
363
364 default: debugf("mDNSNotifier: Unexpected OTEventCode %X", code);
365 break;
366 }
367 }
368
369 #if MDNS_ONLYSYSTEMTASK
370
371 static Boolean ONLYSYSTEMTASKevent;
372 static void *ONLYSYSTEMTASKcontextPtr;
373 static OTEventCode ONLYSYSTEMTASKcode;
374 static OTResult ONLYSYSTEMTASKresult;
375 static void *ONLYSYSTEMTASKcookie;
376
377 mDNSlocal pascal void CallmDNSNotifier(void *contextPtr, OTEventCode code, OTResult result, void *cookie)
378 {
379 ONLYSYSTEMTASKcontextPtr = contextPtr;
380 ONLYSYSTEMTASKcode = code;
381 ONLYSYSTEMTASKresult = result;
382 ONLYSYSTEMTASKcookie = cookie;
383 }
384
385 #else
386
387 mDNSlocal pascal void CallmDNSNotifier(void *contextPtr, OTEventCode code, OTResult result, void *cookie)
388 {
389 mDNS *const m = (mDNS *const)contextPtr;
390 if (!m) debugf("mDNSNotifier FATAL ERROR! No context");
391 if (m->p->nesting) LogMsg("CallmDNSNotifier ERROR! OTEnterNotifier is supposed to suppress notifier callbacks");
392 mDNSNotifier(contextPtr, code, result, cookie);
393 }
394
395 #endif
396
397 static OTNotifyUPP CallmDNSNotifierUPP;
398
399 mDNSlocal OSStatus mDNSOpenEndpoint(const mDNS *const m)
400 {
401 OSStatus err;
402 // m->optReq is pre-set to point to the shared m->optBlock
403 // m->optBlock is filled in by each OTOptionManagement call
404 m->p->optReq.opt.maxlen = sizeof(m->p->optBlock);
405 m->p->optReq.opt.len = sizeof(m->p->optBlock);
406 m->p->optReq.opt.buf = (UInt8*)&m->p->optBlock;
407 m->p->optReq.flags = T_NEGOTIATE;
408
409 // Open an endpoint and start answering queries
410 //printf("Opening endpoint now...\n");
411 m->p->ep = NULL;
412 m->p->mOTstate = mOT_Start;
413 err = OTAsyncOpenEndpoint(OTCreateConfiguration(kUDPName), 0, NULL, CallmDNSNotifierUPP, (void*)m);
414 if (err) { LogMsg("ERROR: OTAsyncOpenEndpoint(UDP) failed with error <%d>", err); return(err); }
415 return(kOTNoError);
416 }
417
418 // Define these here because they're not in older versions of OpenTransport.h
419 enum
420 {
421 xOTStackIsLoading = 0x27000001, /* Sent before Open Transport attempts to load the TCP/IP protocol stack.*/
422 xOTStackWasLoaded = 0x27000002, /* Sent after the TCP/IP stack has been successfully loaded.*/
423 xOTStackIsUnloading = 0x27000003 /* Sent before Open Transport unloads the TCP/IP stack.*/
424 };
425
426 static mDNS *ClientNotifierContext;
427
428 mDNSlocal pascal void ClientNotifier(void *contextPtr, OTEventCode code, OTResult result, void *cookie)
429 {
430 mDNS *const m = ClientNotifierContext;
431
432 #pragma unused(contextPtr) // Usually zero (except one in the 'xOTStackIsLoading' case)
433 #pragma unused(cookie) // Usually 'ipv4' (except for kOTPortNetworkChange)
434 #pragma unused(result) // Usually zero
435
436 switch (code)
437 {
438 case xOTStackIsLoading: break;
439 case xOTStackWasLoaded: if (m->p->mOTstate == mOT_Closed)
440 {
441 LogMsg("kOTStackWasLoaded: Re-opening endpoint");
442 if (m->p->ep)
443 LogMsg("kOTStackWasLoaded: ERROR: m->p->ep already set");
444 m->mDNSPlatformStatus = mStatus_Waiting;
445 m->p->mOTstate = mOT_Reset;
446 #if !MDNS_ONLYSYSTEMTASK
447 mDNSOpenEndpoint(m);
448 #endif
449 }
450 else
451 LogMsg("kOTStackWasLoaded (no action)");
452 break;
453 case xOTStackIsUnloading: break;
454 case kOTPortNetworkChange: break;
455 default: debugf("ClientNotifier unknown code %X, %X, %d", contextPtr, code, result); break;
456 }
457 }
458
459 #if TARGET_API_MAC_CARBON
460
461 mDNSlocal void GetUserSpecifiedComputerName(domainlabel *const namelabel)
462 {
463 CFStringRef cfs = CSCopyMachineName();
464 CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8);
465 CFRelease(cfs);
466 }
467
468 #else
469
470 mDNSlocal OSStatus ConvertStringHandleToUTF8(const StringHandle machineName, UInt8 *const utf8, ByteCount maxlen)
471 {
472 OSStatus status;
473 TextEncoding utf8TextEncoding, SystemTextEncoding;
474 UnicodeMapping theMapping;
475 TextToUnicodeInfo textToUnicodeInfo;
476 ByteCount unicodelen = 0;
477
478 if (maxlen > 255) maxlen = 255; // Can't put more than 255 in a Pascal String
479
480 utf8TextEncoding = CreateTextEncoding(kTextEncodingUnicodeDefault, kTextEncodingDefaultVariant, kUnicodeUTF8Format);
481 UpgradeScriptInfoToTextEncoding(smSystemScript, kTextLanguageDontCare, kTextRegionDontCare, NULL, &SystemTextEncoding);
482 theMapping.unicodeEncoding = utf8TextEncoding;
483 theMapping.otherEncoding = SystemTextEncoding;
484 theMapping.mappingVersion = kUnicodeUseLatestMapping;
485 status = CreateTextToUnicodeInfo(&theMapping, &textToUnicodeInfo);
486 if (status == noErr)
487 {
488 status = ConvertFromPStringToUnicode(textToUnicodeInfo, *machineName, maxlen, &unicodelen, (UniCharArrayPtr)&(utf8[1]));
489 DisposeTextToUnicodeInfo(&textToUnicodeInfo);
490 }
491 utf8[0] = (UInt8)unicodelen;
492 return(status);
493 }
494
495 mDNSlocal void GetUserSpecifiedComputerName(domainlabel *const namelabel)
496 {
497 StringHandle machineName = GetString(-16413); // Get machine name set in file sharing
498 if (machineName)
499 {
500 char machineNameState = HGetState((Handle)machineName);
501 HLock((Handle)machineName);
502 ConvertStringHandleToUTF8(machineName, namelabel->c, MAX_DOMAIN_LABEL);
503 HSetState((Handle)machineName, machineNameState);
504 }
505 }
506
507 #endif
508
509 static pascal void mDNSTimerTask(void *arg)
510 {
511 #if MDNS_ONLYSYSTEMTASK
512 #pragma unused(arg)
513 ONLYSYSTEMTASKevent = true;
514 #else
515 mDNS *const m = (mDNS *const)arg;
516 if (!m->p->ep) LogMsg("mDNSTimerTask NO endpoint");
517 if (m->mDNS_busy) LogMsg("mDNS_busy");
518 if (m->p->nesting) LogMsg("mDNSTimerTask ERROR! OTEnterNotifier is supposed to suppress timer callbacks too");
519
520 // If our timer fires at a time when we have no endpoint, ignore it --
521 // once we reopen our endpoint and get our T_BINDCOMPLETE message we'll call
522 // mDNS_RegisterInterface(), which does a lock/unlock, which retriggers the timer.
523 // Likewise, if m->mDNS_busy or m->p->nesting, we'll catch this on the unlock
524 if (m->p->ep && m->mDNS_busy == 0 && m->p->nesting == 0) mDNS_Execute(m);
525 #endif
526 }
527
528 #if TEST_SLEEP
529 long sleep, wake, mode;
530 #endif
531
532 mDNSexport mStatus mDNSPlatformInit(mDNS *const m)
533 {
534 OSStatus err = InitOpenTransport();
535
536 ClientNotifierContext = m;
537 // Note: OTRegisterAsClient returns kOTNotSupportedErr when running as Carbon code on OS X
538 // -- but that's okay, we don't need a ClientNotifier when running as Carbon code on OS X
539 OTRegisterAsClient(NULL, NewOTNotifyUPP(ClientNotifier));
540
541 m->p->OTTimerTask = OTCreateTimerTask(NewOTProcessUPP(mDNSTimerTask), m);
542 m->p->nesting = 0;
543
544 #if TEST_SLEEP
545 sleep = TickCount() + 600;
546 wake = TickCount() + 1200;
547 mode = 0;
548 #endif
549
550 // Set up the nice label
551 m->nicelabel.c[0] = 0;
552 GetUserSpecifiedComputerName(&m->nicelabel);
553 // m->nicelabel = *(domainlabel*)"\pStu"; // For conflict testing
554 if (m->nicelabel.c[0] == 0) MakeDomainLabelFromLiteralString(&m->nicelabel, "Macintosh");
555
556 // Set up the RFC 1034-compliant label
557 m->hostlabel.c[0] = 0;
558 ConvertUTF8PstringToRFC1034HostLabel(m->nicelabel.c, &m->hostlabel);
559 if (m->hostlabel.c[0] == 0) MakeDomainLabelFromLiteralString(&m->hostlabel, "Macintosh");
560
561 mDNS_SetFQDN(m);
562
563 // When it's finished mDNSOpenEndpoint asynchronously calls mDNSinitComplete() and then mDNS_RegisterInterface()
564 CallmDNSNotifierUPP = NewOTNotifyUPP(CallmDNSNotifier);
565 err = mDNSOpenEndpoint(m);
566 if (err)
567 {
568 LogMsg("mDNSOpenEndpoint failed %d", err);
569 if (m->p->OTTimerTask) OTDestroyTimerTask(m->p->OTTimerTask);
570 OTUnregisterAsClient();
571 CloseOpenTransport();
572 }
573 return(err);
574 }
575
576 extern void mDNSPlatformClose (mDNS *const m)
577 {
578 if (m->p->mOTstate == mOT_Ready)
579 {
580 m->p->mOTstate = mOT_Closed;
581 mDNS_DeregisterInterface(m, &m->p->interface, mDNSfalse);
582 }
583 if (m->p->ep) { OTCloseProvider (m->p->ep); m->p->ep = NULL; }
584 if (m->p->OTTimerTask) { OTDestroyTimerTask(m->p->OTTimerTask); m->p->OTTimerTask = 0; }
585
586 OTUnregisterAsClient();
587 CloseOpenTransport();
588 }
589
590 #if MDNS_ONLYSYSTEMTASK
591 extern void mDNSPlatformIdle(mDNS *const m);
592 mDNSexport void mDNSPlatformIdle(mDNS *const m)
593 {
594 while (ONLYSYSTEMTASKcontextPtr)
595 {
596 void *contextPtr = ONLYSYSTEMTASKcontextPtr;
597 ONLYSYSTEMTASKcontextPtr = NULL;
598 mDNSNotifier(contextPtr, ONLYSYSTEMTASKcode, ONLYSYSTEMTASKresult, ONLYSYSTEMTASKcookie);
599 }
600 if (ONLYSYSTEMTASKevent)
601 {
602 ONLYSYSTEMTASKevent = false;
603 mDNS_Execute(m);
604 }
605
606 if (m->p->mOTstate == mOT_Reset)
607 {
608 printf("\n");
609 printf("******************************************************************************\n");
610 printf("\n");
611 printf("Reopening endpoint\n");
612 mDNSOpenEndpoint(m);
613 m->ResourceRecords = NULL;
614 }
615
616 #if TEST_SLEEP
617 switch (mode)
618 {
619 case 0: if ((long)TickCount() - sleep >= 0) { mDNSCoreMachineSleep(m, 1); mode++; }
620 break;
621 case 1: if ((long)TickCount() - wake >= 0) { mDNSCoreMachineSleep(m, 0); mode++; }
622 break;
623 }
624 #endif
625 }
626 #endif
627
628 mDNSexport void mDNSPlatformLock(const mDNS *const m)
629 {
630 if (!m) { DebugStr("\pmDNSPlatformLock m NULL!"); return; }
631 if (!m->p) { DebugStr("\pmDNSPlatformLock m->p NULL!"); return; }
632
633 // If we try to call OTEnterNotifier and fail because we're already running at
634 // Notifier context, then make sure we don't do the matching OTLeaveNotifier() on exit.
635 // If we haven't even opened our endpoint yet, then just increment m->p->nesting for the same reason
636 if (m->p->mOTstate == mOT_Ready && !m->p->ep) DebugStr("\pmDNSPlatformLock: m->p->mOTstate == mOT_Ready && !m->p->ep");
637 if (!m->p->ep || m->p->nesting || OTEnterNotifier(m->p->ep) == false) m->p->nesting++;
638 }
639
640 mDNSlocal void ScheduleNextTimerCallback(const mDNS *const m)
641 {
642 if (m->mDNSPlatformStatus == mStatus_NoError)
643 {
644 SInt32 interval = m->NextScheduledEvent - mDNS_TimeNow_NoLock(m);
645 if (interval < 1) interval = 1;
646 else if (interval > 0x70000000 / 1000) interval = 0x70000000 / mDNSPlatformOneSecond;
647 else interval = (interval * 1000 + mDNSPlatformOneSecond-1)/ mDNSPlatformOneSecond;
648 OTScheduleTimerTask(m->p->OTTimerTask, (OTTimeout)interval);
649 }
650 }
651
652 mDNSexport void mDNSPlatformUnlock(const mDNS *const m)
653 {
654 if (!m) { DebugStr("\pmDNSPlatformUnlock m NULL!"); return; }
655 if (!m->p) { DebugStr("\pmDNSPlatformUnlock m->p NULL!"); return; }
656
657 if (m->p->ep && m->mDNS_busy == 0) ScheduleNextTimerCallback(m);
658
659 if (m->p->nesting) m->p->nesting--;
660 else OTLeaveNotifier(m->p->ep);
661 }
662
663 mDNSexport void mDNSPlatformStrCopy( void *dst, const void *src) { OTStrCopy((char*)dst, (char*)src); }
664 mDNSexport UInt32 mDNSPlatformStrLen ( const void *src) { return(OTStrLength((char*)src)); }
665 mDNSexport void mDNSPlatformMemCopy( void *dst, const void *src, UInt32 len) { OTMemcpy(dst, src, len); }
666 mDNSexport mDNSBool mDNSPlatformMemSame(const void *dst, const void *src, UInt32 len) { return(OTMemcmp(dst, src, len)); }
667 mDNSexport void mDNSPlatformMemZero( void *dst, UInt32 len) { OTMemzero(dst, len); }
668 mDNSexport void * mDNSPlatformMemAllocate(mDNSu32 len) { return(OTAllocMem(len)); }
669 mDNSexport void mDNSPlatformMemFree(void *mem) { OTFreeMem(mem); }
670 mDNSexport mDNSu32 mDNSPlatformRandomSeed(void) { return(TickCount()); }
671 mDNSexport mStatus mDNSPlatformTimeInit(void) { return(mStatus_NoError); }
672 mDNSexport SInt32 mDNSPlatformRawTime() { return((SInt32)TickCount()); }
673 mDNSexport SInt32 mDNSPlatformOneSecond = 60;
674
675 mDNSexport mDNSs32 mDNSPlatformUTC(void)
676 {
677 // Classic Mac OS since Midnight, 1st Jan 1904
678 // Standard Unix counts from 1970
679 // This value adjusts for the 66 years and 17 leap-days difference
680 mDNSu32 SecsSince1904;
681 MachineLocation ThisLocation;
682 #define TIME_ADJUST (((1970 - 1904) * 365 + 17) * 24 * 60 * 60)
683 #define ThisLocationGMTdelta ((ThisLocation.u.gmtDelta << 8) >> 8)
684 GetDateTime(&SecsSince1904);
685 ReadLocation(&ThisLocation);
686 return((mDNSs32)(SecsSince1904 - ThisLocationGMTdelta - TIME_ADJUST));
687 }