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