2 * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
23 Change History (most recent first):
25 $Log: SubTypeTester.c,v $
26 Revision 1.6 2004/12/16 20:49:35 cheshire
27 <rdar://problem/3324626> Cache memory management improvements
29 Revision 1.5 2004/09/17 01:08:50 cheshire
30 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
31 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
32 declared in that file are ONLY appropriate to single-address-space embedded applications.
33 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
35 Revision 1.4 2004/09/16 00:24:49 cheshire
36 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
38 Revision 1.3 2004/08/13 23:25:01 cheshire
39 Now that we do both uDNS and mDNS, global replace "m->hostname" with
40 "m->MulticastHostname" for clarity
42 Revision 1.2 2004/08/04 22:11:30 cheshire
43 <rdar://problem/3588761> Current method of doing subtypes causes name collisions
44 Change to use "._sub." instead of ".s." to mark subtypes.
46 Revision 1.1 2004/06/11 00:03:28 cheshire
47 Add code for testing avail/busy subtypes
52 #include <stdio.h> // For printf()
53 #include <string.h> // For strlen() etc.
55 #include <Events.h> // For WaitNextEvent()
56 #include <SIOUX.h> // For SIOUXHandleOneEvent()
58 #include "mDNSEmbeddedAPI.h" // Defines the interface to the client layer above
60 #include "mDNSMacOS9.h" // Defines the specific types needed to run mDNS on this platform
62 // These don't have to be globals, but their memory does need to remain valid for as
63 // long as the search is going on. They are declared as globals here for simplicity.
65 static mDNS_PlatformSupport p
;
66 static ServiceRecordSet p1
, p2
;
67 static AuthRecord availRec1
, availRec2
;
68 static Boolean availRec2Active
;
70 // This sample code just calls mDNS_RenameAndReregisterService to automatically pick a new
71 // unique name for the service. For a device such as a printer, this may be appropriate.
72 // For a device with a user interface, and a screen, and a keyboard, the appropriate
73 // response may be to prompt the user and ask them to choose a new name for the service.
74 mDNSlocal
void Callback(mDNS
*const m
, ServiceRecordSet
*const sr
, mStatus result
)
78 case mStatus_NoError
: debugf("Callback: %##s Name Registered", sr
->RR_SRV
.resrec
.name
.c
); break;
79 case mStatus_NameConflict
: debugf("Callback: %##s Name Conflict", sr
->RR_SRV
.resrec
.name
.c
); break;
80 case mStatus_MemFree
: debugf("Callback: %##s Memory Free", sr
->RR_SRV
.resrec
.name
.c
); break;
81 default: debugf("Callback: %##s Unknown Result %d", sr
->RR_SRV
.resrec
.name
.c
, result
); break;
84 if (result
== mStatus_NameConflict
) mDNS_RenameAndReregisterService(m
, sr
, mDNSNULL
);
87 // RegisterService() is a simple wrapper function which takes C string
88 // parameters, converts them to domainname parameters, and calls mDNS_RegisterService()
89 mDNSlocal
void RegisterService(mDNS
*m
, ServiceRecordSet
*recordset
,
90 UInt16 PortAsNumber
, const char txtinfo
[],
91 const domainlabel
*const n
, const char type
[], const char domain
[])
95 char buffer
[MAX_ESCAPED_DOMAIN_NAME
];
98 MakeDomainNameFromDNSNameString(&t
, type
);
99 MakeDomainNameFromDNSNameString(&d
, domain
);
103 strncpy((char*)txtbuffer
+1, txtinfo
, sizeof(txtbuffer
)-1);
104 txtbuffer
[0] = (UInt8
)strlen(txtinfo
);
109 mDNS_RegisterService(m
, recordset
,
110 n
, &t
, &d
, // Name, type, domain
111 mDNSNULL
, mDNSOpaque16fromIntVal(PortAsNumber
),
112 txtbuffer
, (mDNSu16
)(1+txtbuffer
[0]), // TXT data, length
113 mDNSNULL
, 0, // Subtypes (none)
114 mDNSInterface_Any
, // Interface ID
115 Callback
, mDNSNULL
); // Callback and context
117 ConvertDomainNameToCString(recordset
->RR_SRV
.resrec
.name
, buffer
);
118 printf("Made Service Records for %s\n", buffer
);
121 // RegisterFakeServiceForTesting() simulates the effect of services being registered on
122 // dynamically-allocated port numbers. No real service exists on that port -- this is just for testing.
123 mDNSlocal
void RegisterFakeServiceForTesting(mDNS
*m
, ServiceRecordSet
*recordset
, const char txtinfo
[],
124 const char name
[], const char type
[], const char domain
[])
126 static UInt16 NextPort
= 0xF000;
128 MakeDomainLabelFromLiteralString(&n
, name
);
129 RegisterService(m
, recordset
, NextPort
++, txtinfo
, &n
, type
, domain
);
132 // Done once on startup, and then again every time our address changes
133 mDNSlocal OSStatus
mDNSResponderTestSetup(mDNS
*m
)
135 char buffer
[MAX_ESCAPED_DOMAIN_NAME
];
136 mDNSv4Addr ip
= m
->HostInterfaces
->ip
.ip
.v4
;
138 ConvertDomainNameToCString(&m
->MulticastHostname
, buffer
);
139 printf("Name %s\n", buffer
);
140 printf("IP %d.%d.%d.%d\n", ip
.b
[0], ip
.b
[1], ip
.b
[2], ip
.b
[3]);
143 printf("Registering Service Records\n");
144 // Create example printer discovery records
145 //static ServiceRecordSet p1, p2;
147 RegisterFakeServiceForTesting(m
, &p1
, "", "One", "_raop._tcp.", "local.");
148 RegisterFakeServiceForTesting(m
, &p2
, "", "Two", "_raop._tcp.", "local.");
153 mDNSlocal
void AvailCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
155 Boolean
*b
= (Boolean
*)rr
->RecordContext
;
157 // Signal that our record is now free for re-use
158 if (result
== mStatus_MemFree
) *b
= false;
161 mDNSlocal OSStatus
mDNSResponderSetAvail(mDNS
*m
, AuthRecord
*rr
, ServiceRecordSet
*sr
)
163 // 1. Initialize required fields of AuthRecord
164 // 2. Set name of subtype PTR record to our special subtype name denoting "available" instances
165 // 3. Set target of subtype PTR record to point to our SRV record (exactly the same as the main service PTR record)
166 // 4. And register it
167 mDNS_SetupResourceRecord(rr
, mDNSNULL
, mDNSInterface_Any
, kDNSType_PTR
, 2*3600, kDNSRecordTypeShared
, AvailCallback
, &availRec2Active
);
168 MakeDomainNameFromDNSNameString(rr
->resrec
.name
, "a._sub._raop._tcp.local.");
169 AssignDomainName(&rr
->resrec
.rdata
->u
.name
, sr
->RR_SRV
.resrec
.name
);
170 return(mDNS_Register(m
, rr
));
173 // YieldSomeTime() just cooperatively yields some time to other processes running on classic Mac OS
174 mDNSlocal Boolean
YieldSomeTime(UInt32 milliseconds
)
176 extern Boolean SIOUXQuitting
;
178 WaitNextEvent(everyEvent
, &e
, milliseconds
/ 17, NULL
);
179 SIOUXHandleOneEvent(&e
);
180 return(SIOUXQuitting
);
186 Boolean DoneSetup
= false;
187 mDNSs32 nextAvail
, nextBusy
;
189 SIOUXSettings
.asktosaveonclose
= false;
190 SIOUXSettings
.userwindowtitle
= "\pMulticast DNS Responder";
192 printf("Multicast DNS Responder\n\n");
193 printf("This software reports errors using MacsBug breaks,\n");
194 printf("so if you don't have MacsBug installed your Mac may crash.\n\n");
195 printf("******************************************************************************\n");
197 err
= InitOpenTransport();
198 if (err
) { debugf("InitOpenTransport failed %d", err
); return(err
); }
200 err
= mDNS_Init(&m
, &p
, mDNS_Init_NoCache
, mDNS_Init_ZeroCacheSize
,
201 mDNS_Init_AdvertiseLocalAddresses
, mDNS_Init_NoInitCallback
, mDNS_Init_NoInitCallbackContext
);
202 if (err
) return(err
);
204 while (!YieldSomeTime(35))
206 #if MDNS_ONLYSYSTEMTASK
207 // For debugging, use "#define MDNS_ONLYSYSTEMTASK 1" and call mDNSPlatformIdle() periodically.
208 // For shipping code, don't define MDNS_ONLYSYSTEMTASK, and you don't need to call mDNSPlatformIdle()
209 extern void mDNSPlatformIdle(mDNS
*const m
);
210 mDNSPlatformIdle(&m
); // Only needed for debugging version
212 if (m
.mDNSPlatformStatus
== mStatus_NoError
&& !DoneSetup
)
215 printf("\nListening for mDNS queries...\n");
216 mDNSResponderTestSetup(&m
);
217 mDNSResponderSetAvail(&m
, &availRec1
, &p1
);
218 availRec2Active
= false;
219 nextAvail
= mDNS_TimeNow(&m
) + mDNSPlatformOneSecond
* 10;
220 nextBusy
= mDNS_TimeNow(&m
) + mDNSPlatformOneSecond
* 15;
225 // We check availRec2.RecordType because we don't want to re-register this record
226 // if the previous mDNS_Deregister() has not yet completed
227 if (mDNS_TimeNow(&m
) - nextAvail
> 0 && !availRec2Active
)
229 printf("Setting Two now available\n");
230 availRec2Active
= true;
231 mDNSResponderSetAvail(&m
, &availRec2
, &p2
);
232 nextAvail
= nextBusy
+ mDNSPlatformOneSecond
* 10;
234 else if (mDNS_TimeNow(&m
) - nextBusy
> 0)
236 printf("Setting Two now busy\n");
237 mDNS_Deregister(&m
, &availRec2
);
238 nextBusy
= nextAvail
+ mDNSPlatformOneSecond
* 5;
243 if (p1
.RR_SRV
.resrec
.RecordType
) mDNS_DeregisterService(&m
, &p1
);
244 if (p2
.RR_SRV
.resrec
.RecordType
) mDNS_DeregisterService(&m
, &p2
);
245 if (availRec1
.resrec
.RecordType
) mDNS_Deregister(&m
, &availRec1
);
246 if (availRec2Active
) mDNS_Deregister(&m
, &availRec2
);