1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 Change History (most recent first):
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
24 Revision 1.19 2007/04/16 20:49:39 cheshire
25 Fix compile errors for mDNSPosix build
27 Revision 1.18 2006/08/14 23:24:46 cheshire
28 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
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
33 Revision 1.16 2005/02/04 01:00:53 cheshire
34 Add '-d' command-line option to specify domain to browse
36 Revision 1.15 2004/12/16 20:17:11 cheshire
37 <rdar://problem/3324626> Cache memory management improvements
39 Revision 1.14 2004/11/30 22:37:00 cheshire
40 Update copyright dates and add "Mode: C; tab-width: 4" headers
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
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.
53 Revision 1.11 2003/11/17 20:14:32 cheshire
54 Typo: Wrote "domC" where it should have said "domainC"
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.
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
63 Revision 1.8 2003/08/12 19:56:26 cheshire
66 Revision 1.7 2003/07/02 21:19:58 cheshire
67 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
69 Revision 1.6 2003/06/18 05:48:41 cheshire
72 Revision 1.5 2003/05/06 00:00:50 cheshire
73 <rdar://problem/3248914> Rationalize naming of domainname manipulation functions
75 Revision 1.4 2002/12/23 22:13:31 jgraessl
77 Reviewed by: Stuart Cheshire
78 Initial IPv6 support for mDNSResponder.
80 Revision 1.3 2002/09/21 20:44:53 zarzycki
83 Revision 1.2 2002/09/19 04:20:44 cheshire
84 Remove high-ascii characters that confuse some systems
86 Revision 1.1 2002/09/17 06:24:35 cheshire
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"
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
];
108 mDNSexport
const char ProgramName
[] = "mDNSClientPosix";
110 static const char *gProgramName
= ProgramName
;
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.
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
];
126 (void)question
; // Unused
128 assert(answer
->rrtype
== kDNSType_PTR
);
130 DeconstructServiceName(&answer
->rdata
->u
.name
, &name
, &type
, &domain
);
132 ConvertDomainLabelToCString_unescaped(&name
, nameC
);
133 ConvertDomainNameToCString(&type
, typeC
);
134 ConvertDomainNameToCString(&domain
, domainC
);
136 // If the TTL has hit 0, the service is no longer available.
142 fprintf(stderr
, "*** %s name = '%s', type = '%s', domain = '%s'\n", state
, nameC
, typeC
, domainC
);
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.
153 if (result
&& strlen(serviceType
) > 63) {
154 if (printExplanation
) {
156 "%s: Service type specified by -t is too long (must be 63 characters or less)\n",
161 if (result
&& serviceType
[0] == 0) {
162 if (printExplanation
) {
164 "%s: Service type specified by -t can't be empty\n",
172 static const char kDefaultServiceType
[] = "_afpovertcp._tcp";
173 static const char kDefaultDomain
[] = "local.";
175 static void PrintUsage()
178 "Usage: %s [-v level] [-t type] [-d domain]\n",
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
);
188 static const char *gServiceType
= kDefaultServiceType
;
189 static const char *gServiceDomain
= kDefaultDomain
;
191 static void ParseArguments(int argc
, char **argv
)
192 // Parses our command line arguments into the global variables
197 // Set gProgramName to the last path component of argv[0]
199 gProgramName
= strrchr(argv
[0], '/');
200 if (gProgramName
== NULL
) {
201 gProgramName
= argv
[0];
206 // Parse command line options using getopt.
209 ch
= getopt(argc
, argv
, "v:t:d:");
213 gMDNSPlatformPosixVerboseLevel
= atoi(optarg
);
214 if (gMDNSPlatformPosixVerboseLevel
< 0 || gMDNSPlatformPosixVerboseLevel
> 2) {
216 "%s: Verbose mode must be in the range 0..2\n",
222 gServiceType
= optarg
;
223 if ( ! CheckThatServiceTypeIsUsable(gServiceType
, mDNStrue
) ) {
228 gServiceDomain
= optarg
;
239 // Check for any left over command line arguments.
241 if (optind
!= argc
) {
242 fprintf(stderr
, "%s: Unexpected argument '%s'\n", gProgramName
, argv
[optind
]);
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.
253 DNSQuestion question
;
257 // Parse our command line arguments. This won't come back if there's an error.
258 ParseArguments(argc
, argv
);
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
) {
267 // Construct and start the query.
269 MakeDomainNameFromDNSNameString(&type
, gServiceType
);
270 MakeDomainNameFromDNSNameString(&domain
, gServiceDomain
);
272 status
= mDNS_StartBrowse(&mDNSStorage
, &question
, &type
, &domain
, mDNSInterface_Any
, mDNSfalse
, BrowseCallback
, NULL
);
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.
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
);
286 if (status
== mStatus_NoError
) {
291 if ( (result
!= 0) || (gMDNSPlatformPosixVerboseLevel
> 0) ) {
292 fprintf(stderr
, "%s: Finished with status %d, result %d\n", gProgramName
, (int)status
, result
);