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