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