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