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.18 2006/08/14 23:24:46 cheshire
21 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
23 Revision 1.17 2006/06/12 18:22:42 cheshire
24 <rdar://problem/4580067> mDNSResponder building warnings under Red Hat 64-bit (LP64) Linux
26 Revision 1.16 2005/02/04 01:00:53 cheshire
27 Add '-d' command-line option to specify domain to browse
29 Revision 1.15 2004/12/16 20:17:11 cheshire
30 <rdar://problem/3324626> Cache memory management improvements
32 Revision 1.14 2004/11/30 22:37:00 cheshire
33 Update copyright dates and add "Mode: C; tab-width: 4" headers
35 Revision 1.13 2004/10/19 21:33:20 cheshire
36 <rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
37 Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name
38 doesn't force multicast unless you set this flag to indicate explicitly that this is what you want
40 Revision 1.12 2004/09/17 01:08:53 cheshire
41 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
42 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
43 declared in that file are ONLY appropriate to single-address-space embedded applications.
44 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
46 Revision 1.11 2003/11/17 20:14:32 cheshire
47 Typo: Wrote "domC" where it should have said "domainC"
49 Revision 1.10 2003/11/14 21:27:09 cheshire
50 <rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
51 Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers.
53 Revision 1.9 2003/08/14 02:19:55 cheshire
54 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
56 Revision 1.8 2003/08/12 19:56:26 cheshire
59 Revision 1.7 2003/07/02 21:19:58 cheshire
60 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
62 Revision 1.6 2003/06/18 05:48:41 cheshire
65 Revision 1.5 2003/05/06 00:00:50 cheshire
66 <rdar://problem/3248914> Rationalize naming of domainname manipulation functions
68 Revision 1.4 2002/12/23 22:13:31 jgraessl
70 Reviewed by: Stuart Cheshire
71 Initial IPv6 support for mDNSResponder.
73 Revision 1.3 2002/09/21 20:44:53 zarzycki
76 Revision 1.2 2002/09/19 04:20:44 cheshire
77 Remove high-ascii characters that confuse some systems
79 Revision 1.1 2002/09/17 06:24:35 cheshire
91 #include "mDNSEmbeddedAPI.h"// Defines the interface to the mDNS core code
92 #include "mDNSPosix.h" // Defines the specific types needed to run mDNS on this platform
93 #include "ExampleClientApp.h"
96 static mDNS mDNSStorage
; // mDNS core uses this to store its globals
97 static mDNS_PlatformSupport PlatformStorage
; // Stores this platform's globals
98 #define RR_CACHE_SIZE 500
99 static CacheEntity gRRCache
[RR_CACHE_SIZE
];
101 static const char *gProgramName
= "mDNSResponderPosix";
103 static void BrowseCallback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
104 // A callback from the core mDNS code that indicates that we've received a
105 // response to our query. Note that this code runs on the main thread
106 // (in fact, there is only one thread!), so we can safely printf the results.
111 char nameC
[MAX_DOMAIN_LABEL
+1]; // Unescaped name: up to 63 bytes plus C-string terminating NULL.
112 char typeC
[MAX_ESCAPED_DOMAIN_NAME
];
113 char domainC
[MAX_ESCAPED_DOMAIN_NAME
];
117 (void)question
; // Unused
119 assert(answer
->rrtype
== kDNSType_PTR
);
121 DeconstructServiceName(&answer
->rdata
->u
.name
, &name
, &type
, &domain
);
123 ConvertDomainLabelToCString_unescaped(&name
, nameC
);
124 ConvertDomainNameToCString(&type
, typeC
);
125 ConvertDomainNameToCString(&domain
, domainC
);
127 // If the TTL has hit 0, the service is no longer available.
133 fprintf(stderr
, "*** %s name = '%s', type = '%s', domain = '%s'\n", state
, nameC
, typeC
, domainC
);
136 static mDNSBool
CheckThatServiceTypeIsUsable(const char *serviceType
, mDNSBool printExplanation
)
137 // Checks that serviceType is a reasonable service type
138 // label and, if it isn't and printExplanation is true, prints
139 // an explanation of why not.
144 if (result
&& strlen(serviceType
) > 63) {
145 if (printExplanation
) {
147 "%s: Service type specified by -t is too long (must be 63 characters or less)\n",
152 if (result
&& serviceType
[0] == 0) {
153 if (printExplanation
) {
155 "%s: Service type specified by -t can't be empty\n",
163 static const char kDefaultServiceType
[] = "_afpovertcp._tcp";
164 static const char kDefaultDomain
[] = "local.";
166 static void PrintUsage()
169 "Usage: %s [-v level] [-t type] [-d domain]\n",
171 fprintf(stderr
, " -v verbose mode, level is a number from 0 to 2\n");
172 fprintf(stderr
, " 0 = no debugging info (default)\n");
173 fprintf(stderr
, " 1 = standard debugging info\n");
174 fprintf(stderr
, " 2 = intense debugging info\n");
175 fprintf(stderr
, " -t uses 'type' as the service type (default is '%s')\n", kDefaultServiceType
);
176 fprintf(stderr
, " -d uses 'domain' as the domain to browse (default is '%s')\n", kDefaultDomain
);
179 static const char *gServiceType
= kDefaultServiceType
;
180 static const char *gServiceDomain
= kDefaultDomain
;
182 static void ParseArguments(int argc
, char **argv
)
183 // Parses our command line arguments into the global variables
188 // Set gProgramName to the last path component of argv[0]
190 gProgramName
= strrchr(argv
[0], '/');
191 if (gProgramName
== NULL
) {
192 gProgramName
= argv
[0];
197 // Parse command line options using getopt.
200 ch
= getopt(argc
, argv
, "v:t:d:");
204 gMDNSPlatformPosixVerboseLevel
= atoi(optarg
);
205 if (gMDNSPlatformPosixVerboseLevel
< 0 || gMDNSPlatformPosixVerboseLevel
> 2) {
207 "%s: Verbose mode must be in the range 0..2\n",
213 gServiceType
= optarg
;
214 if ( ! CheckThatServiceTypeIsUsable(gServiceType
, mDNStrue
) ) {
219 gServiceDomain
= optarg
;
230 // Check for any left over command line arguments.
232 if (optind
!= argc
) {
233 fprintf(stderr
, "%s: Unexpected argument '%s'\n", gProgramName
, argv
[optind
]);
238 int main(int argc
, char **argv
)
239 // The program's main entry point. The program does a trivial
240 // mDNS query, looking for all AFP servers in the local domain.
244 DNSQuestion question
;
248 // Parse our command line arguments. This won't come back if there's an error.
249 ParseArguments(argc
, argv
);
251 // Initialise the mDNS core.
252 status
= mDNS_Init(&mDNSStorage
, &PlatformStorage
,
253 gRRCache
, RR_CACHE_SIZE
,
254 mDNS_Init_DontAdvertiseLocalAddresses
,
255 mDNS_Init_NoInitCallback
, mDNS_Init_NoInitCallbackContext
);
256 if (status
== mStatus_NoError
) {
258 // Construct and start the query.
260 MakeDomainNameFromDNSNameString(&type
, gServiceType
);
261 MakeDomainNameFromDNSNameString(&domain
, gServiceDomain
);
263 status
= mDNS_StartBrowse(&mDNSStorage
, &question
, &type
, &domain
, mDNSInterface_Any
, mDNSfalse
, BrowseCallback
, NULL
);
265 // Run the platform main event loop until the user types ^C.
266 // The BrowseCallback routine is responsible for printing
267 // any results that we find.
269 if (status
== mStatus_NoError
) {
270 fprintf(stderr
, "Hit ^C when you're bored waiting for responses.\n");
271 ExampleClientEventLoop(&mDNSStorage
);
272 mDNS_StopQuery(&mDNSStorage
, &question
);
273 mDNS_Close(&mDNSStorage
);
277 if (status
== mStatus_NoError
) {
282 if ( (result
!= 0) || (gMDNSPlatformPosixVerboseLevel
> 0) ) {
283 fprintf(stderr
, "%s: Finished with status %d, result %d\n", gProgramName
, (int)status
, result
);