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