]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOS9/SubTypeTester.c
mDNSResponder-212.1.tar.gz
[apple/mdnsresponder.git] / mDNSMacOS9 / SubTypeTester.c
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 Change History (most recent first):
18
19 $Log: SubTypeTester.c,v $
20 Revision 1.7 2006/08/14 23:24:29 cheshire
21 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
22
23 Revision 1.6 2004/12/16 20:49:35 cheshire
24 <rdar://problem/3324626> Cache memory management improvements
25
26 Revision 1.5 2004/09/17 01:08:50 cheshire
27 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
28 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
29 declared in that file are ONLY appropriate to single-address-space embedded applications.
30 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
31
32 Revision 1.4 2004/09/16 00:24:49 cheshire
33 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
34
35 Revision 1.3 2004/08/13 23:25:01 cheshire
36 Now that we do both uDNS and mDNS, global replace "m->hostname" with
37 "m->MulticastHostname" for clarity
38
39 Revision 1.2 2004/08/04 22:11:30 cheshire
40 <rdar://problem/3588761> Current method of doing subtypes causes name collisions
41 Change to use "._sub." instead of ".s." to mark subtypes.
42
43 Revision 1.1 2004/06/11 00:03:28 cheshire
44 Add code for testing avail/busy subtypes
45
46
47 */
48
49 #include <stdio.h> // For printf()
50 #include <string.h> // For strlen() etc.
51
52 #include <Events.h> // For WaitNextEvent()
53 #include <SIOUX.h> // For SIOUXHandleOneEvent()
54
55 #include "mDNSEmbeddedAPI.h" // Defines the interface to the client layer above
56
57 #include "mDNSMacOS9.h" // Defines the specific types needed to run mDNS on this platform
58
59 // These don't have to be globals, but their memory does need to remain valid for as
60 // long as the search is going on. They are declared as globals here for simplicity.
61 static mDNS m;
62 static mDNS_PlatformSupport p;
63 static ServiceRecordSet p1, p2;
64 static AuthRecord availRec1, availRec2;
65 static Boolean availRec2Active;
66
67 // This sample code just calls mDNS_RenameAndReregisterService to automatically pick a new
68 // unique name for the service. For a device such as a printer, this may be appropriate.
69 // For a device with a user interface, and a screen, and a keyboard, the appropriate
70 // response may be to prompt the user and ask them to choose a new name for the service.
71 mDNSlocal void Callback(mDNS *const m, ServiceRecordSet *const sr, mStatus result)
72 {
73 switch (result)
74 {
75 case mStatus_NoError: debugf("Callback: %##s Name Registered", sr->RR_SRV.resrec.name.c); break;
76 case mStatus_NameConflict: debugf("Callback: %##s Name Conflict", sr->RR_SRV.resrec.name.c); break;
77 case mStatus_MemFree: debugf("Callback: %##s Memory Free", sr->RR_SRV.resrec.name.c); break;
78 default: debugf("Callback: %##s Unknown Result %d", sr->RR_SRV.resrec.name.c, result); break;
79 }
80
81 if (result == mStatus_NameConflict) mDNS_RenameAndReregisterService(m, sr, mDNSNULL);
82 }
83
84 // RegisterService() is a simple wrapper function which takes C string
85 // parameters, converts them to domainname parameters, and calls mDNS_RegisterService()
86 mDNSlocal void RegisterService(mDNS *m, ServiceRecordSet *recordset,
87 UInt16 PortAsNumber, const char txtinfo[],
88 const domainlabel *const n, const char type[], const char domain[])
89 {
90 domainname t;
91 domainname d;
92 char buffer[MAX_ESCAPED_DOMAIN_NAME];
93 UInt8 txtbuffer[512];
94
95 MakeDomainNameFromDNSNameString(&t, type);
96 MakeDomainNameFromDNSNameString(&d, domain);
97
98 if (txtinfo)
99 {
100 strncpy((char*)txtbuffer+1, txtinfo, sizeof(txtbuffer)-1);
101 txtbuffer[0] = (UInt8)strlen(txtinfo);
102 }
103 else
104 txtbuffer[0] = 0;
105
106 mDNS_RegisterService(m, recordset,
107 n, &t, &d, // Name, type, domain
108 mDNSNULL, mDNSOpaque16fromIntVal(PortAsNumber),
109 txtbuffer, (mDNSu16)(1+txtbuffer[0]), // TXT data, length
110 mDNSNULL, 0, // Subtypes (none)
111 mDNSInterface_Any, // Interface ID
112 Callback, mDNSNULL); // Callback and context
113
114 ConvertDomainNameToCString(recordset->RR_SRV.resrec.name, buffer);
115 printf("Made Service Records for %s\n", buffer);
116 }
117
118 // RegisterFakeServiceForTesting() simulates the effect of services being registered on
119 // dynamically-allocated port numbers. No real service exists on that port -- this is just for testing.
120 mDNSlocal void RegisterFakeServiceForTesting(mDNS *m, ServiceRecordSet *recordset, const char txtinfo[],
121 const char name[], const char type[], const char domain[])
122 {
123 static UInt16 NextPort = 0xF000;
124 domainlabel n;
125 MakeDomainLabelFromLiteralString(&n, name);
126 RegisterService(m, recordset, NextPort++, txtinfo, &n, type, domain);
127 }
128
129 // Done once on startup, and then again every time our address changes
130 mDNSlocal OSStatus mDNSResponderTestSetup(mDNS *m)
131 {
132 char buffer[MAX_ESCAPED_DOMAIN_NAME];
133 mDNSv4Addr ip = m->HostInterfaces->ip.ip.v4;
134
135 ConvertDomainNameToCString(&m->MulticastHostname, buffer);
136 printf("Name %s\n", buffer);
137 printf("IP %d.%d.%d.%d\n", ip.b[0], ip.b[1], ip.b[2], ip.b[3]);
138
139 printf("\n");
140 printf("Registering Service Records\n");
141 // Create example printer discovery records
142 //static ServiceRecordSet p1, p2;
143
144 RegisterFakeServiceForTesting(m, &p1, "", "One", "_raop._tcp.", "local.");
145 RegisterFakeServiceForTesting(m, &p2, "", "Two", "_raop._tcp.", "local.");
146
147 return(kOTNoError);
148 }
149
150 mDNSlocal void AvailCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
151 {
152 Boolean *b = (Boolean *)rr->RecordContext;
153 (void)m; // Unused
154 // Signal that our record is now free for re-use
155 if (result == mStatus_MemFree) *b = false;
156 }
157
158 mDNSlocal OSStatus mDNSResponderSetAvail(mDNS *m, AuthRecord *rr, ServiceRecordSet *sr)
159 {
160 // 1. Initialize required fields of AuthRecord
161 // 2. Set name of subtype PTR record to our special subtype name denoting "available" instances
162 // 3. Set target of subtype PTR record to point to our SRV record (exactly the same as the main service PTR record)
163 // 4. And register it
164 mDNS_SetupResourceRecord(rr, mDNSNULL, mDNSInterface_Any, kDNSType_PTR, 2*3600, kDNSRecordTypeShared, AvailCallback, &availRec2Active);
165 MakeDomainNameFromDNSNameString(rr->resrec.name, "a._sub._raop._tcp.local.");
166 AssignDomainName(&rr->resrec.rdata->u.name, sr->RR_SRV.resrec.name);
167 return(mDNS_Register(m, rr));
168 }
169
170 // YieldSomeTime() just cooperatively yields some time to other processes running on classic Mac OS
171 mDNSlocal Boolean YieldSomeTime(UInt32 milliseconds)
172 {
173 extern Boolean SIOUXQuitting;
174 EventRecord e;
175 WaitNextEvent(everyEvent, &e, milliseconds / 17, NULL);
176 SIOUXHandleOneEvent(&e);
177 return(SIOUXQuitting);
178 }
179
180 int main()
181 {
182 mStatus err;
183 Boolean DoneSetup = false;
184 mDNSs32 nextAvail, nextBusy;
185
186 SIOUXSettings.asktosaveonclose = false;
187 SIOUXSettings.userwindowtitle = "\pMulticast DNS Responder";
188
189 printf("Multicast DNS Responder\n\n");
190 printf("This software reports errors using MacsBug breaks,\n");
191 printf("so if you don't have MacsBug installed your Mac may crash.\n\n");
192 printf("******************************************************************************\n");
193
194 err = InitOpenTransport();
195 if (err) { debugf("InitOpenTransport failed %d", err); return(err); }
196
197 err = mDNS_Init(&m, &p, mDNS_Init_NoCache, mDNS_Init_ZeroCacheSize,
198 mDNS_Init_AdvertiseLocalAddresses, mDNS_Init_NoInitCallback, mDNS_Init_NoInitCallbackContext);
199 if (err) return(err);
200
201 while (!YieldSomeTime(35))
202 {
203 #if MDNS_ONLYSYSTEMTASK
204 // For debugging, use "#define MDNS_ONLYSYSTEMTASK 1" and call mDNSPlatformIdle() periodically.
205 // For shipping code, don't define MDNS_ONLYSYSTEMTASK, and you don't need to call mDNSPlatformIdle()
206 extern void mDNSPlatformIdle(mDNS *const m);
207 mDNSPlatformIdle(&m); // Only needed for debugging version
208 #endif
209 if (m.mDNSPlatformStatus == mStatus_NoError && !DoneSetup)
210 {
211 DoneSetup = true;
212 printf("\nListening for mDNS queries...\n");
213 mDNSResponderTestSetup(&m);
214 mDNSResponderSetAvail(&m, &availRec1, &p1);
215 availRec2Active = false;
216 nextAvail = mDNS_TimeNow(&m) + mDNSPlatformOneSecond * 10;
217 nextBusy = mDNS_TimeNow(&m) + mDNSPlatformOneSecond * 15;
218 }
219
220 if (DoneSetup)
221 {
222 // We check availRec2.RecordType because we don't want to re-register this record
223 // if the previous mDNS_Deregister() has not yet completed
224 if (mDNS_TimeNow(&m) - nextAvail > 0 && !availRec2Active)
225 {
226 printf("Setting Two now available\n");
227 availRec2Active = true;
228 mDNSResponderSetAvail(&m, &availRec2, &p2);
229 nextAvail = nextBusy + mDNSPlatformOneSecond * 10;
230 }
231 else if (mDNS_TimeNow(&m) - nextBusy > 0)
232 {
233 printf("Setting Two now busy\n");
234 mDNS_Deregister(&m, &availRec2);
235 nextBusy = nextAvail + mDNSPlatformOneSecond * 5;
236 }
237 }
238 }
239
240 if (p1.RR_SRV.resrec.RecordType) mDNS_DeregisterService(&m, &p1);
241 if (p2.RR_SRV.resrec.RecordType) mDNS_DeregisterService(&m, &p2);
242 if (availRec1.resrec.RecordType) mDNS_Deregister(&m, &availRec1);
243 if (availRec2Active) mDNS_Deregister(&m, &availRec2);
244
245 mDNS_Close(&m);
246
247 return(0);
248 }