]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOS9/mDNSMacOS9.c
mDNSResponder-107.1.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.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)
29
30 Revision 1.42 2004/12/16 20:43:39 cheshire
31 interfaceinfo.fMask should be interfaceinfo.fNetmask
32
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
35
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()
39
40 Revision 1.39 2004/09/21 21:02:54 cheshire
41 Set up ifname before calling mDNS_RegisterInterface()
42
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.
48
49 Revision 1.37 2004/09/17 00:19:10 cheshire
50 For consistency with AllDNSLinkGroupv6, rename AllDNSLinkGroup to AllDNSLinkGroupv4
51
52 Revision 1.36 2004/09/16 21:59:16 cheshire
53 For consistency with zerov6Addr, rename zeroIPAddr to zerov4Addr
54
55 Revision 1.35 2004/09/16 00:24:49 cheshire
56 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
57
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
60
61 Revision 1.33 2004/09/14 23:16:31 cheshire
62 Fix compile error: mDNS_SetFQDNs has been renamed to mDNS_SetFQDN
63
64 Revision 1.32 2004/09/14 21:03:16 cheshire
65 Fix spacing
66
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
72
73 Revision 1.30 2004/07/29 19:26:03 ksekar
74 Plaform-level changes for NATPMP support
75
76 Revision 1.29 2004/05/26 20:53:16 cheshire
77 Remove unncecessary "return( -1 );" at the end of mDNSPlatformUTC()
78
79 Revision 1.28 2004/05/20 18:39:06 cheshire
80 Fix build broken by addition of mDNSPlatformUTC requirement
81
82 Revision 1.27 2004/04/21 02:49:11 cheshire
83 To reduce future confusion, renamed 'TxAndRx' to 'McastTxRx'
84
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
87
88 Revision 1.25 2004/03/15 18:55:38 cheshire
89 Comment out debugging message
90
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.
94
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!)
97
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
100
101 Revision 1.21 2004/01/24 04:59:16 cheshire
102 Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again
103
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.
107
108 Revision 1.19 2003/08/18 23:09:20 cheshire
109 <rdar://problem/3382647> mDNSResponder divide by zero in mDNSPlatformRawTime()
110
111 Revision 1.18 2003/08/12 19:56:24 cheshire
112 Update to APSL 2.0
113
114 */
115
116 #include <stdio.h>
117 #include <stdarg.h> // For va_list support
118
119 #include <LowMem.h> // For LMGetCurApName()
120 #include <TextUtils.h> // For smSystemScript
121 #include <UnicodeConverter.h> // For ConvertFromPStringToUnicode()
122
123 #include "mDNSEmbeddedAPI.h" // Defines the interface provided to the client layer above
124
125 #include "mDNSMacOS9.h" // Defines the specific types needed to run mDNS on this platform
126
127 // ***************************************************************************
128 // Constants
129
130 static const TSetBooleanOption kReusePortOption =
131 { kOTBooleanOptionSize, INET_IP, IP_REUSEPORT, 0, true };
132
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 };
142
143 static const TSetByteOption kSetUnicastTTLOption =
144 { kOTOneByteOptionSize, INET_IP, IP_TTL, 0, 255 };
145
146 static const TSetByteOption kSetMulticastTTLOption =
147 { kOTOneByteOptionSize, INET_IP, IP_MULTICAST_TTL, 0, 255 };
148
149 static const TIPAddMulticastOption kAddLinkMulticastOption =
150 { sizeof(TIPAddMulticastOption), INET_IP, IP_ADD_MEMBERSHIP, 0, { 224, 0, 0,251 }, { 0,0,0,0 } };
151
152 //static const TIPAddMulticastOption kAddAdminMulticastOption =
153 // { sizeof(TIPAddMulticastOption), INET_IP, IP_ADD_MEMBERSHIP, 0, { 239,255,255,251 }, { 0,0,0,0 } };
154
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 };
162
163 static const TNetbuf zeroTNetbuf = { 0 };
164
165 // ***************************************************************************
166 // Functions
167
168 mDNSlocal void SafeDebugStr(unsigned char *buffer)
169 {
170 int i;
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] = '.';
173 DebugStr(buffer);
174 }
175
176 #if MDNS_DEBUGMSGS
177 mDNSexport void debugf_(const char *format, ...)
178 {
179 unsigned char buffer[256];
180 va_list ptr;
181 va_start(ptr,format);
182 buffer[0] = (unsigned char)mDNS_vsnprintf((char*)buffer+1, 255, format, ptr);
183 va_end(ptr);
184 #if MDNS_ONLYSYSTEMTASK
185 buffer[1+buffer[0]] = 0;
186 fprintf(stderr, "%s\n", buffer+1);
187 fflush(stderr);
188 #else
189 SafeDebugStr(buffer);
190 #endif
191 }
192 #endif
193
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; }
198 #else
199 mDNSexport void LogMsg(const char *format, ...)
200 {
201 unsigned char buffer[256];
202 va_list ptr;
203 va_start(ptr,format);
204 buffer[0] = (unsigned char)mDNS_vsnprintf((char*)buffer+1, 255, format, ptr);
205 va_end(ptr);
206 #if MDNS_ONLYSYSTEMTASK
207 buffer[1+buffer[0]] = 0;
208 fprintf(stderr, "%s\n", buffer+1);
209 fflush(stderr);
210 #else
211 SafeDebugStr(buffer);
212 #endif
213 }
214 #endif
215
216 mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const msg, const mDNSu8 *const end,
217 mDNSInterfaceID InterfaceID, const mDNSAddr *dst, mDNSIPPort dstPort)
218 {
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)
221
222 InetAddress InetDest;
223 TUnitData senddata;
224
225 if (dst->type != mDNSAddrType_IPv4) return(mStatus_NoError);
226
227 InetDest.fAddressType = AF_INET;
228 InetDest.fPort = dstPort.NotAnInteger;
229 InetDest.fHost = dst->ip.v4.NotAnInteger;
230
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;
238
239 return(OTSndUData(m->p->ep, &senddata));
240 }
241
242 mDNSlocal OSStatus readpacket(mDNS *m)
243 {
244 mDNSAddr senderaddr, destaddr;
245 mDNSInterfaceID interface;
246 mDNSIPPort senderport;
247 InetAddress sender;
248 char options[256];
249 DNSMessage packet;
250 TUnitData recvdata;
251 OTFlags flags = 0;
252 OSStatus err;
253
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;
263
264 err = OTRcvUData(m->p->ep, &recvdata, &flags);
265 if (err && err != kOTNoDataErr) debugf("OTRcvUData error %d", err);
266
267 if (err) return(err);
268
269 senderaddr.type = mDNSAddrType_IPv4;
270 senderaddr.ip.v4.NotAnInteger = sender.fHost;
271 senderport.NotAnInteger = sender.fPort;
272
273 destaddr.type = mDNSAddrType_IPv4;
274 destaddr.ip.v4 = zerov4Addr;
275
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;
279 #endif
280
281 if (recvdata.opt.len)
282 {
283 TOption *c = nil;
284 while (1)
285 {
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));
290 }
291 }
292
293 interface = m->HostInterfaces->InterfaceID;
294
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);
298
299 return(err);
300 }
301
302 mDNSexport mStatus mDNSPlatformTCPConnect(const mDNSAddr *dst, mDNSOpaque16 dstport, mDNSInterfaceID InterfaceID,
303 TCPConnectionCallback callback, void *context, int *descriptor)
304 {
305 (void)dst; // Unused
306 (void)dstport; // Unused
307 (void)InterfaceID; // Unused
308 (void)callback; // Unused
309 (void)context; // Unused
310 (void)descriptor; // Unused
311 return(mStatus_UnsupportedErr);
312 }
313
314 mDNSexport void mDNSPlatformTCPCloseConnection(int sd)
315 {
316 (void)sd; // Unused
317 }
318
319 mDNSexport int mDNSPlatformReadTCP(int sd, void *buf, int buflen)
320 {
321 (void)sd; // Unused
322 (void)buf; // Unused
323 (void)buflen; // Unused
324 return(0);
325 }
326
327 mDNSexport int mDNSPlatformWriteTCP(int sd, const char *msg, int len)
328 {
329 (void)sd; // Unused
330 (void)msg; // Unused
331 (void)len; // Unused
332 return(0);
333 }
334
335 mDNSlocal void mDNSOptionManagement(mDNS *const m)
336 {
337 OSStatus err;
338
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;
344
345 err = OTOptionManagement(m->p->ep, &m->p->optReq, NULL);
346 if (err) LogMsg("OTOptionManagement failed %d", err);
347 }
348
349 mDNSlocal void mDNSinitComplete(mDNS *const m, mStatus result)
350 {
351 m->mDNSPlatformStatus = result;
352 mDNSCoreInitComplete(m, mStatus_NoError);
353 }
354
355 mDNSlocal pascal void mDNSNotifier(void *contextPtr, OTEventCode code, OTResult result, void *cookie)
356 {
357 mDNS *const m = (mDNS *const)contextPtr;
358 if (!m) debugf("mDNSNotifier FATAL ERROR! No context");
359 switch (code)
360 {
361 case T_OPENCOMPLETE:
362 {
363 OSStatus err;
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; }
372
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;
382 }
383
384 case T_OPTMGMTCOMPLETE:
385 case T_BINDCOMPLETE:
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);
391 else
392 #endif
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)
396 {
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);
407 break;
408 default: LogMsg("Unexpected m->p->mOTstate %d", m->p->mOTstate-1);
409 }
410 break;
411
412 case T_DATA:
413 //debugf("T_DATA");
414 while (readpacket(m) == kOTNoError) continue; // Read packets until we run out
415 break;
416
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)
421 {
422 m->p->mOTstate = mOT_Closed;
423 mDNS_DeregisterInterface(m, &m->p->interface);
424 }
425 if (m->p->ep) { OTCloseProvider(m->p->ep); m->p->ep = NULL; }
426 break; // Do we need to do anything?
427
428 default: debugf("mDNSNotifier: Unexpected OTEventCode %X", code);
429 break;
430 }
431 }
432
433 #if MDNS_ONLYSYSTEMTASK
434
435 static Boolean ONLYSYSTEMTASKevent;
436 static void *ONLYSYSTEMTASKcontextPtr;
437 static OTEventCode ONLYSYSTEMTASKcode;
438 static OTResult ONLYSYSTEMTASKresult;
439 static void *ONLYSYSTEMTASKcookie;
440
441 mDNSlocal pascal void CallmDNSNotifier(void *contextPtr, OTEventCode code, OTResult result, void *cookie)
442 {
443 ONLYSYSTEMTASKcontextPtr = contextPtr;
444 ONLYSYSTEMTASKcode = code;
445 ONLYSYSTEMTASKresult = result;
446 ONLYSYSTEMTASKcookie = cookie;
447 }
448
449 #else
450
451 mDNSlocal pascal void CallmDNSNotifier(void *contextPtr, OTEventCode code, OTResult result, void *cookie)
452 {
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);
457 }
458
459 #endif
460
461 static OTNotifyUPP CallmDNSNotifierUPP;
462
463 mDNSlocal OSStatus mDNSOpenEndpoint(const mDNS *const m)
464 {
465 OSStatus err;
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;
472
473 // Open an endpoint and start answering queries
474 //printf("Opening endpoint now...\n");
475 m->p->ep = NULL;
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); }
479 return(kOTNoError);
480 }
481
482 // Define these here because they're not in older versions of OpenTransport.h
483 enum
484 {
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.*/
488 };
489
490 static mDNS *ClientNotifierContext;
491
492 mDNSlocal pascal void ClientNotifier(void *contextPtr, OTEventCode code, OTResult result, void *cookie)
493 {
494 mDNS *const m = ClientNotifierContext;
495
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
499
500 switch (code)
501 {
502 case xOTStackIsLoading: break;
503 case xOTStackWasLoaded: if (m->p->mOTstate == mOT_Closed)
504 {
505 LogMsg("kOTStackWasLoaded: Re-opening endpoint");
506 if (m->p->ep)
507 LogMsg("kOTStackWasLoaded: ERROR: m->p->ep already set");
508 m->mDNSPlatformStatus = mStatus_Waiting;
509 m->p->mOTstate = mOT_Reset;
510 #if !MDNS_ONLYSYSTEMTASK
511 mDNSOpenEndpoint(m);
512 #endif
513 }
514 else
515 LogMsg("kOTStackWasLoaded (no action)");
516 break;
517 case xOTStackIsUnloading: break;
518 case kOTPortNetworkChange: break;
519 default: debugf("ClientNotifier unknown code %X, %X, %d", contextPtr, code, result); break;
520 }
521 }
522
523 #if TARGET_API_MAC_CARBON
524
525 mDNSlocal void GetUserSpecifiedComputerName(domainlabel *const namelabel)
526 {
527 CFStringRef cfs = CSCopyMachineName();
528 CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8);
529 CFRelease(cfs);
530 }
531
532 #else
533
534 mDNSlocal OSStatus ConvertStringHandleToUTF8(const StringHandle machineName, UInt8 *const utf8, ByteCount maxlen)
535 {
536 OSStatus status;
537 TextEncoding utf8TextEncoding, SystemTextEncoding;
538 UnicodeMapping theMapping;
539 TextToUnicodeInfo textToUnicodeInfo;
540 ByteCount unicodelen = 0;
541
542 if (maxlen > 255) maxlen = 255; // Can't put more than 255 in a Pascal String
543
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);
550 if (status == noErr)
551 {
552 status = ConvertFromPStringToUnicode(textToUnicodeInfo, *machineName, maxlen, &unicodelen, (UniCharArrayPtr)&(utf8[1]));
553 DisposeTextToUnicodeInfo(&textToUnicodeInfo);
554 }
555 utf8[0] = (UInt8)unicodelen;
556 return(status);
557 }
558
559 mDNSlocal void GetUserSpecifiedComputerName(domainlabel *const namelabel)
560 {
561 StringHandle machineName = GetString(-16413); // Get machine name set in file sharing
562 if (machineName)
563 {
564 char machineNameState = HGetState((Handle)machineName);
565 HLock((Handle)machineName);
566 ConvertStringHandleToUTF8(machineName, namelabel->c, MAX_DOMAIN_LABEL);
567 HSetState((Handle)machineName, machineNameState);
568 }
569 }
570
571 #endif
572
573 static pascal void mDNSTimerTask(void *arg)
574 {
575 #if MDNS_ONLYSYSTEMTASK
576 #pragma unused(arg)
577 ONLYSYSTEMTASKevent = true;
578 #else
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");
583
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);
589 #endif
590 }
591
592 #if TEST_SLEEP
593 long sleep, wake, mode;
594 #endif
595
596 mDNSexport mStatus mDNSPlatformInit(mDNS *const m)
597 {
598 OSStatus err = InitOpenTransport();
599
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));
604
605 m->p->OTTimerTask = OTCreateTimerTask(NewOTProcessUPP(mDNSTimerTask), m);
606 m->p->nesting = 0;
607
608 #if TEST_SLEEP
609 sleep = TickCount() + 600;
610 wake = TickCount() + 1200;
611 mode = 0;
612 #endif
613
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");
619
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");
624
625 mDNS_SetFQDN(m);
626
627 // When it's finished mDNSOpenEndpoint asynchronously calls mDNSinitComplete() and then mDNS_RegisterInterface()
628 CallmDNSNotifierUPP = NewOTNotifyUPP(CallmDNSNotifier);
629 err = mDNSOpenEndpoint(m);
630 if (err)
631 {
632 LogMsg("mDNSOpenEndpoint failed %d", err);
633 if (m->p->OTTimerTask) OTDestroyTimerTask(m->p->OTTimerTask);
634 OTUnregisterAsClient();
635 CloseOpenTransport();
636 }
637 return(err);
638 }
639
640 extern void mDNSPlatformClose (mDNS *const m)
641 {
642 if (m->p->mOTstate == mOT_Ready)
643 {
644 m->p->mOTstate = mOT_Closed;
645 mDNS_DeregisterInterface(m, &m->p->interface);
646 }
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; }
649
650 OTUnregisterAsClient();
651 CloseOpenTransport();
652 }
653
654 #if MDNS_ONLYSYSTEMTASK
655 extern void mDNSPlatformIdle(mDNS *const m);
656 mDNSexport void mDNSPlatformIdle(mDNS *const m)
657 {
658 while (ONLYSYSTEMTASKcontextPtr)
659 {
660 void *contextPtr = ONLYSYSTEMTASKcontextPtr;
661 ONLYSYSTEMTASKcontextPtr = NULL;
662 mDNSNotifier(contextPtr, ONLYSYSTEMTASKcode, ONLYSYSTEMTASKresult, ONLYSYSTEMTASKcookie);
663 }
664 if (ONLYSYSTEMTASKevent)
665 {
666 ONLYSYSTEMTASKevent = false;
667 mDNS_Execute(m);
668 }
669
670 if (m->p->mOTstate == mOT_Reset)
671 {
672 printf("\n");
673 printf("******************************************************************************\n");
674 printf("\n");
675 printf("Reopening endpoint\n");
676 mDNSOpenEndpoint(m);
677 m->ResourceRecords = NULL;
678 }
679
680 #if TEST_SLEEP
681 switch (mode)
682 {
683 case 0: if ((long)TickCount() - sleep >= 0) { mDNSCoreMachineSleep(m, 1); mode++; }
684 break;
685 case 1: if ((long)TickCount() - wake >= 0) { mDNSCoreMachineSleep(m, 0); mode++; }
686 break;
687 }
688 #endif
689 }
690 #endif
691
692 mDNSexport void mDNSPlatformLock(const mDNS *const m)
693 {
694 if (!m) { DebugStr("\pmDNSPlatformLock m NULL!"); return; }
695 if (!m->p) { DebugStr("\pmDNSPlatformLock m->p NULL!"); return; }
696
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++;
702 }
703
704 mDNSlocal void ScheduleNextTimerCallback(const mDNS *const m)
705 {
706 if (m->mDNSPlatformStatus == mStatus_NoError)
707 {
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);
713 }
714 }
715
716 mDNSexport void mDNSPlatformUnlock(const mDNS *const m)
717 {
718 if (!m) { DebugStr("\pmDNSPlatformUnlock m NULL!"); return; }
719 if (!m->p) { DebugStr("\pmDNSPlatformUnlock m->p NULL!"); return; }
720
721 if (m->p->ep && m->mDNS_busy == 0) ScheduleNextTimerCallback(m);
722
723 if (m->p->nesting) m->p->nesting--;
724 else OTLeaveNotifier(m->p->ep);
725 }
726
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;
738
739 mDNSexport mDNSs32 mDNSPlatformUTC(void)
740 {
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));
751 }