* Refactored MYPortMapper to use a new abstract base class MYDNSService; that way I can re-use it later for implementing Bonjour.
authorJens Alfke <jens@mooseyard.com>
Fri Apr 24 10:10:32 2009 -0700 (2009-04-24)
changeset 2792581f26073e
parent 26 cb9cdf247239
child 28 732576fa8a0d
child 30 096cf03b65d4
* 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.
BLIP/BLIPProperties.m
MYNetwork.xcodeproj/project.pbxproj
PortMapper/MYDNSService.h
PortMapper/MYDNSService.m
PortMapper/MYPortMapper.h
PortMapper/MYPortMapper.m
maindocs.h
     1.1 --- a/BLIP/BLIPProperties.m	Wed Apr 22 16:45:39 2009 -0700
     1.2 +++ b/BLIP/BLIPProperties.m	Fri Apr 24 10:10:32 2009 -0700
     1.3 @@ -228,7 +228,7 @@
     1.4  
     1.5  + (BLIPProperties*) properties
     1.6  {
     1.7 -    return [[self alloc] initWithDictionary: nil];
     1.8 +    return [[[self alloc] initWithDictionary: nil] autorelease];
     1.9  }
    1.10  
    1.11  - (id) init
     2.1 --- a/MYNetwork.xcodeproj/project.pbxproj	Wed Apr 22 16:45:39 2009 -0700
     2.2 +++ b/MYNetwork.xcodeproj/project.pbxproj	Fri Apr 24 10:10:32 2009 -0700
     2.3 @@ -30,6 +30,9 @@
     2.4  		277905240DE9E5BC00C6D295 /* BLIPEchoServer.m in Sources */ = {isa = PBXBuildFile; fileRef = 277903D60DE8EE4800C6D295 /* BLIPEchoServer.m */; };
     2.5  		277905300DE9ED9100C6D295 /* MYUtilitiesTest_main.m in Sources */ = {isa = PBXBuildFile; fileRef = 270462C10DE4A64B003D9D3F /* MYUtilitiesTest_main.m */; };
     2.6  		2779053B0DE9EDAA00C6D295 /* BLIPTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 270460FE0DE49030003D9D3F /* BLIPTest.m */; };
     2.7 +		2780F20C0FA194BD00C0FB83 /* MYDNSService.h in Headers */ = {isa = PBXBuildFile; fileRef = 2780F20A0FA194BD00C0FB83 /* MYDNSService.h */; };
     2.8 +		2780F20D0FA194BD00C0FB83 /* MYDNSService.m in Sources */ = {isa = PBXBuildFile; fileRef = 2780F20B0FA194BD00C0FB83 /* MYDNSService.m */; };
     2.9 +		2780F20E0FA194BD00C0FB83 /* MYDNSService.m in Sources */ = {isa = PBXBuildFile; fileRef = 2780F20B0FA194BD00C0FB83 /* MYDNSService.m */; };
    2.10  		278C1A3D0F9F687800954AE1 /* PortMapperTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 278C1A340F9F687800954AE1 /* PortMapperTest.m */; };
    2.11  		278C1A3E0F9F687800954AE1 /* MYPortMapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 278C1A360F9F687800954AE1 /* MYPortMapper.m */; };
    2.12  		278C1BA60F9F92EA00954AE1 /* MYBonjourBrowser.m in Sources */ = {isa = PBXBuildFile; fileRef = 278C1B9F0F9F92EA00954AE1 /* MYBonjourBrowser.m */; };
    2.13 @@ -80,14 +83,14 @@
    2.14  			isa = PBXContainerItemProxy;
    2.15  			containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
    2.16  			proxyType = 1;
    2.17 -			remoteGlobalIDString = 279E8F9D0F9FDD0800608D8D /* Library */;
    2.18 +			remoteGlobalIDString = 279E8F9D0F9FDD0800608D8D;
    2.19  			remoteInfo = Library;
    2.20  		};
    2.21  		279E8FF80F9FDECD00608D8D /* PBXContainerItemProxy */ = {
    2.22  			isa = PBXContainerItemProxy;
    2.23  			containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
    2.24  			proxyType = 1;
    2.25 -			remoteGlobalIDString = 279E8F9D0F9FDD0800608D8D /* Library */;
    2.26 +			remoteGlobalIDString = 279E8F9D0F9FDD0800608D8D;
    2.27  			remoteInfo = Library;
    2.28  		};
    2.29  /* End PBXContainerItemProxy section */
    2.30 @@ -169,6 +172,8 @@
    2.31  		277904280DE91C7900C6D295 /* BLIP Echo Client-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "BLIP Echo Client-Info.plist"; sourceTree = "<group>"; };
    2.32  		2779048A0DE9204300C6D295 /* BLIPEchoClient.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = BLIPEchoClient.xib; sourceTree = "<group>"; };
    2.33  		2779052D0DE9E5BC00C6D295 /* BLIPEchoServer */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = BLIPEchoServer; sourceTree = BUILT_PRODUCTS_DIR; };
    2.34 +		2780F20A0FA194BD00C0FB83 /* MYDNSService.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYDNSService.h; sourceTree = "<group>"; };
    2.35 +		2780F20B0FA194BD00C0FB83 /* MYDNSService.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYDNSService.m; sourceTree = "<group>"; };
    2.36  		278C1A340F9F687800954AE1 /* PortMapperTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PortMapperTest.m; sourceTree = "<group>"; };
    2.37  		278C1A350F9F687800954AE1 /* MYPortMapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYPortMapper.h; sourceTree = "<group>"; };
    2.38  		278C1A360F9F687800954AE1 /* MYPortMapper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYPortMapper.m; sourceTree = "<group>"; };
    2.39 @@ -372,6 +377,8 @@
    2.40  		278C1A320F9F687800954AE1 /* PortMapper */ = {
    2.41  			isa = PBXGroup;
    2.42  			children = (
    2.43 +				2780F20A0FA194BD00C0FB83 /* MYDNSService.h */,
    2.44 +				2780F20B0FA194BD00C0FB83 /* MYDNSService.m */,
    2.45  				278C1A350F9F687800954AE1 /* MYPortMapper.h */,
    2.46  				278C1A360F9F687800954AE1 /* MYPortMapper.m */,
    2.47  				278C1A340F9F687800954AE1 /* PortMapperTest.m */,
    2.48 @@ -407,6 +414,7 @@
    2.49  			isa = PBXHeadersBuildPhase;
    2.50  			buildActionMask = 2147483647;
    2.51  			files = (
    2.52 +				2780F20C0FA194BD00C0FB83 /* MYDNSService.h in Headers */,
    2.53  			);
    2.54  			runOnlyForDeploymentPostprocessing = 0;
    2.55  		};
    2.56 @@ -561,6 +569,7 @@
    2.57  				279E8FB60F9FDD2600608D8D /* MYBonjourBrowser.m in Sources */,
    2.58  				279E8FB70F9FDD2600608D8D /* MYBonjourService.m in Sources */,
    2.59  				279E8FB80F9FDD2600608D8D /* ConcurrentOperation.m in Sources */,
    2.60 +				2780F20D0FA194BD00C0FB83 /* MYDNSService.m in Sources */,
    2.61  			);
    2.62  			runOnlyForDeploymentPostprocessing = 0;
    2.63  		};
    2.64 @@ -594,6 +603,7 @@
    2.65  				278C1BA60F9F92EA00954AE1 /* MYBonjourBrowser.m in Sources */,
    2.66  				278C1BA70F9F92EA00954AE1 /* MYBonjourService.m in Sources */,
    2.67  				278C1BB90F9F975700954AE1 /* ConcurrentOperation.m in Sources */,
    2.68 +				2780F20E0FA194BD00C0FB83 /* MYDNSService.m in Sources */,
    2.69  			);
    2.70  			runOnlyForDeploymentPostprocessing = 0;
    2.71  		};
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/PortMapper/MYDNSService.h	Fri Apr 24 10:10:32 2009 -0700
     3.3 @@ -0,0 +1,48 @@
     3.4 +//
     3.5 +//  MYDNSService.h
     3.6 +//  MYNetwork
     3.7 +//
     3.8 +//  Created by Jens Alfke on 4/23/09.
     3.9 +//  Copyright 2009 Jens Alfke. All rights reserved.
    3.10 +//
    3.11 +
    3.12 +#import <Foundation/Foundation.h>
    3.13 +#import <CoreFoundation/CFSocket.h>
    3.14 +
    3.15 +
    3.16 +/** Abstract superclass for services based on DNSServiceRefs, such as MYPortMapper. */
    3.17 +@interface MYDNSService : NSObject
    3.18 +{
    3.19 +    @private
    3.20 +    struct _DNSServiceRef_t *_serviceRef;
    3.21 +    CFSocketRef _socket;
    3.22 +    CFRunLoopSourceRef _socketSource;
    3.23 +    SInt32 _error;
    3.24 +}
    3.25 +
    3.26 +/** Starts the service.
    3.27 +    Returns immediately; you can find out when the service actually starts (or fails to)
    3.28 +    by observing the isOpen and error properties.
    3.29 +    It's very unlikely that this call itself will fail (return NO). If it does, it
    3.30 +    probably means that the mDNSResponder process isn't working. */
    3.31 +- (BOOL) open;
    3.32 +
    3.33 +- (void) close;
    3.34 +
    3.35 +
    3.36 +@property (readonly) struct _DNSServiceRef_t* serviceRef;
    3.37 +
    3.38 +/** The error status, a DNSServiceErrorType enum; nonzero if something went wrong. 
    3.39 +    This property is KV observable. */
    3.40 +@property SInt32 error;
    3.41 +
    3.42 +// PROTECTED:
    3.43 +
    3.44 +/** Subclass must implement this abstract method to create a new DNSServiceRef.
    3.45 +    This method is called by -open.
    3.46 +    If an error occurs, the method should set self.error and return NULL.*/
    3.47 +- (struct _DNSServiceRef_t*) createServiceRef;
    3.48 +
    3.49 +- (void) stopService;
    3.50 +
    3.51 +@end
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/PortMapper/MYDNSService.m	Fri Apr 24 10:10:32 2009 -0700
     4.3 @@ -0,0 +1,151 @@
     4.4 +//
     4.5 +//  MYDNSService.m
     4.6 +//  MYNetwork
     4.7 +//
     4.8 +//  Created by Jens Alfke on 4/23/09.
     4.9 +//  Copyright 2009 Jens Alfke. All rights reserved.
    4.10 +//
    4.11 +
    4.12 +#import "MYDNSService.h"
    4.13 +#import "CollectionUtils.h"
    4.14 +#import "Logging.h"
    4.15 +#import "Test.h"
    4.16 +#import "ExceptionUtils.h"
    4.17 +
    4.18 +#import <dns_sd.h>
    4.19 +
    4.20 +
    4.21 +static void serviceCallback(CFSocketRef s, 
    4.22 +                            CFSocketCallBackType type,
    4.23 +                            CFDataRef address,
    4.24 +                            const void *data,
    4.25 +                            void *clientCallBackInfo);
    4.26 +
    4.27 +
    4.28 +@implementation MYDNSService
    4.29 +
    4.30 +
    4.31 +- (void) dealloc
    4.32 +{
    4.33 +    if( _serviceRef )
    4.34 +        [self stopService];
    4.35 +    [super dealloc];
    4.36 +}
    4.37 +
    4.38 +- (void) finalize
    4.39 +{
    4.40 +    if( _serviceRef )
    4.41 +        [self stopService];
    4.42 +    [super finalize];
    4.43 +}
    4.44 +
    4.45 +
    4.46 +@synthesize serviceRef=_serviceRef, error=_error;
    4.47 +
    4.48 +
    4.49 +- (DNSServiceRef) createServiceRef {
    4.50 +    AssertAbstractMethod();
    4.51 +}
    4.52 +
    4.53 +
    4.54 +- (BOOL) open
    4.55 +{
    4.56 +    if (_serviceRef)
    4.57 +        return YES;
    4.58 +    _serviceRef = [self createServiceRef];
    4.59 +    if (_serviceRef) {
    4.60 +        // Wrap a CFSocket around the service's socket:
    4.61 +        CFSocketContext ctxt = { 0, self, CFRetain, CFRelease, NULL };
    4.62 +        _socket = CFSocketCreateWithNative(NULL, 
    4.63 +                                           DNSServiceRefSockFD(_serviceRef), 
    4.64 +                                           kCFSocketReadCallBack, 
    4.65 +                                           &serviceCallback, &ctxt);
    4.66 +        if( _socket ) {
    4.67 +            CFSocketSetSocketFlags(_socket, CFSocketGetSocketFlags(_socket) & ~kCFSocketCloseOnInvalidate);
    4.68 +            // Attach the socket to the runloop so the serviceCallback will be invoked:
    4.69 +            _socketSource = CFSocketCreateRunLoopSource(NULL, _socket, 0);
    4.70 +            if( _socketSource ) {
    4.71 +                CFRunLoopAddSource(CFRunLoopGetCurrent(), _socketSource, kCFRunLoopCommonModes);
    4.72 +                LogTo(DNS,@"Opening %@",self);
    4.73 +                return YES; // success
    4.74 +            }
    4.75 +        }
    4.76 +    }
    4.77 +    if (!_error)
    4.78 +        self.error = kDNSServiceErr_Unknown;
    4.79 +    LogTo(DNS,@"Failed to open %@ -- err=%i",self,_error);
    4.80 +    [self stopService];
    4.81 +    return NO;
    4.82 +}
    4.83 +
    4.84 +
    4.85 +- (void) stopService
    4.86 +{
    4.87 +    if( _socketSource ) {
    4.88 +        CFRunLoopSourceInvalidate(_socketSource);
    4.89 +        CFRelease(_socketSource);
    4.90 +        _socketSource = NULL;
    4.91 +    }
    4.92 +    if( _socket ) {
    4.93 +        CFSocketInvalidate(_socket);
    4.94 +        CFRelease(_socket);
    4.95 +        _socket = NULL;
    4.96 +    }
    4.97 +    if( _serviceRef ) {
    4.98 +        LogTo(DNS,@"Stopped %@",self);
    4.99 +        DNSServiceRefDeallocate(_serviceRef);
   4.100 +        _serviceRef = NULL;
   4.101 +    }
   4.102 +}
   4.103 +
   4.104 +
   4.105 +- (void) close
   4.106 +{
   4.107 +    [self stopService];
   4.108 +    if (_error)
   4.109 +        self.error = 0;
   4.110 +}
   4.111 +
   4.112 +
   4.113 +/** CFSocket callback, informing us that _socket has data available, which means
   4.114 +    that the DNS service has an incoming result to be processed. This will end up invoking
   4.115 +    the service's specific callback. */
   4.116 +static void serviceCallback(CFSocketRef s, 
   4.117 +                            CFSocketCallBackType type,
   4.118 +                            CFDataRef address, const void *data, void *clientCallBackInfo)
   4.119 +{
   4.120 +    MYDNSService *serviceObj = (MYDNSService*)clientCallBackInfo;
   4.121 +    DNSServiceRef service = serviceObj.serviceRef;
   4.122 +    DNSServiceErrorType err = DNSServiceProcessResult(service);
   4.123 +    if( err ) {
   4.124 +        // An error here means the socket has failed and should be closed.
   4.125 +        serviceObj.error = err;
   4.126 +        [serviceObj stopService];
   4.127 +    }
   4.128 +}
   4.129 +
   4.130 +
   4.131 +@end
   4.132 +
   4.133 +
   4.134 +/*
   4.135 + Copyright (c) 2008-2009, Jens Alfke <jens@mooseyard.com>. All rights reserved.
   4.136 + 
   4.137 + Redistribution and use in source and binary forms, with or without modification, are permitted
   4.138 + provided that the following conditions are met:
   4.139 + 
   4.140 + * Redistributions of source code must retain the above copyright notice, this list of conditions
   4.141 + and the following disclaimer.
   4.142 + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
   4.143 + and the following disclaimer in the documentation and/or other materials provided with the
   4.144 + distribution.
   4.145 + 
   4.146 + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   4.147 + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   4.148 + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   4.149 + BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   4.150 + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   4.151 +  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   4.152 + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   4.153 + THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   4.154 + */
     5.1 --- a/PortMapper/MYPortMapper.h	Wed Apr 22 16:45:39 2009 -0700
     5.2 +++ b/PortMapper/MYPortMapper.h	Fri Apr 24 10:10:32 2009 -0700
     5.3 @@ -6,8 +6,7 @@
     5.4  //  Copyright 2008 Jens Alfke. All rights reserved.
     5.5  //
     5.6  
     5.7 -#import <Foundation/Foundation.h>
     5.8 -#import <CoreFoundation/CFSocket.h>
     5.9 +#import "MYDNSService.h"
    5.10  @class IPAddress;
    5.11  
    5.12  
    5.13 @@ -34,14 +33,11 @@
    5.14      * When the MYPortMapper reports changes, you (somehow) notify peers of the changes.
    5.15      * When closing the network service, close the MYPortMapper object too.
    5.16  */ 
    5.17 -@interface MYPortMapper : NSObject
    5.18 +@interface MYPortMapper : MYDNSService
    5.19  {
    5.20 +    @private
    5.21      UInt16 _localPort, _desiredPublicPort;
    5.22      BOOL _mapTCP, _mapUDP;
    5.23 -    SInt32 _error;
    5.24 -    void* /*DNSServiceRef*/ _service; // Typed void* to avoid having to #include <dnssd.h>
    5.25 -    CFSocketRef _socket;
    5.26 -    CFRunLoopSourceRef _socketSource;
    5.27      IPAddress *_publicAddress, *_localAddress;
    5.28  }
    5.29  
    5.30 @@ -65,14 +61,6 @@
    5.31      This property has no effect if changed while the PortMapper is open. */
    5.32  @property UInt16 desiredPublicPort;
    5.33  
    5.34 -/** Opens the PortMapper, using the current settings of the above properties.
    5.35 -    Returns immediately; you can find out when the mapping is created or fails
    5.36 -    by observing the error/publicAddress/publicPort properties, or by listening
    5.37 -    for the PortMapperChangedNotification.
    5.38 -    It's very unlikely that this call will fail (return NO). If it does, it
    5.39 -    probably means that the mDNSResponder process isn't working. */
    5.40 -- (BOOL) open;
    5.41 -
    5.42  /** Blocks till the PortMapper finishes opening. Returns YES if it opened, NO on error.
    5.43      It's not usually a good idea to use this, as it will lock up your application
    5.44      until a response arrives from the NAT. Listen for asynchronous notifications instead.
    5.45 @@ -80,14 +68,6 @@
    5.46      If called when it's already open, it just returns YES. */
    5.47  - (BOOL) waitTillOpened;
    5.48  
    5.49 -/** Closes the PortMapper, terminating any open port mapping. */
    5.50 -- (void) close;
    5.51 -
    5.52 -/** The error status, a DNSServiceErrorType enum; nonzero if something went wrong. 
    5.53 -    The most likely error is kDNSServiceErr_NATPortMappingUnsupported (-65564).
    5.54 -    This property is KV observable. */
    5.55 -@property (readonly) SInt32 error;
    5.56 -
    5.57  /** The known public IPv4 address/port, once it's been determined.
    5.58      This property is KV observable. */
    5.59  @property (readonly,retain) IPAddress* publicAddress;
     6.1 --- a/PortMapper/MYPortMapper.m	Wed Apr 22 16:45:39 2009 -0700
     6.2 +++ b/PortMapper/MYPortMapper.m	Fri Apr 24 10:10:32 2009 -0700
     6.3 @@ -13,24 +13,14 @@
     6.4  #import "ExceptionUtils.h"
     6.5  
     6.6  #import <dns_sd.h>
     6.7 -#import <sys/types.h>
     6.8 -#import <sys/socket.h>
     6.9 -#import <net/if.h>
    6.10 -#import <netinet/in.h>
    6.11 -#import <ifaddrs.h>
    6.12  
    6.13  
    6.14  NSString* const MYPortMapperChangedNotification = @"MYPortMapperChanged";
    6.15  
    6.16  
    6.17  @interface MYPortMapper ()
    6.18 -// Redeclare these properties as settable, internally:
    6.19 -@property (readwrite) SInt32 error;
    6.20 -@property (retain) IPAddress* publicAddress, *localAddress;
    6.21 -// Private getter:
    6.22 -@property (readonly) void* _service;
    6.23 +@property (retain) IPAddress* publicAddress, *localAddress; // redeclare as settable
    6.24  - (void) priv_updateLocalAddress;
    6.25 -- (void) priv_disconnect;
    6.26  @end
    6.27  
    6.28  
    6.29 @@ -61,23 +51,13 @@
    6.30  
    6.31  - (void) dealloc
    6.32  {
    6.33 -    if( _service )
    6.34 -        [self priv_disconnect];
    6.35      [_publicAddress release];
    6.36      [_localAddress release];
    6.37      [super dealloc];
    6.38  }
    6.39  
    6.40 -- (void) finalize
    6.41 -{
    6.42 -    if( _service )
    6.43 -        [self priv_disconnect];
    6.44 -    [super finalize];
    6.45 -}
    6.46 -
    6.47  
    6.48  @synthesize localAddress=_localAddress, publicAddress=_publicAddress,
    6.49 -            error=_error, _service=_service,
    6.50              mapTCP=_mapTCP, mapUDP=_mapUDP,
    6.51              desiredPublicPort=_desiredPublicPort;
    6.52  
    6.53 @@ -158,110 +138,44 @@
    6.54  }
    6.55  
    6.56  
    6.57 -/** CFSocket callback, informing us that _socket has data available, which means
    6.58 -    that the DNS service has an incoming result to be processed. This will end up invoking
    6.59 -    the portMapCallback. */
    6.60 -static void serviceCallback(CFSocketRef s, 
    6.61 -                            CFSocketCallBackType type,
    6.62 -                            CFDataRef address, const void *data, void *clientCallBackInfo)
    6.63 +- (DNSServiceRef) createServiceRef
    6.64  {
    6.65 -    MYPortMapper *mapper = (MYPortMapper*)clientCallBackInfo;
    6.66 -    DNSServiceRef service = mapper._service;
    6.67 -    DNSServiceErrorType err = DNSServiceProcessResult(service);
    6.68 -    if( err ) {
    6.69 -        // An error here means the socket has failed and should be closed.
    6.70 -        [mapper priv_portMapStatus: err publicAddress: 0 publicPort: 0];
    6.71 -        [mapper priv_disconnect];
    6.72 -    }
    6.73 -}
    6.74 -
    6.75 -
    6.76 -
    6.77 -- (BOOL) open
    6.78 -{
    6.79 -    NSAssert(!_service,@"Already open");
    6.80 -    // Create the DNSService:
    6.81      DNSServiceProtocol protocols = 0;
    6.82      if( _mapTCP ) protocols |= kDNSServiceProtocol_TCP;
    6.83      if( _mapUDP ) protocols |= kDNSServiceProtocol_UDP;
    6.84 -    self.error = DNSServiceNATPortMappingCreate((DNSServiceRef*)&_service, 
    6.85 -                                         0 /*flags*/, 
    6.86 -                                         0 /*interfaceIndex*/, 
    6.87 -                                         protocols,
    6.88 -                                         htons(_localPort),
    6.89 -                                         htons(_desiredPublicPort),
    6.90 -                                         0 /*ttl*/,
    6.91 -                                         &portMapCallback, 
    6.92 -                                         self);
    6.93 -    if( _error ) {
    6.94 -        LogTo(PortMapper,@"Error %i creating port mapping",_error);
    6.95 -        return NO;
    6.96 -    }
    6.97 -    
    6.98 -    // Wrap a CFSocket around the service's socket:
    6.99 -    CFSocketContext ctxt = { 0, self, CFRetain, CFRelease, NULL };
   6.100 -    _socket = CFSocketCreateWithNative(NULL, 
   6.101 -                                       DNSServiceRefSockFD(_service), 
   6.102 -                                       kCFSocketReadCallBack, 
   6.103 -                                       &serviceCallback, &ctxt);
   6.104 -    if( _socket ) {
   6.105 -        CFSocketSetSocketFlags(_socket, CFSocketGetSocketFlags(_socket) & ~kCFSocketCloseOnInvalidate);
   6.106 -        // Attach the socket to the runloop so the serviceCallback will be invoked:
   6.107 -        _socketSource = CFSocketCreateRunLoopSource(NULL, _socket, 0);
   6.108 -        if( _socketSource )
   6.109 -            CFRunLoopAddSource(CFRunLoopGetCurrent(), _socketSource, kCFRunLoopCommonModes);
   6.110 -    }
   6.111 -    if( _socketSource ) {
   6.112 -        LogTo(PortMapper,@"Opening");
   6.113 -        return YES;
   6.114 -    } else {
   6.115 -        Warn(@"Failed to open PortMapper");
   6.116 -        [self close];
   6.117 -        _error = kDNSServiceErr_Unknown;
   6.118 -        return NO;
   6.119 -    }
   6.120 +    DNSServiceRef serviceRef = NULL;
   6.121 +    self.error = DNSServiceNATPortMappingCreate(&serviceRef, 
   6.122 +                                                0 /*flags*/, 
   6.123 +                                                0 /*interfaceIndex*/, 
   6.124 +                                                protocols,
   6.125 +                                                htons(_localPort),
   6.126 +                                                htons(_desiredPublicPort),
   6.127 +                                                0 /*ttl*/,
   6.128 +                                                &portMapCallback, 
   6.129 +                                                self);
   6.130 +    return serviceRef;
   6.131 +}
   6.132 +
   6.133 +
   6.134 +- (void) stopService
   6.135 +{
   6.136 +    [super stopService];
   6.137 +    if (_publicAddress)
   6.138 +        self.publicAddress = nil;
   6.139  }
   6.140  
   6.141  
   6.142  - (BOOL) waitTillOpened
   6.143  {
   6.144 -    if( ! _socketSource )
   6.145 +    if( ! self.serviceRef )
   6.146          if( ! [self open] )
   6.147              return NO;
   6.148      // Run the runloop until there's either an error or a result:
   6.149 -    while( _error==0 && _publicAddress==nil )
   6.150 +    while( self.error==0 && _publicAddress==nil )
   6.151          if( ! [[NSRunLoop currentRunLoop] runMode: NSDefaultRunLoopMode
   6.152                                         beforeDate: [NSDate distantFuture]] )
   6.153              break;
   6.154 -    return (_error==0);
   6.155 -}
   6.156 -
   6.157 -
   6.158 -// Close down, but _without_ clearing the 'error' property
   6.159 -- (void) priv_disconnect
   6.160 -{
   6.161 -    if( _socketSource ) {
   6.162 -        CFRunLoopSourceInvalidate(_socketSource);
   6.163 -        CFRelease(_socketSource);
   6.164 -        _socketSource = NULL;
   6.165 -    }
   6.166 -    if( _socket ) {
   6.167 -        CFSocketInvalidate(_socket);
   6.168 -        CFRelease(_socket);
   6.169 -        _socket = NULL;
   6.170 -    }
   6.171 -    if( _service ) {
   6.172 -        LogTo(PortMapper,@"Deleting port mapping");
   6.173 -        DNSServiceRefDeallocate(_service);
   6.174 -        _service = NULL;
   6.175 -        self.publicAddress = nil;
   6.176 -    }
   6.177 -}
   6.178 -
   6.179 -- (void) close
   6.180 -{
   6.181 -    [self priv_disconnect];
   6.182 -    self.error = 0;
   6.183 +    return (self.error==0);
   6.184  }
   6.185  
   6.186  
     7.1 --- a/maindocs.h	Wed Apr 22 16:45:39 2009 -0700
     7.2 +++ b/maindocs.h	Fri Apr 24 10:10:32 2009 -0700
     7.3 @@ -12,117 +12,10 @@
     7.4   
     7.5      <center><b>By <a href="/Jens/">Jens Alfke</a></b></center>
     7.6  
     7.7 -    <img src="BLIP.png">
     7.8 -
     7.9 -\section intro_sec Introduction
    7.10 +    <img src="../../BLIP/logo.png">
    7.11   
    7.12 -    MYNetwork is a set of Objective-C networking classes for Cocoa applications on Mac OS X.
    7.13 -    It consists of:
    7.14 -    <ul>
    7.15 -    <li>Networking utility classes (presently only IPAddress);
    7.16 -    <li>A generic TCP client/server implementation,
    7.17 -        useful for implementing your own network protocols; (see TCPListener and TCPConnection)
    7.18 -    <li>An implementation of <a href="#blipdesc">BLIP</a>, a lightweight network protocol I've invented as an easy way
    7.19 -        to send request and response messages between peers. (see BLIPListener, BLIPConnection, BLIPRequest, etc.)
    7.20 -    </ul>
    7.21 +    <center><a href="annotated.html">Class documentation</a></center>
    7.22   
    7.23 -\section license License and Disclaimer
    7.24 - 
    7.25 - MYNetwork is released under a BSD license, which means you can freely use it in open-source
    7.26 - or commercial projects, provided you give credit in your documentation or About box.
    7.27 - 
    7.28 - As I write this (May 2008), MYNetwork is still very much under development. I am using it as the foundation of my own commercial products, at least one of which is currently at about the alpha stage. I'm making changes to this code as I see fit, fairly often.
    7.29 - 
    7.30 -That's good, in that the code is getting real-world use. But it also means that APIs and functionality are subject to change. (Of course, the entire revision tree is always available, so you're free to stick with any revision you like, and even "cherry-pick" desired changes from future ones.)
    7.31 - 
    7.32 -Not all of this code gets thoroughly exercised by my test cases or my applications, so some things may not work. Obviously, this code comes with no warranty nor any guarantee of tech support, though I will try to do my best to help out. Hopefully the source code is clear enough to let you figure out what's going on.
    7.33 - 
    7.34 -If you come across bugs, please tell me about them. If you fix them, I would love to get your fixes and incorporate them. If you add features I would love to know about them, and I will incorporate them if I think they make sense for the project. Thanks!
    7.35 -
    7.36 -\section blipdesc What's BLIP?
    7.37 - 
    7.38 - <table style="background-color: #fff; padding: 5px; float: right" cellspacing=0>
    7.39 - <tr><td>
    7.40 - <img src="http://groups.google.com/groups/img/3nb/groups_bar.gif"
    7.41 - height=26 width=132 alt="Google Groups">
    7.42 - </td></tr>
    7.43 - <tr><td style="padding-left: 5px;font-size: 125%">
    7.44 - <b>BLIP Protocol</b>
    7.45 - </td></tr>
    7.46 - <tr><td style="padding-left: 5px">
    7.47 - <a href="http://groups.google.com/group/blip-protocol">Visit this group</a>
    7.48 - </td></tr>
    7.49 - </table>
    7.50 - 
    7.51 -BLIP is a message-oriented network protocol that lets the two peers on either end of a TCP socket send request and response messages to each other. It's a generic protocol, in that the requests and responses can contain any kind of data you like. 
    7.52 - 
    7.53 -BLIP was inspired by <a
    7.54 -href="http://beepcore.org">BEEP</a> (in fact BLIP stands for "BEEP-LIke Protocol") but is
    7.55 -deliberately simpler and somewhat more limited. That results in a smaller and cleaner implementation, especially since it takes advantage of Cocoa's and CFNetwork's existing support for network streams, SSL and Bonjour. (BLIP is currently a bit under 2,000 lines of code, and the rest of the MYNetwork classes it builds on add up to another 1,500. That's at least an order of magnitude smaller than existing native-code BEEP libraries.)
    7.56 - 
    7.57 -\subsection blipfeatures BLIP Features:
    7.58 -
    7.59 - <ul>
    7.60 - <li>Each message is very much like a MIME body, as in email or HTTP: it consists of a
    7.61 -blob of data of arbitrary length, plus a set of key/value pairs called "properties". The
    7.62 -properties are mostly ignored by BLIP itself, but clients can use them for metadata about the
    7.63 -body, and for delivery information (i.e. something like BEEP's "profiles".)
    7.64 -
    7.65 -<li>Either peer can send a request at any time; there's no notion of "client" and "server" roles.
    7.66 - 
    7.67 -<li> Multiple messages can be transmitted simultaneously in the same direction over the same connection, so a very long
    7.68 -message does not block any other messages from being delivered. This means that message ordering
    7.69 -is a bit looser than in BEEP or HTTP 1.1: the receiver will see the beginnings of messages in the
    7.70 -same order in which the sender posted them, but they might not <i>end</i> in that same order. (For
    7.71 -example, a long message will take longer to be delivered, so it may finish after messages that
    7.72 -were begun after it.)
    7.73 -
    7.74 -<li>The sender can indicate whether or not a message needs to be replied to; the response is tagged with the
    7.75 -identity of the original message, to make it easy for the sender to recognize. This makes it
    7.76 -straighforward to implement RPC-style (or REST-style) interactions. (Responses
    7.77 -cannot be replied to again, however.)
    7.78 -
    7.79 -<li>A message can be flagged as "urgent". Urgent messages are pushed ahead in the outgoing queue and
    7.80 -get a higher fraction of the available bandwidth.
    7.81 -
    7.82 -<li>A message can be flagged as "compressed". This runs its body through the gzip algorithm, ideally
    7.83 -making it faster to transmit. (Common markup-based data formats like XML and JSON compress
    7.84 -extremely well, at ratios up to 10::1.) The message is decompressed on the receiving end,
    7.85 -invisibly to client code.
    7.86 - 
    7.87 -<li>The implementation supports SSL connections (with optional client-side certificates), and Bonjour service advertising.
    7.88 -</ul>
    7.89 -  
    7.90 -\section config Configuration
    7.91 - 
    7.92 -    MYNetwork requires Mac OS X 10.5 or later, since it uses Objective-C 2 features like
    7.93 -    properties and for...in loops.
    7.94 - 
    7.95 -    MYNetwork uses my <a href="/hg/hgwebdir.cgi/MYUtilities">MYUtilities</a> library. You'll need to have downloaded that library, and added
    7.96 -    the necessary source files and headers to your project. See the MYNetwork Xcode project,
    7.97 -    which contains the minimal set of MYUtilities files needed to build MYUtilities. (That project
    7.98 -    has its search paths set up to assume that MYUtilities is in a directory next to MYNetwork.)
    7.99 -
   7.100 -\section download How To Get It
   7.101 -
   7.102 -    <ul>
   7.103 -    <li><a href="/hg/hgwebdir.cgi/MYNetwork/archive/tip.zip">Download the current source code</a>
   7.104 -    <li>To check out the source code using <a href="http://selenic.com/mercurial">Mercurial</a>:
   7.105 -    \verbatim hg clone /hg/hgwebdir.cgi/MYNetwork/ MYNetwork \endverbatim
   7.106 -    <li>As described above, you'll also need to download or check out <a href="/hg/hgwebdir.cgi/MYUtilities">MYUtilities</a> and put it in 
   7.107 -    a directory next to MYNetwork.
   7.108 -    </ul>
   7.109 -
   7.110 -    Or if you're just looking:
   7.111 -
   7.112 -    <ul>
   7.113 -    <li><a href="/hg/hgwebdir.cgi/MYNetwork/file/tip">Browse the source code</a>
   7.114 -    <li><a href="annotated.html">Browse the class documentation</a>
   7.115 -    </ul>
   7.116 - 
   7.117 -    There isn't any conceptual documentation yet, beyond what's in the API docs, but you can 
   7.118 -    <a href="/hg/hgwebdir.cgi/MYNetwork/file/tip/BLIP/Demo/">look
   7.119 -    at the sample BLIPEcho client and server</a>, which are based on Apple's 
   7.120 -    <a href="http://developer.apple.com/samplecode/CocoaEcho/index.html">CocoaEcho</a> sample code.
   7.121 +    <center><a href="../../Home">Overview, instructions, conceptual documentation</a></center>
   7.122   
   7.123   */