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