/* * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ Change History (most recent first): $Log: mDNSMacOS9.c,v $ Revision 1.43 2004/12/17 23:37:49 cheshire Guard against repeating wireless dissociation/re-association (and other repetitive configuration changes) Revision 1.42 2004/12/16 20:43:39 cheshire interfaceinfo.fMask should be interfaceinfo.fNetmask Revision 1.41 2004/10/16 00:17:00 cheshire Replace IP TTL 255 check with local subnet source address check Revision 1.40 2004/09/27 23:56:27 cheshire Fix infinite loop where mDNSPlatformUnlock() called mDNS_TimeNow(), and then mDNS_TimeNow() called mDNSPlatformUnlock() Revision 1.39 2004/09/21 21:02:54 cheshire Set up ifname before calling mDNS_RegisterInterface() Revision 1.38 2004/09/17 01:08:50 cheshire Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces declared in that file are ONLY appropriate to single-address-space embedded applications. For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used. Revision 1.37 2004/09/17 00:19:10 cheshire For consistency with AllDNSLinkGroupv6, rename AllDNSLinkGroup to AllDNSLinkGroupv4 Revision 1.36 2004/09/16 21:59:16 cheshire For consistency with zerov6Addr, rename zeroIPAddr to zerov4Addr Revision 1.35 2004/09/16 00:24:49 cheshire Fix unsafe use of mDNSPlatformTimeNow() Revision 1.34 2004/09/14 23:42:36 cheshire Need to seed random number generator from platform-layer data Revision 1.33 2004/09/14 23:16:31 cheshire Fix compile error: mDNS_SetFQDNs has been renamed to mDNS_SetFQDN Revision 1.32 2004/09/14 21:03:16 cheshire Fix spacing Revision 1.31 2004/08/14 03:22:42 cheshire Dynamic DNS UI <-> mDNSResponder glue Add GetUserSpecifiedDDNSName() routine Convert ServiceRegDomain to domainname instead of C string Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs Revision 1.30 2004/07/29 19:26:03 ksekar Plaform-level changes for NATPMP support Revision 1.29 2004/05/26 20:53:16 cheshire Remove unncecessary "return( -1 );" at the end of mDNSPlatformUTC() Revision 1.28 2004/05/20 18:39:06 cheshire Fix build broken by addition of mDNSPlatformUTC requirement Revision 1.27 2004/04/21 02:49:11 cheshire To reduce future confusion, renamed 'TxAndRx' to 'McastTxRx' Revision 1.26 2004/04/09 17:43:03 cheshire Make sure to set the McastTxRx field so that duplicate suppression works correctly Revision 1.25 2004/03/15 18:55:38 cheshire Comment out debugging message Revision 1.24 2004/03/12 21:30:26 cheshire Build a System-Context Shared Library from mDNSCore, for the benefit of developers like Muse Research who want to be able to use mDNS/DNS-SD from GPL-licensed code. Revision 1.23 2004/02/09 23:24:43 cheshire Need to set TTL 255 to interoperate with peers that check TTL (oops!) Revision 1.22 2004/01/27 20:15:23 cheshire : Time to prune obsolete code for listening on port 53 Revision 1.21 2004/01/24 04:59:16 cheshire Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again Revision 1.20 2003/11/14 20:59:09 cheshire Clients can't use AssignDomainName macro because mDNSPlatformMemCopy is defined in mDNSPlatformFunctions.h. Best solution is just to combine mDNSEmbeddedAPI.h and mDNSPlatformFunctions.h into a single file. Revision 1.19 2003/08/18 23:09:20 cheshire mDNSResponder divide by zero in mDNSPlatformRawTime() Revision 1.18 2003/08/12 19:56:24 cheshire Update to APSL 2.0 */ #include #include // For va_list support #include // For LMGetCurApName() #include // For smSystemScript #include // For ConvertFromPStringToUnicode() #include "mDNSEmbeddedAPI.h" // Defines the interface provided to the client layer above #include "mDNSMacOS9.h" // Defines the specific types needed to run mDNS on this platform // *************************************************************************** // Constants static const TSetBooleanOption kReusePortOption = { kOTBooleanOptionSize, INET_IP, IP_REUSEPORT, 0, true }; // IP_RCVDSTADDR with TSetByteOption/kOTOneByteOptionSize works on OS 9, OS X Classic, and OS 9 Carbon, // but gives error #-3151 (kOTBadOptionErr) on OS X Carbon. // If we instead use TSetBooleanOption/kOTBooleanOptionSize then OTOptionManagement on OS X Carbon // no longer returns -3151 but it still doesn't actually work -- no destination addresses // are delivered by OTRcvUData. I think it's just a bug in OS X Carbon. static const TSetByteOption kRcvDestAddrOption = { kOTOneByteOptionSize, INET_IP, IP_RCVDSTADDR, 0, true }; //static const TSetBooleanOption kRcvDestAddrOption = // { kOTBooleanOptionSize, INET_IP, IP_RCVDSTADDR, 0, true }; static const TSetByteOption kSetUnicastTTLOption = { kOTOneByteOptionSize, INET_IP, IP_TTL, 0, 255 }; static const TSetByteOption kSetMulticastTTLOption = { kOTOneByteOptionSize, INET_IP, IP_MULTICAST_TTL, 0, 255 }; static const TIPAddMulticastOption kAddLinkMulticastOption = { sizeof(TIPAddMulticastOption), INET_IP, IP_ADD_MEMBERSHIP, 0, { 224, 0, 0,251 }, { 0,0,0,0 } }; //static const TIPAddMulticastOption kAddAdminMulticastOption = // { sizeof(TIPAddMulticastOption), INET_IP, IP_ADD_MEMBERSHIP, 0, { 239,255,255,251 }, { 0,0,0,0 } }; // Bind endpoint to port number. Don't specify any specific IP address -- // we want to receive unicasts on all interfaces, as well as multicasts. typedef struct { OTAddressType fAddressType; mDNSIPPort fPort; mDNSv4Addr fHost; UInt8 fUnused[8]; } mDNSInetAddress; //static const mDNSInetAddress mDNSPortInetAddress = { AF_INET, { 0,0 }, { 0,0,0,0 } }; // For testing legacy client support #define MulticastDNSPortAsNumber 5353 static const mDNSInetAddress mDNSPortInetAddress = { AF_INET, { MulticastDNSPortAsNumber >> 8, MulticastDNSPortAsNumber & 0xFF }, { 0,0,0,0 } }; static const TBind mDNSbindReq = { sizeof(mDNSPortInetAddress), sizeof(mDNSPortInetAddress), (UInt8*)&mDNSPortInetAddress, 0 }; static const TNetbuf zeroTNetbuf = { 0 }; // *************************************************************************** // Functions mDNSlocal void SafeDebugStr(unsigned char *buffer) { int i; // Don't want semicolons in MacsBug messages -- they signify commands to execute for (i=1; i<= buffer[0]; i++) if (buffer[i] == ';') buffer[i] = '.'; DebugStr(buffer); } #if MDNS_DEBUGMSGS mDNSexport void debugf_(const char *format, ...) { unsigned char buffer[256]; va_list ptr; va_start(ptr,format); buffer[0] = (unsigned char)mDNS_vsnprintf((char*)buffer+1, 255, format, ptr); va_end(ptr); #if MDNS_ONLYSYSTEMTASK buffer[1+buffer[0]] = 0; fprintf(stderr, "%s\n", buffer+1); fflush(stderr); #else SafeDebugStr(buffer); #endif } #endif #if MDNS_BUILDINGSHAREDLIBRARY >= 2 // When building the non-debug version of the Extension, intended to go on end-user systems, we don't want // MacsBug breaks for *anything*, not even for the serious LogMsg messages that on OS X would be written to syslog mDNSexport void LogMsg(const char *format, ...) { (void)format; } #else mDNSexport void LogMsg(const char *format, ...) { unsigned char buffer[256]; va_list ptr; va_start(ptr,format); buffer[0] = (unsigned char)mDNS_vsnprintf((char*)buffer+1, 255, format, ptr); va_end(ptr); #if MDNS_ONLYSYSTEMTASK buffer[1+buffer[0]] = 0; fprintf(stderr, "%s\n", buffer+1); fflush(stderr); #else SafeDebugStr(buffer); #endif } #endif mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const msg, const mDNSu8 *const end, mDNSInterfaceID InterfaceID, const mDNSAddr *dst, mDNSIPPort dstPort) { // Note: If we did multi-homing, we'd have to use the InterfaceID parameter to specify from which interface to send this response #pragma unused(InterfaceID) InetAddress InetDest; TUnitData senddata; if (dst->type != mDNSAddrType_IPv4) return(mStatus_NoError); InetDest.fAddressType = AF_INET; InetDest.fPort = dstPort.NotAnInteger; InetDest.fHost = dst->ip.v4.NotAnInteger; senddata.addr .maxlen = sizeof(InetDest); senddata.addr .len = sizeof(InetDest); senddata.addr .buf = (UInt8*)&InetDest; senddata.opt = zeroTNetbuf; senddata.udata.maxlen = (UInt32)((UInt8*)end - (UInt8*)msg); senddata.udata.len = (UInt32)((UInt8*)end - (UInt8*)msg); senddata.udata.buf = (UInt8*)msg; return(OTSndUData(m->p->ep, &senddata)); } mDNSlocal OSStatus readpacket(mDNS *m) { mDNSAddr senderaddr, destaddr; mDNSInterfaceID interface; mDNSIPPort senderport; InetAddress sender; char options[256]; DNSMessage packet; TUnitData recvdata; OTFlags flags = 0; OSStatus err; recvdata.addr .maxlen = sizeof(sender); recvdata.addr .len = 0; recvdata.addr .buf = (UInt8*)&sender; recvdata.opt .maxlen = sizeof(options); recvdata.opt .len = 0; recvdata.opt .buf = (UInt8*)&options; recvdata.udata.maxlen = sizeof(packet); recvdata.udata.len = 0; recvdata.udata.buf = (UInt8*)&packet; err = OTRcvUData(m->p->ep, &recvdata, &flags); if (err && err != kOTNoDataErr) debugf("OTRcvUData error %d", err); if (err) return(err); senderaddr.type = mDNSAddrType_IPv4; senderaddr.ip.v4.NotAnInteger = sender.fHost; senderport.NotAnInteger = sender.fPort; destaddr.type = mDNSAddrType_IPv4; destaddr.ip.v4 = zerov4Addr; #if OTCARBONAPPLICATION // IP_RCVDSTADDR is known to fail on OS X Carbon, so we'll just assume the packet was probably multicast destaddr.ip.v4 = AllDNSLinkGroupv4; #endif if (recvdata.opt.len) { TOption *c = nil; while (1) { err = OTNextOption(recvdata.opt.buf, recvdata.opt.len, &c); if (err || !c) break; if (c->level == INET_IP && c->name == IP_RCVDSTADDR && c->len - kOTOptionHeaderSize == sizeof(destaddr.ip.v4)) mDNSPlatformMemCopy(c->value, &destaddr.ip.v4, sizeof(destaddr.ip.v4)); } } interface = m->HostInterfaces->InterfaceID; if (flags & T_MORE) debugf("ERROR: OTRcvUData() buffer too small (T_MORE set)"); else if (recvdata.addr.len < sizeof(InetAddress)) debugf("ERROR: recvdata.addr.len (%d) too short", recvdata.addr.len); else mDNSCoreReceive(m, &packet, recvdata.udata.buf + recvdata.udata.len, &senderaddr, senderport, &destaddr, MulticastDNSPort, interface); return(err); } mDNSexport mStatus mDNSPlatformTCPConnect(const mDNSAddr *dst, mDNSOpaque16 dstport, mDNSInterfaceID InterfaceID, TCPConnectionCallback callback, void *context, int *descriptor) { (void)dst; // Unused (void)dstport; // Unused (void)InterfaceID; // Unused (void)callback; // Unused (void)context; // Unused (void)descriptor; // Unused return(mStatus_UnsupportedErr); } mDNSexport void mDNSPlatformTCPCloseConnection(int sd) { (void)sd; // Unused } mDNSexport int mDNSPlatformReadTCP(int sd, void *buf, int buflen) { (void)sd; // Unused (void)buf; // Unused (void)buflen; // Unused return(0); } mDNSexport int mDNSPlatformWriteTCP(int sd, const char *msg, int len) { (void)sd; // Unused (void)msg; // Unused (void)len; // Unused return(0); } mDNSlocal void mDNSOptionManagement(mDNS *const m) { OSStatus err; // Make sure the length in the TNetbuf agrees with the length in the TOptionHeader m->p->optReq.opt.len = m->p->optBlock.h.len; m->p->optReq.opt.maxlen = m->p->optBlock.h.len; if (m->p->optReq.opt.maxlen < 4) m->p->optReq.opt.maxlen = 4; err = OTOptionManagement(m->p->ep, &m->p->optReq, NULL); if (err) LogMsg("OTOptionManagement failed %d", err); } mDNSlocal void mDNSinitComplete(mDNS *const m, mStatus result) { m->mDNSPlatformStatus = result; mDNSCoreInitComplete(m, mStatus_NoError); } mDNSlocal pascal void mDNSNotifier(void *contextPtr, OTEventCode code, OTResult result, void *cookie) { mDNS *const m = (mDNS *const)contextPtr; if (!m) debugf("mDNSNotifier FATAL ERROR! No context"); switch (code) { case T_OPENCOMPLETE: { OSStatus err; InetInterfaceInfo interfaceinfo; if (result) { LogMsg("T_OPENCOMPLETE failed %d", result); mDNSinitComplete(m, result); return; } //debugf("T_OPENCOMPLETE"); m->p->ep = (EndpointRef)cookie; //debugf("OTInetGetInterfaceInfo"); // (In future may want to loop over all interfaces instead of just using kDefaultInetInterface) err = OTInetGetInterfaceInfo(&interfaceinfo, kDefaultInetInterface); if (err) { LogMsg("OTInetGetInterfaceInfo failed %d", err); mDNSinitComplete(m, err); return; } // Make our basic standard host resource records (address, PTR, etc.) m->p->interface.InterfaceID = (mDNSInterfaceID)&m->p->interface; m->p->interface.ip .type = mDNSAddrType_IPv4; m->p->interface.ip .ip.v4.NotAnInteger = interfaceinfo.fAddress; m->p->interface.mask.type = mDNSAddrType_IPv4; m->p->interface.mask.ip.v4.NotAnInteger = interfaceinfo.fNetmask; m->p->interface.ifname[0] = 0; m->p->interface.Advertise = m->AdvertiseLocalAddresses; m->p->interface.McastTxRx = mDNStrue; } case T_OPTMGMTCOMPLETE: case T_BINDCOMPLETE: // IP_RCVDSTADDR is known to fail on OS X Carbon, so we don't want to abort for that error // (see comment above at the definition of kRcvDestAddrOption) #if OTCARBONAPPLICATION if (result && m->p->mOTstate == mOT_RcvDestAddr) LogMsg("Carbon IP_RCVDSTADDR option failed %d; continuing anyway", result); else #endif if (result) { LogMsg("T_OPTMGMTCOMPLETE/T_BINDCOMPLETE %d failed %d", m->p->mOTstate, result); mDNSinitComplete(m, result); return; } //LogMsg("T_OPTMGMTCOMPLETE/T_BINDCOMPLETE %d", m->p->mOTstate); switch (++m->p->mOTstate) { case mOT_ReusePort: m->p->optBlock.b = kReusePortOption; mDNSOptionManagement(m); break; case mOT_RcvDestAddr: m->p->optBlock.i = kRcvDestAddrOption; mDNSOptionManagement(m); break; case mOT_SetUTTL: m->p->optBlock.i = kSetUnicastTTLOption; mDNSOptionManagement(m); break; case mOT_SetMTTL: m->p->optBlock.i = kSetMulticastTTLOption; mDNSOptionManagement(m); break; case mOT_LLScope: m->p->optBlock.m = kAddLinkMulticastOption; mDNSOptionManagement(m); break; // case mOT_AdminScope: m->p->optBlock.m = kAddAdminMulticastOption; mDNSOptionManagement(m); break; case mOT_Bind: OTBind(m->p->ep, (TBind*)&mDNSbindReq, NULL); break; case mOT_Ready: mDNSinitComplete(m, mStatus_NoError); // Can't do mDNS_RegisterInterface until *after* mDNSinitComplete has set m->mDNSPlatformStatus to mStatus_NoError mDNS_RegisterInterface(m, &m->p->interface, 0); break; default: LogMsg("Unexpected m->p->mOTstate %d", m->p->mOTstate-1); } break; case T_DATA: //debugf("T_DATA"); while (readpacket(m) == kOTNoError) continue; // Read packets until we run out break; case kOTProviderWillClose: LogMsg("kOTProviderWillClose"); break; case kOTProviderIsClosed: // Machine is going to sleep, shutting down, or reconfiguring IP LogMsg("kOTProviderIsClosed"); if (m->p->mOTstate == mOT_Ready) { m->p->mOTstate = mOT_Closed; mDNS_DeregisterInterface(m, &m->p->interface); } if (m->p->ep) { OTCloseProvider(m->p->ep); m->p->ep = NULL; } break; // Do we need to do anything? default: debugf("mDNSNotifier: Unexpected OTEventCode %X", code); break; } } #if MDNS_ONLYSYSTEMTASK static Boolean ONLYSYSTEMTASKevent; static void *ONLYSYSTEMTASKcontextPtr; static OTEventCode ONLYSYSTEMTASKcode; static OTResult ONLYSYSTEMTASKresult; static void *ONLYSYSTEMTASKcookie; mDNSlocal pascal void CallmDNSNotifier(void *contextPtr, OTEventCode code, OTResult result, void *cookie) { ONLYSYSTEMTASKcontextPtr = contextPtr; ONLYSYSTEMTASKcode = code; ONLYSYSTEMTASKresult = result; ONLYSYSTEMTASKcookie = cookie; } #else mDNSlocal pascal void CallmDNSNotifier(void *contextPtr, OTEventCode code, OTResult result, void *cookie) { mDNS *const m = (mDNS *const)contextPtr; if (!m) debugf("mDNSNotifier FATAL ERROR! No context"); if (m->p->nesting) LogMsg("CallmDNSNotifier ERROR! OTEnterNotifier is supposed to suppress notifier callbacks"); mDNSNotifier(contextPtr, code, result, cookie); } #endif static OTNotifyUPP CallmDNSNotifierUPP; mDNSlocal OSStatus mDNSOpenEndpoint(const mDNS *const m) { OSStatus err; // m->optReq is pre-set to point to the shared m->optBlock // m->optBlock is filled in by each OTOptionManagement call m->p->optReq.opt.maxlen = sizeof(m->p->optBlock); m->p->optReq.opt.len = sizeof(m->p->optBlock); m->p->optReq.opt.buf = (UInt8*)&m->p->optBlock; m->p->optReq.flags = T_NEGOTIATE; // Open an endpoint and start answering queries //printf("Opening endpoint now...\n"); m->p->ep = NULL; m->p->mOTstate = mOT_Start; err = OTAsyncOpenEndpoint(OTCreateConfiguration(kUDPName), 0, NULL, CallmDNSNotifierUPP, (void*)m); if (err) { LogMsg("ERROR: OTAsyncOpenEndpoint(UDP) failed with error <%d>", err); return(err); } return(kOTNoError); } // Define these here because they're not in older versions of OpenTransport.h enum { xOTStackIsLoading = 0x27000001, /* Sent before Open Transport attempts to load the TCP/IP protocol stack.*/ xOTStackWasLoaded = 0x27000002, /* Sent after the TCP/IP stack has been successfully loaded.*/ xOTStackIsUnloading = 0x27000003 /* Sent before Open Transport unloads the TCP/IP stack.*/ }; static mDNS *ClientNotifierContext; mDNSlocal pascal void ClientNotifier(void *contextPtr, OTEventCode code, OTResult result, void *cookie) { mDNS *const m = ClientNotifierContext; #pragma unused(contextPtr) // Usually zero (except one in the 'xOTStackIsLoading' case) #pragma unused(cookie) // Usually 'ipv4' (except for kOTPortNetworkChange) #pragma unused(result) // Usually zero switch (code) { case xOTStackIsLoading: break; case xOTStackWasLoaded: if (m->p->mOTstate == mOT_Closed) { LogMsg("kOTStackWasLoaded: Re-opening endpoint"); if (m->p->ep) LogMsg("kOTStackWasLoaded: ERROR: m->p->ep already set"); m->mDNSPlatformStatus = mStatus_Waiting; m->p->mOTstate = mOT_Reset; #if !MDNS_ONLYSYSTEMTASK mDNSOpenEndpoint(m); #endif } else LogMsg("kOTStackWasLoaded (no action)"); break; case xOTStackIsUnloading: break; case kOTPortNetworkChange: break; default: debugf("ClientNotifier unknown code %X, %X, %d", contextPtr, code, result); break; } } #if TARGET_API_MAC_CARBON mDNSlocal void GetUserSpecifiedComputerName(domainlabel *const namelabel) { CFStringRef cfs = CSCopyMachineName(); CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8); CFRelease(cfs); } #else mDNSlocal OSStatus ConvertStringHandleToUTF8(const StringHandle machineName, UInt8 *const utf8, ByteCount maxlen) { OSStatus status; TextEncoding utf8TextEncoding, SystemTextEncoding; UnicodeMapping theMapping; TextToUnicodeInfo textToUnicodeInfo; ByteCount unicodelen = 0; if (maxlen > 255) maxlen = 255; // Can't put more than 255 in a Pascal String utf8TextEncoding = CreateTextEncoding(kTextEncodingUnicodeDefault, kTextEncodingDefaultVariant, kUnicodeUTF8Format); UpgradeScriptInfoToTextEncoding(smSystemScript, kTextLanguageDontCare, kTextRegionDontCare, NULL, &SystemTextEncoding); theMapping.unicodeEncoding = utf8TextEncoding; theMapping.otherEncoding = SystemTextEncoding; theMapping.mappingVersion = kUnicodeUseLatestMapping; status = CreateTextToUnicodeInfo(&theMapping, &textToUnicodeInfo); if (status == noErr) { status = ConvertFromPStringToUnicode(textToUnicodeInfo, *machineName, maxlen, &unicodelen, (UniCharArrayPtr)&(utf8[1])); DisposeTextToUnicodeInfo(&textToUnicodeInfo); } utf8[0] = (UInt8)unicodelen; return(status); } mDNSlocal void GetUserSpecifiedComputerName(domainlabel *const namelabel) { StringHandle machineName = GetString(-16413); // Get machine name set in file sharing if (machineName) { char machineNameState = HGetState((Handle)machineName); HLock((Handle)machineName); ConvertStringHandleToUTF8(machineName, namelabel->c, MAX_DOMAIN_LABEL); HSetState((Handle)machineName, machineNameState); } } #endif static pascal void mDNSTimerTask(void *arg) { #if MDNS_ONLYSYSTEMTASK #pragma unused(arg) ONLYSYSTEMTASKevent = true; #else mDNS *const m = (mDNS *const)arg; if (!m->p->ep) LogMsg("mDNSTimerTask NO endpoint"); if (m->mDNS_busy) LogMsg("mDNS_busy"); if (m->p->nesting) LogMsg("mDNSTimerTask ERROR! OTEnterNotifier is supposed to suppress timer callbacks too"); // If our timer fires at a time when we have no endpoint, ignore it -- // once we reopen our endpoint and get our T_BINDCOMPLETE message we'll call // mDNS_RegisterInterface(), which does a lock/unlock, which retriggers the timer. // Likewise, if m->mDNS_busy or m->p->nesting, we'll catch this on the unlock if (m->p->ep && m->mDNS_busy == 0 && m->p->nesting == 0) mDNS_Execute(m); #endif } #if TEST_SLEEP long sleep, wake, mode; #endif mDNSexport mStatus mDNSPlatformInit(mDNS *const m) { OSStatus err = InitOpenTransport(); ClientNotifierContext = m; // Note: OTRegisterAsClient returns kOTNotSupportedErr when running as Carbon code on OS X // -- but that's okay, we don't need a ClientNotifier when running as Carbon code on OS X OTRegisterAsClient(NULL, NewOTNotifyUPP(ClientNotifier)); m->p->OTTimerTask = OTCreateTimerTask(NewOTProcessUPP(mDNSTimerTask), m); m->p->nesting = 0; #if TEST_SLEEP sleep = TickCount() + 600; wake = TickCount() + 1200; mode = 0; #endif // Set up the nice label m->nicelabel.c[0] = 0; GetUserSpecifiedComputerName(&m->nicelabel); // m->nicelabel = *(domainlabel*)"\pStu"; // For conflict testing if (m->nicelabel.c[0] == 0) MakeDomainLabelFromLiteralString(&m->nicelabel, "Macintosh"); // Set up the RFC 1034-compliant label m->hostlabel.c[0] = 0; ConvertUTF8PstringToRFC1034HostLabel(m->nicelabel.c, &m->hostlabel); if (m->hostlabel.c[0] == 0) MakeDomainLabelFromLiteralString(&m->hostlabel, "Macintosh"); mDNS_SetFQDN(m); // When it's finished mDNSOpenEndpoint asynchronously calls mDNSinitComplete() and then mDNS_RegisterInterface() CallmDNSNotifierUPP = NewOTNotifyUPP(CallmDNSNotifier); err = mDNSOpenEndpoint(m); if (err) { LogMsg("mDNSOpenEndpoint failed %d", err); if (m->p->OTTimerTask) OTDestroyTimerTask(m->p->OTTimerTask); OTUnregisterAsClient(); CloseOpenTransport(); } return(err); } extern void mDNSPlatformClose (mDNS *const m) { if (m->p->mOTstate == mOT_Ready) { m->p->mOTstate = mOT_Closed; mDNS_DeregisterInterface(m, &m->p->interface); } if (m->p->ep) { OTCloseProvider (m->p->ep); m->p->ep = NULL; } if (m->p->OTTimerTask) { OTDestroyTimerTask(m->p->OTTimerTask); m->p->OTTimerTask = 0; } OTUnregisterAsClient(); CloseOpenTransport(); } #if MDNS_ONLYSYSTEMTASK extern void mDNSPlatformIdle(mDNS *const m); mDNSexport void mDNSPlatformIdle(mDNS *const m) { while (ONLYSYSTEMTASKcontextPtr) { void *contextPtr = ONLYSYSTEMTASKcontextPtr; ONLYSYSTEMTASKcontextPtr = NULL; mDNSNotifier(contextPtr, ONLYSYSTEMTASKcode, ONLYSYSTEMTASKresult, ONLYSYSTEMTASKcookie); } if (ONLYSYSTEMTASKevent) { ONLYSYSTEMTASKevent = false; mDNS_Execute(m); } if (m->p->mOTstate == mOT_Reset) { printf("\n"); printf("******************************************************************************\n"); printf("\n"); printf("Reopening endpoint\n"); mDNSOpenEndpoint(m); m->ResourceRecords = NULL; } #if TEST_SLEEP switch (mode) { case 0: if ((long)TickCount() - sleep >= 0) { mDNSCoreMachineSleep(m, 1); mode++; } break; case 1: if ((long)TickCount() - wake >= 0) { mDNSCoreMachineSleep(m, 0); mode++; } break; } #endif } #endif mDNSexport void mDNSPlatformLock(const mDNS *const m) { if (!m) { DebugStr("\pmDNSPlatformLock m NULL!"); return; } if (!m->p) { DebugStr("\pmDNSPlatformLock m->p NULL!"); return; } // If we try to call OTEnterNotifier and fail because we're already running at // Notifier context, then make sure we don't do the matching OTLeaveNotifier() on exit. // If we haven't even opened our endpoint yet, then just increment m->p->nesting for the same reason if (m->p->mOTstate == mOT_Ready && !m->p->ep) DebugStr("\pmDNSPlatformLock: m->p->mOTstate == mOT_Ready && !m->p->ep"); if (!m->p->ep || m->p->nesting || OTEnterNotifier(m->p->ep) == false) m->p->nesting++; } mDNSlocal void ScheduleNextTimerCallback(const mDNS *const m) { if (m->mDNSPlatformStatus == mStatus_NoError) { SInt32 interval = m->NextScheduledEvent - (mDNSPlatformRawTime() + m->timenow_adjust); if (interval < 1) interval = 1; else if (interval > 0x70000000 / 1000) interval = 0x70000000 / mDNSPlatformOneSecond; else interval = (interval * 1000 + mDNSPlatformOneSecond-1)/ mDNSPlatformOneSecond; OTScheduleTimerTask(m->p->OTTimerTask, (OTTimeout)interval); } } mDNSexport void mDNSPlatformUnlock(const mDNS *const m) { if (!m) { DebugStr("\pmDNSPlatformUnlock m NULL!"); return; } if (!m->p) { DebugStr("\pmDNSPlatformUnlock m->p NULL!"); return; } if (m->p->ep && m->mDNS_busy == 0) ScheduleNextTimerCallback(m); if (m->p->nesting) m->p->nesting--; else OTLeaveNotifier(m->p->ep); } mDNSexport void mDNSPlatformStrCopy(const void *src, void *dst) { OTStrCopy((char*)dst, (char*)src); } mDNSexport UInt32 mDNSPlatformStrLen (const void *src) { return(OTStrLength((char*)src)); } mDNSexport void mDNSPlatformMemCopy(const void *src, void *dst, UInt32 len) { OTMemcpy(dst, src, len); } mDNSexport mDNSBool mDNSPlatformMemSame(const void *src, const void *dst, UInt32 len) { return(OTMemcmp(dst, src, len)); } mDNSexport void mDNSPlatformMemZero( void *dst, UInt32 len) { OTMemzero(dst, len); } mDNSexport void * mDNSPlatformMemAllocate(mDNSu32 len) { return(OTAllocMem(len)); } mDNSexport void mDNSPlatformMemFree(void *mem) { OTFreeMem(mem); } mDNSexport mDNSu32 mDNSPlatformRandomSeed(void) { return(TickCount()); } mDNSexport mStatus mDNSPlatformTimeInit(void) { return(mStatus_NoError); } mDNSexport SInt32 mDNSPlatformRawTime() { return((SInt32)TickCount()); } mDNSexport SInt32 mDNSPlatformOneSecond = 60; mDNSexport mDNSs32 mDNSPlatformUTC(void) { // Classic Mac OS since Midnight, 1st Jan 1904 // Standard Unix counts from 1970 // This value adjusts for the 66 years and 17 leap-days difference mDNSu32 SecsSince1904; MachineLocation ThisLocation; #define TIME_ADJUST (((1970 - 1904) * 365 + 17) * 24 * 60 * 60) #define ThisLocationGMTdelta ((ThisLocation.u.gmtDelta << 8) >> 8) GetDateTime(&SecsSince1904); ReadLocation(&ThisLocation); return((mDNSs32)(SecsSince1904 - ThisLocationGMTdelta - TIME_ADJUST)); }