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