PortMapper/MYDNSService.m
author Jens Alfke <jens@mooseyard.com>
Fri Apr 24 10:10:32 2009 -0700 (2009-04-24)
changeset 27 92581f26073e
child 28 732576fa8a0d
permissions -rw-r--r--
* Refactored MYPortMapper to use a new abstract base class MYDNSService; that way I can re-use it later for implementing Bonjour.
* Fixed issue #1: a memory leak in BLIPProperties, reported by codechemist.
     1 //
     2 //  MYDNSService.m
     3 //  MYNetwork
     4 //
     5 //  Created by Jens Alfke on 4/23/09.
     6 //  Copyright 2009 Jens Alfke. All rights reserved.
     7 //
     8 
     9 #import "MYDNSService.h"
    10 #import "CollectionUtils.h"
    11 #import "Logging.h"
    12 #import "Test.h"
    13 #import "ExceptionUtils.h"
    14 
    15 #import <dns_sd.h>
    16 
    17 
    18 static void serviceCallback(CFSocketRef s, 
    19                             CFSocketCallBackType type,
    20                             CFDataRef address,
    21                             const void *data,
    22                             void *clientCallBackInfo);
    23 
    24 
    25 @implementation MYDNSService
    26 
    27 
    28 - (void) dealloc
    29 {
    30     if( _serviceRef )
    31         [self stopService];
    32     [super dealloc];
    33 }
    34 
    35 - (void) finalize
    36 {
    37     if( _serviceRef )
    38         [self stopService];
    39     [super finalize];
    40 }
    41 
    42 
    43 @synthesize serviceRef=_serviceRef, error=_error;
    44 
    45 
    46 - (DNSServiceRef) createServiceRef {
    47     AssertAbstractMethod();
    48 }
    49 
    50 
    51 - (BOOL) open
    52 {
    53     if (_serviceRef)
    54         return YES;
    55     _serviceRef = [self createServiceRef];
    56     if (_serviceRef) {
    57         // Wrap a CFSocket around the service's socket:
    58         CFSocketContext ctxt = { 0, self, CFRetain, CFRelease, NULL };
    59         _socket = CFSocketCreateWithNative(NULL, 
    60                                            DNSServiceRefSockFD(_serviceRef), 
    61                                            kCFSocketReadCallBack, 
    62                                            &serviceCallback, &ctxt);
    63         if( _socket ) {
    64             CFSocketSetSocketFlags(_socket, CFSocketGetSocketFlags(_socket) & ~kCFSocketCloseOnInvalidate);
    65             // Attach the socket to the runloop so the serviceCallback will be invoked:
    66             _socketSource = CFSocketCreateRunLoopSource(NULL, _socket, 0);
    67             if( _socketSource ) {
    68                 CFRunLoopAddSource(CFRunLoopGetCurrent(), _socketSource, kCFRunLoopCommonModes);
    69                 LogTo(DNS,@"Opening %@",self);
    70                 return YES; // success
    71             }
    72         }
    73     }
    74     if (!_error)
    75         self.error = kDNSServiceErr_Unknown;
    76     LogTo(DNS,@"Failed to open %@ -- err=%i",self,_error);
    77     [self stopService];
    78     return NO;
    79 }
    80 
    81 
    82 - (void) stopService
    83 {
    84     if( _socketSource ) {
    85         CFRunLoopSourceInvalidate(_socketSource);
    86         CFRelease(_socketSource);
    87         _socketSource = NULL;
    88     }
    89     if( _socket ) {
    90         CFSocketInvalidate(_socket);
    91         CFRelease(_socket);
    92         _socket = NULL;
    93     }
    94     if( _serviceRef ) {
    95         LogTo(DNS,@"Stopped %@",self);
    96         DNSServiceRefDeallocate(_serviceRef);
    97         _serviceRef = NULL;
    98     }
    99 }
   100 
   101 
   102 - (void) close
   103 {
   104     [self stopService];
   105     if (_error)
   106         self.error = 0;
   107 }
   108 
   109 
   110 /** CFSocket callback, informing us that _socket has data available, which means
   111     that the DNS service has an incoming result to be processed. This will end up invoking
   112     the service's specific callback. */
   113 static void serviceCallback(CFSocketRef s, 
   114                             CFSocketCallBackType type,
   115                             CFDataRef address, const void *data, void *clientCallBackInfo)
   116 {
   117     MYDNSService *serviceObj = (MYDNSService*)clientCallBackInfo;
   118     DNSServiceRef service = serviceObj.serviceRef;
   119     DNSServiceErrorType err = DNSServiceProcessResult(service);
   120     if( err ) {
   121         // An error here means the socket has failed and should be closed.
   122         serviceObj.error = err;
   123         [serviceObj stopService];
   124     }
   125 }
   126 
   127 
   128 @end
   129 
   130 
   131 /*
   132  Copyright (c) 2008-2009, Jens Alfke <jens@mooseyard.com>. All rights reserved.
   133  
   134  Redistribution and use in source and binary forms, with or without modification, are permitted
   135  provided that the following conditions are met:
   136  
   137  * Redistributions of source code must retain the above copyright notice, this list of conditions
   138  and the following disclaimer.
   139  * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
   140  and the following disclaimer in the documentation and/or other materials provided with the
   141  distribution.
   142  
   143  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   144  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   145  FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   146  BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   147  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   148   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   149  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   150  THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   151  */