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