/* * Copyright (c) 1999-2006 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ #include #include #include #include #include #include #include #include #include #include "showmount.h" struct cbinfo { DNSServiceRef sdref; CFSocketRef sockref; CFRunLoopSourceRef rls; }; struct cbinfo nfsinfo, mountdinfo; /* * CFRunloop callback that calls DNSServiceProcessResult() when * there's new data on the socket. */ static void socket_callback(CFSocketRef s, CFSocketCallBackType callbackType, CFDataRef address, const void *data, void *context) { struct cbinfo *info = context; DNSServiceErrorType err; if (callbackType == kCFSocketNoCallBack) { printf("socket_callback: kCFSocketNoCallBack?\n"); return; } if ((err = DNSServiceProcessResult(info->sdref)) != kDNSServiceErr_NoError) { printf("DNSServiceProcessResult() returned an error! %d\n", err); if (err == kDNSServiceErr_BadReference) { printf("bad reference?: %p, %d, %p, %p %p\n", s, (int)callbackType, address, data, context); return; } if ((context == &nfsinfo) || (context == &mountdinfo)) { /* bail if there's a problem with the main browse connection */ exit(1); } /* dump the troublesome service connection */ CFRunLoopRemoveSource(CFRunLoopGetCurrent(), info->rls, kCFRunLoopDefaultMode); CFRelease(info->rls); CFSocketInvalidate(info->sockref); CFRelease(info->sockref); DNSServiceRefDeallocate(info->sdref); free(info); } } static void resolve_callback( DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *fullName, const char *hostTarget, uint16_t port, uint16_t txtLen, const unsigned char *txtRecord, void *context) { struct cbinfo *info = context; #ifdef DEBUG const char *p; char *q, *s; int len; printf("resolve: %s %s:%d TXT %d\n", fullName, hostTarget, port, txtLen); if ((txtLen > 1) && ((s = malloc(txtLen+2)))) { p = txtRecord; q = s; len = txtLen; while (len > 0) { strncpy(q, p+1, *p); len -= *p + 1; q += *p; p += *p + 1; } *q = '\0'; printf(" %s\n", s); free(s); } #endif do_print(hostTarget); CFRunLoopRemoveSource(CFRunLoopGetCurrent(), info->rls, kCFRunLoopDefaultMode); CFRelease(info->rls); CFSocketInvalidate(info->sockref); CFRelease(info->sockref); DNSServiceRefDeallocate(info->sdref); free(info); } /* * Handle newly-discovered services */ static void browser_callback( DNSServiceRef sdRef, DNSServiceFlags servFlags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *serviceName, const char *regType, const char *replyDomain, void *context) { DNSServiceErrorType err; CFSocketContext ctx = { 0, NULL, NULL, NULL, NULL }; struct cbinfo *info; if (errorCode != kDNSServiceErr_NoError) { printf("DNS service discovery error: %d\n", errorCode); return; } #ifdef DEBUG printf("browse: %s: %s, %s, %s\n", (servFlags & kDNSServiceFlagsAdd) ? "new" : "gone", serviceName, regType, replyDomain); #endif if (!(servFlags & kDNSServiceFlagsAdd)) return; info = malloc(sizeof(*info)); if (!info) { printf("browse: out of memeory\n"); return; } err = DNSServiceResolve(&info->sdref, servFlags, interfaceIndex, serviceName, regType, replyDomain, resolve_callback, info); if (err != kDNSServiceErr_NoError) { printf("DNSServiceResolve failed: %d\n", err); free(info); return; } ctx.info = (void*)info; info->sockref = CFSocketCreateWithNative(kCFAllocatorDefault, DNSServiceRefSockFD(info->sdref), kCFSocketReadCallBack, socket_callback, &ctx); if (!info->sockref) { printf("CFSocketCreateWithNative failed\n"); DNSServiceRefDeallocate(info->sdref); free(info); return; } info->rls = CFSocketCreateRunLoopSource(kCFAllocatorDefault, info->sockref, 1); CFRunLoopAddSource(CFRunLoopGetCurrent(), info->rls, kCFRunLoopDefaultMode); } int browse(void) { DNSServiceErrorType err; CFSocketContext ctx = { 0, NULL, NULL, NULL, NULL }; err = DNSServiceBrowse(&nfsinfo.sdref, 0, 0, "_nfs._tcp", NULL, browser_callback, NULL); if (err != kDNSServiceErr_NoError) return (1); ctx.info = (void*)&nfsinfo; nfsinfo.sockref = CFSocketCreateWithNative(kCFAllocatorDefault, DNSServiceRefSockFD(nfsinfo.sdref), kCFSocketReadCallBack, socket_callback, &ctx); if (!nfsinfo.sockref) return (1); nfsinfo.rls = CFSocketCreateRunLoopSource(kCFAllocatorDefault, nfsinfo.sockref, 1); CFRunLoopAddSource(CFRunLoopGetCurrent(), nfsinfo.rls, kCFRunLoopDefaultMode); /* For backwards compatibility, browse for "mountd" services too */ err = DNSServiceBrowse(&mountdinfo.sdref, 0, 0, "_mountd._tcp", NULL, browser_callback, NULL); if (err != kDNSServiceErr_NoError) return (1); ctx.info = (void*)&mountdinfo; mountdinfo.sockref = CFSocketCreateWithNative(kCFAllocatorDefault, DNSServiceRefSockFD(mountdinfo.sdref), kCFSocketReadCallBack, socket_callback, &ctx); if (!mountdinfo.sockref) return (1); mountdinfo.rls = CFSocketCreateRunLoopSource(kCFAllocatorDefault, mountdinfo.sockref, 1); CFRunLoopAddSource(CFRunLoopGetCurrent(), mountdinfo.rls, kCFRunLoopDefaultMode); CFRunLoopRun(); CFRelease(nfsinfo.rls); CFSocketInvalidate(nfsinfo.sockref); CFRelease(nfsinfo.sockref); DNSServiceRefDeallocate(nfsinfo.sdref); CFRelease(mountdinfo.rls); CFSocketInvalidate(mountdinfo.sockref); CFRelease(mountdinfo.sockref); DNSServiceRefDeallocate(mountdinfo.sdref); return (0); }