]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOS9/SubTypeTester.c
mDNSResponder-108.tar.gz
[apple/mdnsresponder.git] / mDNSMacOS9 / SubTypeTester.c
1 /*
2 * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22
23 Change History (most recent first):
24
25 $Log: SubTypeTester.c,v $
26 Revision 1.6 2004/12/16 20:49:35 cheshire
27 <rdar://problem/3324626> Cache memory management improvements
28
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.
34
35 Revision 1.4 2004/09/16 00:24:49 cheshire
36 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
37
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
41
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.
45
46 Revision 1.1 2004/06/11 00:03:28 cheshire
47 Add code for testing avail/busy subtypes
48
49
50 */
51
52 #include <stdio.h> // For printf()
53 #include <string.h> // For strlen() etc.
54
55 #include <Events.h> // For WaitNextEvent()
56 #include <SIOUX.h> // For SIOUXHandleOneEvent()
57
58 #include "mDNSEmbeddedAPI.h" // Defines the interface to the client layer above
59
60 #include "mDNSMacOS9.h" // Defines the specific types needed to run mDNS on this platform
61
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.
64 static mDNS m;
65 static mDNS_PlatformSupport p;
66 static ServiceRecordSet p1, p2;
67 static AuthRecord availRec1, availRec2;
68 static Boolean availRec2Active;
69
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)
75 {
76 switch (result)
77 {
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;
82 }
83
84 if (result == mStatus_NameConflict) mDNS_RenameAndReregisterService(m, sr, mDNSNULL);
85 }
86
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[])
92 {
93 domainname t;
94 domainname d;
95 char buffer[MAX_ESCAPED_DOMAIN_NAME];
96 UInt8 txtbuffer[512];
97
98 MakeDomainNameFromDNSNameString(&t, type);
99 MakeDomainNameFromDNSNameString(&d, domain);
100
101 if (txtinfo)
102 {
103 strncpy((char*)txtbuffer+1, txtinfo, sizeof(txtbuffer)-1);
104 txtbuffer[0] = (UInt8)strlen(txtinfo);
105 }
106 else
107 txtbuffer[0] = 0;
108
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
116
117 ConvertDomainNameToCString(recordset->RR_SRV.resrec.name, buffer);
118 printf("Made Service Records for %s\n", buffer);
119 }
120
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[])
125 {
126 static UInt16 NextPort = 0xF000;
127 domainlabel n;
128 MakeDomainLabelFromLiteralString(&n, name);
129 RegisterService(m, recordset, NextPort++, txtinfo, &n, type, domain);
130 }
131
132 // Done once on startup, and then again every time our address changes
133 mDNSlocal OSStatus mDNSResponderTestSetup(mDNS *m)
134 {
135 char buffer[MAX_ESCAPED_DOMAIN_NAME];
136 mDNSv4Addr ip = m->HostInterfaces->ip.ip.v4;
137
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]);
141
142 printf("\n");
143 printf("Registering Service Records\n");
144 // Create example printer discovery records
145 //static ServiceRecordSet p1, p2;
146
147 RegisterFakeServiceForTesting(m, &p1, "", "One", "_raop._tcp.", "local.");
148 RegisterFakeServiceForTesting(m, &p2, "", "Two", "_raop._tcp.", "local.");
149
150 return(kOTNoError);
151 }
152
153 mDNSlocal void AvailCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
154 {
155 Boolean *b = (Boolean *)rr->RecordContext;
156 (void)m; // Unused
157 // Signal that our record is now free for re-use
158 if (result == mStatus_MemFree) *b = false;
159 }
160
161 mDNSlocal OSStatus mDNSResponderSetAvail(mDNS *m, AuthRecord *rr, ServiceRecordSet *sr)
162 {
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));
171 }
172
173 // YieldSomeTime() just cooperatively yields some time to other processes running on classic Mac OS
174 mDNSlocal Boolean YieldSomeTime(UInt32 milliseconds)
175 {
176 extern Boolean SIOUXQuitting;
177 EventRecord e;
178 WaitNextEvent(everyEvent, &e, milliseconds / 17, NULL);
179 SIOUXHandleOneEvent(&e);
180 return(SIOUXQuitting);
181 }
182
183 int main()
184 {
185 mStatus err;
186 Boolean DoneSetup = false;
187 mDNSs32 nextAvail, nextBusy;
188
189 SIOUXSettings.asktosaveonclose = false;
190 SIOUXSettings.userwindowtitle = "\pMulticast DNS Responder";
191
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");
196
197 err = InitOpenTransport();
198 if (err) { debugf("InitOpenTransport failed %d", err); return(err); }
199
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);
203
204 while (!YieldSomeTime(35))
205 {
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
211 #endif
212 if (m.mDNSPlatformStatus == mStatus_NoError && !DoneSetup)
213 {
214 DoneSetup = true;
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;
221 }
222
223 if (DoneSetup)
224 {
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)
228 {
229 printf("Setting Two now available\n");
230 availRec2Active = true;
231 mDNSResponderSetAvail(&m, &availRec2, &p2);
232 nextAvail = nextBusy + mDNSPlatformOneSecond * 10;
233 }
234 else if (mDNS_TimeNow(&m) - nextBusy > 0)
235 {
236 printf("Setting Two now busy\n");
237 mDNS_Deregister(&m, &availRec2);
238 nextBusy = nextAvail + mDNSPlatformOneSecond * 5;
239 }
240 }
241 }
242
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);
247
248 mDNS_Close(&m);
249
250 return(0);
251 }