xref: /aosp_15_r20/external/mdnsresponder/mDNSPosix/Client.c (revision 48a54d368dc4fa860885eef7b70b6c53499e7c25)
1*48a54d36SAndroid Build Coastguard Worker /* -*- Mode: C; tab-width: 4 -*-
2*48a54d36SAndroid Build Coastguard Worker  *
3*48a54d36SAndroid Build Coastguard Worker  * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
4*48a54d36SAndroid Build Coastguard Worker  *
5*48a54d36SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
6*48a54d36SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
7*48a54d36SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
8*48a54d36SAndroid Build Coastguard Worker  *
9*48a54d36SAndroid Build Coastguard Worker  *     http://www.apache.org/licenses/LICENSE-2.0
10*48a54d36SAndroid Build Coastguard Worker  *
11*48a54d36SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
12*48a54d36SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
13*48a54d36SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14*48a54d36SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
15*48a54d36SAndroid Build Coastguard Worker  * limitations under the License.
16*48a54d36SAndroid Build Coastguard Worker  */
17*48a54d36SAndroid Build Coastguard Worker 
18*48a54d36SAndroid Build Coastguard Worker #include <assert.h>
19*48a54d36SAndroid Build Coastguard Worker #include <signal.h>
20*48a54d36SAndroid Build Coastguard Worker #include <stdio.h>
21*48a54d36SAndroid Build Coastguard Worker #include <string.h>
22*48a54d36SAndroid Build Coastguard Worker #include <unistd.h>
23*48a54d36SAndroid Build Coastguard Worker #include <stdlib.h>
24*48a54d36SAndroid Build Coastguard Worker 
25*48a54d36SAndroid Build Coastguard Worker #include "mDNSEmbeddedAPI.h"// Defines the interface to the mDNS core code
26*48a54d36SAndroid Build Coastguard Worker #include "mDNSPosix.h"    // Defines the specific types needed to run mDNS on this platform
27*48a54d36SAndroid Build Coastguard Worker #include "ExampleClientApp.h"
28*48a54d36SAndroid Build Coastguard Worker 
29*48a54d36SAndroid Build Coastguard Worker // Globals
30*48a54d36SAndroid Build Coastguard Worker static mDNS mDNSStorage;       // mDNS core uses this to store its globals
31*48a54d36SAndroid Build Coastguard Worker static mDNS_PlatformSupport PlatformStorage;  // Stores this platform's globals
32*48a54d36SAndroid Build Coastguard Worker #define RR_CACHE_SIZE 500
33*48a54d36SAndroid Build Coastguard Worker static CacheEntity gRRCache[RR_CACHE_SIZE];
34*48a54d36SAndroid Build Coastguard Worker 
35*48a54d36SAndroid Build Coastguard Worker mDNSexport const char ProgramName[] = "mDNSClientPosix";
36*48a54d36SAndroid Build Coastguard Worker 
37*48a54d36SAndroid Build Coastguard Worker static const char *gProgramName = ProgramName;
38*48a54d36SAndroid Build Coastguard Worker 
BrowseCallback(mDNS * const m,DNSQuestion * question,const ResourceRecord * const answer,QC_result AddRecord)39*48a54d36SAndroid Build Coastguard Worker static void BrowseCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
40*48a54d36SAndroid Build Coastguard Worker     // A callback from the core mDNS code that indicates that we've received a
41*48a54d36SAndroid Build Coastguard Worker     // response to our query.  Note that this code runs on the main thread
42*48a54d36SAndroid Build Coastguard Worker     // (in fact, there is only one thread!), so we can safely printf the results.
43*48a54d36SAndroid Build Coastguard Worker {
44*48a54d36SAndroid Build Coastguard Worker     domainlabel name;
45*48a54d36SAndroid Build Coastguard Worker     domainname  type;
46*48a54d36SAndroid Build Coastguard Worker     domainname  domain;
47*48a54d36SAndroid Build Coastguard Worker 	char nameC  [MAX_DOMAIN_LABEL+1];			// Unescaped name: up to 63 bytes plus C-string terminating NULL.
48*48a54d36SAndroid Build Coastguard Worker 	char typeC  [MAX_ESCAPED_DOMAIN_NAME];
49*48a54d36SAndroid Build Coastguard Worker 	char domainC[MAX_ESCAPED_DOMAIN_NAME];
50*48a54d36SAndroid Build Coastguard Worker     const char *state;
51*48a54d36SAndroid Build Coastguard Worker 
52*48a54d36SAndroid Build Coastguard Worker 	(void)m;		// Unused
53*48a54d36SAndroid Build Coastguard Worker 	(void)question;	// Unused
54*48a54d36SAndroid Build Coastguard Worker 
55*48a54d36SAndroid Build Coastguard Worker     assert(answer->rrtype == kDNSType_PTR);
56*48a54d36SAndroid Build Coastguard Worker 
57*48a54d36SAndroid Build Coastguard Worker     DeconstructServiceName(&answer->rdata->u.name, &name, &type, &domain);
58*48a54d36SAndroid Build Coastguard Worker 
59*48a54d36SAndroid Build Coastguard Worker     ConvertDomainLabelToCString_unescaped(&name, nameC);
60*48a54d36SAndroid Build Coastguard Worker     ConvertDomainNameToCString(&type, typeC);
61*48a54d36SAndroid Build Coastguard Worker     ConvertDomainNameToCString(&domain, domainC);
62*48a54d36SAndroid Build Coastguard Worker 
63*48a54d36SAndroid Build Coastguard Worker     // If the TTL has hit 0, the service is no longer available.
64*48a54d36SAndroid Build Coastguard Worker     if (!AddRecord) {
65*48a54d36SAndroid Build Coastguard Worker         state = "Lost ";
66*48a54d36SAndroid Build Coastguard Worker     } else {
67*48a54d36SAndroid Build Coastguard Worker         state = "Found";
68*48a54d36SAndroid Build Coastguard Worker     }
69*48a54d36SAndroid Build Coastguard Worker     fprintf(stderr, "*** %s name = '%s', type = '%s', domain = '%s'\n", state, nameC, typeC, domainC);
70*48a54d36SAndroid Build Coastguard Worker }
71*48a54d36SAndroid Build Coastguard Worker 
CheckThatServiceTypeIsUsable(const char * serviceType,mDNSBool printExplanation)72*48a54d36SAndroid Build Coastguard Worker static mDNSBool CheckThatServiceTypeIsUsable(const char *serviceType, mDNSBool printExplanation)
73*48a54d36SAndroid Build Coastguard Worker     // Checks that serviceType is a reasonable service type
74*48a54d36SAndroid Build Coastguard Worker     // label and, if it isn't and printExplanation is true, prints
75*48a54d36SAndroid Build Coastguard Worker     // an explanation of why not.
76*48a54d36SAndroid Build Coastguard Worker {
77*48a54d36SAndroid Build Coastguard Worker     mDNSBool result;
78*48a54d36SAndroid Build Coastguard Worker 
79*48a54d36SAndroid Build Coastguard Worker     result = mDNStrue;
80*48a54d36SAndroid Build Coastguard Worker     if (result && strlen(serviceType) > 63) {
81*48a54d36SAndroid Build Coastguard Worker         if (printExplanation) {
82*48a54d36SAndroid Build Coastguard Worker             fprintf(stderr,
83*48a54d36SAndroid Build Coastguard Worker                     "%s: Service type specified by -t is too long (must be 63 characters or less)\n",
84*48a54d36SAndroid Build Coastguard Worker                     gProgramName);
85*48a54d36SAndroid Build Coastguard Worker         }
86*48a54d36SAndroid Build Coastguard Worker         result = mDNSfalse;
87*48a54d36SAndroid Build Coastguard Worker     }
88*48a54d36SAndroid Build Coastguard Worker     if (result && serviceType[0] == 0) {
89*48a54d36SAndroid Build Coastguard Worker         if (printExplanation) {
90*48a54d36SAndroid Build Coastguard Worker             fprintf(stderr,
91*48a54d36SAndroid Build Coastguard Worker                     "%s: Service type specified by -t can't be empty\n",
92*48a54d36SAndroid Build Coastguard Worker                     gProgramName);
93*48a54d36SAndroid Build Coastguard Worker         }
94*48a54d36SAndroid Build Coastguard Worker         result = mDNSfalse;
95*48a54d36SAndroid Build Coastguard Worker     }
96*48a54d36SAndroid Build Coastguard Worker     return result;
97*48a54d36SAndroid Build Coastguard Worker }
98*48a54d36SAndroid Build Coastguard Worker 
99*48a54d36SAndroid Build Coastguard Worker static const char kDefaultServiceType[] = "_afpovertcp._tcp";
100*48a54d36SAndroid Build Coastguard Worker static const char kDefaultDomain[]      = "local.";
101*48a54d36SAndroid Build Coastguard Worker 
PrintUsage()102*48a54d36SAndroid Build Coastguard Worker static void PrintUsage()
103*48a54d36SAndroid Build Coastguard Worker {
104*48a54d36SAndroid Build Coastguard Worker     fprintf(stderr,
105*48a54d36SAndroid Build Coastguard Worker             "Usage: %s [-v level] [-t type] [-d domain]\n",
106*48a54d36SAndroid Build Coastguard Worker             gProgramName);
107*48a54d36SAndroid Build Coastguard Worker     fprintf(stderr, "          -v verbose mode, level is a number from 0 to 2\n");
108*48a54d36SAndroid Build Coastguard Worker     fprintf(stderr, "             0 = no debugging info (default)\n");
109*48a54d36SAndroid Build Coastguard Worker     fprintf(stderr, "             1 = standard debugging info\n");
110*48a54d36SAndroid Build Coastguard Worker     fprintf(stderr, "             2 = intense debugging info\n");
111*48a54d36SAndroid Build Coastguard Worker     fprintf(stderr, "          -t uses 'type' as the service type (default is '%s')\n", kDefaultServiceType);
112*48a54d36SAndroid Build Coastguard Worker     fprintf(stderr, "          -d uses 'domain' as the domain to browse (default is '%s')\n", kDefaultDomain);
113*48a54d36SAndroid Build Coastguard Worker }
114*48a54d36SAndroid Build Coastguard Worker 
115*48a54d36SAndroid Build Coastguard Worker static const char *gServiceType      = kDefaultServiceType;
116*48a54d36SAndroid Build Coastguard Worker static const char *gServiceDomain    = kDefaultDomain;
117*48a54d36SAndroid Build Coastguard Worker 
ParseArguments(int argc,char ** argv)118*48a54d36SAndroid Build Coastguard Worker static void ParseArguments(int argc, char **argv)
119*48a54d36SAndroid Build Coastguard Worker     // Parses our command line arguments into the global variables
120*48a54d36SAndroid Build Coastguard Worker     // listed above.
121*48a54d36SAndroid Build Coastguard Worker {
122*48a54d36SAndroid Build Coastguard Worker     int ch;
123*48a54d36SAndroid Build Coastguard Worker 
124*48a54d36SAndroid Build Coastguard Worker     // Set gProgramName to the last path component of argv[0]
125*48a54d36SAndroid Build Coastguard Worker 
126*48a54d36SAndroid Build Coastguard Worker     gProgramName = strrchr(argv[0], '/');
127*48a54d36SAndroid Build Coastguard Worker     if (gProgramName == NULL) {
128*48a54d36SAndroid Build Coastguard Worker         gProgramName = argv[0];
129*48a54d36SAndroid Build Coastguard Worker     } else {
130*48a54d36SAndroid Build Coastguard Worker         gProgramName += 1;
131*48a54d36SAndroid Build Coastguard Worker     }
132*48a54d36SAndroid Build Coastguard Worker 
133*48a54d36SAndroid Build Coastguard Worker     // Parse command line options using getopt.
134*48a54d36SAndroid Build Coastguard Worker 
135*48a54d36SAndroid Build Coastguard Worker     do {
136*48a54d36SAndroid Build Coastguard Worker         ch = getopt(argc, argv, "v:t:d:");
137*48a54d36SAndroid Build Coastguard Worker         if (ch != -1) {
138*48a54d36SAndroid Build Coastguard Worker             switch (ch) {
139*48a54d36SAndroid Build Coastguard Worker                 case 'v':
140*48a54d36SAndroid Build Coastguard Worker                     gMDNSPlatformPosixVerboseLevel = atoi(optarg);
141*48a54d36SAndroid Build Coastguard Worker                     if (gMDNSPlatformPosixVerboseLevel < 0 || gMDNSPlatformPosixVerboseLevel > 2) {
142*48a54d36SAndroid Build Coastguard Worker                         fprintf(stderr,
143*48a54d36SAndroid Build Coastguard Worker                                 "%s: Verbose mode must be in the range 0..2\n",
144*48a54d36SAndroid Build Coastguard Worker                                 gProgramName);
145*48a54d36SAndroid Build Coastguard Worker                         exit(1);
146*48a54d36SAndroid Build Coastguard Worker                     }
147*48a54d36SAndroid Build Coastguard Worker                     break;
148*48a54d36SAndroid Build Coastguard Worker                 case 't':
149*48a54d36SAndroid Build Coastguard Worker                     gServiceType = optarg;
150*48a54d36SAndroid Build Coastguard Worker                     if ( ! CheckThatServiceTypeIsUsable(gServiceType, mDNStrue) ) {
151*48a54d36SAndroid Build Coastguard Worker                         exit(1);
152*48a54d36SAndroid Build Coastguard Worker                     }
153*48a54d36SAndroid Build Coastguard Worker                     break;
154*48a54d36SAndroid Build Coastguard Worker                 case 'd':
155*48a54d36SAndroid Build Coastguard Worker                     gServiceDomain = optarg;
156*48a54d36SAndroid Build Coastguard Worker                     break;
157*48a54d36SAndroid Build Coastguard Worker                 case '?':
158*48a54d36SAndroid Build Coastguard Worker                 default:
159*48a54d36SAndroid Build Coastguard Worker                     PrintUsage();
160*48a54d36SAndroid Build Coastguard Worker                     exit(1);
161*48a54d36SAndroid Build Coastguard Worker                     break;
162*48a54d36SAndroid Build Coastguard Worker             }
163*48a54d36SAndroid Build Coastguard Worker         }
164*48a54d36SAndroid Build Coastguard Worker     } while (ch != -1);
165*48a54d36SAndroid Build Coastguard Worker 
166*48a54d36SAndroid Build Coastguard Worker     // Check for any left over command line arguments.
167*48a54d36SAndroid Build Coastguard Worker 
168*48a54d36SAndroid Build Coastguard Worker     if (optind != argc) {
169*48a54d36SAndroid Build Coastguard Worker         fprintf(stderr, "%s: Unexpected argument '%s'\n", gProgramName, argv[optind]);
170*48a54d36SAndroid Build Coastguard Worker         exit(1);
171*48a54d36SAndroid Build Coastguard Worker     }
172*48a54d36SAndroid Build Coastguard Worker }
173*48a54d36SAndroid Build Coastguard Worker 
main(int argc,char ** argv)174*48a54d36SAndroid Build Coastguard Worker int main(int argc, char **argv)
175*48a54d36SAndroid Build Coastguard Worker     // The program's main entry point.  The program does a trivial
176*48a54d36SAndroid Build Coastguard Worker     // mDNS query, looking for all AFP servers in the local domain.
177*48a54d36SAndroid Build Coastguard Worker {
178*48a54d36SAndroid Build Coastguard Worker     int     result;
179*48a54d36SAndroid Build Coastguard Worker     mStatus     status;
180*48a54d36SAndroid Build Coastguard Worker     DNSQuestion question;
181*48a54d36SAndroid Build Coastguard Worker     domainname  type;
182*48a54d36SAndroid Build Coastguard Worker     domainname  domain;
183*48a54d36SAndroid Build Coastguard Worker 
184*48a54d36SAndroid Build Coastguard Worker     // Parse our command line arguments.  This won't come back if there's an error.
185*48a54d36SAndroid Build Coastguard Worker     ParseArguments(argc, argv);
186*48a54d36SAndroid Build Coastguard Worker 
187*48a54d36SAndroid Build Coastguard Worker     // Initialise the mDNS core.
188*48a54d36SAndroid Build Coastguard Worker 	status = mDNS_Init(&mDNSStorage, &PlatformStorage,
189*48a54d36SAndroid Build Coastguard Worker     	gRRCache, RR_CACHE_SIZE,
190*48a54d36SAndroid Build Coastguard Worker     	mDNS_Init_DontAdvertiseLocalAddresses,
191*48a54d36SAndroid Build Coastguard Worker     	mDNS_Init_NoInitCallback, mDNS_Init_NoInitCallbackContext);
192*48a54d36SAndroid Build Coastguard Worker     if (status == mStatus_NoError) {
193*48a54d36SAndroid Build Coastguard Worker 
194*48a54d36SAndroid Build Coastguard Worker         // Construct and start the query.
195*48a54d36SAndroid Build Coastguard Worker 
196*48a54d36SAndroid Build Coastguard Worker         MakeDomainNameFromDNSNameString(&type, gServiceType);
197*48a54d36SAndroid Build Coastguard Worker         MakeDomainNameFromDNSNameString(&domain, gServiceDomain);
198*48a54d36SAndroid Build Coastguard Worker 
199*48a54d36SAndroid Build Coastguard Worker         status = mDNS_StartBrowse(&mDNSStorage, &question, &type, &domain, mDNSInterface_Any, mDNSfalse, BrowseCallback, NULL);
200*48a54d36SAndroid Build Coastguard Worker 
201*48a54d36SAndroid Build Coastguard Worker         // Run the platform main event loop until the user types ^C.
202*48a54d36SAndroid Build Coastguard Worker         // The BrowseCallback routine is responsible for printing
203*48a54d36SAndroid Build Coastguard Worker         // any results that we find.
204*48a54d36SAndroid Build Coastguard Worker 
205*48a54d36SAndroid Build Coastguard Worker         if (status == mStatus_NoError) {
206*48a54d36SAndroid Build Coastguard Worker             fprintf(stderr, "Hit ^C when you're bored waiting for responses.\n");
207*48a54d36SAndroid Build Coastguard Worker         	ExampleClientEventLoop(&mDNSStorage);
208*48a54d36SAndroid Build Coastguard Worker             mDNS_StopQuery(&mDNSStorage, &question);
209*48a54d36SAndroid Build Coastguard Worker 			mDNS_Close(&mDNSStorage);
210*48a54d36SAndroid Build Coastguard Worker         }
211*48a54d36SAndroid Build Coastguard Worker     }
212*48a54d36SAndroid Build Coastguard Worker 
213*48a54d36SAndroid Build Coastguard Worker     if (status == mStatus_NoError) {
214*48a54d36SAndroid Build Coastguard Worker         result = 0;
215*48a54d36SAndroid Build Coastguard Worker     } else {
216*48a54d36SAndroid Build Coastguard Worker         result = 2;
217*48a54d36SAndroid Build Coastguard Worker     }
218*48a54d36SAndroid Build Coastguard Worker     if ( (result != 0) || (gMDNSPlatformPosixVerboseLevel > 0) ) {
219*48a54d36SAndroid Build Coastguard Worker         fprintf(stderr, "%s: Finished with status %d, result %d\n", gProgramName, (int)status, result);
220*48a54d36SAndroid Build Coastguard Worker     }
221*48a54d36SAndroid Build Coastguard Worker 
222*48a54d36SAndroid Build Coastguard Worker     return 0;
223*48a54d36SAndroid Build Coastguard Worker }
224