]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOS9/Searcher.c
0e880c9bc7d7fd27a15b2475ac4b45c30a7913bf
[apple/mdnsresponder.git] / mDNSMacOS9 / Searcher.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: Searcher.c,v $
20 Revision 1.3 2006/08/14 23:24:29 cheshire
21 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
22
23 Revision 1.2 2004/05/27 06:30:21 cheshire
24 Add code to test DNSServiceQueryRecord()
25
26 Revision 1.1 2004/03/12 21:30:25 cheshire
27 Build a System-Context Shared Library from mDNSCore, for the benefit of developers
28 like Muse Research who want to be able to use mDNS/DNS-SD from GPL-licensed code.
29
30 */
31
32 #include <stdio.h> // For printf()
33 #include <string.h> // For strcpy()
34
35 #include <Events.h> // For WaitNextEvent()
36 #include <CodeFragments.h> // For SIOkUnresolvedCFragSymbolAddress
37
38 #include <SIOUX.h> // For SIOUXHandleOneEvent()
39
40 #include <OpenTransport.h>
41 #include <OpenTptInternet.h>
42
43 #include "dns_sd.h"
44
45 #define ns_c_in 1
46 #define ns_t_a 1
47
48 typedef union { UInt8 b[2]; UInt16 NotAnInteger; } mDNSOpaque16;
49 static UInt16 mDNSVal16(mDNSOpaque16 x) { return((UInt16)(x.b[0]<<8 | x.b[1])); }
50 static mDNSOpaque16 mDNSOpaque16fromIntVal(UInt16 v)
51 { mDNSOpaque16 x; x.b[0] = (UInt8)(v >> 8); x.b[1] = (UInt8)(v & 0xFF); return(x); }
52
53 typedef struct
54 {
55 OTLIFO serviceinfolist;
56 Boolean headerPrinted;
57 Boolean lostRecords;
58 } SearcherServices;
59
60 typedef struct
61 {
62 SearcherServices *services;
63 char name[kDNSServiceMaxDomainName];
64 char type[kDNSServiceMaxDomainName];
65 char domn[kDNSServiceMaxDomainName];
66 char host[kDNSServiceMaxDomainName];
67 char text[kDNSServiceMaxDomainName];
68 InetHost address;
69 mDNSOpaque16 notAnIntPort;
70 DNSServiceRef sdRef;
71 Boolean add;
72 Boolean dom;
73 OTLink link;
74 } linkedServiceInfo;
75
76 static SearcherServices services;
77
78 // PrintServiceInfo prints the service information to standard out
79 // A real application might want to do something else with the information
80 static void PrintServiceInfo(SearcherServices *services)
81 {
82 OTLink *link = OTReverseList(OTLIFOStealList(&services->serviceinfolist));
83
84 while (link)
85 {
86 linkedServiceInfo *s = OTGetLinkObject(link, linkedServiceInfo, link);
87
88 if (!services->headerPrinted)
89 {
90 printf("%-55s Type Domain Target Host IP Address Port Info\n", "Name");
91 services->headerPrinted = true;
92 }
93
94 if (s->dom)
95 {
96 if (s->add) printf("%-55s available for browsing\n", s->domn);
97 else printf("%-55s no longer available for browsing\n", s->domn);
98 }
99 else
100 {
101 char ip[16];
102 unsigned char *p = (unsigned char *)&s->address;
103 sprintf(ip, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
104 printf("%-55s %-16s %-14s ", s->name, s->type, s->domn);
105 if (s->add) printf("%-15s %-15s %5d %s\n", s->host, ip, mDNSVal16(s->notAnIntPort), s->text);
106 else printf("Removed\n");
107 }
108
109 link = link->fNext;
110 OTFreeMem(s);
111 }
112 }
113
114 static void FoundInstanceAddress(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode,
115 const char *fullname, uint16_t rrtype, uint16_t rrclass, uint16_t rdlen, const void *rdata, uint32_t ttl, void *context)
116 {
117 linkedServiceInfo *info = (linkedServiceInfo *)context;
118 SearcherServices *services = info->services;
119 (void)sdRef; // Unused
120 (void)interfaceIndex; // Unused
121 (void)fullname; // Unused
122 (void)ttl; // Unused
123 if (errorCode == kDNSServiceErr_NoError)
124 if (flags & kDNSServiceFlagsAdd)
125 if (rrclass == ns_c_in && rrtype == ns_t_a && rdlen == sizeof(info->address))
126 {
127 memcpy(&info->address, rdata, sizeof(info->address));
128 DNSServiceRefDeallocate(info->sdRef);
129 OTLIFOEnqueue(&services->serviceinfolist, &info->link);
130 }
131 }
132
133 static void FoundInstanceInfo(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex,
134 DNSServiceErrorType errorCode, const char *fullname, const char *hosttarget, uint16_t notAnIntPort,
135 uint16_t txtLen, const char *txtRecord, void *context)
136 {
137 linkedServiceInfo *info = (linkedServiceInfo *)context;
138 SearcherServices *services = info->services;
139 (void)sdRef; // Unused
140 (void)flags; // Unused
141 (void)interfaceIndex; // Unused
142 (void)errorCode; // Unused
143 (void)fullname; // Unused
144 strcpy(info->host, hosttarget);
145 if (txtLen == 0) info->text[0] = 0;
146 else
147 {
148 strncpy(info->text, txtRecord+1, txtRecord[0]);
149 info->text[txtRecord[0]] = 0;
150 }
151 info->notAnIntPort.NotAnInteger = notAnIntPort;
152 DNSServiceRefDeallocate(info->sdRef);
153 DNSServiceQueryRecord(&info->sdRef, 0, 0, info->host, ns_t_a, ns_c_in, FoundInstanceAddress, info);
154 }
155
156 // When a new named instance of a service is found, FoundInstance() is called.
157 // In this sample code we turn around and immediately to a DNSServiceResolve() to resolve that service name
158 // to find its target host, port, and txtinfo, but a normal browing application would just display the name.
159 // Resolving every single thing you find can be quite hard on the network, so you shouldn't do this
160 // in a real application. Defer resolving until the client has picked which instance from the
161 // long list of services is the one they want to use, and then resolve only that one.
162 static void FoundInstance(DNSServiceRef client, DNSServiceFlags flags, uint32_t interface, DNSServiceErrorType errorCode,
163 const char *replyName, const char *replyType, const char *replyDomain, void *context)
164 {
165 #pragma unused(client, interface, errorCode)
166 SearcherServices *services = (SearcherServices *)context;
167 linkedServiceInfo *info;
168
169 if (!services) { DebugStr("\pFoundInstance: services is NULL"); return; }
170
171 info = (linkedServiceInfo *)OTAllocMem(sizeof(linkedServiceInfo));
172 if (!info) { services->lostRecords = true; return; }
173
174 info->services = services;
175 strcpy(info->name, replyName);
176 strcpy(info->type, replyType);
177 strcpy(info->domn, replyDomain);
178 info->text[0] = 0;
179 info->add = (flags & kDNSServiceFlagsAdd) ? true : false;
180 info->dom = false;
181
182 if (!info->add) // If TTL == 0 we're deleting a service,
183 OTLIFOEnqueue(&services->serviceinfolist, &info->link);
184 else // else we're adding a new service
185 DNSServiceResolve(&info->sdRef, 0, 0, info->name, info->type, info->domn, FoundInstanceInfo, info);
186 }
187
188 // YieldSomeTime() just cooperatively yields some time to other processes running on classic Mac OS
189 static Boolean YieldSomeTime(UInt32 milliseconds)
190 {
191 extern Boolean SIOUXQuitting;
192 EventRecord e;
193 WaitNextEvent(everyEvent, &e, milliseconds / 17, NULL);
194 SIOUXHandleOneEvent(&e);
195 return(SIOUXQuitting);
196 }
197
198 int main()
199 {
200 OSStatus err;
201 void *tempmem;
202 DNSServiceRef sdRef;
203 DNSServiceErrorType dse;
204
205 SIOUXSettings.asktosaveonclose = false;
206 SIOUXSettings.userwindowtitle = "\pMulticast DNS Searcher";
207 SIOUXSettings.rows = 40;
208 SIOUXSettings.columns = 160;
209
210 printf("DNS-SD Search Client\n\n");
211 printf("This software reports errors using MacsBug breaks,\n");
212 printf("so if you don't have MacsBug installed your Mac may crash.\n\n");
213 printf("******************************************************************************\n\n");
214
215 if (DNSServiceBrowse == (void*)kUnresolvedCFragSymbolAddress)
216 {
217 printf("Before you can use mDNS/DNS-SD clients, you need to place the \n");
218 printf("\"Multicast DNS & DNS-SD\" Extension in the Extensions Folder and restart\n");
219 return(-1);
220 }
221
222 err = InitOpenTransport();
223 if (err) { printf("InitOpenTransport failed %d", err); return(err); }
224
225 // Make sure OT has a large enough memory pool for us to draw from at OTNotifier (interrupt) time
226 tempmem = OTAllocMem(0x10000);
227 if (tempmem) OTFreeMem(tempmem);
228 else printf("**** Warning: OTAllocMem couldn't pre-allocate 64K for us.\n");
229
230 services.serviceinfolist.fHead = NULL;
231 services.headerPrinted = false;
232 services.lostRecords = false;
233
234 printf("Sending mDNS service lookup queries and waiting for responses...\n\n");
235 dse = DNSServiceBrowse(&sdRef, 0, 0, "_http._tcp", "", FoundInstance, &services);
236 if (dse == kDNSServiceErr_NoError)
237 {
238 while (!YieldSomeTime(35))
239 {
240 if (services.serviceinfolist.fHead)
241 PrintServiceInfo(&services);
242
243 if (services.lostRecords)
244 {
245 services.lostRecords = false;
246 printf("**** Warning: Out of memory: Records have been missed.\n");
247 }
248 }
249 }
250
251 DNSServiceRefDeallocate(sdRef);
252 CloseOpenTransport();
253 return(0);
254 }