]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSPosix/Client.c
mDNSResponder-108.2.tar.gz
[apple/mdnsresponder.git] / mDNSPosix / Client.c
1 /* -*- Mode: C; tab-width: 4 -*-
2 *
3 * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
4 *
5 * @APPLE_LICENSE_HEADER_START@
6 *
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
12 * file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23
24 Change History (most recent first):
25
26 $Log: Client.c,v $
27 Revision 1.16 2005/02/04 01:00:53 cheshire
28 Add '-d' command-line option to specify domain to browse
29
30 Revision 1.15 2004/12/16 20:17:11 cheshire
31 <rdar://problem/3324626> Cache memory management improvements
32
33 Revision 1.14 2004/11/30 22:37:00 cheshire
34 Update copyright dates and add "Mode: C; tab-width: 4" headers
35
36 Revision 1.13 2004/10/19 21:33:20 cheshire
37 <rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
38 Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name
39 doesn't force multicast unless you set this flag to indicate explicitly that this is what you want
40
41 Revision 1.12 2004/09/17 01:08:53 cheshire
42 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
43 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
44 declared in that file are ONLY appropriate to single-address-space embedded applications.
45 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
46
47 Revision 1.11 2003/11/17 20:14:32 cheshire
48 Typo: Wrote "domC" where it should have said "domainC"
49
50 Revision 1.10 2003/11/14 21:27:09 cheshire
51 <rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
52 Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers.
53
54 Revision 1.9 2003/08/14 02:19:55 cheshire
55 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
56
57 Revision 1.8 2003/08/12 19:56:26 cheshire
58 Update to APSL 2.0
59
60 Revision 1.7 2003/07/02 21:19:58 cheshire
61 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
62
63 Revision 1.6 2003/06/18 05:48:41 cheshire
64 Fix warnings
65
66 Revision 1.5 2003/05/06 00:00:50 cheshire
67 <rdar://problem/3248914> Rationalize naming of domainname manipulation functions
68
69 Revision 1.4 2002/12/23 22:13:31 jgraessl
70
71 Reviewed by: Stuart Cheshire
72 Initial IPv6 support for mDNSResponder.
73
74 Revision 1.3 2002/09/21 20:44:53 zarzycki
75 Added APSL info
76
77 Revision 1.2 2002/09/19 04:20:44 cheshire
78 Remove high-ascii characters that confuse some systems
79
80 Revision 1.1 2002/09/17 06:24:35 cheshire
81 First checkin
82
83 */
84
85 #include <assert.h>
86 #include <signal.h>
87 #include <stdio.h>
88 #include <string.h>
89 #include <unistd.h>
90 #include <stdlib.h>
91
92 #include "mDNSEmbeddedAPI.h"// Defines the interface to the mDNS core code
93 #include "mDNSPosix.h" // Defines the specific types needed to run mDNS on this platform
94 #include "ExampleClientApp.h"
95
96 // Globals
97 static mDNS mDNSStorage; // mDNS core uses this to store its globals
98 static mDNS_PlatformSupport PlatformStorage; // Stores this platform's globals
99 #define RR_CACHE_SIZE 500
100 static CacheEntity gRRCache[RR_CACHE_SIZE];
101
102 static const char *gProgramName = "mDNSResponderPosix";
103
104 static void BrowseCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
105 // A callback from the core mDNS code that indicates that we've received a
106 // response to our query. Note that this code runs on the main thread
107 // (in fact, there is only one thread!), so we can safely printf the results.
108 {
109 domainlabel name;
110 domainname type;
111 domainname domain;
112 char nameC [MAX_DOMAIN_LABEL+1]; // Unescaped name: up to 63 bytes plus C-string terminating NULL.
113 char typeC [MAX_ESCAPED_DOMAIN_NAME];
114 char domainC[MAX_ESCAPED_DOMAIN_NAME];
115 const char *state;
116
117 (void)m; // Unused
118 (void)question; // Unused
119
120 assert(answer->rrtype == kDNSType_PTR);
121
122 DeconstructServiceName(&answer->rdata->u.name, &name, &type, &domain);
123
124 ConvertDomainLabelToCString_unescaped(&name, nameC);
125 ConvertDomainNameToCString(&type, typeC);
126 ConvertDomainNameToCString(&domain, domainC);
127
128 // If the TTL has hit 0, the service is no longer available.
129 if (!AddRecord) {
130 state = "Lost ";
131 } else {
132 state = "Found";
133 }
134 fprintf(stderr, "*** %s name = '%s', type = '%s', domain = '%s'\n", state, nameC, typeC, domainC);
135 }
136
137 static mDNSBool CheckThatServiceTypeIsUsable(const char *serviceType, mDNSBool printExplanation)
138 // Checks that serviceType is a reasonable service type
139 // label and, if it isn't and printExplanation is true, prints
140 // an explanation of why not.
141 {
142 mDNSBool result;
143
144 result = mDNStrue;
145 if (result && strlen(serviceType) > 63) {
146 if (printExplanation) {
147 fprintf(stderr,
148 "%s: Service type specified by -t is too long (must be 63 characters or less)\n",
149 gProgramName);
150 }
151 result = mDNSfalse;
152 }
153 if (result && serviceType[0] == 0) {
154 if (printExplanation) {
155 fprintf(stderr,
156 "%s: Service type specified by -t can't be empty\n",
157 gProgramName);
158 }
159 result = mDNSfalse;
160 }
161 return result;
162 }
163
164 static const char kDefaultServiceType[] = "_afpovertcp._tcp";
165 static const char kDefaultDomain[] = "local.";
166
167 static void PrintUsage()
168 {
169 fprintf(stderr,
170 "Usage: %s [-v level] [-t type] [-d domain]\n",
171 gProgramName);
172 fprintf(stderr, " -v verbose mode, level is a number from 0 to 2\n");
173 fprintf(stderr, " 0 = no debugging info (default)\n");
174 fprintf(stderr, " 1 = standard debugging info\n");
175 fprintf(stderr, " 2 = intense debugging info\n");
176 fprintf(stderr, " -t uses 'type' as the service type (default is '%s')\n", kDefaultServiceType);
177 fprintf(stderr, " -d uses 'domain' as the domain to browse (default is '%s')\n", kDefaultDomain);
178 }
179
180 static const char *gServiceType = kDefaultServiceType;
181 static const char *gServiceDomain = kDefaultDomain;
182
183 static void ParseArguments(int argc, char **argv)
184 // Parses our command line arguments into the global variables
185 // listed above.
186 {
187 int ch;
188
189 // Set gProgramName to the last path component of argv[0]
190
191 gProgramName = strrchr(argv[0], '/');
192 if (gProgramName == NULL) {
193 gProgramName = argv[0];
194 } else {
195 gProgramName += 1;
196 }
197
198 // Parse command line options using getopt.
199
200 do {
201 ch = getopt(argc, argv, "v:t:d:");
202 if (ch != -1) {
203 switch (ch) {
204 case 'v':
205 gMDNSPlatformPosixVerboseLevel = atoi(optarg);
206 if (gMDNSPlatformPosixVerboseLevel < 0 || gMDNSPlatformPosixVerboseLevel > 2) {
207 fprintf(stderr,
208 "%s: Verbose mode must be in the range 0..2\n",
209 gProgramName);
210 exit(1);
211 }
212 break;
213 case 't':
214 gServiceType = optarg;
215 if ( ! CheckThatServiceTypeIsUsable(gServiceType, mDNStrue) ) {
216 exit(1);
217 }
218 break;
219 case 'd':
220 gServiceDomain = optarg;
221 break;
222 case '?':
223 default:
224 PrintUsage();
225 exit(1);
226 break;
227 }
228 }
229 } while (ch != -1);
230
231 // Check for any left over command line arguments.
232
233 if (optind != argc) {
234 fprintf(stderr, "%s: Unexpected argument '%s'\n", gProgramName, argv[optind]);
235 exit(1);
236 }
237 }
238
239 int main(int argc, char **argv)
240 // The program's main entry point. The program does a trivial
241 // mDNS query, looking for all AFP servers in the local domain.
242 {
243 int result;
244 mStatus status;
245 DNSQuestion question;
246 domainname type;
247 domainname domain;
248
249 // Parse our command line arguments. This won't come back if there's an error.
250 ParseArguments(argc, argv);
251
252 // Initialise the mDNS core.
253 status = mDNS_Init(&mDNSStorage, &PlatformStorage,
254 gRRCache, RR_CACHE_SIZE,
255 mDNS_Init_DontAdvertiseLocalAddresses,
256 mDNS_Init_NoInitCallback, mDNS_Init_NoInitCallbackContext);
257 if (status == mStatus_NoError) {
258
259 // Construct and start the query.
260
261 MakeDomainNameFromDNSNameString(&type, gServiceType);
262 MakeDomainNameFromDNSNameString(&domain, gServiceDomain);
263
264 status = mDNS_StartBrowse(&mDNSStorage, &question, &type, &domain, mDNSInterface_Any, mDNSfalse, BrowseCallback, NULL);
265
266 // Run the platform main event loop until the user types ^C.
267 // The BrowseCallback routine is responsible for printing
268 // any results that we find.
269
270 if (status == mStatus_NoError) {
271 fprintf(stderr, "Hit ^C when you're bored waiting for responses.\n");
272 ExampleClientEventLoop(&mDNSStorage);
273 mDNS_StopQuery(&mDNSStorage, &question);
274 mDNS_Close(&mDNSStorage);
275 }
276 }
277
278 if (status == mStatus_NoError) {
279 result = 0;
280 } else {
281 result = 2;
282 }
283 if ( (result != 0) || (gMDNSPlatformPosixVerboseLevel > 0) ) {
284 fprintf(stderr, "%s: Finished with status %ld, result %d\n", gProgramName, status, result);
285 }
286
287 return 0;
288 }