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.21 2008/11/04 19:46:01 cheshire
21 Updated comment about MAX_ESCAPED_DOMAIN_NAME size (should be 1009, not 1005)
23 Revision 1.20 2007/07/27 19:30:41 cheshire
24 Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
25 to properly reflect tri-state nature of the possible responses
27 Revision 1.19 2007/04/16 20:49:39 cheshire
28 Fix compile errors for mDNSPosix build
30 Revision 1.18 2006/08/14 23:24:46 cheshire
31 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
33 Revision 1.17 2006/06/12 18:22:42 cheshire
34 <rdar://problem/4580067> mDNSResponder building warnings under Red Hat 64-bit (LP64) Linux
36 Revision 1.16 2005/02/04 01:00:53 cheshire
37 Add '-d' command-line option to specify domain to browse
39 Revision 1.15 2004/12/16 20:17:11 cheshire
40 <rdar://problem/3324626> Cache memory management improvements
42 Revision 1.14 2004/11/30 22:37:00 cheshire
43 Update copyright dates and add "Mode: C; tab-width: 4" headers
45 Revision 1.13 2004/10/19 21:33:20 cheshire
46 <rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
47 Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name
48 doesn't force multicast unless you set this flag to indicate explicitly that this is what you want
50 Revision 1.12 2004/09/17 01:08:53 cheshire
51 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
52 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
53 declared in that file are ONLY appropriate to single-address-space embedded applications.
54 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
56 Revision 1.11 2003/11/17 20:14:32 cheshire
57 Typo: Wrote "domC" where it should have said "domainC"
59 Revision 1.10 2003/11/14 21:27:09 cheshire
60 <rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
61 Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1009) instead of 256-byte buffers.
63 Revision 1.9 2003/08/14 02:19:55 cheshire
64 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
66 Revision 1.8 2003/08/12 19:56:26 cheshire
69 Revision 1.7 2003/07/02 21:19:58 cheshire
70 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
72 Revision 1.6 2003/06/18 05:48:41 cheshire
75 Revision 1.5 2003/05/06 00:00:50 cheshire
76 <rdar://problem/3248914> Rationalize naming of domainname manipulation functions
78 Revision 1.4 2002/12/23 22:13:31 jgraessl
80 Reviewed by: Stuart Cheshire
81 Initial IPv6 support for mDNSResponder.
83 Revision 1.3 2002/09/21 20:44:53 zarzycki
86 Revision 1.2 2002/09/19 04:20:44 cheshire
87 Remove high-ascii characters that confuse some systems
89 Revision 1.1 2002/09/17 06:24:35 cheshire
101 #include "mDNSEmbeddedAPI.h"// Defines the interface to the mDNS core code
102 #include "mDNSPosix.h" // Defines the specific types needed to run mDNS on this platform
103 #include "ExampleClientApp.h"
106 static mDNS mDNSStorage
; // mDNS core uses this to store its globals
107 static mDNS_PlatformSupport PlatformStorage
; // Stores this platform's globals
108 #define RR_CACHE_SIZE 500
109 static CacheEntity gRRCache
[RR_CACHE_SIZE
];
111 mDNSexport
const char ProgramName
[] = "mDNSClientPosix";
113 static const char *gProgramName
= ProgramName
;
115 static void BrowseCallback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
116 // A callback from the core mDNS code that indicates that we've received a
117 // response to our query. Note that this code runs on the main thread
118 // (in fact, there is only one thread!), so we can safely printf the results.
123 char nameC
[MAX_DOMAIN_LABEL
+1]; // Unescaped name: up to 63 bytes plus C-string terminating NULL.
124 char typeC
[MAX_ESCAPED_DOMAIN_NAME
];
125 char domainC
[MAX_ESCAPED_DOMAIN_NAME
];
129 (void)question
; // Unused
131 assert(answer
->rrtype
== kDNSType_PTR
);
133 DeconstructServiceName(&answer
->rdata
->u
.name
, &name
, &type
, &domain
);
135 ConvertDomainLabelToCString_unescaped(&name
, nameC
);
136 ConvertDomainNameToCString(&type
, typeC
);
137 ConvertDomainNameToCString(&domain
, domainC
);
139 // If the TTL has hit 0, the service is no longer available.
145 fprintf(stderr
, "*** %s name = '%s', type = '%s', domain = '%s'\n", state
, nameC
, typeC
, domainC
);
148 static mDNSBool
CheckThatServiceTypeIsUsable(const char *serviceType
, mDNSBool printExplanation
)
149 // Checks that serviceType is a reasonable service type
150 // label and, if it isn't and printExplanation is true, prints
151 // an explanation of why not.
156 if (result
&& strlen(serviceType
) > 63) {
157 if (printExplanation
) {
159 "%s: Service type specified by -t is too long (must be 63 characters or less)\n",
164 if (result
&& serviceType
[0] == 0) {
165 if (printExplanation
) {
167 "%s: Service type specified by -t can't be empty\n",
175 static const char kDefaultServiceType
[] = "_afpovertcp._tcp";
176 static const char kDefaultDomain
[] = "local.";
178 static void PrintUsage()
181 "Usage: %s [-v level] [-t type] [-d domain]\n",
183 fprintf(stderr
, " -v verbose mode, level is a number from 0 to 2\n");
184 fprintf(stderr
, " 0 = no debugging info (default)\n");
185 fprintf(stderr
, " 1 = standard debugging info\n");
186 fprintf(stderr
, " 2 = intense debugging info\n");
187 fprintf(stderr
, " -t uses 'type' as the service type (default is '%s')\n", kDefaultServiceType
);
188 fprintf(stderr
, " -d uses 'domain' as the domain to browse (default is '%s')\n", kDefaultDomain
);
191 static const char *gServiceType
= kDefaultServiceType
;
192 static const char *gServiceDomain
= kDefaultDomain
;
194 static void ParseArguments(int argc
, char **argv
)
195 // Parses our command line arguments into the global variables
200 // Set gProgramName to the last path component of argv[0]
202 gProgramName
= strrchr(argv
[0], '/');
203 if (gProgramName
== NULL
) {
204 gProgramName
= argv
[0];
209 // Parse command line options using getopt.
212 ch
= getopt(argc
, argv
, "v:t:d:");
216 gMDNSPlatformPosixVerboseLevel
= atoi(optarg
);
217 if (gMDNSPlatformPosixVerboseLevel
< 0 || gMDNSPlatformPosixVerboseLevel
> 2) {
219 "%s: Verbose mode must be in the range 0..2\n",
225 gServiceType
= optarg
;
226 if ( ! CheckThatServiceTypeIsUsable(gServiceType
, mDNStrue
) ) {
231 gServiceDomain
= optarg
;
242 // Check for any left over command line arguments.
244 if (optind
!= argc
) {
245 fprintf(stderr
, "%s: Unexpected argument '%s'\n", gProgramName
, argv
[optind
]);
250 int main(int argc
, char **argv
)
251 // The program's main entry point. The program does a trivial
252 // mDNS query, looking for all AFP servers in the local domain.
256 DNSQuestion question
;
260 // Parse our command line arguments. This won't come back if there's an error.
261 ParseArguments(argc
, argv
);
263 // Initialise the mDNS core.
264 status
= mDNS_Init(&mDNSStorage
, &PlatformStorage
,
265 gRRCache
, RR_CACHE_SIZE
,
266 mDNS_Init_DontAdvertiseLocalAddresses
,
267 mDNS_Init_NoInitCallback
, mDNS_Init_NoInitCallbackContext
);
268 if (status
== mStatus_NoError
) {
270 // Construct and start the query.
272 MakeDomainNameFromDNSNameString(&type
, gServiceType
);
273 MakeDomainNameFromDNSNameString(&domain
, gServiceDomain
);
275 status
= mDNS_StartBrowse(&mDNSStorage
, &question
, &type
, &domain
, mDNSInterface_Any
, mDNSfalse
, BrowseCallback
, NULL
);
277 // Run the platform main event loop until the user types ^C.
278 // The BrowseCallback routine is responsible for printing
279 // any results that we find.
281 if (status
== mStatus_NoError
) {
282 fprintf(stderr
, "Hit ^C when you're bored waiting for responses.\n");
283 ExampleClientEventLoop(&mDNSStorage
);
284 mDNS_StopQuery(&mDNSStorage
, &question
);
285 mDNS_Close(&mDNSStorage
);
289 if (status
== mStatus_NoError
) {
294 if ( (result
!= 0) || (gMDNSPlatformPosixVerboseLevel
> 0) ) {
295 fprintf(stderr
, "%s: Finished with status %d, result %d\n", gProgramName
, (int)status
, result
);