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.
24 #include <sys/socket.h>
26 #include "mDNSEmbeddedAPI.h" // Defines the interface to the mDNS core code
27 #include "mDNSPosix.h" // Defines the specific types needed to run mDNS on this platform
28 #include "ExampleClientApp.h"
31 mDNSexport mDNS mDNSStorage
; // mDNS core uses this to store its globals
32 static mDNS_PlatformSupport PlatformStorage
; // Stores this platform's globals
33 #define RR_CACHE_SIZE 500
34 static CacheEntity gRRCache
[RR_CACHE_SIZE
];
36 mDNSexport
const char ProgramName
[] = "mDNSClientPosix";
38 static const char *gProgramName
= ProgramName
;
40 static void BrowseCallback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
41 // A callback from the core mDNS code that indicates that we've received a
42 // response to our query. Note that this code runs on the main thread
43 // (in fact, there is only one thread!), so we can safely printf the results.
48 char nameC
[MAX_DOMAIN_LABEL
+1]; // Unescaped name: up to 63 bytes plus C-string terminating NULL.
49 char typeC
[MAX_ESCAPED_DOMAIN_NAME
];
50 char domainC
[MAX_ESCAPED_DOMAIN_NAME
];
54 (void)question
; // Unused
56 assert(answer
->rrtype
== kDNSType_PTR
);
58 DeconstructServiceName(&answer
->rdata
->u
.name
, &name
, &type
, &domain
);
60 ConvertDomainLabelToCString_unescaped(&name
, nameC
);
61 ConvertDomainNameToCString(&type
, typeC
);
62 ConvertDomainNameToCString(&domain
, domainC
);
64 // If the TTL has hit 0, the service is no longer available.
70 fprintf(stderr
, "*** %s name = '%s', type = '%s', domain = '%s'\n", state
, nameC
, typeC
, domainC
);
73 static mDNSBool
CheckThatServiceTypeIsUsable(const char *serviceType
, mDNSBool printExplanation
)
74 // Checks that serviceType is a reasonable service type
75 // label and, if it isn't and printExplanation is true, prints
76 // an explanation of why not.
81 if (result
&& strlen(serviceType
) > 63) {
82 if (printExplanation
) {
84 "%s: Service type specified by -t is too long (must be 63 characters or less)\n",
89 if (result
&& serviceType
[0] == 0) {
90 if (printExplanation
) {
92 "%s: Service type specified by -t can't be empty\n",
100 static const char kDefaultServiceType
[] = "_afpovertcp._tcp";
101 static const char kDefaultDomain
[] = "local.";
103 static void PrintUsage()
106 "Usage: %s [-v level] [-t type] [-d domain]\n",
108 fprintf(stderr
, " -v verbose mode, level is a number from 0 to 2\n");
109 fprintf(stderr
, " 0 = no debugging info (default)\n");
110 fprintf(stderr
, " 1 = standard debugging info\n");
111 fprintf(stderr
, " 2 = intense debugging info\n");
112 fprintf(stderr
, " -t uses 'type' as the service type (default is '%s')\n", kDefaultServiceType
);
113 fprintf(stderr
, " -d uses 'domain' as the domain to browse (default is '%s')\n", kDefaultDomain
);
116 static const char *gServiceType
= kDefaultServiceType
;
117 static const char *gServiceDomain
= kDefaultDomain
;
119 static void ParseArguments(int argc
, char **argv
)
120 // Parses our command line arguments into the global variables
125 // Set gProgramName to the last path component of argv[0]
127 gProgramName
= strrchr(argv
[0], '/');
128 if (gProgramName
== NULL
) {
129 gProgramName
= argv
[0];
134 // Parse command line options using getopt.
137 ch
= getopt(argc
, argv
, "v:t:d:");
141 gMDNSPlatformPosixVerboseLevel
= atoi(optarg
);
142 if (gMDNSPlatformPosixVerboseLevel
< 0 || gMDNSPlatformPosixVerboseLevel
> 2) {
144 "%s: Verbose mode must be in the range 0..2\n",
150 gServiceType
= optarg
;
151 if ( !CheckThatServiceTypeIsUsable(gServiceType
, mDNStrue
) ) {
156 gServiceDomain
= optarg
;
167 // Check for any left over command line arguments.
169 if (optind
!= argc
) {
170 fprintf(stderr
, "%s: Unexpected argument '%s'\n", gProgramName
, argv
[optind
]);
175 int main(int argc
, char **argv
)
176 // The program's main entry point. The program does a trivial
177 // mDNS query, looking for all AFP servers in the local domain.
181 DNSQuestion question
;
185 // Parse our command line arguments. This won't come back if there's an error.
186 ParseArguments(argc
, argv
);
188 // Initialise the mDNS core.
189 status
= mDNS_Init(&mDNSStorage
, &PlatformStorage
,
190 gRRCache
, RR_CACHE_SIZE
,
191 mDNS_Init_DontAdvertiseLocalAddresses
,
192 mDNS_Init_NoInitCallback
, mDNS_Init_NoInitCallbackContext
);
193 if (status
== mStatus_NoError
) {
195 // Construct and start the query.
197 MakeDomainNameFromDNSNameString(&type
, gServiceType
);
198 MakeDomainNameFromDNSNameString(&domain
, gServiceDomain
);
200 status
= mDNS_StartBrowse(&mDNSStorage
, &question
, &type
, &domain
, mDNSInterface_Any
, 0, mDNSfalse
, mDNSfalse
, BrowseCallback
, NULL
);
202 // Run the platform main event loop until the user types ^C.
203 // The BrowseCallback routine is responsible for printing
204 // any results that we find.
206 if (status
== mStatus_NoError
) {
207 fprintf(stderr
, "Hit ^C when you're bored waiting for responses.\n");
208 ExampleClientEventLoop(&mDNSStorage
);
209 mDNS_StopQuery(&mDNSStorage
, &question
);
210 mDNS_Close(&mDNSStorage
);
214 if (status
== mStatus_NoError
) {
219 if ( (result
!= 0) || (gMDNSPlatformPosixVerboseLevel
> 0) ) {
220 fprintf(stderr
, "%s: Finished with status %d, result %d\n", gProgramName
, (int)status
, result
);