2 * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
23 Change History (most recent first):
25 $Log: mDNSMacOS9.c,v $
26 Revision 1.43 2004/12/17 23:37:49 cheshire
27 <rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
28 (and other repetitive configuration changes)
30 Revision 1.42 2004/12/16 20:43:39 cheshire
31 interfaceinfo.fMask should be interfaceinfo.fNetmask
33 Revision 1.41 2004/10/16 00:17:00 cheshire
34 <rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
36 Revision 1.40 2004/09/27 23:56:27 cheshire
37 Fix infinite loop where mDNSPlatformUnlock() called mDNS_TimeNow(),
38 and then mDNS_TimeNow() called mDNSPlatformUnlock()
40 Revision 1.39 2004/09/21 21:02:54 cheshire
41 Set up ifname before calling mDNS_RegisterInterface()
43 Revision 1.38 2004/09/17 01:08:50 cheshire
44 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
45 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
46 declared in that file are ONLY appropriate to single-address-space embedded applications.
47 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
49 Revision 1.37 2004/09/17 00:19:10 cheshire
50 For consistency with AllDNSLinkGroupv6, rename AllDNSLinkGroup to AllDNSLinkGroupv4
52 Revision 1.36 2004/09/16 21:59:16 cheshire
53 For consistency with zerov6Addr, rename zeroIPAddr to zerov4Addr
55 Revision 1.35 2004/09/16 00:24:49 cheshire
56 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
58 Revision 1.34 2004/09/14 23:42:36 cheshire
59 <rdar://problem/3801296> Need to seed random number generator from platform-layer data
61 Revision 1.33 2004/09/14 23:16:31 cheshire
62 Fix compile error: mDNS_SetFQDNs has been renamed to mDNS_SetFQDN
64 Revision 1.32 2004/09/14 21:03:16 cheshire
67 Revision 1.31 2004/08/14 03:22:42 cheshire
68 <rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
69 Add GetUserSpecifiedDDNSName() routine
70 Convert ServiceRegDomain to domainname instead of C string
71 Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
73 Revision 1.30 2004/07/29 19:26:03 ksekar
74 Plaform-level changes for NATPMP support
76 Revision 1.29 2004/05/26 20:53:16 cheshire
77 Remove unncecessary "return( -1 );" at the end of mDNSPlatformUTC()
79 Revision 1.28 2004/05/20 18:39:06 cheshire
80 Fix build broken by addition of mDNSPlatformUTC requirement
82 Revision 1.27 2004/04/21 02:49:11 cheshire
83 To reduce future confusion, renamed 'TxAndRx' to 'McastTxRx'
85 Revision 1.26 2004/04/09 17:43:03 cheshire
86 Make sure to set the McastTxRx field so that duplicate suppression works correctly
88 Revision 1.25 2004/03/15 18:55:38 cheshire
89 Comment out debugging message
91 Revision 1.24 2004/03/12 21:30:26 cheshire
92 Build a System-Context Shared Library from mDNSCore, for the benefit of developers
93 like Muse Research who want to be able to use mDNS/DNS-SD from GPL-licensed code.
95 Revision 1.23 2004/02/09 23:24:43 cheshire
96 Need to set TTL 255 to interoperate with peers that check TTL (oops!)
98 Revision 1.22 2004/01/27 20:15:23 cheshire
99 <rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
101 Revision 1.21 2004/01/24 04:59:16 cheshire
102 Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again
104 Revision 1.20 2003/11/14 20:59:09 cheshire
105 Clients can't use AssignDomainName macro because mDNSPlatformMemCopy is defined in mDNSPlatformFunctions.h.
106 Best solution is just to combine mDNSEmbeddedAPI.h and mDNSPlatformFunctions.h into a single file.
108 Revision 1.19 2003/08/18 23:09:20 cheshire
109 <rdar://problem/3382647> mDNSResponder divide by zero in mDNSPlatformRawTime()
111 Revision 1.18 2003/08/12 19:56:24 cheshire
117 #include <stdarg.h> // For va_list support
119 #include <LowMem.h> // For LMGetCurApName()
120 #include <TextUtils.h> // For smSystemScript
121 #include <UnicodeConverter.h> // For ConvertFromPStringToUnicode()
123 #include "mDNSEmbeddedAPI.h" // Defines the interface provided to the client layer above
125 #include "mDNSMacOS9.h" // Defines the specific types needed to run mDNS on this platform
127 // ***************************************************************************
130 static const TSetBooleanOption kReusePortOption
=
131 { kOTBooleanOptionSize
, INET_IP
, IP_REUSEPORT
, 0, true };
133 // IP_RCVDSTADDR with TSetByteOption/kOTOneByteOptionSize works on OS 9, OS X Classic, and OS 9 Carbon,
134 // but gives error #-3151 (kOTBadOptionErr) on OS X Carbon.
135 // If we instead use TSetBooleanOption/kOTBooleanOptionSize then OTOptionManagement on OS X Carbon
136 // no longer returns -3151 but it still doesn't actually work -- no destination addresses
137 // are delivered by OTRcvUData. I think it's just a bug in OS X Carbon.
138 static const TSetByteOption kRcvDestAddrOption
=
139 { kOTOneByteOptionSize
, INET_IP
, IP_RCVDSTADDR
, 0, true };
140 //static const TSetBooleanOption kRcvDestAddrOption =
141 // { kOTBooleanOptionSize, INET_IP, IP_RCVDSTADDR, 0, true };
143 static const TSetByteOption kSetUnicastTTLOption
=
144 { kOTOneByteOptionSize
, INET_IP
, IP_TTL
, 0, 255 };
146 static const TSetByteOption kSetMulticastTTLOption
=
147 { kOTOneByteOptionSize
, INET_IP
, IP_MULTICAST_TTL
, 0, 255 };
149 static const TIPAddMulticastOption kAddLinkMulticastOption
=
150 { sizeof(TIPAddMulticastOption
), INET_IP
, IP_ADD_MEMBERSHIP
, 0, { 224, 0, 0,251 }, { 0,0,0,0 } };
152 //static const TIPAddMulticastOption kAddAdminMulticastOption =
153 // { sizeof(TIPAddMulticastOption), INET_IP, IP_ADD_MEMBERSHIP, 0, { 239,255,255,251 }, { 0,0,0,0 } };
155 // Bind endpoint to port number. Don't specify any specific IP address --
156 // we want to receive unicasts on all interfaces, as well as multicasts.
157 typedef struct { OTAddressType fAddressType
; mDNSIPPort fPort
; mDNSv4Addr fHost
; UInt8 fUnused
[8]; } mDNSInetAddress
;
158 //static const mDNSInetAddress mDNSPortInetAddress = { AF_INET, { 0,0 }, { 0,0,0,0 } }; // For testing legacy client support
159 #define MulticastDNSPortAsNumber 5353
160 static const mDNSInetAddress mDNSPortInetAddress
= { AF_INET
, { MulticastDNSPortAsNumber
>> 8, MulticastDNSPortAsNumber
& 0xFF }, { 0,0,0,0 } };
161 static const TBind mDNSbindReq
= { sizeof(mDNSPortInetAddress
), sizeof(mDNSPortInetAddress
), (UInt8
*)&mDNSPortInetAddress
, 0 };
163 static const TNetbuf zeroTNetbuf
= { 0 };
165 // ***************************************************************************
168 mDNSlocal
void SafeDebugStr(unsigned char *buffer
)
171 // Don't want semicolons in MacsBug messages -- they signify commands to execute
172 for (i
=1; i
<= buffer
[0]; i
++) if (buffer
[i
] == ';') buffer
[i
] = '.';
177 mDNSexport
void debugf_(const char *format
, ...)
179 unsigned char buffer
[256];
181 va_start(ptr
,format
);
182 buffer
[0] = (unsigned char)mDNS_vsnprintf((char*)buffer
+1, 255, format
, ptr
);
184 #if MDNS_ONLYSYSTEMTASK
185 buffer
[1+buffer
[0]] = 0;
186 fprintf(stderr
, "%s\n", buffer
+1);
189 SafeDebugStr(buffer
);
194 #if MDNS_BUILDINGSHAREDLIBRARY >= 2
195 // When building the non-debug version of the Extension, intended to go on end-user systems, we don't want
196 // MacsBug breaks for *anything*, not even for the serious LogMsg messages that on OS X would be written to syslog
197 mDNSexport
void LogMsg(const char *format
, ...) { (void)format
; }
199 mDNSexport
void LogMsg(const char *format
, ...)
201 unsigned char buffer
[256];
203 va_start(ptr
,format
);
204 buffer
[0] = (unsigned char)mDNS_vsnprintf((char*)buffer
+1, 255, format
, ptr
);
206 #if MDNS_ONLYSYSTEMTASK
207 buffer
[1+buffer
[0]] = 0;
208 fprintf(stderr
, "%s\n", buffer
+1);
211 SafeDebugStr(buffer
);
216 mDNSexport mStatus
mDNSPlatformSendUDP(const mDNS
*const m
, const void *const msg
, const mDNSu8
*const end
,
217 mDNSInterfaceID InterfaceID
, const mDNSAddr
*dst
, mDNSIPPort dstPort
)
219 // Note: If we did multi-homing, we'd have to use the InterfaceID parameter to specify from which interface to send this response
220 #pragma unused(InterfaceID)
222 InetAddress InetDest
;
225 if (dst
->type
!= mDNSAddrType_IPv4
) return(mStatus_NoError
);
227 InetDest
.fAddressType
= AF_INET
;
228 InetDest
.fPort
= dstPort
.NotAnInteger
;
229 InetDest
.fHost
= dst
->ip
.v4
.NotAnInteger
;
231 senddata
.addr
.maxlen
= sizeof(InetDest
);
232 senddata
.addr
.len
= sizeof(InetDest
);
233 senddata
.addr
.buf
= (UInt8
*)&InetDest
;
234 senddata
.opt
= zeroTNetbuf
;
235 senddata
.udata
.maxlen
= (UInt32
)((UInt8
*)end
- (UInt8
*)msg
);
236 senddata
.udata
.len
= (UInt32
)((UInt8
*)end
- (UInt8
*)msg
);
237 senddata
.udata
.buf
= (UInt8
*)msg
;
239 return(OTSndUData(m
->p
->ep
, &senddata
));
242 mDNSlocal OSStatus
readpacket(mDNS
*m
)
244 mDNSAddr senderaddr
, destaddr
;
245 mDNSInterfaceID interface
;
246 mDNSIPPort senderport
;
254 recvdata
.addr
.maxlen
= sizeof(sender
);
255 recvdata
.addr
.len
= 0;
256 recvdata
.addr
.buf
= (UInt8
*)&sender
;
257 recvdata
.opt
.maxlen
= sizeof(options
);
258 recvdata
.opt
.len
= 0;
259 recvdata
.opt
.buf
= (UInt8
*)&options
;
260 recvdata
.udata
.maxlen
= sizeof(packet
);
261 recvdata
.udata
.len
= 0;
262 recvdata
.udata
.buf
= (UInt8
*)&packet
;
264 err
= OTRcvUData(m
->p
->ep
, &recvdata
, &flags
);
265 if (err
&& err
!= kOTNoDataErr
) debugf("OTRcvUData error %d", err
);
267 if (err
) return(err
);
269 senderaddr
.type
= mDNSAddrType_IPv4
;
270 senderaddr
.ip
.v4
.NotAnInteger
= sender
.fHost
;
271 senderport
.NotAnInteger
= sender
.fPort
;
273 destaddr
.type
= mDNSAddrType_IPv4
;
274 destaddr
.ip
.v4
= zerov4Addr
;
276 #if OTCARBONAPPLICATION
277 // IP_RCVDSTADDR is known to fail on OS X Carbon, so we'll just assume the packet was probably multicast
278 destaddr
.ip
.v4
= AllDNSLinkGroupv4
;
281 if (recvdata
.opt
.len
)
286 err
= OTNextOption(recvdata
.opt
.buf
, recvdata
.opt
.len
, &c
);
287 if (err
|| !c
) break;
288 if (c
->level
== INET_IP
&& c
->name
== IP_RCVDSTADDR
&& c
->len
- kOTOptionHeaderSize
== sizeof(destaddr
.ip
.v4
))
289 mDNSPlatformMemCopy(c
->value
, &destaddr
.ip
.v4
, sizeof(destaddr
.ip
.v4
));
293 interface
= m
->HostInterfaces
->InterfaceID
;
295 if (flags
& T_MORE
) debugf("ERROR: OTRcvUData() buffer too small (T_MORE set)");
296 else if (recvdata
.addr
.len
< sizeof(InetAddress
)) debugf("ERROR: recvdata.addr.len (%d) too short", recvdata
.addr
.len
);
297 else mDNSCoreReceive(m
, &packet
, recvdata
.udata
.buf
+ recvdata
.udata
.len
, &senderaddr
, senderport
, &destaddr
, MulticastDNSPort
, interface
);
302 mDNSexport mStatus
mDNSPlatformTCPConnect(const mDNSAddr
*dst
, mDNSOpaque16 dstport
, mDNSInterfaceID InterfaceID
,
303 TCPConnectionCallback callback
, void *context
, int *descriptor
)
306 (void)dstport
; // Unused
307 (void)InterfaceID
; // Unused
308 (void)callback
; // Unused
309 (void)context
; // Unused
310 (void)descriptor
; // Unused
311 return(mStatus_UnsupportedErr
);
314 mDNSexport
void mDNSPlatformTCPCloseConnection(int sd
)
319 mDNSexport
int mDNSPlatformReadTCP(int sd
, void *buf
, int buflen
)
323 (void)buflen
; // Unused
327 mDNSexport
int mDNSPlatformWriteTCP(int sd
, const char *msg
, int len
)
335 mDNSlocal
void mDNSOptionManagement(mDNS
*const m
)
339 // Make sure the length in the TNetbuf agrees with the length in the TOptionHeader
340 m
->p
->optReq
.opt
.len
= m
->p
->optBlock
.h
.len
;
341 m
->p
->optReq
.opt
.maxlen
= m
->p
->optBlock
.h
.len
;
342 if (m
->p
->optReq
.opt
.maxlen
< 4)
343 m
->p
->optReq
.opt
.maxlen
= 4;
345 err
= OTOptionManagement(m
->p
->ep
, &m
->p
->optReq
, NULL
);
346 if (err
) LogMsg("OTOptionManagement failed %d", err
);
349 mDNSlocal
void mDNSinitComplete(mDNS
*const m
, mStatus result
)
351 m
->mDNSPlatformStatus
= result
;
352 mDNSCoreInitComplete(m
, mStatus_NoError
);
355 mDNSlocal
pascal void mDNSNotifier(void *contextPtr
, OTEventCode code
, OTResult result
, void *cookie
)
357 mDNS
*const m
= (mDNS
*const)contextPtr
;
358 if (!m
) debugf("mDNSNotifier FATAL ERROR! No context");
364 InetInterfaceInfo interfaceinfo
;
365 if (result
) { LogMsg("T_OPENCOMPLETE failed %d", result
); mDNSinitComplete(m
, result
); return; }
366 //debugf("T_OPENCOMPLETE");
367 m
->p
->ep
= (EndpointRef
)cookie
;
368 //debugf("OTInetGetInterfaceInfo");
369 // (In future may want to loop over all interfaces instead of just using kDefaultInetInterface)
370 err
= OTInetGetInterfaceInfo(&interfaceinfo
, kDefaultInetInterface
);
371 if (err
) { LogMsg("OTInetGetInterfaceInfo failed %d", err
); mDNSinitComplete(m
, err
); return; }
373 // Make our basic standard host resource records (address, PTR, etc.)
374 m
->p
->interface
.InterfaceID
= (mDNSInterfaceID
)&m
->p
->interface
;
375 m
->p
->interface
.ip
.type
= mDNSAddrType_IPv4
;
376 m
->p
->interface
.ip
.ip
.v4
.NotAnInteger
= interfaceinfo
.fAddress
;
377 m
->p
->interface
.mask
.type
= mDNSAddrType_IPv4
;
378 m
->p
->interface
.mask
.ip
.v4
.NotAnInteger
= interfaceinfo
.fNetmask
;
379 m
->p
->interface
.ifname
[0] = 0;
380 m
->p
->interface
.Advertise
= m
->AdvertiseLocalAddresses
;
381 m
->p
->interface
.McastTxRx
= mDNStrue
;
384 case T_OPTMGMTCOMPLETE
:
386 // IP_RCVDSTADDR is known to fail on OS X Carbon, so we don't want to abort for that error
387 // (see comment above at the definition of kRcvDestAddrOption)
388 #if OTCARBONAPPLICATION
389 if (result
&& m
->p
->mOTstate
== mOT_RcvDestAddr
)
390 LogMsg("Carbon IP_RCVDSTADDR option failed %d; continuing anyway", result
);
393 if (result
) { LogMsg("T_OPTMGMTCOMPLETE/T_BINDCOMPLETE %d failed %d", m
->p
->mOTstate
, result
); mDNSinitComplete(m
, result
); return; }
394 //LogMsg("T_OPTMGMTCOMPLETE/T_BINDCOMPLETE %d", m->p->mOTstate);
395 switch (++m
->p
->mOTstate
)
397 case mOT_ReusePort
: m
->p
->optBlock
.b
= kReusePortOption
; mDNSOptionManagement(m
); break;
398 case mOT_RcvDestAddr
: m
->p
->optBlock
.i
= kRcvDestAddrOption
; mDNSOptionManagement(m
); break;
399 case mOT_SetUTTL
: m
->p
->optBlock
.i
= kSetUnicastTTLOption
; mDNSOptionManagement(m
); break;
400 case mOT_SetMTTL
: m
->p
->optBlock
.i
= kSetMulticastTTLOption
; mDNSOptionManagement(m
); break;
401 case mOT_LLScope
: m
->p
->optBlock
.m
= kAddLinkMulticastOption
; mDNSOptionManagement(m
); break;
402 // case mOT_AdminScope: m->p->optBlock.m = kAddAdminMulticastOption; mDNSOptionManagement(m); break;
403 case mOT_Bind
: OTBind(m
->p
->ep
, (TBind
*)&mDNSbindReq
, NULL
); break;
404 case mOT_Ready
: mDNSinitComplete(m
, mStatus_NoError
);
405 // Can't do mDNS_RegisterInterface until *after* mDNSinitComplete has set m->mDNSPlatformStatus to mStatus_NoError
406 mDNS_RegisterInterface(m
, &m
->p
->interface
, 0);
408 default: LogMsg("Unexpected m->p->mOTstate %d", m
->p
->mOTstate
-1);
414 while (readpacket(m
) == kOTNoError
) continue; // Read packets until we run out
417 case kOTProviderWillClose
: LogMsg("kOTProviderWillClose"); break;
418 case kOTProviderIsClosed
: // Machine is going to sleep, shutting down, or reconfiguring IP
419 LogMsg("kOTProviderIsClosed");
420 if (m
->p
->mOTstate
== mOT_Ready
)
422 m
->p
->mOTstate
= mOT_Closed
;
423 mDNS_DeregisterInterface(m
, &m
->p
->interface
);
425 if (m
->p
->ep
) { OTCloseProvider(m
->p
->ep
); m
->p
->ep
= NULL
; }
426 break; // Do we need to do anything?
428 default: debugf("mDNSNotifier: Unexpected OTEventCode %X", code
);
433 #if MDNS_ONLYSYSTEMTASK
435 static Boolean ONLYSYSTEMTASKevent
;
436 static void *ONLYSYSTEMTASKcontextPtr
;
437 static OTEventCode ONLYSYSTEMTASKcode
;
438 static OTResult ONLYSYSTEMTASKresult
;
439 static void *ONLYSYSTEMTASKcookie
;
441 mDNSlocal
pascal void CallmDNSNotifier(void *contextPtr
, OTEventCode code
, OTResult result
, void *cookie
)
443 ONLYSYSTEMTASKcontextPtr
= contextPtr
;
444 ONLYSYSTEMTASKcode
= code
;
445 ONLYSYSTEMTASKresult
= result
;
446 ONLYSYSTEMTASKcookie
= cookie
;
451 mDNSlocal
pascal void CallmDNSNotifier(void *contextPtr
, OTEventCode code
, OTResult result
, void *cookie
)
453 mDNS
*const m
= (mDNS
*const)contextPtr
;
454 if (!m
) debugf("mDNSNotifier FATAL ERROR! No context");
455 if (m
->p
->nesting
) LogMsg("CallmDNSNotifier ERROR! OTEnterNotifier is supposed to suppress notifier callbacks");
456 mDNSNotifier(contextPtr
, code
, result
, cookie
);
461 static OTNotifyUPP CallmDNSNotifierUPP
;
463 mDNSlocal OSStatus
mDNSOpenEndpoint(const mDNS
*const m
)
466 // m->optReq is pre-set to point to the shared m->optBlock
467 // m->optBlock is filled in by each OTOptionManagement call
468 m
->p
->optReq
.opt
.maxlen
= sizeof(m
->p
->optBlock
);
469 m
->p
->optReq
.opt
.len
= sizeof(m
->p
->optBlock
);
470 m
->p
->optReq
.opt
.buf
= (UInt8
*)&m
->p
->optBlock
;
471 m
->p
->optReq
.flags
= T_NEGOTIATE
;
473 // Open an endpoint and start answering queries
474 //printf("Opening endpoint now...\n");
476 m
->p
->mOTstate
= mOT_Start
;
477 err
= OTAsyncOpenEndpoint(OTCreateConfiguration(kUDPName
), 0, NULL
, CallmDNSNotifierUPP
, (void*)m
);
478 if (err
) { LogMsg("ERROR: OTAsyncOpenEndpoint(UDP) failed with error <%d>", err
); return(err
); }
482 // Define these here because they're not in older versions of OpenTransport.h
485 xOTStackIsLoading
= 0x27000001, /* Sent before Open Transport attempts to load the TCP/IP protocol stack.*/
486 xOTStackWasLoaded
= 0x27000002, /* Sent after the TCP/IP stack has been successfully loaded.*/
487 xOTStackIsUnloading
= 0x27000003 /* Sent before Open Transport unloads the TCP/IP stack.*/
490 static mDNS
*ClientNotifierContext
;
492 mDNSlocal
pascal void ClientNotifier(void *contextPtr
, OTEventCode code
, OTResult result
, void *cookie
)
494 mDNS
*const m
= ClientNotifierContext
;
496 #pragma unused(contextPtr) // Usually zero (except one in the 'xOTStackIsLoading' case)
497 #pragma unused(cookie) // Usually 'ipv4' (except for kOTPortNetworkChange)
498 #pragma unused(result) // Usually zero
502 case xOTStackIsLoading
: break;
503 case xOTStackWasLoaded
: if (m
->p
->mOTstate
== mOT_Closed
)
505 LogMsg("kOTStackWasLoaded: Re-opening endpoint");
507 LogMsg("kOTStackWasLoaded: ERROR: m->p->ep already set");
508 m
->mDNSPlatformStatus
= mStatus_Waiting
;
509 m
->p
->mOTstate
= mOT_Reset
;
510 #if !MDNS_ONLYSYSTEMTASK
515 LogMsg("kOTStackWasLoaded (no action)");
517 case xOTStackIsUnloading
: break;
518 case kOTPortNetworkChange
: break;
519 default: debugf("ClientNotifier unknown code %X, %X, %d", contextPtr
, code
, result
); break;
523 #if TARGET_API_MAC_CARBON
525 mDNSlocal
void GetUserSpecifiedComputerName(domainlabel
*const namelabel
)
527 CFStringRef cfs
= CSCopyMachineName();
528 CFStringGetPascalString(cfs
, namelabel
->c
, sizeof(*namelabel
), kCFStringEncodingUTF8
);
534 mDNSlocal OSStatus
ConvertStringHandleToUTF8(const StringHandle machineName
, UInt8
*const utf8
, ByteCount maxlen
)
537 TextEncoding utf8TextEncoding
, SystemTextEncoding
;
538 UnicodeMapping theMapping
;
539 TextToUnicodeInfo textToUnicodeInfo
;
540 ByteCount unicodelen
= 0;
542 if (maxlen
> 255) maxlen
= 255; // Can't put more than 255 in a Pascal String
544 utf8TextEncoding
= CreateTextEncoding(kTextEncodingUnicodeDefault
, kTextEncodingDefaultVariant
, kUnicodeUTF8Format
);
545 UpgradeScriptInfoToTextEncoding(smSystemScript
, kTextLanguageDontCare
, kTextRegionDontCare
, NULL
, &SystemTextEncoding
);
546 theMapping
.unicodeEncoding
= utf8TextEncoding
;
547 theMapping
.otherEncoding
= SystemTextEncoding
;
548 theMapping
.mappingVersion
= kUnicodeUseLatestMapping
;
549 status
= CreateTextToUnicodeInfo(&theMapping
, &textToUnicodeInfo
);
552 status
= ConvertFromPStringToUnicode(textToUnicodeInfo
, *machineName
, maxlen
, &unicodelen
, (UniCharArrayPtr
)&(utf8
[1]));
553 DisposeTextToUnicodeInfo(&textToUnicodeInfo
);
555 utf8
[0] = (UInt8
)unicodelen
;
559 mDNSlocal
void GetUserSpecifiedComputerName(domainlabel
*const namelabel
)
561 StringHandle machineName
= GetString(-16413); // Get machine name set in file sharing
564 char machineNameState
= HGetState((Handle
)machineName
);
565 HLock((Handle
)machineName
);
566 ConvertStringHandleToUTF8(machineName
, namelabel
->c
, MAX_DOMAIN_LABEL
);
567 HSetState((Handle
)machineName
, machineNameState
);
573 static pascal void mDNSTimerTask(void *arg
)
575 #if MDNS_ONLYSYSTEMTASK
577 ONLYSYSTEMTASKevent
= true;
579 mDNS
*const m
= (mDNS
*const)arg
;
580 if (!m
->p
->ep
) LogMsg("mDNSTimerTask NO endpoint");
581 if (m
->mDNS_busy
) LogMsg("mDNS_busy");
582 if (m
->p
->nesting
) LogMsg("mDNSTimerTask ERROR! OTEnterNotifier is supposed to suppress timer callbacks too");
584 // If our timer fires at a time when we have no endpoint, ignore it --
585 // once we reopen our endpoint and get our T_BINDCOMPLETE message we'll call
586 // mDNS_RegisterInterface(), which does a lock/unlock, which retriggers the timer.
587 // Likewise, if m->mDNS_busy or m->p->nesting, we'll catch this on the unlock
588 if (m
->p
->ep
&& m
->mDNS_busy
== 0 && m
->p
->nesting
== 0) mDNS_Execute(m
);
593 long sleep
, wake
, mode
;
596 mDNSexport mStatus
mDNSPlatformInit(mDNS
*const m
)
598 OSStatus err
= InitOpenTransport();
600 ClientNotifierContext
= m
;
601 // Note: OTRegisterAsClient returns kOTNotSupportedErr when running as Carbon code on OS X
602 // -- but that's okay, we don't need a ClientNotifier when running as Carbon code on OS X
603 OTRegisterAsClient(NULL
, NewOTNotifyUPP(ClientNotifier
));
605 m
->p
->OTTimerTask
= OTCreateTimerTask(NewOTProcessUPP(mDNSTimerTask
), m
);
609 sleep
= TickCount() + 600;
610 wake
= TickCount() + 1200;
614 // Set up the nice label
615 m
->nicelabel
.c
[0] = 0;
616 GetUserSpecifiedComputerName(&m
->nicelabel
);
617 // m->nicelabel = *(domainlabel*)"\pStu"; // For conflict testing
618 if (m
->nicelabel
.c
[0] == 0) MakeDomainLabelFromLiteralString(&m
->nicelabel
, "Macintosh");
620 // Set up the RFC 1034-compliant label
621 m
->hostlabel
.c
[0] = 0;
622 ConvertUTF8PstringToRFC1034HostLabel(m
->nicelabel
.c
, &m
->hostlabel
);
623 if (m
->hostlabel
.c
[0] == 0) MakeDomainLabelFromLiteralString(&m
->hostlabel
, "Macintosh");
627 // When it's finished mDNSOpenEndpoint asynchronously calls mDNSinitComplete() and then mDNS_RegisterInterface()
628 CallmDNSNotifierUPP
= NewOTNotifyUPP(CallmDNSNotifier
);
629 err
= mDNSOpenEndpoint(m
);
632 LogMsg("mDNSOpenEndpoint failed %d", err
);
633 if (m
->p
->OTTimerTask
) OTDestroyTimerTask(m
->p
->OTTimerTask
);
634 OTUnregisterAsClient();
635 CloseOpenTransport();
640 extern void mDNSPlatformClose (mDNS
*const m
)
642 if (m
->p
->mOTstate
== mOT_Ready
)
644 m
->p
->mOTstate
= mOT_Closed
;
645 mDNS_DeregisterInterface(m
, &m
->p
->interface
);
647 if (m
->p
->ep
) { OTCloseProvider (m
->p
->ep
); m
->p
->ep
= NULL
; }
648 if (m
->p
->OTTimerTask
) { OTDestroyTimerTask(m
->p
->OTTimerTask
); m
->p
->OTTimerTask
= 0; }
650 OTUnregisterAsClient();
651 CloseOpenTransport();
654 #if MDNS_ONLYSYSTEMTASK
655 extern void mDNSPlatformIdle(mDNS
*const m
);
656 mDNSexport
void mDNSPlatformIdle(mDNS
*const m
)
658 while (ONLYSYSTEMTASKcontextPtr
)
660 void *contextPtr
= ONLYSYSTEMTASKcontextPtr
;
661 ONLYSYSTEMTASKcontextPtr
= NULL
;
662 mDNSNotifier(contextPtr
, ONLYSYSTEMTASKcode
, ONLYSYSTEMTASKresult
, ONLYSYSTEMTASKcookie
);
664 if (ONLYSYSTEMTASKevent
)
666 ONLYSYSTEMTASKevent
= false;
670 if (m
->p
->mOTstate
== mOT_Reset
)
673 printf("******************************************************************************\n");
675 printf("Reopening endpoint\n");
677 m
->ResourceRecords
= NULL
;
683 case 0: if ((long)TickCount() - sleep
>= 0) { mDNSCoreMachineSleep(m
, 1); mode
++; }
685 case 1: if ((long)TickCount() - wake
>= 0) { mDNSCoreMachineSleep(m
, 0); mode
++; }
692 mDNSexport
void mDNSPlatformLock(const mDNS
*const m
)
694 if (!m
) { DebugStr("\pmDNSPlatformLock m NULL!"); return; }
695 if (!m
->p
) { DebugStr("\pmDNSPlatformLock m->p NULL!"); return; }
697 // If we try to call OTEnterNotifier and fail because we're already running at
698 // Notifier context, then make sure we don't do the matching OTLeaveNotifier() on exit.
699 // If we haven't even opened our endpoint yet, then just increment m->p->nesting for the same reason
700 if (m
->p
->mOTstate
== mOT_Ready
&& !m
->p
->ep
) DebugStr("\pmDNSPlatformLock: m->p->mOTstate == mOT_Ready && !m->p->ep");
701 if (!m
->p
->ep
|| m
->p
->nesting
|| OTEnterNotifier(m
->p
->ep
) == false) m
->p
->nesting
++;
704 mDNSlocal
void ScheduleNextTimerCallback(const mDNS
*const m
)
706 if (m
->mDNSPlatformStatus
== mStatus_NoError
)
708 SInt32 interval
= m
->NextScheduledEvent
- (mDNSPlatformRawTime() + m
->timenow_adjust
);
709 if (interval
< 1) interval
= 1;
710 else if (interval
> 0x70000000 / 1000) interval
= 0x70000000 / mDNSPlatformOneSecond
;
711 else interval
= (interval
* 1000 + mDNSPlatformOneSecond
-1)/ mDNSPlatformOneSecond
;
712 OTScheduleTimerTask(m
->p
->OTTimerTask
, (OTTimeout
)interval
);
716 mDNSexport
void mDNSPlatformUnlock(const mDNS
*const m
)
718 if (!m
) { DebugStr("\pmDNSPlatformUnlock m NULL!"); return; }
719 if (!m
->p
) { DebugStr("\pmDNSPlatformUnlock m->p NULL!"); return; }
721 if (m
->p
->ep
&& m
->mDNS_busy
== 0) ScheduleNextTimerCallback(m
);
723 if (m
->p
->nesting
) m
->p
->nesting
--;
724 else OTLeaveNotifier(m
->p
->ep
);
727 mDNSexport
void mDNSPlatformStrCopy(const void *src
, void *dst
) { OTStrCopy((char*)dst
, (char*)src
); }
728 mDNSexport UInt32
mDNSPlatformStrLen (const void *src
) { return(OTStrLength((char*)src
)); }
729 mDNSexport
void mDNSPlatformMemCopy(const void *src
, void *dst
, UInt32 len
) { OTMemcpy(dst
, src
, len
); }
730 mDNSexport mDNSBool
mDNSPlatformMemSame(const void *src
, const void *dst
, UInt32 len
) { return(OTMemcmp(dst
, src
, len
)); }
731 mDNSexport
void mDNSPlatformMemZero( void *dst
, UInt32 len
) { OTMemzero(dst
, len
); }
732 mDNSexport
void * mDNSPlatformMemAllocate(mDNSu32 len
) { return(OTAllocMem(len
)); }
733 mDNSexport
void mDNSPlatformMemFree(void *mem
) { OTFreeMem(mem
); }
734 mDNSexport mDNSu32
mDNSPlatformRandomSeed(void) { return(TickCount()); }
735 mDNSexport mStatus
mDNSPlatformTimeInit(void) { return(mStatus_NoError
); }
736 mDNSexport SInt32
mDNSPlatformRawTime() { return((SInt32
)TickCount()); }
737 mDNSexport SInt32 mDNSPlatformOneSecond
= 60;
739 mDNSexport mDNSs32
mDNSPlatformUTC(void)
741 // Classic Mac OS since Midnight, 1st Jan 1904
742 // Standard Unix counts from 1970
743 // This value adjusts for the 66 years and 17 leap-days difference
744 mDNSu32 SecsSince1904
;
745 MachineLocation ThisLocation
;
746 #define TIME_ADJUST (((1970 - 1904) * 365 + 17) * 24 * 60 * 60)
747 #define ThisLocationGMTdelta ((ThisLocation.u.gmtDelta << 8) >> 8)
748 GetDateTime(&SecsSince1904
);
749 ReadLocation(&ThisLocation
);
750 return((mDNSs32
)(SecsSince1904
- ThisLocationGMTdelta
- TIME_ADJUST
));