1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
22 * @APPLE_LICENSE_HEADER_END@
24 Change History (most recent first):
27 Revision 1.15 2004/12/16 20:17:11 cheshire
28 <rdar://problem/3324626> Cache memory management improvements
30 Revision 1.14 2004/11/30 22:37:00 cheshire
31 Update copyright dates and add "Mode: C; tab-width: 4" headers
33 Revision 1.13 2004/10/19 21:33:20 cheshire
34 <rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
35 Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name
36 doesn't force multicast unless you set this flag to indicate explicitly that this is what you want
38 Revision 1.12 2004/09/17 01:08:53 cheshire
39 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
40 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
41 declared in that file are ONLY appropriate to single-address-space embedded applications.
42 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
44 Revision 1.11 2003/11/17 20:14:32 cheshire
45 Typo: Wrote "domC" where it should have said "domainC"
47 Revision 1.10 2003/11/14 21:27:09 cheshire
48 <rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
49 Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers.
51 Revision 1.9 2003/08/14 02:19:55 cheshire
52 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
54 Revision 1.8 2003/08/12 19:56:26 cheshire
57 Revision 1.7 2003/07/02 21:19:58 cheshire
58 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
60 Revision 1.6 2003/06/18 05:48:41 cheshire
63 Revision 1.5 2003/05/06 00:00:50 cheshire
64 <rdar://problem/3248914> Rationalize naming of domainname manipulation functions
66 Revision 1.4 2002/12/23 22:13:31 jgraessl
68 Reviewed by: Stuart Cheshire
69 Initial IPv6 support for mDNSResponder.
71 Revision 1.3 2002/09/21 20:44:53 zarzycki
74 Revision 1.2 2002/09/19 04:20:44 cheshire
75 Remove high-ascii characters that confuse some systems
77 Revision 1.1 2002/09/17 06:24:35 cheshire
89 #include "mDNSEmbeddedAPI.h"// Defines the interface to the mDNS core code
90 #include "mDNSPosix.h" // Defines the specific types needed to run mDNS on this platform
91 #include "ExampleClientApp.h"
94 static mDNS mDNSStorage
; // mDNS core uses this to store its globals
95 static mDNS_PlatformSupport PlatformStorage
; // Stores this platform's globals
96 #define RR_CACHE_SIZE 500
97 static CacheEntity gRRCache
[RR_CACHE_SIZE
];
99 static const char *gProgramName
= "mDNSResponderPosix";
101 static void BrowseCallback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
102 // A callback from the core mDNS code that indicates that we've received a
103 // response to our query. Note that this code runs on the main thread
104 // (in fact, there is only one thread!), so we can safely printf the results.
109 char nameC
[MAX_DOMAIN_LABEL
+1]; // Unescaped name: up to 63 bytes plus C-string terminating NULL.
110 char typeC
[MAX_ESCAPED_DOMAIN_NAME
];
111 char domainC
[MAX_ESCAPED_DOMAIN_NAME
];
115 (void)question
; // Unused
117 assert(answer
->rrtype
== kDNSType_PTR
);
119 DeconstructServiceName(&answer
->rdata
->u
.name
, &name
, &type
, &domain
);
121 ConvertDomainLabelToCString_unescaped(&name
, nameC
);
122 ConvertDomainNameToCString(&type
, typeC
);
123 ConvertDomainNameToCString(&domain
, domainC
);
125 // If the TTL has hit 0, the service is no longer available.
131 fprintf(stderr
, "*** %s name = '%s', type = '%s', domain = '%s'\n", state
, nameC
, typeC
, domainC
);
134 static mDNSBool
CheckThatServiceTypeIsUsable(const char *serviceType
, mDNSBool printExplanation
)
135 // Checks that serviceType is a reasonable service type
136 // label and, if it isn't and printExplanation is true, prints
137 // an explanation of why not.
142 if (result
&& strlen(serviceType
) > 63) {
143 if (printExplanation
) {
145 "%s: Service type specified by -t is too long (must be 63 characters or less)\n",
150 if (result
&& serviceType
[0] == 0) {
151 if (printExplanation
) {
153 "%s: Service type specified by -t can't be empty\n",
161 static const char kDefaultServiceType
[] = "_afpovertcp._tcp.";
163 static void PrintUsage()
166 "Usage: %s [-v level] [-t type]\n",
168 fprintf(stderr
, " -v verbose mode, level is a number from 0 to 2\n");
169 fprintf(stderr
, " 0 = no debugging info (default)\n");
170 fprintf(stderr
, " 1 = standard debugging info\n");
171 fprintf(stderr
, " 2 = intense debugging info\n");
172 fprintf(stderr
, " -t uses 'type' as the service type (default is '%s')\n", kDefaultServiceType
);
175 static const char *gServiceType
= kDefaultServiceType
;
177 static void ParseArguments(int argc
, char **argv
)
178 // Parses our command line arguments into the global variables
183 // Set gProgramName to the last path component of argv[0]
185 gProgramName
= strrchr(argv
[0], '/');
186 if (gProgramName
== NULL
) {
187 gProgramName
= argv
[0];
192 // Parse command line options using getopt.
195 ch
= getopt(argc
, argv
, "v:t:");
199 gMDNSPlatformPosixVerboseLevel
= atoi(optarg
);
200 if (gMDNSPlatformPosixVerboseLevel
< 0 || gMDNSPlatformPosixVerboseLevel
> 2) {
202 "%s: Verbose mode must be in the range 0..2\n",
208 gServiceType
= optarg
;
209 if ( ! CheckThatServiceTypeIsUsable(gServiceType
, mDNStrue
) ) {
222 // Check for any left over command line arguments.
224 if (optind
!= argc
) {
225 fprintf(stderr
, "%s: Unexpected argument '%s'\n", gProgramName
, argv
[optind
]);
230 int main(int argc
, char **argv
)
231 // The program's main entry point. The program does a trivial
232 // mDNS query, looking for all AFP servers in the local domain.
236 DNSQuestion question
;
240 // Parse our command line arguments. This won't come back if there's an error.
241 ParseArguments(argc
, argv
);
243 // Initialise the mDNS core.
244 status
= mDNS_Init(&mDNSStorage
, &PlatformStorage
,
245 gRRCache
, RR_CACHE_SIZE
,
246 mDNS_Init_DontAdvertiseLocalAddresses
,
247 mDNS_Init_NoInitCallback
, mDNS_Init_NoInitCallbackContext
);
248 if (status
== mStatus_NoError
) {
250 // Construct and start the query.
252 MakeDomainNameFromDNSNameString(&type
, gServiceType
);
253 MakeDomainNameFromDNSNameString(&domain
, "local.");
255 status
= mDNS_StartBrowse(&mDNSStorage
, &question
, &type
, &domain
, mDNSInterface_Any
, mDNSfalse
, BrowseCallback
, NULL
);
257 // Run the platform main event loop until the user types ^C.
258 // The BrowseCallback routine is responsible for printing
259 // any results that we find.
261 if (status
== mStatus_NoError
) {
262 fprintf(stderr
, "Hit ^C when you're bored waiting for responses.\n");
263 ExampleClientEventLoop(&mDNSStorage
);
264 mDNS_StopQuery(&mDNSStorage
, &question
);
265 mDNS_Close(&mDNSStorage
);
269 if (status
== mStatus_NoError
) {
274 if ( (result
!= 0) || (gMDNSPlatformPosixVerboseLevel
> 0) ) {
275 fprintf(stderr
, "%s: Finished with status %ld, result %d\n", gProgramName
, status
, result
);