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