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