diff options
Diffstat (limited to 'mDNSResponder/mDNSPosix/Client.c')
-rwxr-xr-x | mDNSResponder/mDNSPosix/Client.c | 223 |
1 files changed, 223 insertions, 0 deletions
diff --git a/mDNSResponder/mDNSPosix/Client.c b/mDNSResponder/mDNSPosix/Client.c new file mode 100755 index 00000000..c0badf43 --- /dev/null +++ b/mDNSResponder/mDNSPosix/Client.c @@ -0,0 +1,223 @@ +/* -*- Mode: C; tab-width: 4 -*- + * + * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <assert.h> +#include <signal.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <stdlib.h> + +#include "mDNSEmbeddedAPI.h" // Defines the interface to the mDNS core code +#include "mDNSPosix.h" // Defines the specific types needed to run mDNS on this platform +#include "ExampleClientApp.h" + +// Globals +static mDNS mDNSStorage; // mDNS core uses this to store its globals +static mDNS_PlatformSupport PlatformStorage; // Stores this platform's globals +#define RR_CACHE_SIZE 500 +static CacheEntity gRRCache[RR_CACHE_SIZE]; + +mDNSexport const char ProgramName[] = "mDNSClientPosix"; + +static const char *gProgramName = ProgramName; + +static void BrowseCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord) +// A callback from the core mDNS code that indicates that we've received a +// response to our query. Note that this code runs on the main thread +// (in fact, there is only one thread!), so we can safely printf the results. +{ + domainlabel name; + domainname type; + domainname domain; + char nameC [MAX_DOMAIN_LABEL+1]; // Unescaped name: up to 63 bytes plus C-string terminating NULL. + char typeC [MAX_ESCAPED_DOMAIN_NAME]; + char domainC[MAX_ESCAPED_DOMAIN_NAME]; + const char *state; + + (void)m; // Unused + (void)question; // Unused + + assert(answer->rrtype == kDNSType_PTR); + + DeconstructServiceName(&answer->rdata->u.name, &name, &type, &domain); + + ConvertDomainLabelToCString_unescaped(&name, nameC); + ConvertDomainNameToCString(&type, typeC); + ConvertDomainNameToCString(&domain, domainC); + + // If the TTL has hit 0, the service is no longer available. + if (!AddRecord) { + state = "Lost "; + } else { + state = "Found"; + } + fprintf(stderr, "*** %s name = '%s', type = '%s', domain = '%s'\n", state, nameC, typeC, domainC); +} + +static mDNSBool CheckThatServiceTypeIsUsable(const char *serviceType, mDNSBool printExplanation) +// Checks that serviceType is a reasonable service type +// label and, if it isn't and printExplanation is true, prints +// an explanation of why not. +{ + mDNSBool result; + + result = mDNStrue; + if (result && strlen(serviceType) > 63) { + if (printExplanation) { + fprintf(stderr, + "%s: Service type specified by -t is too long (must be 63 characters or less)\n", + gProgramName); + } + result = mDNSfalse; + } + if (result && serviceType[0] == 0) { + if (printExplanation) { + fprintf(stderr, + "%s: Service type specified by -t can't be empty\n", + gProgramName); + } + result = mDNSfalse; + } + return result; +} + +static const char kDefaultServiceType[] = "_afpovertcp._tcp"; +static const char kDefaultDomain[] = "local."; + +static void PrintUsage() +{ + fprintf(stderr, + "Usage: %s [-v level] [-t type] [-d domain]\n", + gProgramName); + fprintf(stderr, " -v verbose mode, level is a number from 0 to 2\n"); + fprintf(stderr, " 0 = no debugging info (default)\n"); + fprintf(stderr, " 1 = standard debugging info\n"); + fprintf(stderr, " 2 = intense debugging info\n"); + fprintf(stderr, " -t uses 'type' as the service type (default is '%s')\n", kDefaultServiceType); + fprintf(stderr, " -d uses 'domain' as the domain to browse (default is '%s')\n", kDefaultDomain); +} + +static const char *gServiceType = kDefaultServiceType; +static const char *gServiceDomain = kDefaultDomain; + +static void ParseArguments(int argc, char **argv) +// Parses our command line arguments into the global variables +// listed above. +{ + int ch; + + // Set gProgramName to the last path component of argv[0] + + gProgramName = strrchr(argv[0], '/'); + if (gProgramName == NULL) { + gProgramName = argv[0]; + } else { + gProgramName += 1; + } + + // Parse command line options using getopt. + + do { + ch = getopt(argc, argv, "v:t:d:"); + if (ch != -1) { + switch (ch) { + case 'v': + gMDNSPlatformPosixVerboseLevel = atoi(optarg); + if (gMDNSPlatformPosixVerboseLevel < 0 || gMDNSPlatformPosixVerboseLevel > 2) { + fprintf(stderr, + "%s: Verbose mode must be in the range 0..2\n", + gProgramName); + exit(1); + } + break; + case 't': + gServiceType = optarg; + if ( !CheckThatServiceTypeIsUsable(gServiceType, mDNStrue) ) { + exit(1); + } + break; + case 'd': + gServiceDomain = optarg; + break; + case '?': + default: + PrintUsage(); + exit(1); + break; + } + } + } while (ch != -1); + + // Check for any left over command line arguments. + + if (optind != argc) { + fprintf(stderr, "%s: Unexpected argument '%s'\n", gProgramName, argv[optind]); + exit(1); + } +} + +int main(int argc, char **argv) +// The program's main entry point. The program does a trivial +// mDNS query, looking for all AFP servers in the local domain. +{ + int result; + mStatus status; + DNSQuestion question; + domainname type; + domainname domain; + + // Parse our command line arguments. This won't come back if there's an error. + ParseArguments(argc, argv); + + // Initialise the mDNS core. + status = mDNS_Init(&mDNSStorage, &PlatformStorage, + gRRCache, RR_CACHE_SIZE, + mDNS_Init_DontAdvertiseLocalAddresses, + mDNS_Init_NoInitCallback, mDNS_Init_NoInitCallbackContext); + if (status == mStatus_NoError) { + + // Construct and start the query. + + MakeDomainNameFromDNSNameString(&type, gServiceType); + MakeDomainNameFromDNSNameString(&domain, gServiceDomain); + + status = mDNS_StartBrowse(&mDNSStorage, &question, &type, &domain, mDNSNULL, mDNSInterface_Any, 0, mDNSfalse, mDNSfalse, BrowseCallback, NULL); + + // Run the platform main event loop until the user types ^C. + // The BrowseCallback routine is responsible for printing + // any results that we find. + + if (status == mStatus_NoError) { + fprintf(stderr, "Hit ^C when you're bored waiting for responses.\n"); + ExampleClientEventLoop(&mDNSStorage); + mDNS_StopQuery(&mDNSStorage, &question); + mDNS_Close(&mDNSStorage); + } + } + + if (status == mStatus_NoError) { + result = 0; + } else { + result = 2; + } + if ( (result != 0) || (gMDNSPlatformPosixVerboseLevel > 0) ) { + fprintf(stderr, "%s: Finished with status %d, result %d\n", gProgramName, (int)status, result); + } + + return 0; +} |