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