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