| /* -*- Mode: C; tab-width: 4 -*- |
| * |
| * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include <stdio.h> |
| #include <stdarg.h> // For va_list support |
| |
| #include <LowMem.h> // For LMGetCurApName() |
| #include <TextUtils.h> // For smSystemScript |
| #include <UnicodeConverter.h> // 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 = AllDNSLinkGroup_v4.ip.v4; |
| #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(&destaddr.ip.v4, c->value, 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 TCPSocket *mDNSPlatformTCPSocket(mDNS * const m, TCPSocketFlags flags, mDNSIPPort * port) |
| { |
| (void)m; // Unused |
| (void)flags; // Unused |
| (void)port; // Unused |
| return NULL; |
| } |
| |
| mDNSexport TCPSocket *mDNSPlatformTCPAccept(TCPSocketFlags flags, int sd) |
| { |
| (void)flags; // Unused |
| (void)sd; // Unused |
| return NULL; |
| } |
| |
| mDNSexport int mDNSPlatformTCPGetFD(TCPSocket *sock) |
| { |
| (void)sock; // Unused |
| return -1; |
| } |
| |
| mDNSexport mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr * dst, mDNSOpaque16 dstport, mDNSInterfaceID InterfaceID, |
| TCPConnectionCallback callback, void * context) |
| { |
| (void)sock; // Unused |
| (void)dst; // Unused |
| (void)dstport; // Unused |
| (void)InterfaceID; // Unused |
| (void)callback; // Unused |
| (void)context; // Unused |
| return(mStatus_UnsupportedErr); |
| } |
| |
| mDNSexport void mDNSPlatformTCPCloseConnection(TCPSocket *sd) |
| { |
| (void)sd; // Unused |
| } |
| |
| mDNSexport long mDNSPlatformReadTCP(TCPSocket *sock, void *buf, unsigned long buflen, mDNSBool *closed) |
| { |
| (void)sock; // Unused |
| (void)buf; // Unused |
| (void)buflen; // Unused |
| (void)closed; // Unused |
| return(0); |
| } |
| |
| mDNSexport long mDNSPlatformWriteTCP(TCPSocket *sock, const char *msg, unsigned long len) |
| { |
| (void)sock; // Unused |
| (void)msg; // Unused |
| (void)len; // Unused |
| return(0); |
| } |
| |
| mDNSexport UDPSocket *mDNSPlatformUDPSocket(mDNS * const m, mDNSIPPort port) |
| { |
| (void)m; // Unused |
| (void)port; // Unused |
| return NULL; |
| } |
| |
| mDNSexport void mDNSPlatformUDPClose(UDPSocket *sock) |
| { |
| (void)sock; // Unused |
| } |
| |
| 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, mDNSfalse); |
| 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, mDNSfalse); |
| } |
| 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, mDNSfalse); |
| } |
| 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 - mDNS_TimeNow_NoLock(m); |
| 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( void *dst, const void *src) { OTStrCopy((char*)dst, (char*)src); } |
| mDNSexport UInt32 mDNSPlatformStrLen ( const void *src) { return(OTStrLength((char*)src)); } |
| mDNSexport void mDNSPlatformMemCopy( void *dst, const void *src, UInt32 len) { OTMemcpy(dst, src, len); } |
| mDNSexport mDNSBool mDNSPlatformMemSame(const void *dst, const void *src, 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)); |
| } |