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