* Added MYBonjourBrowser and MYBonjourService.
authorJens Alfke <jens@mooseyard.com>
Wed Apr 22 16:45:39 2009 -0700 (2009-04-22)
changeset 26cb9cdf247239
parent 25 a4875607a3a0
child 27 92581f26073e
* Added MYBonjourBrowser and MYBonjourService.
* Added MYPortMapper.
* Added -[TCPEndpoint setPeerToPeerIdentity:].
* Created a static-library target.
BLIP/BLIP.h
BLIP/BLIPConnection.h
BLIP/BLIPDispatcher.h
BLIP/BLIPMessage.h
BLIP/BLIPProperties.h
BLIP/BLIPProperties.m
BLIP/BLIPReader.h
BLIP/BLIPTest.m
BLIP/BLIPWriter.h
BLIP/Demo/BLIP Echo Client-Info.plist
BLIP/Demo/BLIPEchoClient.h
BLIP/Demo/BLIPEchoClient.m
BLIP/Demo/BLIPEchoClient.xib
BLIP/Demo/BLIPEchoServer.m
Bonjour/MYBonjourBrowser.h
Bonjour/MYBonjourBrowser.m
Bonjour/MYBonjourService.h
Bonjour/MYBonjourService.m
IPAddress.h
IPAddress.m
MYNetwork-iPhone.xcodeproj/project.pbxproj
MYNetwork.h
MYNetwork.xcodeproj/project.pbxproj
PortMapper/MYPortMapper.h
PortMapper/MYPortMapper.m
PortMapper/PortMapperTest.m
TCP/TCPConnection.h
TCP/TCPConnection.m
TCP/TCPEndpoint.h
TCP/TCPEndpoint.m
TCP/TCPListener.m
TCP/TCPStream.m
TCP/TCP_Internal.h
iPhone/Classes/MyViewController.m
iPhone/main.m
     1.1 --- a/BLIP/BLIP.h	Tue Dec 02 22:42:56 2008 -0800
     1.2 +++ b/BLIP/BLIP.h	Wed Apr 22 16:45:39 2009 -0700
     1.3 @@ -3,7 +3,7 @@
     1.4  //  MYNetwork
     1.5  //
     1.6  //  Created by Jens Alfke on 5/24/08.
     1.7 -//  Copyright 2008 __MyCompanyName__. All rights reserved.
     1.8 +//  Copyright 2008 Jens Alfke. All rights reserved.
     1.9  //
    1.10  
    1.11  #import "BLIPConnection.h"
     2.1 --- a/BLIP/BLIPConnection.h	Tue Dec 02 22:42:56 2008 -0800
     2.2 +++ b/BLIP/BLIPConnection.h	Wed Apr 22 16:45:39 2009 -0700
     2.3 @@ -19,6 +19,7 @@
     2.4      Most of the API is inherited from TCPConnection. */
     2.5  @interface BLIPConnection : TCPConnection
     2.6  {
     2.7 +    @private
     2.8      BLIPDispatcher *_dispatcher;
     2.9      BOOL _blipClosing;
    2.10  }
     3.1 --- a/BLIP/BLIPDispatcher.h	Tue Dec 02 22:42:56 2008 -0800
     3.2 +++ b/BLIP/BLIPDispatcher.h	Wed Apr 22 16:45:39 2009 -0700
     3.3 @@ -25,6 +25,7 @@
     3.4      request based on property values. */
     3.5  @interface BLIPDispatcher : NSObject 
     3.6  {
     3.7 +    @private
     3.8      NSMutableArray *_predicates, *_targets;
     3.9      BLIPDispatcher *_parent;
    3.10  }
     4.1 --- a/BLIP/BLIPMessage.h	Tue Dec 02 22:42:56 2008 -0800
     4.2 +++ b/BLIP/BLIPMessage.h	Wed Apr 22 16:45:39 2009 -0700
     4.3 @@ -36,6 +36,7 @@
     4.4  /** Abstract superclass for <a href=".#blipdesc">BLIP</a> requests and responses. */
     4.5  @interface BLIPMessage : NSObject 
     4.6  {
     4.7 +    @protected
     4.8      BLIPConnection *_connection;
     4.9      UInt16 _flags;
    4.10      UInt32 _number;
     5.1 --- a/BLIP/BLIPProperties.h	Tue Dec 02 22:42:56 2008 -0800
     5.2 +++ b/BLIP/BLIPProperties.h	Wed Apr 22 16:45:39 2009 -0700
     5.3 @@ -45,6 +45,7 @@
     5.4  /** Mutable subclass of BLIPProperties, used for creating new instances. */
     5.5  @interface BLIPMutableProperties : BLIPProperties
     5.6  {
     5.7 +    @private
     5.8      NSMutableDictionary *_properties;
     5.9  }
    5.10  
     6.1 --- a/BLIP/BLIPProperties.m	Tue Dec 02 22:42:56 2008 -0800
     6.2 +++ b/BLIP/BLIPProperties.m	Wed Apr 22 16:45:39 2009 -0700
     6.3 @@ -69,7 +69,7 @@
     6.4      else
     6.5          props = [BLIPProperties properties];
     6.6      
     6.7 -    *usedLength = props ?length :-1;
     6.8 +    *usedLength = props ?(ssize_t)length :-1;
     6.9      return props;
    6.10  }
    6.11  
    6.12 @@ -132,7 +132,7 @@
    6.13              goto fail;
    6.14  
    6.15          // The data consists of consecutive NUL-terminated strings, alternating key/value:
    6.16 -        unsigned capacity = 0;
    6.17 +        int capacity = 0;
    6.18          const char *end = bytes+length;
    6.19          for( const char *str=bytes; str < end; str += strlen(str)+1, _nStrings++ ) {
    6.20              if( _nStrings >= capacity ) {
    6.21 @@ -285,7 +285,7 @@
    6.22  static void appendStr( NSMutableData *data, NSString *str ) {
    6.23      const char *utf8 = [str UTF8String];
    6.24      size_t size = strlen(utf8)+1;
    6.25 -    for( int i=0; i<kNAbbreviations; i++ )
    6.26 +    for( unsigned i=0; i<kNAbbreviations; i++ )
    6.27          if( memcmp(utf8,kAbbreviations[i],size)==0 ) {
    6.28              const UInt8 abbrev[2] = {i+1,0};
    6.29              [data appendBytes: &abbrev length: 2];
    6.30 @@ -345,7 +345,7 @@
    6.31      
    6.32      props = [BLIPProperties properties];
    6.33      CAssert(props);
    6.34 -    CAssertEq(props.count,0);
    6.35 +    CAssertEq(props.count,0U);
    6.36      Log(@"Empty properties:\n%@", props.allProperties);
    6.37      NSData *data = props.encodedData;
    6.38      Log(@"As data: %@", data);
    6.39 @@ -359,7 +359,7 @@
    6.40      
    6.41      ssize_t used;
    6.42      props = [BLIPProperties propertiesWithEncodedData: data usedLength: &used];
    6.43 -    CAssertEq(used,data.length);
    6.44 +    CAssertEq(used,(ssize_t)data.length);
    6.45      CAssertEqual(props,mprops);
    6.46      
    6.47      [mprops setValue: @"Jens" ofProperty: @"First-Name"];
    6.48 @@ -377,7 +377,7 @@
    6.49          CAssertEq(used,0);
    6.50      }
    6.51      props = [BLIPProperties propertiesWithEncodedData: data usedLength: &used];
    6.52 -    CAssertEq(used,data.length);
    6.53 +    CAssertEq(used,(ssize_t)data.length);
    6.54      Log(@"Read back in:\n%@",props.allProperties);
    6.55      CAssertEqual(props,mprops);
    6.56      
     7.1 --- a/BLIP/BLIPReader.h	Tue Dec 02 22:42:56 2008 -0800
     7.2 +++ b/BLIP/BLIPReader.h	Wed Apr 22 16:45:39 2009 -0700
     7.3 @@ -14,6 +14,7 @@
     7.4  /** INTERNAL class that reads BLIP frames from the socket. */
     7.5  @interface BLIPReader : TCPReader
     7.6  {
     7.7 +    @private
     7.8      BLIPFrameHeader _curHeader;
     7.9      UInt32 _curBytesRead;
    7.10      NSMutableData *_curBody;
     8.1 --- a/BLIP/BLIPTest.m	Tue Dec 02 22:42:56 2008 -0800
     8.2 +++ b/BLIP/BLIPTest.m	Wed Apr 22 16:45:39 2009 -0700
     8.3 @@ -19,10 +19,13 @@
     8.4  #import "Logging.h"
     8.5  #import "Test.h"
     8.6  
     8.7 -#define HAVE_KEYCHAIN_FRAMEWORK 0
     8.8 -#if HAVE_KEYCHAIN_FRAMEWORK
     8.9 -#import <Keychain/Keychain.h>
    8.10 -#endif
    8.11 +#import <Security/Security.h>
    8.12 +#import <SecurityInterface/SFChooseIdentityPanel.h>
    8.13 +
    8.14 +@interface TCPEndpoint ()
    8.15 ++ (NSString*) describeCert: (SecCertificateRef)cert;
    8.16 ++ (NSString*) describeIdentity: (SecIdentityRef)identity;
    8.17 +@end
    8.18  
    8.19  
    8.20  #define kListenerHost               @"localhost"
    8.21 @@ -31,20 +34,41 @@
    8.22  #define kNBatchedMessages           20
    8.23  #define kUseCompression             YES
    8.24  #define kUrgentEvery                4
    8.25 -#define kClientRequiresSSL          NO
    8.26 -#define kClientUsesSSLCert          NO
    8.27 -#define kListenerRequiresSSL        NO
    8.28 -#define kListenerRequiresClientCert NO
    8.29  #define kListenerCloseAfter         50
    8.30  #define kClientAcceptCloseRequest   YES
    8.31  
    8.32 +#define kListenerUsesSSL            YES     // Does the listener (server) use an SSL connection?
    8.33 +#define kListenerRequiresClientCert YES     // Does the listener require clients to have an SSL cert?
    8.34 +#define kClientRequiresSSL          YES     // Does the client require the listener to use SSL?
    8.35 +#define kClientUsesSSLCert          YES     // Does the client use an SSL cert?
    8.36 +
    8.37 +
    8.38 +static SecIdentityRef ChooseIdentity( NSString *prompt ) {
    8.39 +    NSMutableArray *identities = [NSMutableArray array];
    8.40 +    SecKeychainRef kc;
    8.41 +    SecKeychainCopyDefault(&kc);
    8.42 +    SecIdentitySearchRef search;
    8.43 +    SecIdentitySearchCreate(kc, CSSM_KEYUSE_ANY, &search);
    8.44 +    SecIdentityRef identity;
    8.45 +    while (SecIdentitySearchCopyNext(search, &identity) == noErr)
    8.46 +        [identities addObject: (id)identity];
    8.47 +    Log(@"Found %u identities -- prompting '%@'", identities.count, prompt);
    8.48 +    if (identities.count > 0) {
    8.49 +        SFChooseIdentityPanel *panel = [SFChooseIdentityPanel sharedChooseIdentityPanel];
    8.50 +        if ([panel runModalForIdentities: identities message: prompt] == NSOKButton) {
    8.51 +            Log(@"Using SSL identity: %@", panel.identity);
    8.52 +            return panel.identity;
    8.53 +        }
    8.54 +    }
    8.55 +    return NULL;
    8.56 +}
    8.57  
    8.58  static SecIdentityRef GetClientIdentity(void) {
    8.59 -    return NULL;    // Make this return a valid identity to test client-side certs
    8.60 +    return ChooseIdentity(@"Choose an identity for the BLIP Client Test:");
    8.61  }
    8.62  
    8.63  static SecIdentityRef GetListenerIdentity(void) {
    8.64 -    return NULL;    // Make this return a valid identity to test client-side certs
    8.65 +    return ChooseIdentity(@"Choose an identity for the BLIP Listener Test:");
    8.66  }
    8.67  
    8.68  
    8.69 @@ -75,15 +99,11 @@
    8.70              [self release];
    8.71              return nil;
    8.72          }
    8.73 -        if( kClientRequiresSSL ) {
    8.74 -            _conn.SSLProperties = $mdict({kTCPPropertySSLAllowsAnyRoot, $true});
    8.75 -            if( kClientUsesSSLCert ) {
    8.76 -                SecIdentityRef clientIdentity = GetClientIdentity();
    8.77 -                if( clientIdentity ) {
    8.78 -                    [_conn setSSLProperty: $array((id)clientIdentity)
    8.79 -                                   forKey: kTCPPropertySSLCertificates];
    8.80 -                }
    8.81 -            }
    8.82 +        if( kClientUsesSSLCert ) {
    8.83 +            [_conn setPeerToPeerIdentity: GetClientIdentity()];
    8.84 +        } else if( kClientRequiresSSL ) {
    8.85 +            _conn.SSLProperties = $mdict({kTCPPropertySSLAllowsAnyRoot, $true},
    8.86 +                                        {(id)kCFStreamSSLPeerName, [NSNull null]});
    8.87          }
    8.88          _conn.delegate = self;
    8.89          Log(@"** Opening connection...");
    8.90 @@ -148,22 +168,20 @@
    8.91  }
    8.92  - (BOOL) connection: (TCPConnection*)connection authorizeSSLPeer: (SecCertificateRef)peerCert
    8.93  {
    8.94 -#if HAVE_KEYCHAIN_FRAMEWORK
    8.95 -    Certificate *cert = peerCert ?[Certificate certificateWithCertificateRef: peerCert] :nil;
    8.96 -    Log(@"** %@ authorizeSSLPeer: %@",self,cert);
    8.97 -#else
    8.98 -    Log(@"** %@ authorizeSSLPeer: %@",self,peerCert);
    8.99 -#endif
   8.100 +    Log(@"** %@ authorizeSSLPeer: %@",self, [TCPEndpoint describeCert:peerCert]);
   8.101      return peerCert != nil;
   8.102  }
   8.103  - (void) connection: (TCPConnection*)connection failedToOpen: (NSError*)error
   8.104  {
   8.105 -    Log(@"** %@ failedToOpen: %@",connection,error);
   8.106 +    Warn(@"** %@ failedToOpen: %@",connection,error);
   8.107      CFRunLoopStop(CFRunLoopGetCurrent());
   8.108  }
   8.109  - (void) connectionDidClose: (TCPConnection*)connection
   8.110  {
   8.111 -    Log(@"** %@ didClose",connection);
   8.112 +    if (connection.error)
   8.113 +        Warn(@"** %@ didClose: %@", connection,connection.error);
   8.114 +    else
   8.115 +        Log(@"** %@ didClose", connection);
   8.116      setObj(&_conn,nil);
   8.117      [NSObject cancelPreviousPerformRequestsWithTarget: self];
   8.118      CFRunLoopStop(CFRunLoopGetCurrent());
   8.119 @@ -188,7 +206,7 @@
   8.120          const UInt8 *bytes = body.bytes;
   8.121          for( size_t i=0; i<size; i++ )
   8.122              AssertEq(bytes[i],i % 256);
   8.123 -        AssertEq(size,sizeObj.intValue);
   8.124 +        AssertEq(size,sizeObj.unsignedIntValue);
   8.125      }
   8.126      Assert(sizeObj);
   8.127      [_pending removeObjectForKey: $object(response.number)];
   8.128 @@ -207,9 +225,7 @@
   8.129  
   8.130  
   8.131  TestCase(BLIPConnection) {
   8.132 -#if HAVE_KEYCHAIN_FRAMEWORK
   8.133 -    [Keychain setUserInteractionAllowed: YES];
   8.134 -#endif
   8.135 +    SecKeychainSetUserInteractionAllowed(true);
   8.136      BLIPConnectionTester *tester = [[BLIPConnectionTester alloc] init];
   8.137      CAssert(tester);
   8.138      
   8.139 @@ -244,12 +260,11 @@
   8.140          _listener.delegate = self;
   8.141          _listener.pickAvailablePort = YES;
   8.142          _listener.bonjourServiceType = @"_bliptest._tcp";
   8.143 -        if( kListenerRequiresSSL ) {
   8.144 -            SecIdentityRef listenerIdentity = GetListenerIdentity();
   8.145 -            Assert(listenerIdentity);
   8.146 -            _listener.SSLProperties = $mdict({kTCPPropertySSLCertificates, $array((id)listenerIdentity)},
   8.147 -                                             {kTCPPropertySSLAllowsAnyRoot,$true},
   8.148 -                            {kTCPPropertySSLClientSideAuthentication, $object(kTCPTryAuthenticate)});
   8.149 +        if( kListenerUsesSSL ) {
   8.150 +            [_listener setPeerToPeerIdentity: GetListenerIdentity()];
   8.151 +            if (!kListenerRequiresClientCert)
   8.152 +                [_listener setSSLProperty: $object(kTCPTryAuthenticate) 
   8.153 +                                   forKey: kTCPPropertySSLClientSideAuthentication];
   8.154          }
   8.155          Assert( [_listener open] );
   8.156          Log(@"%@ is listening...",self);
   8.157 @@ -293,12 +308,7 @@
   8.158  }
   8.159  - (BOOL) connection: (TCPConnection*)connection authorizeSSLPeer: (SecCertificateRef)peerCert
   8.160  {
   8.161 -#if HAVE_KEYCHAIN_FRAMEWORK
   8.162 -    Certificate *cert = peerCert ?[Certificate certificateWithCertificateRef: peerCert] :nil;
   8.163 -    Log(@"** %@ authorizeSSLPeer: %@",connection,cert);
   8.164 -#else
   8.165 -    Log(@"** %@ authorizeSSLPeer: %@",self,peerCert);
   8.166 -#endif
   8.167 +    Log(@"** %@ authorizeSSLPeer: %@",self, [TCPEndpoint describeCert:peerCert]);
   8.168      return peerCert != nil || ! kListenerRequiresClientCert;
   8.169  }
   8.170  - (void) connection: (TCPConnection*)connection failedToOpen: (NSError*)error
   8.171 @@ -307,7 +317,10 @@
   8.172  }
   8.173  - (void) connectionDidClose: (TCPConnection*)connection
   8.174  {
   8.175 -    Log(@"** %@ didClose",connection);
   8.176 +    if (connection.error)
   8.177 +        Warn(@"** %@ didClose: %@", connection,connection.error);
   8.178 +    else
   8.179 +        Log(@"** %@ didClose", connection);
   8.180      [connection release];
   8.181  }
   8.182  - (void) connection: (BLIPConnection*)connection receivedRequest: (BLIPRequest*)request
   8.183 @@ -322,7 +335,7 @@
   8.184      
   8.185      AssertEqual([request valueOfProperty: @"Content-Type"], @"application/octet-stream");
   8.186      Assert([request valueOfProperty: @"User-Agent"] != nil);
   8.187 -    AssertEq([[request valueOfProperty: @"Size"] intValue], size);
   8.188 +    AssertEq((size_t)[[request valueOfProperty: @"Size"] intValue], size);
   8.189  
   8.190      [request respondWithData: body contentType: request.contentType];
   8.191      
   8.192 @@ -351,9 +364,7 @@
   8.193      EnableLogTo(BLIP,YES);
   8.194      EnableLogTo(PortMapper,YES);
   8.195      EnableLogTo(Bonjour,YES);
   8.196 -#if HAVE_KEYCHAIN_FRAMEWORK
   8.197 -    [Keychain setUserInteractionAllowed: YES];
   8.198 -#endif
   8.199 +    SecKeychainSetUserInteractionAllowed(true);
   8.200      BLIPTestListener *listener = [[BLIPTestListener alloc] init];
   8.201      
   8.202      [[NSRunLoop currentRunLoop] run];
     9.1 --- a/BLIP/BLIPWriter.h	Tue Dec 02 22:42:56 2008 -0800
     9.2 +++ b/BLIP/BLIPWriter.h	Wed Apr 22 16:45:39 2009 -0700
     9.3 @@ -10,8 +10,10 @@
     9.4  @class BLIPRequest, BLIPResponse, BLIPMessage;
     9.5  
     9.6  
     9.7 +/** INTERNAL class that sends BLIP frames over the socket. */
     9.8  @interface BLIPWriter : TCPWriter
     9.9  {
    9.10 +    @private
    9.11      NSMutableArray *_outBox;
    9.12      UInt32 _numRequestsSent;
    9.13  }
    10.1 --- a/BLIP/Demo/BLIP Echo Client-Info.plist	Tue Dec 02 22:42:56 2008 -0800
    10.2 +++ b/BLIP/Demo/BLIP Echo Client-Info.plist	Wed Apr 22 16:45:39 2009 -0700
    10.3 @@ -7,7 +7,7 @@
    10.4  	<key>CFBundleExecutable</key>
    10.5  	<string>${EXECUTABLE_NAME}</string>
    10.6  	<key>CFBundleIdentifier</key>
    10.7 -	<string>com.yourcompany.${PRODUCT_NAME:identifier}</string>
    10.8 +	<string>com.mooseyard.BLIPEchoClient</string>
    10.9  	<key>CFBundleInfoDictionaryVersion</key>
   10.10  	<string>6.0</string>
   10.11  	<key>CFBundlePackageType</key>
    11.1 --- a/BLIP/Demo/BLIPEchoClient.h	Tue Dec 02 22:42:56 2008 -0800
    11.2 +++ b/BLIP/Demo/BLIPEchoClient.h	Wed Apr 22 16:45:39 2009 -0700
    11.3 @@ -9,23 +9,24 @@
    11.4  //
    11.5  
    11.6  #import <Cocoa/Cocoa.h>
    11.7 -@class BLIPConnection;
    11.8 +#import "BLIPConnection.h"
    11.9 +@class MYBonjourBrowser;
   11.10  
   11.11  
   11.12 -@interface BLIPEchoClient : NSObject
   11.13 +@interface BLIPEchoClient : NSObject <BLIPConnectionDelegate>
   11.14  {
   11.15      IBOutlet NSTextField * inputField;
   11.16      IBOutlet NSTextField * responseField;
   11.17      IBOutlet NSTableView * serverTableView;
   11.18      
   11.19 -    NSNetServiceBrowser * _serviceBrowser;
   11.20 -    NSMutableArray * _serviceList;
   11.21 -
   11.22 +    MYBonjourBrowser * _serviceBrowser;
   11.23      BLIPConnection *_connection;
   11.24  }
   11.25  
   11.26 -@property (readonly) NSMutableArray *serviceList;
   11.27 +@property (readonly) MYBonjourBrowser *serviceBrowser;
   11.28 +@property (readonly) NSArray *serviceList;
   11.29  
   11.30 +- (IBAction)serverClicked:(id)sender;
   11.31  - (IBAction)sendText:(id)sender;
   11.32  
   11.33  @end
    12.1 --- a/BLIP/Demo/BLIPEchoClient.m	Tue Dec 02 22:42:56 2008 -0800
    12.2 +++ b/BLIP/Demo/BLIPEchoClient.m	Wed Apr 22 16:45:39 2009 -0700
    12.3 @@ -9,44 +9,36 @@
    12.4  //
    12.5  
    12.6  #import "BLIPEchoClient.h"
    12.7 -#import "BLIP.h"
    12.8 +#import "MYBonjourBrowser.h"
    12.9 +#import "MYBonjourService.h"
   12.10 +#import "CollectionUtils.h"
   12.11 +#import "MYNetwork.h"
   12.12  #import "Target.h"
   12.13  
   12.14  
   12.15  @implementation BLIPEchoClient
   12.16  
   12.17 -@synthesize serviceList=_serviceList;
   12.18  
   12.19  - (void)awakeFromNib 
   12.20  {
   12.21 -    _serviceBrowser = [[NSNetServiceBrowser alloc] init];
   12.22 -    _serviceList = [[NSMutableArray alloc] init];
   12.23 -    [_serviceBrowser setDelegate:self];
   12.24 -    
   12.25 -    [_serviceBrowser searchForServicesOfType:@"_blipecho._tcp." inDomain:@""];
   12.26 +    [self.serviceBrowser start];
   12.27  }
   12.28  
   12.29 -#pragma mark -
   12.30 -#pragma mark NSNetServiceBrowser delegate methods
   12.31 -
   12.32 -// We broadcast the willChangeValueForKey: and didChangeValueForKey: for the NSTableView binding to work.
   12.33 -
   12.34 -- (void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didFindService:(NSNetService *)aNetService moreComing:(BOOL)moreComing {
   12.35 -    if (![_serviceList containsObject:aNetService]) {
   12.36 -        [self willChangeValueForKey:@"serviceList"];
   12.37 -        [_serviceList addObject:aNetService];
   12.38 -        [self didChangeValueForKey:@"serviceList"];
   12.39 -    }
   12.40 +- (MYBonjourBrowser*) serviceBrowser {
   12.41 +    if (!_serviceBrowser)
   12.42 +        _serviceBrowser = [[MYBonjourBrowser alloc] initWithServiceType: @"_blipecho._tcp."];
   12.43 +    return _serviceBrowser;
   12.44  }
   12.45  
   12.46 -- (void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didRemoveService:(NSNetService *)aNetService moreComing:(BOOL)moreComing {
   12.47 -    if ([_serviceList containsObject:aNetService]) {
   12.48 -        [self willChangeValueForKey:@"serviceList"];
   12.49 -        [_serviceList removeObject:aNetService];
   12.50 -        [self didChangeValueForKey:@"serviceList"];
   12.51 -    }
   12.52 +- (NSArray*) serviceList {
   12.53 +    return [_serviceBrowser.services.allObjects sortedArrayUsingSelector: @selector(compare:)];
   12.54  }
   12.55  
   12.56 ++ (NSArray*) keyPathsForValuesAffectingServiceList {
   12.57 +    return $array(@"serviceBrowser.services");
   12.58 +}
   12.59 +
   12.60 +
   12.61  #pragma mark -
   12.62  #pragma mark BLIPConnection support
   12.63  
   12.64 @@ -54,9 +46,10 @@
   12.65  - (void)openConnection: (NSNetService*)service 
   12.66  {
   12.67      _connection = [[BLIPConnection alloc] initToNetService: service];
   12.68 -    if( _connection )
   12.69 +    if( _connection ) {
   12.70 +        _connection.delegate = self;
   12.71          [_connection open];
   12.72 -    else
   12.73 +    } else
   12.74          NSBeep();
   12.75  }
   12.76  
   12.77 @@ -64,10 +57,35 @@
   12.78  - (void)closeConnection
   12.79  {
   12.80      [_connection close];
   12.81 -    [_connection release];
   12.82 -    _connection = nil;
   12.83  }
   12.84  
   12.85 +/** Called after the connection successfully opens. */
   12.86 +- (void) connectionDidOpen: (TCPConnection*)connection {
   12.87 +    if (connection==_connection) {
   12.88 +        [inputField setEnabled: YES];
   12.89 +        [responseField setEnabled: YES];
   12.90 +        [inputField.window makeFirstResponder: inputField];
   12.91 +    }
   12.92 +}
   12.93 +
   12.94 +/** Called after the connection fails to open due to an error. */
   12.95 +- (void) connection: (TCPConnection*)connection failedToOpen: (NSError*)error {
   12.96 +    [serverTableView.window presentError: error];
   12.97 +}
   12.98 +
   12.99 +/** Called after the connection closes. */
  12.100 +- (void) connectionDidClose: (TCPConnection*)connection {
  12.101 +    if (connection==_connection) {
  12.102 +        if (connection.error)
  12.103 +            [serverTableView.window presentError: connection.error];
  12.104 +        [_connection release];
  12.105 +        _connection = nil;
  12.106 +        [inputField setEnabled: NO];
  12.107 +        [responseField setEnabled: NO];
  12.108 +    }
  12.109 +}
  12.110 +
  12.111 +
  12.112  #pragma mark -
  12.113  #pragma mark GUI action methods
  12.114  
  12.115 @@ -77,7 +95,7 @@
  12.116      
  12.117      [self closeConnection];
  12.118      if (-1 != selectedRow)
  12.119 -        [self openConnection: [_serviceList objectAtIndex:selectedRow]];
  12.120 +        [self openConnection: [[self.serviceList objectAtIndex:selectedRow] netService]];
  12.121  }
  12.122  
  12.123  /* Send a BLIP request containing the string in the textfield */
  12.124 @@ -86,7 +104,11 @@
  12.125      BLIPRequest *r = [_connection request];
  12.126      r.bodyString = [sender stringValue];
  12.127      BLIPResponse *response = [r send];
  12.128 -    response.onComplete = $target(self,gotResponse:);
  12.129 +    if (response) {
  12.130 +        response.onComplete = $target(self,gotResponse:);
  12.131 +        [inputField setStringValue: @""];
  12.132 +    } else
  12.133 +        NSBeep();
  12.134  }
  12.135  
  12.136  /* Receive the response to the BLIP request, and put its contents into the response field */
  12.137 @@ -100,5 +122,6 @@
  12.138  
  12.139  int main(int argc, char *argv[])
  12.140  {
  12.141 +    //RunTestCases(argc,(const char**)argv);
  12.142      return NSApplicationMain(argc,  (const char **) argv);
  12.143  }
    13.1 --- a/BLIP/Demo/BLIPEchoClient.xib	Tue Dec 02 22:42:56 2008 -0800
    13.2 +++ b/BLIP/Demo/BLIPEchoClient.xib	Wed Apr 22 16:45:39 2009 -0700
    13.3 @@ -1,20 +1,29 @@
    13.4  <?xml version="1.0" encoding="UTF-8"?>
    13.5 -<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.02">
    13.6 +<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.03">
    13.7  	<data>
    13.8  		<int key="IBDocument.SystemTarget">1050</int>
    13.9 -		<string key="IBDocument.SystemVersion">9C7010</string>
   13.10 -		<string key="IBDocument.InterfaceBuilderVersion">658</string>
   13.11 -		<string key="IBDocument.AppKitVersion">949.26</string>
   13.12 -		<string key="IBDocument.HIToolboxVersion">352.00</string>
   13.13 +		<string key="IBDocument.SystemVersion">9G55</string>
   13.14 +		<string key="IBDocument.InterfaceBuilderVersion">677</string>
   13.15 +		<string key="IBDocument.AppKitVersion">949.43</string>
   13.16 +		<string key="IBDocument.HIToolboxVersion">353.00</string>
   13.17  		<object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
   13.18  			<bool key="EncodedWithXMLCoder">YES</bool>
   13.19 -			<integer value="21"/>
   13.20  			<integer value="29"/>
   13.21 +			<integer value="2"/>
   13.22  		</object>
   13.23  		<object class="NSArray" key="IBDocument.PluginDependencies">
   13.24  			<bool key="EncodedWithXMLCoder">YES</bool>
   13.25  			<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
   13.26  		</object>
   13.27 +		<object class="NSMutableDictionary" key="IBDocument.Metadata">
   13.28 +			<bool key="EncodedWithXMLCoder">YES</bool>
   13.29 +			<object class="NSArray" key="dict.sortedKeys">
   13.30 +				<bool key="EncodedWithXMLCoder">YES</bool>
   13.31 +			</object>
   13.32 +			<object class="NSMutableArray" key="dict.values">
   13.33 +				<bool key="EncodedWithXMLCoder">YES</bool>
   13.34 +			</object>
   13.35 +		</object>
   13.36  		<object class="NSMutableArray" key="IBDocument.RootObjects" id="81650750">
   13.37  			<bool key="EncodedWithXMLCoder">YES</bool>
   13.38  			<object class="NSCustomObject" id="568359733">
   13.39 @@ -38,6 +47,7 @@
   13.40  				<object class="NSMutableString" key="NSViewClass">
   13.41  					<characters key="NS.bytes">View</characters>
   13.42  				</object>
   13.43 +				<string key="NSWindowContentMaxSize">{3.40282e+38, 3.40282e+38}</string>
   13.44  				<string key="NSWindowContentMinSize">{213, 107}</string>
   13.45  				<object class="NSView" key="NSWindowView" id="707481179">
   13.46  					<reference key="NSNextResponder"/>
   13.47 @@ -217,7 +227,7 @@
   13.48  							<reference key="NSSuperview" ref="707481179"/>
   13.49  							<bool key="NSEnabled">YES</bool>
   13.50  							<object class="NSTextFieldCell" key="NSCell" id="364162739">
   13.51 -								<int key="NSCellFlags">-1804468671</int>
   13.52 +								<int key="NSCellFlags">-1267597759</int>
   13.53  								<int key="NSCellFlags2">272630784</int>
   13.54  								<string key="NSContents"/>
   13.55  								<reference key="NSSupport" ref="343719836"/>
   13.56 @@ -244,7 +254,7 @@
   13.57  							<reference key="NSSuperview" ref="707481179"/>
   13.58  							<bool key="NSEnabled">YES</bool>
   13.59  							<object class="NSTextFieldCell" key="NSCell" id="617761818">
   13.60 -								<int key="NSCellFlags">-2072904127</int>
   13.61 +								<int key="NSCellFlags">-1536033215</int>
   13.62  								<int key="NSCellFlags2">272630784</int>
   13.63  								<string key="NSContents"/>
   13.64  								<reference key="NSSupport" ref="343719836"/>
   13.65 @@ -1880,7 +1890,6 @@
   13.66  					<string>208.IBPluginDependency</string>
   13.67  					<string>208.ImportedFromIB2</string>
   13.68  					<string>21.IBEditorWindowLastContentRect</string>
   13.69 -					<string>21.IBPluginDependency</string>
   13.70  					<string>21.IBWindowTemplateEditedContentRect</string>
   13.71  					<string>21.ImportedFromIB2</string>
   13.72  					<string>21.NSWindowTemplate.visibleAtLaunch</string>
   13.73 @@ -1894,11 +1903,18 @@
   13.74  					<string>213.ImportedFromIB2</string>
   13.75  					<string>214.IBPluginDependency</string>
   13.76  					<string>214.ImportedFromIB2</string>
   13.77 +					<string>228.IBPluginDependency</string>
   13.78 +					<string>229.IBPluginDependency</string>
   13.79  					<string>23.IBPluginDependency</string>
   13.80  					<string>23.ImportedFromIB2</string>
   13.81 +					<string>230.IBPluginDependency</string>
   13.82 +					<string>231.IBPluginDependency</string>
   13.83  					<string>231.IBShouldRemoveOnLegacySave</string>
   13.84 +					<string>232.IBPluginDependency</string>
   13.85  					<string>232.IBShouldRemoveOnLegacySave</string>
   13.86 +					<string>233.IBPluginDependency</string>
   13.87  					<string>233.IBShouldRemoveOnLegacySave</string>
   13.88 +					<string>234.IBPluginDependency</string>
   13.89  					<string>234.IBShouldRemoveOnLegacySave</string>
   13.90  					<string>24.IBPluginDependency</string>
   13.91  					<string>24.ImportedFromIB2</string>
   13.92 @@ -2040,9 +2056,8 @@
   13.93  					<reference ref="5"/>
   13.94  					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
   13.95  					<reference ref="5"/>
   13.96 -					<string>{{108, 555}, {529, 256}}</string>
   13.97 -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
   13.98 -					<string>{{108, 555}, {529, 256}}</string>
   13.99 +					<string>{{82, 548}, {529, 256}}</string>
  13.100 +					<string>{{82, 548}, {529, 256}}</string>
  13.101  					<reference ref="5"/>
  13.102  					<reference ref="5"/>
  13.103  					<reference ref="5"/>
  13.104 @@ -2056,10 +2071,17 @@
  13.105  					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
  13.106  					<reference ref="5"/>
  13.107  					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
  13.108 +					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
  13.109 +					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
  13.110  					<reference ref="5"/>
  13.111 +					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
  13.112 +					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
  13.113  					<reference ref="5"/>
  13.114 +					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
  13.115  					<reference ref="5"/>
  13.116 +					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
  13.117  					<reference ref="5"/>
  13.118 +					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
  13.119  					<reference ref="5"/>
  13.120  					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
  13.121  					<reference ref="5"/>
  13.122 @@ -2129,8 +2151,17 @@
  13.123  					<string key="className">BLIPEchoClient</string>
  13.124  					<string key="superclassName">NSObject</string>
  13.125  					<object class="NSMutableDictionary" key="actions">
  13.126 -						<string key="NS.key.0">sendText:</string>
  13.127 -						<string key="NS.object.0">id</string>
  13.128 +						<bool key="EncodedWithXMLCoder">YES</bool>
  13.129 +						<object class="NSMutableArray" key="dict.sortedKeys">
  13.130 +							<bool key="EncodedWithXMLCoder">YES</bool>
  13.131 +							<string>sendText:</string>
  13.132 +							<string>serverClicked:</string>
  13.133 +						</object>
  13.134 +						<object class="NSMutableArray" key="dict.values">
  13.135 +							<bool key="EncodedWithXMLCoder">YES</bool>
  13.136 +							<string>id</string>
  13.137 +							<string>id</string>
  13.138 +						</object>
  13.139  					</object>
  13.140  					<object class="NSMutableDictionary" key="outlets">
  13.141  						<bool key="EncodedWithXMLCoder">YES</bool>
  13.142 @@ -2162,6 +2193,7 @@
  13.143  				</object>
  13.144  				<object class="IBPartialClassDescription">
  13.145  					<string key="className">FirstResponder</string>
  13.146 +					<string key="superclassName">NSObject</string>
  13.147  					<object class="IBClassDescriptionSource" key="sourceIdentifier">
  13.148  						<string key="majorKey">IBUserSource</string>
  13.149  						<string key="minorKey"/>
  13.150 @@ -2170,7 +2202,7 @@
  13.151  			</object>
  13.152  		</object>
  13.153  		<int key="IBDocument.localizationMode">0</int>
  13.154 -		<nil key="IBDocument.LastKnownRelativeProjectPath"/>
  13.155 +		<string key="IBDocument.LastKnownRelativeProjectPath">../../MYNetwork.xcodeproj</string>
  13.156  		<int key="IBDocument.defaultPropertyAccessControl">3</int>
  13.157  	</data>
  13.158  </archive>
    14.1 --- a/BLIP/Demo/BLIPEchoServer.m	Tue Dec 02 22:42:56 2008 -0800
    14.2 +++ b/BLIP/Demo/BLIPEchoServer.m	Wed Apr 22 16:45:39 2009 -0700
    14.3 @@ -7,7 +7,7 @@
    14.4  //
    14.5  
    14.6  #import "BLIPEchoServer.h"
    14.7 -#import "BLIP.h"
    14.8 +#import "MYNetwork.h"
    14.9  
   14.10  
   14.11  @implementation BLIPEchoServer
    15.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.2 +++ b/Bonjour/MYBonjourBrowser.h	Wed Apr 22 16:45:39 2009 -0700
    15.3 @@ -0,0 +1,52 @@
    15.4 +//
    15.5 +//  MYBonjourBrowser.h
    15.6 +//  MYNetwork
    15.7 +//
    15.8 +//  Created by Jens Alfke on 1/22/08.
    15.9 +//  Copyright 2008 Jens Alfke. All rights reserved.
   15.10 +//
   15.11 +
   15.12 +#import <Foundation/Foundation.h>
   15.13 +
   15.14 +
   15.15 +/** Searches for Bonjour services of a specific type. */
   15.16 +@interface MYBonjourBrowser : NSObject
   15.17 +{
   15.18 +    @private
   15.19 +    NSString *_serviceType;
   15.20 +    NSNetServiceBrowser *_browser;
   15.21 +    BOOL _browsing;
   15.22 +    NSError *_error;
   15.23 +    Class _serviceClass;
   15.24 +    NSMutableSet *_services, *_addServices, *_rmvServices;
   15.25 +}
   15.26 +
   15.27 +/** Initializes a new BonjourBrowser.
   15.28 +    Call -start to begin browsing.
   15.29 +    @param serviceType  The name of the service type to look for, e.g. "_http._tcp". */
   15.30 +- (id) initWithServiceType: (NSString*)serviceType;
   15.31 +
   15.32 +/** Starts browsing. This is asynchronous, so nothing will happen immediately. */
   15.33 +- (void) start;
   15.34 +
   15.35 +/** Stops browsing. */
   15.36 +- (void) stop;
   15.37 +
   15.38 +/** Is the browser currently browsing? */
   15.39 +@property (readonly) BOOL browsing;
   15.40 +
   15.41 +/** The current error status, if any.
   15.42 +    This is KV-observable. */
   15.43 +@property (readonly,retain) NSError* error;
   15.44 +
   15.45 +/** The set of currently found services. These are instances of the serviceClass,
   15.46 +    which is BonjourService by default.
   15.47 +    This is KV-observable. */
   15.48 +@property (readonly) NSSet *services;
   15.49 +
   15.50 +/** The class of objects to create to represent services.
   15.51 +    The default value is [BonjourService class]; you can change this, but only
   15.52 +    to a subclass of that. */
   15.53 +@property Class serviceClass;
   15.54 +
   15.55 +@end
    16.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.2 +++ b/Bonjour/MYBonjourBrowser.m	Wed Apr 22 16:45:39 2009 -0700
    16.3 @@ -0,0 +1,239 @@
    16.4 +//
    16.5 +//  MYBonjourBrowser.m
    16.6 +//  MYNetwork
    16.7 +//
    16.8 +//  Created by Jens Alfke on 1/22/08.
    16.9 +//  Copyright 2008 Jens Alfke. All rights reserved.
   16.10 +//
   16.11 +
   16.12 +#import "MYBonjourBrowser.h"
   16.13 +#import "MYBonjourService.h"
   16.14 +#import "Test.h"
   16.15 +#import "Logging.h"
   16.16 +
   16.17 +
   16.18 +@interface MYBonjourBrowser ()
   16.19 +@property BOOL browsing;
   16.20 +@property (retain) NSError* error;
   16.21 +@end
   16.22 +
   16.23 +
   16.24 +@implementation MYBonjourBrowser
   16.25 +
   16.26 +
   16.27 +- (id) initWithServiceType: (NSString*)serviceType
   16.28 +{
   16.29 +    Assert(serviceType);
   16.30 +    self = [super init];
   16.31 +    if (self != nil) {
   16.32 +        _serviceType = [serviceType copy];
   16.33 +        _browser = [[NSNetServiceBrowser alloc] init];
   16.34 +        _browser.delegate = self;
   16.35 +        _services = [[NSMutableSet alloc] init];
   16.36 +        _addServices = [[NSMutableSet alloc] init];
   16.37 +        _rmvServices = [[NSMutableSet alloc] init];
   16.38 +        _serviceClass = [MYBonjourService class];
   16.39 +    }
   16.40 +    return self;
   16.41 +}
   16.42 +
   16.43 +
   16.44 +- (void) dealloc
   16.45 +{
   16.46 +    LogTo(Bonjour,@"DEALLOC BonjourBrowser");
   16.47 +    [_browser stop];
   16.48 +    _browser.delegate = nil;
   16.49 +    [_browser release];
   16.50 +    [_serviceType release];
   16.51 +    [_error release];
   16.52 +    [_services release];
   16.53 +    [_addServices release];
   16.54 +    [_rmvServices release];
   16.55 +    [super dealloc];
   16.56 +}
   16.57 +
   16.58 +
   16.59 +@synthesize browsing=_browsing, error=_error, services=_services, serviceClass=_serviceClass;
   16.60 +
   16.61 +
   16.62 +- (void) start
   16.63 +{
   16.64 +    [_browser searchForServicesOfType: _serviceType inDomain: @"local."];
   16.65 +}
   16.66 +
   16.67 +- (void) stop
   16.68 +{
   16.69 +    [_browser stop];
   16.70 +}
   16.71 +
   16.72 +
   16.73 +- (void)netServiceBrowserWillSearch:(NSNetServiceBrowser *)netServiceBrowser
   16.74 +{
   16.75 +    LogTo(Bonjour,@"%@ started browsing",self);
   16.76 +    self.browsing = YES;
   16.77 +}
   16.78 +
   16.79 +- (void)netServiceBrowserDidStopSearch:(NSNetServiceBrowser *)netServiceBrowser
   16.80 +{
   16.81 +    LogTo(Bonjour,@"%@ stopped browsing",self);
   16.82 +    self.browsing = NO;
   16.83 +}
   16.84 +
   16.85 +- (void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser 
   16.86 +             didNotSearch:(NSDictionary *)errorDict
   16.87 +{
   16.88 +    NSString *domain = [errorDict objectForKey: NSNetServicesErrorDomain];
   16.89 +    int err = [[errorDict objectForKey: NSNetServicesErrorCode] intValue];
   16.90 +    self.error = [NSError errorWithDomain: domain code: err userInfo: nil];
   16.91 +    LogTo(Bonjour,@"%@ got error: ",self,self.error);
   16.92 +    self.browsing = NO;
   16.93 +}
   16.94 +
   16.95 +
   16.96 +- (void) _updateServiceList
   16.97 +{
   16.98 +    if( _rmvServices.count ) {
   16.99 +        [self willChangeValueForKey: @"services" 
  16.100 +                    withSetMutation: NSKeyValueMinusSetMutation
  16.101 +                       usingObjects: _rmvServices];
  16.102 +        [_services minusSet: _rmvServices];
  16.103 +        [self didChangeValueForKey: @"services" 
  16.104 +                   withSetMutation: NSKeyValueMinusSetMutation
  16.105 +                      usingObjects: _rmvServices];
  16.106 +        [_rmvServices makeObjectsPerformSelector: @selector(removed)];
  16.107 +        [_rmvServices removeAllObjects];
  16.108 +    }
  16.109 +    if( _addServices.count ) {
  16.110 +        [_addServices makeObjectsPerformSelector: @selector(added)];
  16.111 +        [self willChangeValueForKey: @"services" 
  16.112 +                    withSetMutation: NSKeyValueUnionSetMutation
  16.113 +                       usingObjects: _addServices];
  16.114 +        [_services unionSet: _addServices];
  16.115 +        [self didChangeValueForKey: @"services" 
  16.116 +                   withSetMutation: NSKeyValueUnionSetMutation
  16.117 +                      usingObjects: _addServices];
  16.118 +        [_addServices removeAllObjects];
  16.119 +    }
  16.120 +}
  16.121 +
  16.122 +
  16.123 +- (void) _handleService: (NSNetService*)netService 
  16.124 +                  addTo: (NSMutableSet*)addTo
  16.125 +             removeFrom: (NSMutableSet*)removeFrom
  16.126 +             moreComing: (BOOL)moreComing
  16.127 +{
  16.128 +    // Wrap the NSNetService in a BonjourService, using an existing instance if possible:
  16.129 +    MYBonjourService *service = [[_serviceClass alloc] initWithNetService: netService];
  16.130 +    MYBonjourService *existingService = [_services member: service];
  16.131 +    if( existingService ) {
  16.132 +        [service release];
  16.133 +        service = [existingService retain];
  16.134 +    }
  16.135 +    
  16.136 +    if( [removeFrom containsObject: service] )
  16.137 +        [removeFrom removeObject: service];
  16.138 +    else
  16.139 +        [addTo addObject: service];
  16.140 +    [service release];
  16.141 +    if( ! moreComing )
  16.142 +        [self _updateServiceList];
  16.143 +}
  16.144 +
  16.145 +- (void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser 
  16.146 +           didFindService:(NSNetService *)netService
  16.147 +               moreComing:(BOOL)moreComing 
  16.148 +{
  16.149 +    //LogTo(Bonjour,@"Add service %@",netService);
  16.150 +    [self _handleService: netService addTo: _addServices removeFrom: _rmvServices moreComing: moreComing];
  16.151 +}
  16.152 +
  16.153 +- (void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser 
  16.154 +         didRemoveService:(NSNetService *)netService 
  16.155 +               moreComing:(BOOL)moreComing 
  16.156 +{
  16.157 +    //LogTo(Bonjour,@"Remove service %@",netService);
  16.158 +    [self _handleService: netService addTo: _rmvServices removeFrom: _addServices moreComing: moreComing];
  16.159 +}
  16.160 +
  16.161 +
  16.162 +@end
  16.163 +
  16.164 +
  16.165 +
  16.166 +#pragma mark -
  16.167 +#pragma mark TESTING:
  16.168 +
  16.169 +@interface BonjourTester : NSObject
  16.170 +{
  16.171 +    MYBonjourBrowser *_browser;
  16.172 +}
  16.173 +@end
  16.174 +
  16.175 +@implementation BonjourTester
  16.176 +
  16.177 +- (id) init
  16.178 +{
  16.179 +    self = [super init];
  16.180 +    if (self != nil) {
  16.181 +        _browser = [[MYBonjourBrowser alloc] initWithServiceType: @"_http._tcp"];
  16.182 +        [_browser addObserver: self forKeyPath: @"services" options: NSKeyValueObservingOptionNew context: NULL];
  16.183 +        [_browser addObserver: self forKeyPath: @"browsing" options: NSKeyValueObservingOptionNew context: NULL];
  16.184 +        [_browser start];
  16.185 +    }
  16.186 +    return self;
  16.187 +}
  16.188 +
  16.189 +- (void) dealloc
  16.190 +{
  16.191 +    [_browser stop];
  16.192 +    [_browser removeObserver: self forKeyPath: @"services"];
  16.193 +    [_browser removeObserver: self forKeyPath: @"browsing"];
  16.194 +    [_browser release];
  16.195 +    [super dealloc];
  16.196 +}
  16.197 +
  16.198 +- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
  16.199 +{
  16.200 +    LogTo(Bonjour,@"Observed change in %@: %@",keyPath,change);
  16.201 +    if( $equal(keyPath,@"services") ) {
  16.202 +        if( [[change objectForKey: NSKeyValueChangeKindKey] intValue]==NSKeyValueChangeInsertion ) {
  16.203 +            NSSet *newServices = [change objectForKey: NSKeyValueChangeNewKey];
  16.204 +            for( MYBonjourService *service in newServices ) {
  16.205 +                LogTo(Bonjour,@"    --> %@ : TXT=%@", service,service.txtRecord);
  16.206 +            }
  16.207 +        }
  16.208 +    }
  16.209 +}
  16.210 +
  16.211 +@end
  16.212 +
  16.213 +TestCase(Bonjour) {
  16.214 +    [NSRunLoop currentRunLoop]; // create runloop
  16.215 +    BonjourTester *tester = [[BonjourTester alloc] init];
  16.216 +    [[NSRunLoop currentRunLoop] runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 15]];
  16.217 +    [tester release];
  16.218 +}
  16.219 +
  16.220 +
  16.221 +
  16.222 +/*
  16.223 + Copyright (c) 2008-2009, Jens Alfke <jens@mooseyard.com>. All rights reserved.
  16.224 + 
  16.225 + Redistribution and use in source and binary forms, with or without modification, are permitted
  16.226 + provided that the following conditions are met:
  16.227 + 
  16.228 + * Redistributions of source code must retain the above copyright notice, this list of conditions
  16.229 + and the following disclaimer.
  16.230 + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
  16.231 + and the following disclaimer in the documentation and/or other materials provided with the
  16.232 + distribution.
  16.233 + 
  16.234 + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
  16.235 + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
  16.236 + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
  16.237 + BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  16.238 + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
  16.239 +  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
  16.240 + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
  16.241 + THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  16.242 + */
    17.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    17.2 +++ b/Bonjour/MYBonjourService.h	Wed Apr 22 16:45:39 2009 -0700
    17.3 @@ -0,0 +1,70 @@
    17.4 +//
    17.5 +//  MYBonjourService.h
    17.6 +//  MYNetwork
    17.7 +//
    17.8 +//  Created by Jens Alfke on 1/22/08.
    17.9 +//  Copyright 2008 Jens Alfke. All rights reserved.
   17.10 +//
   17.11 +
   17.12 +#import <Foundation/Foundation.h>
   17.13 +#import "ConcurrentOperation.h"
   17.14 +@class MYBonjourResolveOperation;
   17.15 +
   17.16 +
   17.17 +/** Represents a Bonjour service discovered by a BonjourBrowser. */
   17.18 +@interface MYBonjourService : NSObject 
   17.19 +{
   17.20 +    @private
   17.21 +    NSNetService *_netService;
   17.22 +    NSDictionary *_txtRecord;
   17.23 +    NSSet *_addresses;
   17.24 +    CFAbsoluteTime _addressesExpireAt;
   17.25 +    MYBonjourResolveOperation *_resolveOp;
   17.26 +}
   17.27 +
   17.28 +/** The service's name. */
   17.29 +@property (readonly) NSString *name;
   17.30 +
   17.31 +/** The service's metadata dictionary, from its DNS TXT record */
   17.32 +@property (readonly,copy) NSDictionary *txtRecord;
   17.33 +
   17.34 +/** A convenience to access a single property from the TXT record. */
   17.35 +- (NSString*) txtStringForKey: (NSString*)key;
   17.36 +
   17.37 +/** Returns a set of IPAddress objects; may be the empty set if address resolution failed,
   17.38 +    or nil if addresses have not been resolved yet (or expired).
   17.39 +    In the latter case, call -resolve and wait for the returned Operation to finish. */
   17.40 +@property (readonly,copy) NSSet* addresses;
   17.41 +
   17.42 +/** Starts looking up the IP address(es) of this service.
   17.43 +    @return  The NSOperation representing the lookup; you can observe this to see when it
   17.44 +        completes, or you can observe the service's 'addresses' property. */
   17.45 +- (MYBonjourResolveOperation*) resolve;
   17.46 +
   17.47 +/** The underlying NSNetSerice object. */
   17.48 +@property (readonly) NSNetService *netService;
   17.49 +
   17.50 +
   17.51 +// Protected methods, for subclass use only:
   17.52 +
   17.53 +- (id) initWithNetService: (NSNetService*)netService;
   17.54 +
   17.55 +// (for subclasses to override, but not call):
   17.56 +- (void) added;
   17.57 +- (void) removed;
   17.58 +- (void) txtRecordChanged;
   17.59 +
   17.60 +@end
   17.61 +
   17.62 +
   17.63 +
   17.64 +@interface MYBonjourResolveOperation : ConcurrentOperation
   17.65 +{
   17.66 +    MYBonjourService *_service;
   17.67 +    NSSet *_addresses;
   17.68 +}
   17.69 +
   17.70 +@property (readonly) MYBonjourService *service;
   17.71 +@property (readonly,retain) NSSet *addresses;
   17.72 +
   17.73 +@end
    18.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    18.2 +++ b/Bonjour/MYBonjourService.m	Wed Apr 22 16:45:39 2009 -0700
    18.3 @@ -0,0 +1,251 @@
    18.4 +//
    18.5 +//  MYBonjourService.m
    18.6 +//  MYNetwork
    18.7 +//
    18.8 +//  Created by Jens Alfke on 1/22/08.
    18.9 +//  Copyright 2008 Jens Alfke. All rights reserved.
   18.10 +//
   18.11 +
   18.12 +#import "MYBonjourService.h"
   18.13 +#import "IPAddress.h"
   18.14 +#import "ConcurrentOperation.h"
   18.15 +#import "Test.h"
   18.16 +#import "Logging.h"
   18.17 +
   18.18 +
   18.19 +NSString* const kBonjourServiceResolvedAddressesNotification = @"BonjourServiceResolvedAddresses";
   18.20 +
   18.21 +
   18.22 +@interface MYBonjourService ()
   18.23 +@property (copy) NSSet* addresses;
   18.24 +@end
   18.25 +
   18.26 +@interface MYBonjourResolveOperation ()
   18.27 +@property (assign) MYBonjourService *service;
   18.28 +@property (retain) NSSet *addresses;
   18.29 +@end
   18.30 +
   18.31 +
   18.32 +
   18.33 +@implementation MYBonjourService
   18.34 +
   18.35 +
   18.36 +- (id) initWithNetService: (NSNetService*)netService
   18.37 +{
   18.38 +    self = [super init];
   18.39 +    if (self != nil) {
   18.40 +        _netService = [netService retain];
   18.41 +        _netService.delegate = self;
   18.42 +    }
   18.43 +    return self;
   18.44 +}
   18.45 +
   18.46 +- (void) dealloc
   18.47 +{
   18.48 +    Log(@"DEALLOC %@",self);
   18.49 +    _netService.delegate = nil;
   18.50 +    [_netService release];
   18.51 +    [_txtRecord release];
   18.52 +    [_addresses release];
   18.53 +    [super dealloc];
   18.54 +}
   18.55 +
   18.56 +
   18.57 +- (NSString*) description
   18.58 +{
   18.59 +    return $sprintf(@"%@['%@'.%@%@]", self.class,self.name,_netService.type,_netService.domain);
   18.60 +}
   18.61 +
   18.62 +
   18.63 +- (NSComparisonResult) compare: (id)obj
   18.64 +{
   18.65 +    return [self.name caseInsensitiveCompare: [obj name]];
   18.66 +}
   18.67 +
   18.68 +
   18.69 +- (NSNetService*) netService        {return _netService;}
   18.70 +- (BOOL) isEqual: (id)obj           {return [obj isKindOfClass: [MYBonjourService class]] && [_netService isEqual: [obj netService]];}
   18.71 +- (NSUInteger) hash                 {return _netService.hash;}
   18.72 +- (NSString*) name                  {return _netService.name;}
   18.73 +
   18.74 +
   18.75 +- (void) added
   18.76 +{
   18.77 +    LogTo(Bonjour,@"Added %@",_netService);
   18.78 +}
   18.79 +
   18.80 +- (void) removed
   18.81 +{
   18.82 +    LogTo(Bonjour,@"Removed %@",_netService);
   18.83 +    [_netService stopMonitoring];
   18.84 +    _netService.delegate = nil;
   18.85 +    
   18.86 +    if( _resolveOp ) {
   18.87 +        [_resolveOp cancel];
   18.88 +        [_resolveOp release];
   18.89 +        _resolveOp = nil;
   18.90 +    }
   18.91 +}
   18.92 +
   18.93 +
   18.94 +#pragma mark -
   18.95 +#pragma mark TXT RECORD:
   18.96 +
   18.97 +
   18.98 +- (NSDictionary*) txtRecord
   18.99 +{
  18.100 +    [_netService startMonitoring];
  18.101 +    return _txtRecord;
  18.102 +}
  18.103 +
  18.104 +- (void) txtRecordChanged
  18.105 +{
  18.106 +    // no-op (this is here for subclassers to override)
  18.107 +}
  18.108 +
  18.109 +- (NSString*) txtStringForKey: (NSString*)key
  18.110 +{
  18.111 +    NSData *value = [self.txtRecord objectForKey: key];
  18.112 +    if( ! value )
  18.113 +        return nil;
  18.114 +    if( ! [value isKindOfClass: [NSData class]] ) {
  18.115 +        Warn(@"TXT dictionary has unexpected value type: %@",value.class);
  18.116 +        return nil;
  18.117 +    }
  18.118 +    NSString *str = [[NSString alloc] initWithData: value encoding: NSUTF8StringEncoding];
  18.119 +    if( ! str )
  18.120 +        str = [[NSString alloc] initWithData: value encoding: NSWindowsCP1252StringEncoding];
  18.121 +    return [str autorelease];
  18.122 +}
  18.123 +
  18.124 +
  18.125 +- (void)netService:(NSNetService *)sender didUpdateTXTRecordData:(NSData *)data
  18.126 +{
  18.127 +    NSDictionary *txtDict = [NSNetService dictionaryFromTXTRecordData: data];
  18.128 +    if( ! $equal(txtDict,_txtRecord) ) {
  18.129 +        LogTo(Bonjour,@"%@ got TXT record (%u bytes)",self,data.length);
  18.130 +        [self willChangeValueForKey: @"txtRecord"];
  18.131 +        setObj(&_txtRecord,txtDict);
  18.132 +        [self didChangeValueForKey: @"txtRecord"];
  18.133 +        [self txtRecordChanged];
  18.134 +    }
  18.135 +}
  18.136 +
  18.137 +
  18.138 +#pragma mark -
  18.139 +#pragma mark ADDRESS RESOLUTION:
  18.140 +
  18.141 +
  18.142 +#define kAddressResolveTimeout      10.0
  18.143 +#define kAddressExpirationInterval  60.0
  18.144 +#define kAddressErrorRetryInterval   5.0
  18.145 +
  18.146 +
  18.147 +- (NSSet*) addresses
  18.148 +{
  18.149 +    if( _addresses && CFAbsoluteTimeGetCurrent() >= _addressesExpireAt ) {
  18.150 +        setObj(&_addresses,nil);            // eww, toss 'em and get new ones
  18.151 +        [self resolve];
  18.152 +    }
  18.153 +    return _addresses;
  18.154 +}
  18.155 +
  18.156 +
  18.157 +- (MYBonjourResolveOperation*) resolve
  18.158 +{
  18.159 +    if( ! _resolveOp ) {
  18.160 +        LogTo(Bonjour,@"Resolving %@",self);
  18.161 +        _resolveOp = [[MYBonjourResolveOperation alloc] init];
  18.162 +        _resolveOp.service = self;
  18.163 +        [_resolveOp start];
  18.164 +        Assert(_netService);
  18.165 +        Assert(_netService.delegate=self);
  18.166 +        [_netService resolveWithTimeout: kAddressResolveTimeout];
  18.167 +    }
  18.168 +    return _resolveOp;
  18.169 +}
  18.170 +
  18.171 +- (void) setAddresses: (NSSet*)addresses
  18.172 +{
  18.173 +    setObj(&_addresses,addresses);
  18.174 +}
  18.175 +
  18.176 +
  18.177 +- (void) _finishedResolving: (NSSet*)addresses expireIn: (NSTimeInterval)expirationInterval
  18.178 +{
  18.179 +    _addressesExpireAt = CFAbsoluteTimeGetCurrent() + expirationInterval;
  18.180 +    self.addresses = addresses;
  18.181 +    _resolveOp.addresses = addresses;
  18.182 +    [_resolveOp finish];
  18.183 +    [_resolveOp release];
  18.184 +    _resolveOp = nil;
  18.185 +}
  18.186 +
  18.187 +
  18.188 +- (void)netServiceDidResolveAddress:(NSNetService *)sender
  18.189 +{
  18.190 +    // Convert the raw sockaddrs into IPAddress objects:
  18.191 +    NSMutableSet *addresses = [NSMutableSet setWithCapacity: 2];
  18.192 +    for( NSData *rawAddr in _netService.addresses ) {
  18.193 +        IPAddress *addr = [[IPAddress alloc] initWithSockAddr: rawAddr.bytes];
  18.194 +        if( addr ) {
  18.195 +            [addresses addObject: addr];
  18.196 +            [addr release];
  18.197 +        }
  18.198 +    }
  18.199 +    LogTo(Bonjour,@"Resolved %@: %@",self,addresses);
  18.200 +    [self _finishedResolving: addresses expireIn: kAddressExpirationInterval];
  18.201 +}
  18.202 +
  18.203 +- (void)netService:(NSNetService *)sender didNotResolve:(NSDictionary *)errorDict
  18.204 +{
  18.205 +    LogTo(Bonjour,@"Error resolving %@ -- %@",self,errorDict);
  18.206 +    [self _finishedResolving: [NSArray array] expireIn: kAddressErrorRetryInterval];
  18.207 +}
  18.208 +
  18.209 +- (void)netServiceDidStop:(NSNetService *)sender
  18.210 +{
  18.211 +    LogTo(Bonjour,@"Resolve stopped for %@",self);
  18.212 +    [self _finishedResolving: [NSArray array] expireIn: kAddressErrorRetryInterval];
  18.213 +}
  18.214 +
  18.215 +
  18.216 +@end
  18.217 +
  18.218 +
  18.219 +
  18.220 +
  18.221 +@implementation MYBonjourResolveOperation
  18.222 +
  18.223 +@synthesize service=_service, addresses=_addresses;
  18.224 +
  18.225 +- (void) dealloc
  18.226 +{
  18.227 +    [_addresses release];
  18.228 +    [super dealloc];
  18.229 +}
  18.230 +
  18.231 +@end
  18.232 +
  18.233 +
  18.234 +/*
  18.235 + Copyright (c) 2008-2009, Jens Alfke <jens@mooseyard.com>. All rights reserved.
  18.236 + 
  18.237 + Redistribution and use in source and binary forms, with or without modification, are permitted
  18.238 + provided that the following conditions are met:
  18.239 + 
  18.240 + * Redistributions of source code must retain the above copyright notice, this list of conditions
  18.241 + and the following disclaimer.
  18.242 + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
  18.243 + and the following disclaimer in the documentation and/or other materials provided with the
  18.244 + distribution.
  18.245 + 
  18.246 + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
  18.247 + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
  18.248 + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
  18.249 + BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  18.250 + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
  18.251 +  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
  18.252 + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
  18.253 + THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  18.254 + */
    19.1 --- a/IPAddress.h	Tue Dec 02 22:42:56 2008 -0800
    19.2 +++ b/IPAddress.h	Wed Apr 22 16:45:39 2009 -0700
    19.3 @@ -35,6 +35,10 @@
    19.4  /** Initializes an IPAddress from a BSD struct sockaddr. */
    19.5  - (id) initWithSockAddr: (const struct sockaddr*)sockaddr;
    19.6  
    19.7 +/** Returns the IP address of this host (plus the specified port number).
    19.8 +    If multiple network interfaces are active, the main one's address is returned. */
    19.9 ++ (IPAddress*) localAddressWithPort: (UInt16)port;
   19.10 +
   19.11  /** Returns the IP address of this host (with a port number of zero).
   19.12      If multiple network interfaces are active, the main one's address is returned. */
   19.13  + (IPAddress*) localAddress;
    20.1 --- a/IPAddress.m	Tue Dec 02 22:42:56 2008 -0800
    20.2 +++ b/IPAddress.m	Wed Apr 22 16:45:39 2009 -0700
    20.3 @@ -160,7 +160,7 @@
    20.4  }
    20.5  
    20.6  
    20.7 -+ (IPAddress*) localAddress
    20.8 ++ (IPAddress*) localAddressWithPort: (UInt16)port
    20.9  {
   20.10      // getifaddrs returns a linked list of interface entries;
   20.11      // find the first active non-loopback interface with IPv4:
   20.12 @@ -179,7 +179,12 @@
   20.13          }
   20.14          freeifaddrs(interfaces);
   20.15      }
   20.16 -    return [[[self alloc] initWithIPv4: address] autorelease];
   20.17 +    return [[[self alloc] initWithIPv4: address port: port] autorelease];
   20.18 +}
   20.19 +
   20.20 ++ (IPAddress*) localAddress
   20.21 +{
   20.22 +    return [self localAddressWithPort: 0];
   20.23  }
   20.24  
   20.25  
   20.26 @@ -339,7 +344,7 @@
   20.27  TestCase(IPAddress) {
   20.28      RequireTestCase(CollectionUtils);
   20.29      IPAddress *addr = [[IPAddress alloc] initWithIPv4: htonl(0x0A0001FE) port: 8080];
   20.30 -    CAssertEq(addr.ipv4,htonl(0x0A0001FE));
   20.31 +    CAssertEq(addr.ipv4,(UInt32)htonl(0x0A0001FE));
   20.32      CAssertEq(addr.port,8080);
   20.33      CAssertEqual(addr.hostname,@"10.0.1.254");
   20.34      CAssertEqual(addr.description,@"10.0.1.254:8080");
   20.35 @@ -347,7 +352,7 @@
   20.36      
   20.37      addr = [[IPAddress alloc] initWithHostname: @"66.66.0.255" port: 123];
   20.38      CAssertEq(addr.class,[IPAddress class]);
   20.39 -    CAssertEq(addr.ipv4,htonl(0x424200FF));
   20.40 +    CAssertEq(addr.ipv4,(UInt32)htonl(0x424200FF));
   20.41      CAssertEq(addr.port,123);
   20.42      CAssertEqual(addr.hostname,@"66.66.0.255");
   20.43      CAssertEqual(addr.description,@"66.66.0.255:123");
   20.44 @@ -355,8 +360,8 @@
   20.45      
   20.46      addr = [[IPAddress alloc] initWithHostname: @"www.apple.com" port: 80];
   20.47      CAssertEq(addr.class,[HostAddress class]);
   20.48 -    Log(@"www.apple.com = 0x%08X", addr.ipv4);
   20.49 -    CAssertEq(addr.ipv4,htonl(0x1195A00A));
   20.50 +    Log(@"www.apple.com = %@ [0x%08X]", addr.ipv4name, ntohl(addr.ipv4));
   20.51 +    CAssertEq(addr.ipv4,(UInt32)htonl(0x11FBC820));
   20.52      CAssertEq(addr.port,80);
   20.53      CAssertEqual(addr.hostname,@"www.apple.com");
   20.54      CAssertEqual(addr.description,@"www.apple.com:80");
    21.1 --- a/MYNetwork-iPhone.xcodeproj/project.pbxproj	Tue Dec 02 22:42:56 2008 -0800
    21.2 +++ b/MYNetwork-iPhone.xcodeproj/project.pbxproj	Wed Apr 22 16:45:39 2009 -0700
    21.3 @@ -36,6 +36,11 @@
    21.4  		270E9B9A0EE64B45003F17CA /* Icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 270E9B970EE64B45003F17CA /* Icon.png */; };
    21.5  		270E9BA10EE64B4E003F17CA /* HelloWorldAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 270E9B9E0EE64B4E003F17CA /* HelloWorldAppDelegate.m */; };
    21.6  		270E9BA20EE64B4E003F17CA /* MyViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 270E9BA00EE64B4E003F17CA /* MyViewController.m */; };
    21.7 +		2777C78D0F75E141007F8D30 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2777C78C0F75E141007F8D30 /* Security.framework */; };
    21.8 +		278C1B2E0F9F865800954AE1 /* MYPortMapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 278C1B2C0F9F865800954AE1 /* MYPortMapper.m */; };
    21.9 +		278C1B2F0F9F865800954AE1 /* PortMapperTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 278C1B2D0F9F865800954AE1 /* PortMapperTest.m */; };
   21.10 +		278C1B350F9F86A100954AE1 /* MYUtilities_Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 278C1B330F9F86A100954AE1 /* MYUtilities_Debug.xcconfig */; };
   21.11 +		278C1B360F9F86A100954AE1 /* MYUtilities_Release.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 278C1B340F9F86A100954AE1 /* MYUtilities_Release.xcconfig */; };
   21.12  		280E754F0DD40C5E005A515E /* MainWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 280E754C0DD40C5E005A515E /* MainWindow.xib */; };
   21.13  /* End PBXBuildFile section */
   21.14  
   21.15 @@ -96,6 +101,12 @@
   21.16  		270E9B9E0EE64B4E003F17CA /* HelloWorldAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HelloWorldAppDelegate.m; sourceTree = "<group>"; };
   21.17  		270E9B9F0EE64B4E003F17CA /* MyViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MyViewController.h; sourceTree = "<group>"; };
   21.18  		270E9BA00EE64B4E003F17CA /* MyViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MyViewController.m; sourceTree = "<group>"; };
   21.19 +		2777C78C0F75E141007F8D30 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; };
   21.20 +		278C1B2B0F9F865800954AE1 /* MYPortMapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYPortMapper.h; sourceTree = "<group>"; };
   21.21 +		278C1B2C0F9F865800954AE1 /* MYPortMapper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYPortMapper.m; sourceTree = "<group>"; };
   21.22 +		278C1B2D0F9F865800954AE1 /* PortMapperTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PortMapperTest.m; sourceTree = "<group>"; };
   21.23 +		278C1B330F9F86A100954AE1 /* MYUtilities_Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = MYUtilities_Debug.xcconfig; sourceTree = "<group>"; };
   21.24 +		278C1B340F9F86A100954AE1 /* MYUtilities_Release.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = MYUtilities_Release.xcconfig; sourceTree = "<group>"; };
   21.25  		280E754C0DD40C5E005A515E /* MainWindow.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MainWindow.xib; sourceTree = "<group>"; };
   21.26  		29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = iPhone/main.m; sourceTree = "<group>"; };
   21.27  		8D1107310486CEB800E47090 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
   21.28 @@ -110,6 +121,7 @@
   21.29  				1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */,
   21.30  				270E9AE90EE61167003F17CA /* libz.dylib in Frameworks */,
   21.31  				270E9B4F0EE63F8F003F17CA /* CFNetwork.framework in Frameworks */,
   21.32 +				2777C78D0F75E141007F8D30 /* Security.framework in Frameworks */,
   21.33  			);
   21.34  			runOnlyForDeploymentPostprocessing = 0;
   21.35  		};
   21.36 @@ -141,6 +153,7 @@
   21.37  				270E9AA20EE61113003F17CA /* IPAddress.m */,
   21.38  				270E9AA30EE61113003F17CA /* TCP */,
   21.39  				270E9AAF0EE61113003F17CA /* BLIP */,
   21.40 +				278C1B2A0F9F865800954AE1 /* PortMapper */,
   21.41  			);
   21.42  			name = MYNetwork;
   21.43  			sourceTree = "<group>";
   21.44 @@ -201,6 +214,8 @@
   21.45  				270E9AD70EE6111A003F17CA /* Target.m */,
   21.46  				270E9AD80EE6111A003F17CA /* Test.h */,
   21.47  				270E9AD90EE6111A003F17CA /* Test.m */,
   21.48 +				278C1B330F9F86A100954AE1 /* MYUtilities_Debug.xcconfig */,
   21.49 +				278C1B340F9F86A100954AE1 /* MYUtilities_Release.xcconfig */,
   21.50  				270E9ADA0EE6111A003F17CA /* GoogleToolboxSubset */,
   21.51  			);
   21.52  			name = MYUtilities;
   21.53 @@ -228,6 +243,16 @@
   21.54  			path = Classes;
   21.55  			sourceTree = "<group>";
   21.56  		};
   21.57 +		278C1B2A0F9F865800954AE1 /* PortMapper */ = {
   21.58 +			isa = PBXGroup;
   21.59 +			children = (
   21.60 +				278C1B2B0F9F865800954AE1 /* MYPortMapper.h */,
   21.61 +				278C1B2C0F9F865800954AE1 /* MYPortMapper.m */,
   21.62 +				278C1B2D0F9F865800954AE1 /* PortMapperTest.m */,
   21.63 +			);
   21.64 +			path = PortMapper;
   21.65 +			sourceTree = "<group>";
   21.66 +		};
   21.67  		29B97314FDCFA39411CA2CEA /* CustomTemplate */ = {
   21.68  			isa = PBXGroup;
   21.69  			children = (
   21.70 @@ -237,6 +262,7 @@
   21.71  				29B97315FDCFA39411CA2CEA /* Other Sources */,
   21.72  				29B97323FDCFA39411CA2CEA /* Frameworks */,
   21.73  				19C28FACFE9D520D11CA2CBB /* Products */,
   21.74 +				2777C78C0F75E141007F8D30 /* Security.framework */,
   21.75  			);
   21.76  			name = CustomTemplate;
   21.77  			sourceTree = "<group>";
   21.78 @@ -325,6 +351,8 @@
   21.79  				270E9B950EE64B3C003F17CA /* HelloWorld.xib in Resources */,
   21.80  				270E9B990EE64B45003F17CA /* Default.png in Resources */,
   21.81  				270E9B9A0EE64B45003F17CA /* Icon.png in Resources */,
   21.82 +				278C1B350F9F86A100954AE1 /* MYUtilities_Debug.xcconfig in Resources */,
   21.83 +				278C1B360F9F86A100954AE1 /* MYUtilities_Release.xcconfig in Resources */,
   21.84  			);
   21.85  			runOnlyForDeploymentPostprocessing = 0;
   21.86  		};
   21.87 @@ -357,6 +385,8 @@
   21.88  				270E9AE40EE6111A003F17CA /* GTMNSData+zlib.m in Sources */,
   21.89  				270E9BA10EE64B4E003F17CA /* HelloWorldAppDelegate.m in Sources */,
   21.90  				270E9BA20EE64B4E003F17CA /* MyViewController.m in Sources */,
   21.91 +				278C1B2E0F9F865800954AE1 /* MYPortMapper.m in Sources */,
   21.92 +				278C1B2F0F9F865800954AE1 /* PortMapperTest.m in Sources */,
   21.93  			);
   21.94  			runOnlyForDeploymentPostprocessing = 0;
   21.95  		};
   21.96 @@ -366,56 +396,37 @@
   21.97  		1D6058940D05DD3E006BFB54 /* Debug */ = {
   21.98  			isa = XCBuildConfiguration;
   21.99  			buildSettings = {
  21.100 -				ALWAYS_SEARCH_USER_PATHS = NO;
  21.101 -				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer: Jens Alfke";
  21.102 -				COPY_PHASE_STRIP = NO;
  21.103 -				GCC_DYNAMIC_NO_PIC = NO;
  21.104 -				GCC_OPTIMIZATION_LEVEL = 0;
  21.105 -				GCC_PRECOMPILE_PREFIX_HEADER = YES;
  21.106 -				GCC_PREFIX_HEADER = iPhone/MYNetwork_iPhone_Prefix.pch;
  21.107  				INFOPLIST_FILE = iPhone/Info.plist;
  21.108  				PRODUCT_NAME = BLIPEcho;
  21.109 -				PROVISIONING_PROFILE = "166C8314-D005-438F-841B-B20D42F71712";
  21.110  			};
  21.111  			name = Debug;
  21.112  		};
  21.113  		1D6058950D05DD3E006BFB54 /* Release */ = {
  21.114  			isa = XCBuildConfiguration;
  21.115  			buildSettings = {
  21.116 -				ALWAYS_SEARCH_USER_PATHS = NO;
  21.117 -				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer: Jens Alfke";
  21.118 -				COPY_PHASE_STRIP = YES;
  21.119 -				GCC_PRECOMPILE_PREFIX_HEADER = YES;
  21.120 -				GCC_PREFIX_HEADER = iPhone/MYNetwork_iPhone_Prefix.pch;
  21.121  				INFOPLIST_FILE = iPhone/Info.plist;
  21.122  				PRODUCT_NAME = BLIPEcho;
  21.123 -				PROVISIONING_PROFILE = "166C8314-D005-438F-841B-B20D42F71712";
  21.124  			};
  21.125  			name = Release;
  21.126  		};
  21.127  		C01FCF4F08A954540054247B /* Debug */ = {
  21.128  			isa = XCBuildConfiguration;
  21.129 +			baseConfigurationReference = 278C1B330F9F86A100954AE1 /* MYUtilities_Debug.xcconfig */;
  21.130  			buildSettings = {
  21.131  				ARCHS = "$(ARCHS_STANDARD_32_BIT)";
  21.132  				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
  21.133 -				GCC_C_LANGUAGE_STANDARD = c99;
  21.134 -				GCC_WARN_ABOUT_RETURN_TYPE = YES;
  21.135 -				GCC_WARN_UNUSED_VARIABLE = YES;
  21.136 +				EXCLUDED_RECURSIVE_SEARCH_PATH_SUBDIRECTORIES = "*.nib *.lproj *.framework *.gch *.xcode* (*) CVS .svn .hg";
  21.137  				ONLY_ACTIVE_ARCH = YES;
  21.138 -				PREBINDING = NO;
  21.139  				SDKROOT = iphonesimulator2.0;
  21.140  			};
  21.141  			name = Debug;
  21.142  		};
  21.143  		C01FCF5008A954540054247B /* Release */ = {
  21.144  			isa = XCBuildConfiguration;
  21.145 +			baseConfigurationReference = 278C1B340F9F86A100954AE1 /* MYUtilities_Release.xcconfig */;
  21.146  			buildSettings = {
  21.147  				ARCHS = "$(ARCHS_STANDARD_32_BIT)";
  21.148  				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
  21.149 -				GCC_C_LANGUAGE_STANDARD = c99;
  21.150 -				GCC_WARN_ABOUT_RETURN_TYPE = YES;
  21.151 -				GCC_WARN_UNUSED_VARIABLE = YES;
  21.152 -				PREBINDING = NO;
  21.153  				SDKROOT = iphonesimulator2.0;
  21.154  			};
  21.155  			name = Release;
    22.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    22.2 +++ b/MYNetwork.h	Wed Apr 22 16:45:39 2009 -0700
    22.3 @@ -0,0 +1,14 @@
    22.4 +/*
    22.5 + *  MYNetwork.h
    22.6 + *  MYNetwork
    22.7 + *
    22.8 + *  Created by Jens Alfke on 4/21/09.
    22.9 + *  Copyright 2009 Jens Alfke. All rights reserved.
   22.10 + *
   22.11 + */
   22.12 +
   22.13 +#import "BLIP.h"
   22.14 +#import "MYBonjourBrowser.h"
   22.15 +#import "MYBonjourService.h"
   22.16 +#import "IPAddress.h"
   22.17 +#import "MYPortMapper.h"
    23.1 --- a/MYNetwork.xcodeproj/project.pbxproj	Tue Dec 02 22:42:56 2008 -0800
    23.2 +++ b/MYNetwork.xcodeproj/project.pbxproj	Wed Apr 22 16:45:39 2009 -0700
    23.3 @@ -24,60 +24,74 @@
    23.4  		270461370DE4918D003D9D3F /* ExceptionUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 270461350DE4918D003D9D3F /* ExceptionUtils.m */; };
    23.5  		270461470DE491A6003D9D3F /* Target.m in Sources */ = {isa = PBXBuildFile; fileRef = 270461460DE491A6003D9D3F /* Target.m */; };
    23.6  		270461890DE49634003D9D3F /* CollectionUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 270461870DE49634003D9D3F /* CollectionUtils.m */; };
    23.7 -		2704618C0DE49652003D9D3F /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2704618B0DE49652003D9D3F /* libz.dylib */; };
    23.8 -		270461920DE4975D003D9D3F /* CoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 270461910DE4975C003D9D3F /* CoreServices.framework */; };
    23.9 -		277904330DE91DE600C6D295 /* BLIPConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = 270460F40DE49030003D9D3F /* BLIPConnection.m */; };
   23.10 -		277904340DE91DE700C6D295 /* BLIPDispatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 270460F60DE49030003D9D3F /* BLIPDispatcher.m */; };
   23.11 -		277904350DE91DE800C6D295 /* BLIPEchoClient.m in Sources */ = {isa = PBXBuildFile; fileRef = 277903E90DE8F08100C6D295 /* BLIPEchoClient.m */; };
   23.12 -		277904370DE91DEB00C6D295 /* BLIPMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = 270460F90DE49030003D9D3F /* BLIPMessage.m */; };
   23.13 -		277904380DE91DEC00C6D295 /* BLIPProperties.m in Sources */ = {isa = PBXBuildFile; fileRef = 270460FB0DE49030003D9D3F /* BLIPProperties.m */; };
   23.14 -		277904390DE91DEE00C6D295 /* BLIPReader.m in Sources */ = {isa = PBXBuildFile; fileRef = 270460FD0DE49030003D9D3F /* BLIPReader.m */; };
   23.15 -		2779043A0DE91DEF00C6D295 /* BLIPRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 27D5EC060DE5FEDE00CD84FA /* BLIPRequest.m */; };
   23.16 -		2779043C0DE91DF100C6D295 /* BLIPWriter.m in Sources */ = {isa = PBXBuildFile; fileRef = 270461000DE49030003D9D3F /* BLIPWriter.m */; };
   23.17 -		2779043D0DE91DF300C6D295 /* IPAddress.m in Sources */ = {isa = PBXBuildFile; fileRef = 270461020DE49030003D9D3F /* IPAddress.m */; };
   23.18 -		2779043E0DE91DF500C6D295 /* TCPConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = 2704610A0DE49030003D9D3F /* TCPConnection.m */; };
   23.19 -		2779043F0DE91DF800C6D295 /* TCPEndpoint.m in Sources */ = {isa = PBXBuildFile; fileRef = 2704610C0DE49030003D9D3F /* TCPEndpoint.m */; };
   23.20 -		277904400DE91DF900C6D295 /* TCPListener.m in Sources */ = {isa = PBXBuildFile; fileRef = 2704610E0DE49030003D9D3F /* TCPListener.m */; };
   23.21 -		277904410DE91DFA00C6D295 /* TCPStream.m in Sources */ = {isa = PBXBuildFile; fileRef = 270461100DE49030003D9D3F /* TCPStream.m */; };
   23.22 -		277904420DE91DFC00C6D295 /* TCPWriter.m in Sources */ = {isa = PBXBuildFile; fileRef = 270461120DE49030003D9D3F /* TCPWriter.m */; };
   23.23 -		277904440DE91E3500C6D295 /* CollectionUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 270461870DE49634003D9D3F /* CollectionUtils.m */; };
   23.24 -		277904450DE91E3600C6D295 /* ExceptionUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 270461350DE4918D003D9D3F /* ExceptionUtils.m */; };
   23.25 -		277904460DE91E3700C6D295 /* Logging.m in Sources */ = {isa = PBXBuildFile; fileRef = 2704612A0DE49088003D9D3F /* Logging.m */; };
   23.26 -		277904480DE91E3900C6D295 /* Target.m in Sources */ = {isa = PBXBuildFile; fileRef = 270461460DE491A6003D9D3F /* Target.m */; };
   23.27 -		277904490DE91E3A00C6D295 /* Test.m in Sources */ = {isa = PBXBuildFile; fileRef = 270461280DE49088003D9D3F /* Test.m */; };
   23.28 +		2706F1D90F9D3EF300292CCF /* SecurityInterface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2706F1D80F9D3EF300292CCF /* SecurityInterface.framework */; };
   23.29 +		2777C9110F7602A7007F8D30 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2777C9100F7602A7007F8D30 /* Security.framework */; };
   23.30  		2779048B0DE9204300C6D295 /* BLIPEchoClient.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2779048A0DE9204300C6D295 /* BLIPEchoClient.xib */; };
   23.31 -		277905110DE9E5BC00C6D295 /* BLIPConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = 270460F40DE49030003D9D3F /* BLIPConnection.m */; };
   23.32 -		277905120DE9E5BC00C6D295 /* BLIPDispatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 270460F60DE49030003D9D3F /* BLIPDispatcher.m */; };
   23.33 -		277905130DE9E5BC00C6D295 /* BLIPMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = 270460F90DE49030003D9D3F /* BLIPMessage.m */; };
   23.34 -		277905140DE9E5BC00C6D295 /* BLIPProperties.m in Sources */ = {isa = PBXBuildFile; fileRef = 270460FB0DE49030003D9D3F /* BLIPProperties.m */; };
   23.35 -		277905150DE9E5BC00C6D295 /* BLIPReader.m in Sources */ = {isa = PBXBuildFile; fileRef = 270460FD0DE49030003D9D3F /* BLIPReader.m */; };
   23.36 -		277905160DE9E5BC00C6D295 /* BLIPWriter.m in Sources */ = {isa = PBXBuildFile; fileRef = 270461000DE49030003D9D3F /* BLIPWriter.m */; };
   23.37 -		277905170DE9E5BC00C6D295 /* IPAddress.m in Sources */ = {isa = PBXBuildFile; fileRef = 270461020DE49030003D9D3F /* IPAddress.m */; };
   23.38 -		277905180DE9E5BC00C6D295 /* TCPConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = 2704610A0DE49030003D9D3F /* TCPConnection.m */; };
   23.39 -		277905190DE9E5BC00C6D295 /* TCPEndpoint.m in Sources */ = {isa = PBXBuildFile; fileRef = 2704610C0DE49030003D9D3F /* TCPEndpoint.m */; };
   23.40 -		2779051A0DE9E5BC00C6D295 /* TCPListener.m in Sources */ = {isa = PBXBuildFile; fileRef = 2704610E0DE49030003D9D3F /* TCPListener.m */; };
   23.41 -		2779051B0DE9E5BC00C6D295 /* TCPStream.m in Sources */ = {isa = PBXBuildFile; fileRef = 270461100DE49030003D9D3F /* TCPStream.m */; };
   23.42 -		2779051C0DE9E5BC00C6D295 /* TCPWriter.m in Sources */ = {isa = PBXBuildFile; fileRef = 270461120DE49030003D9D3F /* TCPWriter.m */; };
   23.43 -		2779051D0DE9E5BC00C6D295 /* Test.m in Sources */ = {isa = PBXBuildFile; fileRef = 270461280DE49088003D9D3F /* Test.m */; };
   23.44 -		2779051E0DE9E5BC00C6D295 /* Logging.m in Sources */ = {isa = PBXBuildFile; fileRef = 2704612A0DE49088003D9D3F /* Logging.m */; };
   23.45 -		2779051F0DE9E5BC00C6D295 /* ExceptionUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 270461350DE4918D003D9D3F /* ExceptionUtils.m */; };
   23.46 -		277905200DE9E5BC00C6D295 /* Target.m in Sources */ = {isa = PBXBuildFile; fileRef = 270461460DE491A6003D9D3F /* Target.m */; };
   23.47 -		277905220DE9E5BC00C6D295 /* CollectionUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 270461870DE49634003D9D3F /* CollectionUtils.m */; };
   23.48 -		277905230DE9E5BC00C6D295 /* BLIPRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 27D5EC060DE5FEDE00CD84FA /* BLIPRequest.m */; };
   23.49  		277905240DE9E5BC00C6D295 /* BLIPEchoServer.m in Sources */ = {isa = PBXBuildFile; fileRef = 277903D60DE8EE4800C6D295 /* BLIPEchoServer.m */; };
   23.50 -		277905260DE9E5BC00C6D295 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08FB779EFE84155DC02AAC07 /* Foundation.framework */; };
   23.51 -		277905270DE9E5BC00C6D295 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2704618B0DE49652003D9D3F /* libz.dylib */; };
   23.52 -		277905280DE9E5BC00C6D295 /* CoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 270461910DE4975C003D9D3F /* CoreServices.framework */; };
   23.53  		277905300DE9ED9100C6D295 /* MYUtilitiesTest_main.m in Sources */ = {isa = PBXBuildFile; fileRef = 270462C10DE4A64B003D9D3F /* MYUtilitiesTest_main.m */; };
   23.54  		2779053B0DE9EDAA00C6D295 /* BLIPTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 270460FE0DE49030003D9D3F /* BLIPTest.m */; };
   23.55 -		277ECFBC0E2A73A100D756BB /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2704618B0DE49652003D9D3F /* libz.dylib */; };
   23.56 +		278C1A3D0F9F687800954AE1 /* PortMapperTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 278C1A340F9F687800954AE1 /* PortMapperTest.m */; };
   23.57 +		278C1A3E0F9F687800954AE1 /* MYPortMapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 278C1A360F9F687800954AE1 /* MYPortMapper.m */; };
   23.58 +		278C1BA60F9F92EA00954AE1 /* MYBonjourBrowser.m in Sources */ = {isa = PBXBuildFile; fileRef = 278C1B9F0F9F92EA00954AE1 /* MYBonjourBrowser.m */; };
   23.59 +		278C1BA70F9F92EA00954AE1 /* MYBonjourService.m in Sources */ = {isa = PBXBuildFile; fileRef = 278C1BA10F9F92EA00954AE1 /* MYBonjourService.m */; };
   23.60 +		278C1BB90F9F975700954AE1 /* ConcurrentOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 278C1BB60F9F975700954AE1 /* ConcurrentOperation.m */; };
   23.61 +		279DDA590F9E2DFA00D75D91 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 279DD99E0F9E290500D75D91 /* Foundation.framework */; };
   23.62 +		279DDAE00F9E2E0F00D75D91 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 279DD99E0F9E290500D75D91 /* Foundation.framework */; };
   23.63 +		279DDC4E0F9E2E2700D75D91 /* CoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 279DD9B30F9E296E00D75D91 /* CoreServices.framework */; };
   23.64 +		279DDC520F9E2E3A00D75D91 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 279DD9B10F9E296200D75D91 /* libz.dylib */; };
   23.65 +		279DDC970F9E2EF400D75D91 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 279DD99E0F9E290500D75D91 /* Foundation.framework */; };
   23.66 +		279DDC9B0F9E2F2A00D75D91 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 279DDC9A0F9E2F2A00D75D91 /* AppKit.framework */; };
   23.67 +		279DDCD10F9E38DD00D75D91 /* BLIPEchoClient.m in Sources */ = {isa = PBXBuildFile; fileRef = 277903E90DE8F08100C6D295 /* BLIPEchoClient.m */; };
   23.68 +		279E8FA10F9FDD2600608D8D /* BLIPConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = 270460F40DE49030003D9D3F /* BLIPConnection.m */; };
   23.69 +		279E8FA20F9FDD2600608D8D /* BLIPDispatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 270460F60DE49030003D9D3F /* BLIPDispatcher.m */; };
   23.70 +		279E8FA30F9FDD2600608D8D /* BLIPMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = 270460F90DE49030003D9D3F /* BLIPMessage.m */; };
   23.71 +		279E8FA40F9FDD2600608D8D /* BLIPProperties.m in Sources */ = {isa = PBXBuildFile; fileRef = 270460FB0DE49030003D9D3F /* BLIPProperties.m */; };
   23.72 +		279E8FA50F9FDD2600608D8D /* BLIPReader.m in Sources */ = {isa = PBXBuildFile; fileRef = 270460FD0DE49030003D9D3F /* BLIPReader.m */; };
   23.73 +		279E8FA60F9FDD2600608D8D /* BLIPRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 27D5EC060DE5FEDE00CD84FA /* BLIPRequest.m */; };
   23.74 +		279E8FA70F9FDD2600608D8D /* BLIPWriter.m in Sources */ = {isa = PBXBuildFile; fileRef = 270461000DE49030003D9D3F /* BLIPWriter.m */; };
   23.75 +		279E8FA80F9FDD2600608D8D /* IPAddress.m in Sources */ = {isa = PBXBuildFile; fileRef = 270461020DE49030003D9D3F /* IPAddress.m */; };
   23.76 +		279E8FA90F9FDD2600608D8D /* TCPConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = 2704610A0DE49030003D9D3F /* TCPConnection.m */; };
   23.77 +		279E8FAA0F9FDD2600608D8D /* TCPEndpoint.m in Sources */ = {isa = PBXBuildFile; fileRef = 2704610C0DE49030003D9D3F /* TCPEndpoint.m */; };
   23.78 +		279E8FAB0F9FDD2600608D8D /* TCPListener.m in Sources */ = {isa = PBXBuildFile; fileRef = 2704610E0DE49030003D9D3F /* TCPListener.m */; };
   23.79 +		279E8FAC0F9FDD2600608D8D /* TCPStream.m in Sources */ = {isa = PBXBuildFile; fileRef = 270461100DE49030003D9D3F /* TCPStream.m */; };
   23.80 +		279E8FAD0F9FDD2600608D8D /* TCPWriter.m in Sources */ = {isa = PBXBuildFile; fileRef = 270461120DE49030003D9D3F /* TCPWriter.m */; };
   23.81 +		279E8FAE0F9FDD2600608D8D /* CollectionUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 270461870DE49634003D9D3F /* CollectionUtils.m */; };
   23.82 +		279E8FAF0F9FDD2600608D8D /* ExceptionUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 270461350DE4918D003D9D3F /* ExceptionUtils.m */; };
   23.83 +		279E8FB00F9FDD2600608D8D /* GTMNSData+zlib.m in Sources */ = {isa = PBXBuildFile; fileRef = 27E0DBEF0DF3450F00E7F648 /* GTMNSData+zlib.m */; };
   23.84 +		279E8FB10F9FDD2600608D8D /* Logging.m in Sources */ = {isa = PBXBuildFile; fileRef = 2704612A0DE49088003D9D3F /* Logging.m */; };
   23.85 +		279E8FB20F9FDD2600608D8D /* Target.m in Sources */ = {isa = PBXBuildFile; fileRef = 270461460DE491A6003D9D3F /* Target.m */; };
   23.86 +		279E8FB30F9FDD2600608D8D /* Test.m in Sources */ = {isa = PBXBuildFile; fileRef = 270461280DE49088003D9D3F /* Test.m */; };
   23.87 +		279E8FB40F9FDD2600608D8D /* PortMapperTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 278C1A340F9F687800954AE1 /* PortMapperTest.m */; };
   23.88 +		279E8FB50F9FDD2600608D8D /* MYPortMapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 278C1A360F9F687800954AE1 /* MYPortMapper.m */; };
   23.89 +		279E8FB60F9FDD2600608D8D /* MYBonjourBrowser.m in Sources */ = {isa = PBXBuildFile; fileRef = 278C1B9F0F9F92EA00954AE1 /* MYBonjourBrowser.m */; };
   23.90 +		279E8FB70F9FDD2600608D8D /* MYBonjourService.m in Sources */ = {isa = PBXBuildFile; fileRef = 278C1BA10F9F92EA00954AE1 /* MYBonjourService.m */; };
   23.91 +		279E8FB80F9FDD2600608D8D /* ConcurrentOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 278C1BB60F9F975700954AE1 /* ConcurrentOperation.m */; };
   23.92 +		279E8FD70F9FDDE900608D8D /* libMYNetwork.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 279E8F9E0F9FDD0800608D8D /* libMYNetwork.a */; };
   23.93 +		279E8FEF0F9FDE5A00608D8D /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2777C9100F7602A7007F8D30 /* Security.framework */; };
   23.94 +		279E8FFA0F9FDEEB00608D8D /* libMYNetwork.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 279E8F9E0F9FDD0800608D8D /* libMYNetwork.a */; };
   23.95 +		279E8FFC0F9FDEFB00608D8D /* CoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 279DD9B30F9E296E00D75D91 /* CoreServices.framework */; };
   23.96 +		279E8FFE0F9FDF0600608D8D /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2777C9100F7602A7007F8D30 /* Security.framework */; };
   23.97  		27D5EC070DE5FEDE00CD84FA /* BLIPRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 27D5EC060DE5FEDE00CD84FA /* BLIPRequest.m */; };
   23.98 -		27E0DBF00DF3450F00E7F648 /* GTMNSData+zlib.m in Sources */ = {isa = PBXBuildFile; fileRef = 27E0DBEF0DF3450F00E7F648 /* GTMNSData+zlib.m */; };
   23.99  		27E0DBF10DF3450F00E7F648 /* GTMNSData+zlib.m in Sources */ = {isa = PBXBuildFile; fileRef = 27E0DBEF0DF3450F00E7F648 /* GTMNSData+zlib.m */; };
  23.100 -		27E0DBF20DF3450F00E7F648 /* GTMNSData+zlib.m in Sources */ = {isa = PBXBuildFile; fileRef = 27E0DBEF0DF3450F00E7F648 /* GTMNSData+zlib.m */; };
  23.101 -		8DD76F9C0486AA7600D96B5E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08FB779EFE84155DC02AAC07 /* Foundation.framework */; };
  23.102  /* End PBXBuildFile section */
  23.103  
  23.104 +/* Begin PBXContainerItemProxy section */
  23.105 +		279E8FD50F9FDDD900608D8D /* PBXContainerItemProxy */ = {
  23.106 +			isa = PBXContainerItemProxy;
  23.107 +			containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
  23.108 +			proxyType = 1;
  23.109 +			remoteGlobalIDString = 279E8F9D0F9FDD0800608D8D /* Library */;
  23.110 +			remoteInfo = Library;
  23.111 +		};
  23.112 +		279E8FF80F9FDECD00608D8D /* PBXContainerItemProxy */ = {
  23.113 +			isa = PBXContainerItemProxy;
  23.114 +			containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
  23.115 +			proxyType = 1;
  23.116 +			remoteGlobalIDString = 279E8F9D0F9FDD0800608D8D /* Library */;
  23.117 +			remoteInfo = Library;
  23.118 +		};
  23.119 +/* End PBXContainerItemProxy section */
  23.120 +
  23.121  /* Begin PBXCopyFilesBuildPhase section */
  23.122  		277905290DE9E5BC00C6D295 /* CopyFiles */ = {
  23.123  			isa = PBXCopyFilesBuildPhase;
  23.124 @@ -100,7 +114,6 @@
  23.125  /* End PBXCopyFilesBuildPhase section */
  23.126  
  23.127  /* Begin PBXFileReference section */
  23.128 -		08FB779EFE84155DC02AAC07 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
  23.129  		270460F30DE49030003D9D3F /* BLIPConnection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BLIPConnection.h; sourceTree = "<group>"; };
  23.130  		270460F40DE49030003D9D3F /* BLIPConnection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BLIPConnection.m; sourceTree = "<group>"; };
  23.131  		270460F50DE49030003D9D3F /* BLIPDispatcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BLIPDispatcher.h; sourceTree = "<group>"; };
  23.132 @@ -112,7 +125,7 @@
  23.133  		270460FB0DE49030003D9D3F /* BLIPProperties.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BLIPProperties.m; sourceTree = "<group>"; };
  23.134  		270460FC0DE49030003D9D3F /* BLIPReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BLIPReader.h; sourceTree = "<group>"; };
  23.135  		270460FD0DE49030003D9D3F /* BLIPReader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BLIPReader.m; sourceTree = "<group>"; };
  23.136 -		270460FE0DE49030003D9D3F /* BLIPTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BLIPTest.m; path = BLIP/BLIPTest.m; sourceTree = "<group>"; };
  23.137 +		270460FE0DE49030003D9D3F /* BLIPTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BLIPTest.m; path = ../BLIPTest.m; sourceTree = "<group>"; };
  23.138  		270460FF0DE49030003D9D3F /* BLIPWriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BLIPWriter.h; sourceTree = "<group>"; };
  23.139  		270461000DE49030003D9D3F /* BLIPWriter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BLIPWriter.m; sourceTree = "<group>"; };
  23.140  		270461010DE49030003D9D3F /* IPAddress.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IPAddress.h; sourceTree = "<group>"; };
  23.141 @@ -139,11 +152,13 @@
  23.142  		270461720DE49340003D9D3F /* MYNetwork */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = MYNetwork; sourceTree = BUILT_PRODUCTS_DIR; };
  23.143  		270461870DE49634003D9D3F /* CollectionUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CollectionUtils.m; sourceTree = "<group>"; };
  23.144  		270461880DE49634003D9D3F /* CollectionUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CollectionUtils.h; sourceTree = "<group>"; };
  23.145 -		2704618B0DE49652003D9D3F /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = /usr/lib/libz.dylib; sourceTree = "<absolute>"; };
  23.146 -		270461910DE4975C003D9D3F /* CoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreServices.framework; path = /System/Library/Frameworks/CoreServices.framework; sourceTree = "<absolute>"; };
  23.147  		270462C00DE4A639003D9D3F /* MYUtilities_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYUtilities_Prefix.pch; sourceTree = "<group>"; };
  23.148  		270462C10DE4A64B003D9D3F /* MYUtilitiesTest_main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYUtilitiesTest_main.m; sourceTree = "<group>"; };
  23.149  		270462C30DE4A65B003D9D3F /* BLIP Overview.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = "BLIP Overview.txt"; path = "BLIP/BLIP Overview.txt"; sourceTree = "<group>"; wrapsLines = 1; };
  23.150 +		2706F1D80F9D3EF300292CCF /* SecurityInterface.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SecurityInterface.framework; path = System/Library/Frameworks/SecurityInterface.framework; sourceTree = SDKROOT; };
  23.151 +		274122DD0F9CDD1600F21842 /* MYUtilities_Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = MYUtilities_Debug.xcconfig; sourceTree = "<group>"; };
  23.152 +		274122DE0F9CDD1600F21842 /* MYUtilities_Release.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = MYUtilities_Release.xcconfig; sourceTree = "<group>"; };
  23.153 +		2777C9100F7602A7007F8D30 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; };
  23.154  		277903830DE8C2DD00C6D295 /* maindocs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = maindocs.h; sourceTree = "<group>"; wrapsLines = 1; };
  23.155  		277903D50DE8EE4800C6D295 /* BLIPEchoServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BLIPEchoServer.h; sourceTree = "<group>"; };
  23.156  		277903D60DE8EE4800C6D295 /* BLIPEchoServer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BLIPEchoServer.m; sourceTree = "<group>"; };
  23.157 @@ -154,6 +169,21 @@
  23.158  		277904280DE91C7900C6D295 /* BLIP Echo Client-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "BLIP Echo Client-Info.plist"; sourceTree = "<group>"; };
  23.159  		2779048A0DE9204300C6D295 /* BLIPEchoClient.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = BLIPEchoClient.xib; sourceTree = "<group>"; };
  23.160  		2779052D0DE9E5BC00C6D295 /* BLIPEchoServer */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = BLIPEchoServer; sourceTree = BUILT_PRODUCTS_DIR; };
  23.161 +		278C1A340F9F687800954AE1 /* PortMapperTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PortMapperTest.m; sourceTree = "<group>"; };
  23.162 +		278C1A350F9F687800954AE1 /* MYPortMapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYPortMapper.h; sourceTree = "<group>"; };
  23.163 +		278C1A360F9F687800954AE1 /* MYPortMapper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYPortMapper.m; sourceTree = "<group>"; };
  23.164 +		278C1B9E0F9F92EA00954AE1 /* MYBonjourBrowser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYBonjourBrowser.h; sourceTree = "<group>"; };
  23.165 +		278C1B9F0F9F92EA00954AE1 /* MYBonjourBrowser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYBonjourBrowser.m; sourceTree = "<group>"; };
  23.166 +		278C1BA00F9F92EA00954AE1 /* MYBonjourService.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYBonjourService.h; sourceTree = "<group>"; };
  23.167 +		278C1BA10F9F92EA00954AE1 /* MYBonjourService.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYBonjourService.m; sourceTree = "<group>"; };
  23.168 +		278C1BB50F9F975700954AE1 /* ConcurrentOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConcurrentOperation.h; sourceTree = "<group>"; };
  23.169 +		278C1BB60F9F975700954AE1 /* ConcurrentOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ConcurrentOperation.m; sourceTree = "<group>"; };
  23.170 +		279DD99E0F9E290500D75D91 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
  23.171 +		279DD9B10F9E296200D75D91 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; };
  23.172 +		279DD9B30F9E296E00D75D91 /* CoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreServices.framework; path = System/Library/Frameworks/CoreServices.framework; sourceTree = SDKROOT; };
  23.173 +		279DDC9A0F9E2F2A00D75D91 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; };
  23.174 +		279DDCCB0F9E381500D75D91 /* MYNetwork.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYNetwork.h; sourceTree = "<group>"; };
  23.175 +		279E8F9E0F9FDD0800608D8D /* libMYNetwork.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libMYNetwork.a; sourceTree = BUILT_PRODUCTS_DIR; };
  23.176  		27D5EC050DE5FEDE00CD84FA /* BLIPRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BLIPRequest.h; sourceTree = "<group>"; };
  23.177  		27D5EC060DE5FEDE00CD84FA /* BLIPRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BLIPRequest.m; sourceTree = "<group>"; };
  23.178  		27E0DBED0DF3450F00E7F648 /* GTMDefines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GTMDefines.h; sourceTree = "<group>"; };
  23.179 @@ -166,7 +196,10 @@
  23.180  			isa = PBXFrameworksBuildPhase;
  23.181  			buildActionMask = 2147483647;
  23.182  			files = (
  23.183 -				277ECFBC0E2A73A100D756BB /* libz.dylib in Frameworks */,
  23.184 +				279DDC970F9E2EF400D75D91 /* Foundation.framework in Frameworks */,
  23.185 +				279DDC9B0F9E2F2A00D75D91 /* AppKit.framework in Frameworks */,
  23.186 +				279E8FD70F9FDDE900608D8D /* libMYNetwork.a in Frameworks */,
  23.187 +				279E8FEF0F9FDE5A00608D8D /* Security.framework in Frameworks */,
  23.188  			);
  23.189  			runOnlyForDeploymentPostprocessing = 0;
  23.190  		};
  23.191 @@ -174,9 +207,17 @@
  23.192  			isa = PBXFrameworksBuildPhase;
  23.193  			buildActionMask = 2147483647;
  23.194  			files = (
  23.195 -				277905260DE9E5BC00C6D295 /* Foundation.framework in Frameworks */,
  23.196 -				277905270DE9E5BC00C6D295 /* libz.dylib in Frameworks */,
  23.197 -				277905280DE9E5BC00C6D295 /* CoreServices.framework in Frameworks */,
  23.198 +				279DDAE00F9E2E0F00D75D91 /* Foundation.framework in Frameworks */,
  23.199 +				279E8FFA0F9FDEEB00608D8D /* libMYNetwork.a in Frameworks */,
  23.200 +				279E8FFC0F9FDEFB00608D8D /* CoreServices.framework in Frameworks */,
  23.201 +				279E8FFE0F9FDF0600608D8D /* Security.framework in Frameworks */,
  23.202 +			);
  23.203 +			runOnlyForDeploymentPostprocessing = 0;
  23.204 +		};
  23.205 +		279E8F9C0F9FDD0800608D8D /* Frameworks */ = {
  23.206 +			isa = PBXFrameworksBuildPhase;
  23.207 +			buildActionMask = 2147483647;
  23.208 +			files = (
  23.209  			);
  23.210  			runOnlyForDeploymentPostprocessing = 0;
  23.211  		};
  23.212 @@ -184,9 +225,11 @@
  23.213  			isa = PBXFrameworksBuildPhase;
  23.214  			buildActionMask = 2147483647;
  23.215  			files = (
  23.216 -				8DD76F9C0486AA7600D96B5E /* Foundation.framework in Frameworks */,
  23.217 -				2704618C0DE49652003D9D3F /* libz.dylib in Frameworks */,
  23.218 -				270461920DE4975D003D9D3F /* CoreServices.framework in Frameworks */,
  23.219 +				2777C9110F7602A7007F8D30 /* Security.framework in Frameworks */,
  23.220 +				2706F1D90F9D3EF300292CCF /* SecurityInterface.framework in Frameworks */,
  23.221 +				279DDA590F9E2DFA00D75D91 /* Foundation.framework in Frameworks */,
  23.222 +				279DDC4E0F9E2E2700D75D91 /* CoreServices.framework in Frameworks */,
  23.223 +				279DDC520F9E2E3A00D75D91 /* libz.dylib in Frameworks */,
  23.224  			);
  23.225  			runOnlyForDeploymentPostprocessing = 0;
  23.226  		};
  23.227 @@ -200,7 +243,6 @@
  23.228  				277903830DE8C2DD00C6D295 /* maindocs.h */,
  23.229  				270460F00DE49030003D9D3F /* MYNetwork */,
  23.230  				270461220DE49055003D9D3F /* MYUtilities */,
  23.231 -				270460FE0DE49030003D9D3F /* BLIPTest.m */,
  23.232  				277903E70DE8F05F00C6D295 /* Demo */,
  23.233  				08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */,
  23.234  				1AB674ADFE9D54B511CA2CBB /* Products */,
  23.235 @@ -211,9 +253,12 @@
  23.236  		08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */ = {
  23.237  			isa = PBXGroup;
  23.238  			children = (
  23.239 -				270461910DE4975C003D9D3F /* CoreServices.framework */,
  23.240 -				08FB779EFE84155DC02AAC07 /* Foundation.framework */,
  23.241 -				2704618B0DE49652003D9D3F /* libz.dylib */,
  23.242 +				279DDC9A0F9E2F2A00D75D91 /* AppKit.framework */,
  23.243 +				279DD9B30F9E296E00D75D91 /* CoreServices.framework */,
  23.244 +				279DD99E0F9E290500D75D91 /* Foundation.framework */,
  23.245 +				2777C9100F7602A7007F8D30 /* Security.framework */,
  23.246 +				2706F1D80F9D3EF300292CCF /* SecurityInterface.framework */,
  23.247 +				279DD9B10F9E296200D75D91 /* libz.dylib */,
  23.248  			);
  23.249  			name = "External Frameworks and Libraries";
  23.250  			sourceTree = "<group>";
  23.251 @@ -224,6 +269,7 @@
  23.252  				270461720DE49340003D9D3F /* MYNetwork */,
  23.253  				277904260DE91C7900C6D295 /* BLIP Echo Client.app */,
  23.254  				2779052D0DE9E5BC00C6D295 /* BLIPEchoServer */,
  23.255 +				279E8F9E0F9FDD0800608D8D /* libMYNetwork.a */,
  23.256  			);
  23.257  			name = Products;
  23.258  			sourceTree = "<group>";
  23.259 @@ -231,10 +277,13 @@
  23.260  		270460F00DE49030003D9D3F /* MYNetwork */ = {
  23.261  			isa = PBXGroup;
  23.262  			children = (
  23.263 +				279DDCCB0F9E381500D75D91 /* MYNetwork.h */,
  23.264  				270461010DE49030003D9D3F /* IPAddress.h */,
  23.265  				270461020DE49030003D9D3F /* IPAddress.m */,
  23.266  				270461070DE49030003D9D3F /* TCP */,
  23.267 +				278C1A320F9F687800954AE1 /* PortMapper */,
  23.268  				270460F10DE49030003D9D3F /* BLIP */,
  23.269 +				278C1B9D0F9F92D600954AE1 /* Bonjour */,
  23.270  			);
  23.271  			name = MYNetwork;
  23.272  			sourceTree = "<group>";
  23.273 @@ -283,6 +332,8 @@
  23.274  		270461220DE49055003D9D3F /* MYUtilities */ = {
  23.275  			isa = PBXGroup;
  23.276  			children = (
  23.277 +				278C1BB50F9F975700954AE1 /* ConcurrentOperation.h */,
  23.278 +				278C1BB60F9F975700954AE1 /* ConcurrentOperation.m */,
  23.279  				270462C10DE4A64B003D9D3F /* MYUtilitiesTest_main.m */,
  23.280  				270462C00DE4A639003D9D3F /* MYUtilities_Prefix.pch */,
  23.281  				270461880DE49634003D9D3F /* CollectionUtils.h */,
  23.282 @@ -295,6 +346,8 @@
  23.283  				270461460DE491A6003D9D3F /* Target.m */,
  23.284  				270461290DE49088003D9D3F /* Test.h */,
  23.285  				270461280DE49088003D9D3F /* Test.m */,
  23.286 +				274122DD0F9CDD1600F21842 /* MYUtilities_Debug.xcconfig */,
  23.287 +				274122DE0F9CDD1600F21842 /* MYUtilities_Release.xcconfig */,
  23.288  				27E0DBEC0DF3450F00E7F648 /* GoogleToolboxSubset */,
  23.289  			);
  23.290  			name = MYUtilities;
  23.291 @@ -304,6 +357,7 @@
  23.292  		277903E70DE8F05F00C6D295 /* Demo */ = {
  23.293  			isa = PBXGroup;
  23.294  			children = (
  23.295 +				270460FE0DE49030003D9D3F /* BLIPTest.m */,
  23.296  				277903D50DE8EE4800C6D295 /* BLIPEchoServer.h */,
  23.297  				277903D60DE8EE4800C6D295 /* BLIPEchoServer.m */,
  23.298  				277903E80DE8F08100C6D295 /* BLIPEchoClient.h */,
  23.299 @@ -315,6 +369,27 @@
  23.300  			path = BLIP/Demo;
  23.301  			sourceTree = "<group>";
  23.302  		};
  23.303 +		278C1A320F9F687800954AE1 /* PortMapper */ = {
  23.304 +			isa = PBXGroup;
  23.305 +			children = (
  23.306 +				278C1A350F9F687800954AE1 /* MYPortMapper.h */,
  23.307 +				278C1A360F9F687800954AE1 /* MYPortMapper.m */,
  23.308 +				278C1A340F9F687800954AE1 /* PortMapperTest.m */,
  23.309 +			);
  23.310 +			path = PortMapper;
  23.311 +			sourceTree = "<group>";
  23.312 +		};
  23.313 +		278C1B9D0F9F92D600954AE1 /* Bonjour */ = {
  23.314 +			isa = PBXGroup;
  23.315 +			children = (
  23.316 +				278C1B9E0F9F92EA00954AE1 /* MYBonjourBrowser.h */,
  23.317 +				278C1B9F0F9F92EA00954AE1 /* MYBonjourBrowser.m */,
  23.318 +				278C1BA00F9F92EA00954AE1 /* MYBonjourService.h */,
  23.319 +				278C1BA10F9F92EA00954AE1 /* MYBonjourService.m */,
  23.320 +			);
  23.321 +			path = Bonjour;
  23.322 +			sourceTree = "<group>";
  23.323 +		};
  23.324  		27E0DBEC0DF3450F00E7F648 /* GoogleToolboxSubset */ = {
  23.325  			isa = PBXGroup;
  23.326  			children = (
  23.327 @@ -327,6 +402,16 @@
  23.328  		};
  23.329  /* End PBXGroup section */
  23.330  
  23.331 +/* Begin PBXHeadersBuildPhase section */
  23.332 +		279E8F9A0F9FDD0800608D8D /* Headers */ = {
  23.333 +			isa = PBXHeadersBuildPhase;
  23.334 +			buildActionMask = 2147483647;
  23.335 +			files = (
  23.336 +			);
  23.337 +			runOnlyForDeploymentPostprocessing = 0;
  23.338 +		};
  23.339 +/* End PBXHeadersBuildPhase section */
  23.340 +
  23.341  /* Begin PBXNativeTarget section */
  23.342  		277904250DE91C7900C6D295 /* BLIP Echo Client */ = {
  23.343  			isa = PBXNativeTarget;
  23.344 @@ -339,6 +424,7 @@
  23.345  			buildRules = (
  23.346  			);
  23.347  			dependencies = (
  23.348 +				279E8FD60F9FDDD900608D8D /* PBXTargetDependency */,
  23.349  			);
  23.350  			name = "BLIP Echo Client";
  23.351  			productName = "BLIP Echo Client";
  23.352 @@ -356,6 +442,7 @@
  23.353  			buildRules = (
  23.354  			);
  23.355  			dependencies = (
  23.356 +				279E8FF90F9FDECD00608D8D /* PBXTargetDependency */,
  23.357  			);
  23.358  			name = "BLIP Echo Server";
  23.359  			productInstallPath = "$(HOME)/bin";
  23.360 @@ -363,9 +450,26 @@
  23.361  			productReference = 2779052D0DE9E5BC00C6D295 /* BLIPEchoServer */;
  23.362  			productType = "com.apple.product-type.tool";
  23.363  		};
  23.364 -		8DD76F960486AA7600D96B5E /* MYNetwork */ = {
  23.365 +		279E8F9D0F9FDD0800608D8D /* Library */ = {
  23.366  			isa = PBXNativeTarget;
  23.367 -			buildConfigurationList = 1DEB927408733DD40010E9CD /* Build configuration list for PBXNativeTarget "MYNetwork" */;
  23.368 +			buildConfigurationList = 279E8FCC0F9FDD8900608D8D /* Build configuration list for PBXNativeTarget "Library" */;
  23.369 +			buildPhases = (
  23.370 +				279E8F9A0F9FDD0800608D8D /* Headers */,
  23.371 +				279E8F9B0F9FDD0800608D8D /* Sources */,
  23.372 +				279E8F9C0F9FDD0800608D8D /* Frameworks */,
  23.373 +			);
  23.374 +			buildRules = (
  23.375 +			);
  23.376 +			dependencies = (
  23.377 +			);
  23.378 +			name = Library;
  23.379 +			productName = Library;
  23.380 +			productReference = 279E8F9E0F9FDD0800608D8D /* libMYNetwork.a */;
  23.381 +			productType = "com.apple.product-type.library.static";
  23.382 +		};
  23.383 +		8DD76F960486AA7600D96B5E /* SelfTest */ = {
  23.384 +			isa = PBXNativeTarget;
  23.385 +			buildConfigurationList = 1DEB927408733DD40010E9CD /* Build configuration list for PBXNativeTarget "SelfTest" */;
  23.386  			buildPhases = (
  23.387  				8DD76F990486AA7600D96B5E /* Sources */,
  23.388  				8DD76F9B0486AA7600D96B5E /* Frameworks */,
  23.389 @@ -375,7 +479,7 @@
  23.390  			);
  23.391  			dependencies = (
  23.392  			);
  23.393 -			name = MYNetwork;
  23.394 +			name = SelfTest;
  23.395  			productInstallPath = "$(HOME)/bin";
  23.396  			productName = MYNetwork;
  23.397  			productReference = 270461720DE49340003D9D3F /* MYNetwork */;
  23.398 @@ -393,7 +497,8 @@
  23.399  			projectDirPath = "";
  23.400  			projectRoot = "";
  23.401  			targets = (
  23.402 -				8DD76F960486AA7600D96B5E /* MYNetwork */,
  23.403 +				279E8F9D0F9FDD0800608D8D /* Library */,
  23.404 +				8DD76F960486AA7600D96B5E /* SelfTest */,
  23.405  				277904250DE91C7900C6D295 /* BLIP Echo Client */,
  23.406  				2779050F0DE9E5BC00C6D295 /* BLIP Echo Server */,
  23.407  			);
  23.408 @@ -416,26 +521,7 @@
  23.409  			isa = PBXSourcesBuildPhase;
  23.410  			buildActionMask = 2147483647;
  23.411  			files = (
  23.412 -				277904330DE91DE600C6D295 /* BLIPConnection.m in Sources */,
  23.413 -				277904340DE91DE700C6D295 /* BLIPDispatcher.m in Sources */,
  23.414 -				277904350DE91DE800C6D295 /* BLIPEchoClient.m in Sources */,
  23.415 -				277904370DE91DEB00C6D295 /* BLIPMessage.m in Sources */,
  23.416 -				277904380DE91DEC00C6D295 /* BLIPProperties.m in Sources */,
  23.417 -				277904390DE91DEE00C6D295 /* BLIPReader.m in Sources */,
  23.418 -				2779043A0DE91DEF00C6D295 /* BLIPRequest.m in Sources */,
  23.419 -				2779043C0DE91DF100C6D295 /* BLIPWriter.m in Sources */,
  23.420 -				2779043D0DE91DF300C6D295 /* IPAddress.m in Sources */,
  23.421 -				2779043E0DE91DF500C6D295 /* TCPConnection.m in Sources */,
  23.422 -				2779043F0DE91DF800C6D295 /* TCPEndpoint.m in Sources */,
  23.423 -				277904400DE91DF900C6D295 /* TCPListener.m in Sources */,
  23.424 -				277904410DE91DFA00C6D295 /* TCPStream.m in Sources */,
  23.425 -				277904420DE91DFC00C6D295 /* TCPWriter.m in Sources */,
  23.426 -				277904440DE91E3500C6D295 /* CollectionUtils.m in Sources */,
  23.427 -				277904450DE91E3600C6D295 /* ExceptionUtils.m in Sources */,
  23.428 -				277904460DE91E3700C6D295 /* Logging.m in Sources */,
  23.429 -				277904480DE91E3900C6D295 /* Target.m in Sources */,
  23.430 -				277904490DE91E3A00C6D295 /* Test.m in Sources */,
  23.431 -				27E0DBF00DF3450F00E7F648 /* GTMNSData+zlib.m in Sources */,
  23.432 +				279DDCD10F9E38DD00D75D91 /* BLIPEchoClient.m in Sources */,
  23.433  			);
  23.434  			runOnlyForDeploymentPostprocessing = 0;
  23.435  		};
  23.436 @@ -443,26 +529,38 @@
  23.437  			isa = PBXSourcesBuildPhase;
  23.438  			buildActionMask = 2147483647;
  23.439  			files = (
  23.440 -				277905110DE9E5BC00C6D295 /* BLIPConnection.m in Sources */,
  23.441 -				277905120DE9E5BC00C6D295 /* BLIPDispatcher.m in Sources */,
  23.442 -				277905130DE9E5BC00C6D295 /* BLIPMessage.m in Sources */,
  23.443 -				277905140DE9E5BC00C6D295 /* BLIPProperties.m in Sources */,
  23.444 -				277905150DE9E5BC00C6D295 /* BLIPReader.m in Sources */,
  23.445 -				277905160DE9E5BC00C6D295 /* BLIPWriter.m in Sources */,
  23.446 -				277905170DE9E5BC00C6D295 /* IPAddress.m in Sources */,
  23.447 -				277905180DE9E5BC00C6D295 /* TCPConnection.m in Sources */,
  23.448 -				277905190DE9E5BC00C6D295 /* TCPEndpoint.m in Sources */,
  23.449 -				2779051A0DE9E5BC00C6D295 /* TCPListener.m in Sources */,
  23.450 -				2779051B0DE9E5BC00C6D295 /* TCPStream.m in Sources */,
  23.451 -				2779051C0DE9E5BC00C6D295 /* TCPWriter.m in Sources */,
  23.452 -				2779051D0DE9E5BC00C6D295 /* Test.m in Sources */,
  23.453 -				2779051E0DE9E5BC00C6D295 /* Logging.m in Sources */,
  23.454 -				2779051F0DE9E5BC00C6D295 /* ExceptionUtils.m in Sources */,
  23.455 -				277905200DE9E5BC00C6D295 /* Target.m in Sources */,
  23.456 -				277905220DE9E5BC00C6D295 /* CollectionUtils.m in Sources */,
  23.457 -				277905230DE9E5BC00C6D295 /* BLIPRequest.m in Sources */,
  23.458  				277905240DE9E5BC00C6D295 /* BLIPEchoServer.m in Sources */,
  23.459 -				27E0DBF20DF3450F00E7F648 /* GTMNSData+zlib.m in Sources */,
  23.460 +			);
  23.461 +			runOnlyForDeploymentPostprocessing = 0;
  23.462 +		};
  23.463 +		279E8F9B0F9FDD0800608D8D /* Sources */ = {
  23.464 +			isa = PBXSourcesBuildPhase;
  23.465 +			buildActionMask = 2147483647;
  23.466 +			files = (
  23.467 +				279E8FA10F9FDD2600608D8D /* BLIPConnection.m in Sources */,
  23.468 +				279E8FA20F9FDD2600608D8D /* BLIPDispatcher.m in Sources */,
  23.469 +				279E8FA30F9FDD2600608D8D /* BLIPMessage.m in Sources */,
  23.470 +				279E8FA40F9FDD2600608D8D /* BLIPProperties.m in Sources */,
  23.471 +				279E8FA50F9FDD2600608D8D /* BLIPReader.m in Sources */,
  23.472 +				279E8FA60F9FDD2600608D8D /* BLIPRequest.m in Sources */,
  23.473 +				279E8FA70F9FDD2600608D8D /* BLIPWriter.m in Sources */,
  23.474 +				279E8FA80F9FDD2600608D8D /* IPAddress.m in Sources */,
  23.475 +				279E8FA90F9FDD2600608D8D /* TCPConnection.m in Sources */,
  23.476 +				279E8FAA0F9FDD2600608D8D /* TCPEndpoint.m in Sources */,
  23.477 +				279E8FAB0F9FDD2600608D8D /* TCPListener.m in Sources */,
  23.478 +				279E8FAC0F9FDD2600608D8D /* TCPStream.m in Sources */,
  23.479 +				279E8FAD0F9FDD2600608D8D /* TCPWriter.m in Sources */,
  23.480 +				279E8FAE0F9FDD2600608D8D /* CollectionUtils.m in Sources */,
  23.481 +				279E8FAF0F9FDD2600608D8D /* ExceptionUtils.m in Sources */,
  23.482 +				279E8FB00F9FDD2600608D8D /* GTMNSData+zlib.m in Sources */,
  23.483 +				279E8FB10F9FDD2600608D8D /* Logging.m in Sources */,
  23.484 +				279E8FB20F9FDD2600608D8D /* Target.m in Sources */,
  23.485 +				279E8FB30F9FDD2600608D8D /* Test.m in Sources */,
  23.486 +				279E8FB40F9FDD2600608D8D /* PortMapperTest.m in Sources */,
  23.487 +				279E8FB50F9FDD2600608D8D /* MYPortMapper.m in Sources */,
  23.488 +				279E8FB60F9FDD2600608D8D /* MYBonjourBrowser.m in Sources */,
  23.489 +				279E8FB70F9FDD2600608D8D /* MYBonjourService.m in Sources */,
  23.490 +				279E8FB80F9FDD2600608D8D /* ConcurrentOperation.m in Sources */,
  23.491  			);
  23.492  			runOnlyForDeploymentPostprocessing = 0;
  23.493  		};
  23.494 @@ -491,26 +589,33 @@
  23.495  				277905300DE9ED9100C6D295 /* MYUtilitiesTest_main.m in Sources */,
  23.496  				2779053B0DE9EDAA00C6D295 /* BLIPTest.m in Sources */,
  23.497  				27E0DBF10DF3450F00E7F648 /* GTMNSData+zlib.m in Sources */,
  23.498 +				278C1A3D0F9F687800954AE1 /* PortMapperTest.m in Sources */,
  23.499 +				278C1A3E0F9F687800954AE1 /* MYPortMapper.m in Sources */,
  23.500 +				278C1BA60F9F92EA00954AE1 /* MYBonjourBrowser.m in Sources */,
  23.501 +				278C1BA70F9F92EA00954AE1 /* MYBonjourService.m in Sources */,
  23.502 +				278C1BB90F9F975700954AE1 /* ConcurrentOperation.m in Sources */,
  23.503  			);
  23.504  			runOnlyForDeploymentPostprocessing = 0;
  23.505  		};
  23.506  /* End PBXSourcesBuildPhase section */
  23.507  
  23.508 +/* Begin PBXTargetDependency section */
  23.509 +		279E8FD60F9FDDD900608D8D /* PBXTargetDependency */ = {
  23.510 +			isa = PBXTargetDependency;
  23.511 +			target = 279E8F9D0F9FDD0800608D8D /* Library */;
  23.512 +			targetProxy = 279E8FD50F9FDDD900608D8D /* PBXContainerItemProxy */;
  23.513 +		};
  23.514 +		279E8FF90F9FDECD00608D8D /* PBXTargetDependency */ = {
  23.515 +			isa = PBXTargetDependency;
  23.516 +			target = 279E8F9D0F9FDD0800608D8D /* Library */;
  23.517 +			targetProxy = 279E8FF80F9FDECD00608D8D /* PBXContainerItemProxy */;
  23.518 +		};
  23.519 +/* End PBXTargetDependency section */
  23.520 +
  23.521  /* Begin XCBuildConfiguration section */
  23.522  		1DEB927508733DD40010E9CD /* Debug */ = {
  23.523  			isa = XCBuildConfiguration;
  23.524  			buildSettings = {
  23.525 -				ALWAYS_SEARCH_USER_PATHS = NO;
  23.526 -				COPY_PHASE_STRIP = NO;
  23.527 -				GCC_C_LANGUAGE_STANDARD = c99;
  23.528 -				GCC_DYNAMIC_NO_PIC = NO;
  23.529 -				GCC_ENABLE_FIX_AND_CONTINUE = YES;
  23.530 -				GCC_MODEL_TUNING = G5;
  23.531 -				GCC_OPTIMIZATION_LEVEL = 0;
  23.532 -				GCC_PRECOMPILE_PREFIX_HEADER = YES;
  23.533 -				GCC_PREFIX_HEADER = ../MYUtilities/MYUtilities_Prefix.pch;
  23.534 -				GCC_PREPROCESSOR_DEFINITIONS = DEBUG;
  23.535 -				INSTALL_PATH = /usr/local/bin;
  23.536  				PRODUCT_NAME = MYNetwork;
  23.537  			};
  23.538  			name = Debug;
  23.539 @@ -518,68 +623,31 @@
  23.540  		1DEB927608733DD40010E9CD /* Release */ = {
  23.541  			isa = XCBuildConfiguration;
  23.542  			buildSettings = {
  23.543 -				ALWAYS_SEARCH_USER_PATHS = NO;
  23.544 -				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
  23.545 -				GCC_C_LANGUAGE_STANDARD = c99;
  23.546 -				GCC_MODEL_TUNING = G5;
  23.547 -				GCC_PRECOMPILE_PREFIX_HEADER = YES;
  23.548 -				GCC_PREFIX_HEADER = ../MYUtilities/MYUtilities_Prefix.pch;
  23.549 -				INSTALL_PATH = /usr/local/bin;
  23.550  				PRODUCT_NAME = MYNetwork;
  23.551  			};
  23.552  			name = Release;
  23.553  		};
  23.554  		1DEB927908733DD40010E9CD /* Debug */ = {
  23.555  			isa = XCBuildConfiguration;
  23.556 +			baseConfigurationReference = 274122DD0F9CDD1600F21842 /* MYUtilities_Debug.xcconfig */;
  23.557  			buildSettings = {
  23.558 -				ARCHS = "$(ARCHS_STANDARD_32_BIT)";
  23.559 -				GCC_C_LANGUAGE_STANDARD = c99;
  23.560 -				GCC_OPTIMIZATION_LEVEL = 0;
  23.561 -				GCC_PREPROCESSOR_DEFINITIONS = DEBUG;
  23.562 -				GCC_TREAT_WARNINGS_AS_ERRORS = YES;
  23.563 -				GCC_WARN_ABOUT_RETURN_TYPE = YES;
  23.564 -				GCC_WARN_UNUSED_VARIABLE = YES;
  23.565 -				ONLY_ACTIVE_ARCH = YES;
  23.566 -				PREBINDING = NO;
  23.567  				SDKROOT = macosx10.5;
  23.568 -				WARNING_CFLAGS = "-Wall";
  23.569  			};
  23.570  			name = Debug;
  23.571  		};
  23.572  		1DEB927A08733DD40010E9CD /* Release */ = {
  23.573  			isa = XCBuildConfiguration;
  23.574 +			baseConfigurationReference = 274122DE0F9CDD1600F21842 /* MYUtilities_Release.xcconfig */;
  23.575  			buildSettings = {
  23.576 -				ARCHS = "$(ARCHS_STANDARD_32_BIT)";
  23.577 -				GCC_C_LANGUAGE_STANDARD = c99;
  23.578 -				GCC_TREAT_WARNINGS_AS_ERRORS = YES;
  23.579 -				GCC_WARN_ABOUT_RETURN_TYPE = YES;
  23.580 -				GCC_WARN_UNUSED_VARIABLE = YES;
  23.581 -				PREBINDING = NO;
  23.582  				SDKROOT = macosx10.5;
  23.583 -				WARNING_CFLAGS = "-Wall";
  23.584  			};
  23.585  			name = Release;
  23.586  		};
  23.587  		277904290DE91C7A00C6D295 /* Debug */ = {
  23.588  			isa = XCBuildConfiguration;
  23.589  			buildSettings = {
  23.590 -				ALWAYS_SEARCH_USER_PATHS = NO;
  23.591 -				COPY_PHASE_STRIP = NO;
  23.592 -				GCC_DYNAMIC_NO_PIC = NO;
  23.593 -				GCC_ENABLE_FIX_AND_CONTINUE = YES;
  23.594 -				GCC_MODEL_TUNING = G5;
  23.595 -				GCC_OPTIMIZATION_LEVEL = 0;
  23.596 -				GCC_PRECOMPILE_PREFIX_HEADER = YES;
  23.597 -				GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/AppKit.framework/Headers/AppKit.h";
  23.598  				INFOPLIST_FILE = "BLIP/Demo/BLIP Echo Client-Info.plist";
  23.599  				INSTALL_PATH = "$(HOME)/Applications";
  23.600 -				OTHER_LDFLAGS = (
  23.601 -					"-framework",
  23.602 -					Foundation,
  23.603 -					"-framework",
  23.604 -					AppKit,
  23.605 -				);
  23.606 -				PREBINDING = NO;
  23.607  				PRODUCT_NAME = "BLIP Echo Client";
  23.608  			};
  23.609  			name = Debug;
  23.610 @@ -587,41 +655,15 @@
  23.611  		2779042A0DE91C7A00C6D295 /* Release */ = {
  23.612  			isa = XCBuildConfiguration;
  23.613  			buildSettings = {
  23.614 -				ALWAYS_SEARCH_USER_PATHS = NO;
  23.615 -				COPY_PHASE_STRIP = YES;
  23.616 -				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
  23.617 -				GCC_ENABLE_FIX_AND_CONTINUE = NO;
  23.618 -				GCC_MODEL_TUNING = G5;
  23.619 -				GCC_PRECOMPILE_PREFIX_HEADER = YES;
  23.620 -				GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/AppKit.framework/Headers/AppKit.h";
  23.621  				INFOPLIST_FILE = "BLIP/Demo/BLIP Echo Client-Info.plist";
  23.622  				INSTALL_PATH = "$(HOME)/Applications";
  23.623 -				OTHER_LDFLAGS = (
  23.624 -					"-framework",
  23.625 -					Foundation,
  23.626 -					"-framework",
  23.627 -					AppKit,
  23.628 -				);
  23.629 -				PREBINDING = NO;
  23.630  				PRODUCT_NAME = "BLIP Echo Client";
  23.631 -				ZERO_LINK = NO;
  23.632  			};
  23.633  			name = Release;
  23.634  		};
  23.635  		2779052B0DE9E5BC00C6D295 /* Debug */ = {
  23.636  			isa = XCBuildConfiguration;
  23.637  			buildSettings = {
  23.638 -				ALWAYS_SEARCH_USER_PATHS = NO;
  23.639 -				COPY_PHASE_STRIP = NO;
  23.640 -				GCC_C_LANGUAGE_STANDARD = gnu99;
  23.641 -				GCC_DYNAMIC_NO_PIC = NO;
  23.642 -				GCC_ENABLE_FIX_AND_CONTINUE = YES;
  23.643 -				GCC_MODEL_TUNING = G5;
  23.644 -				GCC_OPTIMIZATION_LEVEL = 0;
  23.645 -				GCC_PRECOMPILE_PREFIX_HEADER = YES;
  23.646 -				GCC_PREFIX_HEADER = ../MYUtilities/MYUtilities_Prefix.pch;
  23.647 -				GCC_PREPROCESSOR_DEFINITIONS = DEBUG;
  23.648 -				INSTALL_PATH = /usr/local/bin;
  23.649  				PRODUCT_NAME = BLIPEchoServer;
  23.650  			};
  23.651  			name = Debug;
  23.652 @@ -629,21 +671,30 @@
  23.653  		2779052C0DE9E5BC00C6D295 /* Release */ = {
  23.654  			isa = XCBuildConfiguration;
  23.655  			buildSettings = {
  23.656 -				ALWAYS_SEARCH_USER_PATHS = NO;
  23.657 -				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
  23.658 -				GCC_C_LANGUAGE_STANDARD = gnu99;
  23.659 -				GCC_MODEL_TUNING = G5;
  23.660 -				GCC_PRECOMPILE_PREFIX_HEADER = YES;
  23.661 -				GCC_PREFIX_HEADER = MYNetwork_Prefix.pch;
  23.662 -				INSTALL_PATH = /usr/local/bin;
  23.663  				PRODUCT_NAME = BLIPEchoServer;
  23.664  			};
  23.665  			name = Release;
  23.666  		};
  23.667 +		279E8F9F0F9FDD0900608D8D /* Debug */ = {
  23.668 +			isa = XCBuildConfiguration;
  23.669 +			buildSettings = {
  23.670 +				INSTALL_PATH = /usr/local/lib;
  23.671 +				PRODUCT_NAME = MYNetwork;
  23.672 +			};
  23.673 +			name = Debug;
  23.674 +		};
  23.675 +		279E8FA00F9FDD0900608D8D /* Release */ = {
  23.676 +			isa = XCBuildConfiguration;
  23.677 +			buildSettings = {
  23.678 +				INSTALL_PATH = /usr/local/lib;
  23.679 +				PRODUCT_NAME = MYNetwork;
  23.680 +			};
  23.681 +			name = Release;
  23.682 +		};
  23.683  /* End XCBuildConfiguration section */
  23.684  
  23.685  /* Begin XCConfigurationList section */
  23.686 -		1DEB927408733DD40010E9CD /* Build configuration list for PBXNativeTarget "MYNetwork" */ = {
  23.687 +		1DEB927408733DD40010E9CD /* Build configuration list for PBXNativeTarget "SelfTest" */ = {
  23.688  			isa = XCConfigurationList;
  23.689  			buildConfigurations = (
  23.690  				1DEB927508733DD40010E9CD /* Debug */,
  23.691 @@ -679,6 +730,15 @@
  23.692  			defaultConfigurationIsVisible = 0;
  23.693  			defaultConfigurationName = Release;
  23.694  		};
  23.695 +		279E8FCC0F9FDD8900608D8D /* Build configuration list for PBXNativeTarget "Library" */ = {
  23.696 +			isa = XCConfigurationList;
  23.697 +			buildConfigurations = (
  23.698 +				279E8F9F0F9FDD0900608D8D /* Debug */,
  23.699 +				279E8FA00F9FDD0900608D8D /* Release */,
  23.700 +			);
  23.701 +			defaultConfigurationIsVisible = 0;
  23.702 +			defaultConfigurationName = Release;
  23.703 +		};
  23.704  /* End XCConfigurationList section */
  23.705  	};
  23.706  	rootObject = 08FB7793FE84155DC02AAC07 /* Project object */;
    24.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    24.2 +++ b/PortMapper/MYPortMapper.h	Wed Apr 22 16:45:39 2009 -0700
    24.3 @@ -0,0 +1,119 @@
    24.4 +//
    24.5 +//  MYPortMapper.m
    24.6 +//  MYNetwork
    24.7 +//
    24.8 +//  Created by Jens Alfke on 1/4/08.
    24.9 +//  Copyright 2008 Jens Alfke. All rights reserved.
   24.10 +//
   24.11 +
   24.12 +#import <Foundation/Foundation.h>
   24.13 +#import <CoreFoundation/CFSocket.h>
   24.14 +@class IPAddress;
   24.15 +
   24.16 +
   24.17 +/*  MYPortMapper attempts to make a particular network port on this computer publicly reachable
   24.18 +    for incoming connections, by "opening a hole" through a Network Address Translator 
   24.19 +    (NAT) or firewall that may be in between the computer and the public Internet.
   24.20 + 
   24.21 +    The port mapping may fail if:
   24.22 +    * the NAT/router/firewall does not support either the UPnP or NAT-PMP protocols;
   24.23 +    * the device doesn't implement the protocols correctly (this happens);
   24.24 +    * the network administrator has disabled port-mapping;
   24.25 +    * there is a second layer of NAT/firewall (this happens in some ISP networks.)
   24.26 + 
   24.27 +    The PortMapper is asynchronous. It will take a nonzero amount of time to set up the
   24.28 +    mapping, and the mapping may change in the future as the network configuration changes.
   24.29 +    To be informed of changes, either use key-value observing to watch the "error" and
   24.30 +    "publicAddress" properties, or observe the MYPortMapperChangedNotification.
   24.31 + 
   24.32 +    Typical usage is to:
   24.33 +    * Start a network service that listens for incoming connections on a port
   24.34 +    * Open a MYPortMapper
   24.35 +    * When the MYPortMapper reports the public address and port of the mapping, you somehow
   24.36 +      notify other peers of that address and port, so they can connect to you.
   24.37 +    * When the MYPortMapper reports changes, you (somehow) notify peers of the changes.
   24.38 +    * When closing the network service, close the MYPortMapper object too.
   24.39 +*/ 
   24.40 +@interface MYPortMapper : NSObject
   24.41 +{
   24.42 +    UInt16 _localPort, _desiredPublicPort;
   24.43 +    BOOL _mapTCP, _mapUDP;
   24.44 +    SInt32 _error;
   24.45 +    void* /*DNSServiceRef*/ _service; // Typed void* to avoid having to #include <dnssd.h>
   24.46 +    CFSocketRef _socket;
   24.47 +    CFRunLoopSourceRef _socketSource;
   24.48 +    IPAddress *_publicAddress, *_localAddress;
   24.49 +}
   24.50 +
   24.51 +/** Initializes a PortMapper that will map the given local (private) port.
   24.52 +    By default it will map TCP and not UDP, and will not suggest a desired public port,
   24.53 +    but this can be configured by setting properties before opening the PortMapper. */
   24.54 +- (id) initWithLocalPort: (UInt16)localPort;
   24.55 +
   24.56 +/** Initializes a PortMapper that will not map any ports.
   24.57 +    This is useful if you just want to find out your public IP address.
   24.58 +    (For a simplified, but synchronous, convenience method for this, see
   24.59 +    +findPublicAddress.) */
   24.60 +- (id) initWithNullMapping;
   24.61 +
   24.62 +/** Should the TCP or UDP port, or both, be mapped? By default, TCP only.
   24.63 +    These properties have no effect if changed while the PortMapper is open. */
   24.64 +@property BOOL mapTCP, mapUDP;
   24.65 +
   24.66 +/** You can set this to the public port number you'd like to get.
   24.67 +    It defaults to 0, which means "no preference".
   24.68 +    This property has no effect if changed while the PortMapper is open. */
   24.69 +@property UInt16 desiredPublicPort;
   24.70 +
   24.71 +/** Opens the PortMapper, using the current settings of the above properties.
   24.72 +    Returns immediately; you can find out when the mapping is created or fails
   24.73 +    by observing the error/publicAddress/publicPort properties, or by listening
   24.74 +    for the PortMapperChangedNotification.
   24.75 +    It's very unlikely that this call will fail (return NO). If it does, it
   24.76 +    probably means that the mDNSResponder process isn't working. */
   24.77 +- (BOOL) open;
   24.78 +
   24.79 +/** Blocks till the PortMapper finishes opening. Returns YES if it opened, NO on error.
   24.80 +    It's not usually a good idea to use this, as it will lock up your application
   24.81 +    until a response arrives from the NAT. Listen for asynchronous notifications instead.
   24.82 +    If called when the PortMapper is closed, it will call -open for you.
   24.83 +    If called when it's already open, it just returns YES. */
   24.84 +- (BOOL) waitTillOpened;
   24.85 +
   24.86 +/** Closes the PortMapper, terminating any open port mapping. */
   24.87 +- (void) close;
   24.88 +
   24.89 +/** The error status, a DNSServiceErrorType enum; nonzero if something went wrong. 
   24.90 +    The most likely error is kDNSServiceErr_NATPortMappingUnsupported (-65564).
   24.91 +    This property is KV observable. */
   24.92 +@property (readonly) SInt32 error;
   24.93 +
   24.94 +/** The known public IPv4 address/port, once it's been determined.
   24.95 +    This property is KV observable. */
   24.96 +@property (readonly,retain) IPAddress* publicAddress;
   24.97 +
   24.98 +/** The current local address/port, as of the time the port mapping was last updated.
   24.99 +    The address part is of the main interface; the port is the specified local port.
  24.100 +    This property is KV observable. */
  24.101 +@property (readonly,retain) IPAddress* localAddress;
  24.102 +
  24.103 +/** Returns YES if a non-null port mapping is in effect: 
  24.104 +    that is, if the public address differs from the local one. */
  24.105 +@property (readonly) BOOL isMapped;
  24.106 +
  24.107 +
  24.108 +// UTILITY CLASS METHOD:
  24.109 +
  24.110 +/** Determine the main interface's public IP address, without mapping any ports.
  24.111 +    This method internally calls -waitTillOpened, so it may take a nontrivial amount
  24.112 +    of time (and will crank the runloop while it waits.)
  24.113 +    If you want to do this asynchronously, you should instead create a new
  24.114 +    MYPortMapper instance using -initWithNullMapping. */
  24.115 ++ (IPAddress*) findPublicAddress;
  24.116 +
  24.117 +@end
  24.118 +
  24.119 +
  24.120 +/** This notification is posted asynchronously when the status of a PortMapper
  24.121 +    (its error, publicAddress or publicPort) changes. */
  24.122 +extern NSString* const MYPortMapperChangedNotification;
    25.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    25.2 +++ b/PortMapper/MYPortMapper.m	Wed Apr 22 16:45:39 2009 -0700
    25.3 @@ -0,0 +1,303 @@
    25.4 +//
    25.5 +//  MYPortMapper.m
    25.6 +//  MYNetwork
    25.7 +//
    25.8 +//  Created by Jens Alfke on 1/4/08.
    25.9 +//  Copyright 2008 Jens Alfke. All rights reserved.
   25.10 +//
   25.11 +
   25.12 +#import "MYPortMapper.h"
   25.13 +#import "IPAddress.h"
   25.14 +#import "CollectionUtils.h"
   25.15 +#import "Logging.h"
   25.16 +#import "ExceptionUtils.h"
   25.17 +
   25.18 +#import <dns_sd.h>
   25.19 +#import <sys/types.h>
   25.20 +#import <sys/socket.h>
   25.21 +#import <net/if.h>
   25.22 +#import <netinet/in.h>
   25.23 +#import <ifaddrs.h>
   25.24 +
   25.25 +
   25.26 +NSString* const MYPortMapperChangedNotification = @"MYPortMapperChanged";
   25.27 +
   25.28 +
   25.29 +@interface MYPortMapper ()
   25.30 +// Redeclare these properties as settable, internally:
   25.31 +@property (readwrite) SInt32 error;
   25.32 +@property (retain) IPAddress* publicAddress, *localAddress;
   25.33 +// Private getter:
   25.34 +@property (readonly) void* _service;
   25.35 +- (void) priv_updateLocalAddress;
   25.36 +- (void) priv_disconnect;
   25.37 +@end
   25.38 +
   25.39 +
   25.40 +@implementation MYPortMapper
   25.41 +
   25.42 +
   25.43 +- (id) initWithLocalPort: (UInt16)localPort
   25.44 +{
   25.45 +    self = [super init];
   25.46 +    if (self != nil) {
   25.47 +        _localPort = localPort;
   25.48 +        _mapTCP = YES;
   25.49 +        [self priv_updateLocalAddress];
   25.50 +    }
   25.51 +    return self;
   25.52 +}
   25.53 +
   25.54 +- (id) initWithNullMapping
   25.55 +{
   25.56 +    // A PortMapper with no port or protocols will cause the DNSService to look up 
   25.57 +    // our public address without creating a mapping.
   25.58 +    if ([self initWithLocalPort: 0]) {
   25.59 +        _mapTCP = _mapUDP = NO;
   25.60 +    }
   25.61 +    return self;
   25.62 +}
   25.63 +
   25.64 +
   25.65 +- (void) dealloc
   25.66 +{
   25.67 +    if( _service )
   25.68 +        [self priv_disconnect];
   25.69 +    [_publicAddress release];
   25.70 +    [_localAddress release];
   25.71 +    [super dealloc];
   25.72 +}
   25.73 +
   25.74 +- (void) finalize
   25.75 +{
   25.76 +    if( _service )
   25.77 +        [self priv_disconnect];
   25.78 +    [super finalize];
   25.79 +}
   25.80 +
   25.81 +
   25.82 +@synthesize localAddress=_localAddress, publicAddress=_publicAddress,
   25.83 +            error=_error, _service=_service,
   25.84 +            mapTCP=_mapTCP, mapUDP=_mapUDP,
   25.85 +            desiredPublicPort=_desiredPublicPort;
   25.86 +
   25.87 +
   25.88 +- (BOOL) isMapped
   25.89 +{
   25.90 +    return ! $equal(_publicAddress,_localAddress);
   25.91 +}
   25.92 +
   25.93 +- (void) priv_updateLocalAddress 
   25.94 +{
   25.95 +    IPAddress *localAddress = [IPAddress localAddressWithPort: _localPort];
   25.96 +    if (!$equal(localAddress,_localAddress))
   25.97 +        self.localAddress = localAddress;
   25.98 +}
   25.99 +
  25.100 +
  25.101 +static IPAddress* makeIPAddr( UInt32 rawAddr, UInt16 port ) {
  25.102 +    if (rawAddr)
  25.103 +        return [[[IPAddress alloc] initWithIPv4: rawAddr port: port] autorelease];
  25.104 +    else
  25.105 +        return nil;
  25.106 +}
  25.107 +
  25.108 +/** Called whenever the port mapping changes (see comment for callback, below.) */
  25.109 +- (void) priv_portMapStatus: (DNSServiceErrorType)errorCode 
  25.110 +              publicAddress: (UInt32)rawPublicAddress
  25.111 +                 publicPort: (UInt16)publicPort
  25.112 +{
  25.113 +    LogTo(PortMapper,@"Callback got err %i, addr %08X:%hu",
  25.114 +          errorCode, rawPublicAddress, publicPort);
  25.115 +    if( errorCode==kDNSServiceErr_NoError ) {
  25.116 +        if( rawPublicAddress==0 || (publicPort==0 && (_mapTCP || _mapUDP)) ) {
  25.117 +            LogTo(PortMapper,@"(Callback reported no mapping available)");
  25.118 +            errorCode = kDNSServiceErr_NATPortMappingUnsupported;
  25.119 +        }
  25.120 +    }
  25.121 +    if( errorCode != self.error )
  25.122 +        self.error = errorCode;
  25.123 +
  25.124 +    [self priv_updateLocalAddress];
  25.125 +    IPAddress *publicAddress = makeIPAddr(rawPublicAddress,publicPort);
  25.126 +    if (!$equal(publicAddress,_publicAddress))
  25.127 +        self.publicAddress = publicAddress;
  25.128 +    
  25.129 +    if( ! errorCode ) {
  25.130 +        LogTo(PortMapper,@"Callback got %08X:%hu -> %@ (mapped=%i)",
  25.131 +              rawPublicAddress,publicPort, self.publicAddress, self.isMapped);
  25.132 +    }
  25.133 +    [[NSNotificationCenter defaultCenter] postNotificationName: MYPortMapperChangedNotification
  25.134 +                                                        object: self];
  25.135 +}
  25.136 +
  25.137 +
  25.138 +/** Asynchronous callback from DNSServiceNATPortMappingCreate.
  25.139 +    This is invoked whenever the status of the port mapping changes.
  25.140 +    All it does is dispatch to the object's priv_portMapStatus:publicAddress:publicPort: method. */
  25.141 +static void portMapCallback (
  25.142 +                      DNSServiceRef                    sdRef,
  25.143 +                      DNSServiceFlags                  flags,
  25.144 +                      uint32_t                         interfaceIndex,
  25.145 +                      DNSServiceErrorType              errorCode,
  25.146 +                      uint32_t                         publicAddress,    /* four byte IPv4 address in network byte order */
  25.147 +                      DNSServiceProtocol               protocol,
  25.148 +                      uint16_t                         privatePort,
  25.149 +                      uint16_t                         publicPort,       /* may be different than the requested port */
  25.150 +                      uint32_t                         ttl,              /* may be different than the requested ttl */
  25.151 +                      void                             *context
  25.152 +                      )
  25.153 +{
  25.154 +    NSAutoreleasePool *pool = [NSAutoreleasePool new];
  25.155 +    @try{
  25.156 +        [(MYPortMapper*)context priv_portMapStatus: errorCode 
  25.157 +                                     publicAddress: publicAddress
  25.158 +                                        publicPort: ntohs(publicPort)];  // port #s in network byte order!
  25.159 +    }catchAndReport(@"PortMapper");
  25.160 +    [pool drain];
  25.161 +}
  25.162 +
  25.163 +
  25.164 +/** CFSocket callback, informing us that _socket has data available, which means
  25.165 +    that the DNS service has an incoming result to be processed. This will end up invoking
  25.166 +    the portMapCallback. */
  25.167 +static void serviceCallback(CFSocketRef s, 
  25.168 +                            CFSocketCallBackType type,
  25.169 +                            CFDataRef address, const void *data, void *clientCallBackInfo)
  25.170 +{
  25.171 +    MYPortMapper *mapper = (MYPortMapper*)clientCallBackInfo;
  25.172 +    DNSServiceRef service = mapper._service;
  25.173 +    DNSServiceErrorType err = DNSServiceProcessResult(service);
  25.174 +    if( err ) {
  25.175 +        // An error here means the socket has failed and should be closed.
  25.176 +        [mapper priv_portMapStatus: err publicAddress: 0 publicPort: 0];
  25.177 +        [mapper priv_disconnect];
  25.178 +    }
  25.179 +}
  25.180 +
  25.181 +
  25.182 +
  25.183 +- (BOOL) open
  25.184 +{
  25.185 +    NSAssert(!_service,@"Already open");
  25.186 +    // Create the DNSService:
  25.187 +    DNSServiceProtocol protocols = 0;
  25.188 +    if( _mapTCP ) protocols |= kDNSServiceProtocol_TCP;
  25.189 +    if( _mapUDP ) protocols |= kDNSServiceProtocol_UDP;
  25.190 +    self.error = DNSServiceNATPortMappingCreate((DNSServiceRef*)&_service, 
  25.191 +                                         0 /*flags*/, 
  25.192 +                                         0 /*interfaceIndex*/, 
  25.193 +                                         protocols,
  25.194 +                                         htons(_localPort),
  25.195 +                                         htons(_desiredPublicPort),
  25.196 +                                         0 /*ttl*/,
  25.197 +                                         &portMapCallback, 
  25.198 +                                         self);
  25.199 +    if( _error ) {
  25.200 +        LogTo(PortMapper,@"Error %i creating port mapping",_error);
  25.201 +        return NO;
  25.202 +    }
  25.203 +    
  25.204 +    // Wrap a CFSocket around the service's socket:
  25.205 +    CFSocketContext ctxt = { 0, self, CFRetain, CFRelease, NULL };
  25.206 +    _socket = CFSocketCreateWithNative(NULL, 
  25.207 +                                       DNSServiceRefSockFD(_service), 
  25.208 +                                       kCFSocketReadCallBack, 
  25.209 +                                       &serviceCallback, &ctxt);
  25.210 +    if( _socket ) {
  25.211 +        CFSocketSetSocketFlags(_socket, CFSocketGetSocketFlags(_socket) & ~kCFSocketCloseOnInvalidate);
  25.212 +        // Attach the socket to the runloop so the serviceCallback will be invoked:
  25.213 +        _socketSource = CFSocketCreateRunLoopSource(NULL, _socket, 0);
  25.214 +        if( _socketSource )
  25.215 +            CFRunLoopAddSource(CFRunLoopGetCurrent(), _socketSource, kCFRunLoopCommonModes);
  25.216 +    }
  25.217 +    if( _socketSource ) {
  25.218 +        LogTo(PortMapper,@"Opening");
  25.219 +        return YES;
  25.220 +    } else {
  25.221 +        Warn(@"Failed to open PortMapper");
  25.222 +        [self close];
  25.223 +        _error = kDNSServiceErr_Unknown;
  25.224 +        return NO;
  25.225 +    }
  25.226 +}
  25.227 +
  25.228 +
  25.229 +- (BOOL) waitTillOpened
  25.230 +{
  25.231 +    if( ! _socketSource )
  25.232 +        if( ! [self open] )
  25.233 +            return NO;
  25.234 +    // Run the runloop until there's either an error or a result:
  25.235 +    while( _error==0 && _publicAddress==nil )
  25.236 +        if( ! [[NSRunLoop currentRunLoop] runMode: NSDefaultRunLoopMode
  25.237 +                                       beforeDate: [NSDate distantFuture]] )
  25.238 +            break;
  25.239 +    return (_error==0);
  25.240 +}
  25.241 +
  25.242 +
  25.243 +// Close down, but _without_ clearing the 'error' property
  25.244 +- (void) priv_disconnect
  25.245 +{
  25.246 +    if( _socketSource ) {
  25.247 +        CFRunLoopSourceInvalidate(_socketSource);
  25.248 +        CFRelease(_socketSource);
  25.249 +        _socketSource = NULL;
  25.250 +    }
  25.251 +    if( _socket ) {
  25.252 +        CFSocketInvalidate(_socket);
  25.253 +        CFRelease(_socket);
  25.254 +        _socket = NULL;
  25.255 +    }
  25.256 +    if( _service ) {
  25.257 +        LogTo(PortMapper,@"Deleting port mapping");
  25.258 +        DNSServiceRefDeallocate(_service);
  25.259 +        _service = NULL;
  25.260 +        self.publicAddress = nil;
  25.261 +    }
  25.262 +}
  25.263 +
  25.264 +- (void) close
  25.265 +{
  25.266 +    [self priv_disconnect];
  25.267 +    self.error = 0;
  25.268 +}
  25.269 +
  25.270 +
  25.271 ++ (IPAddress*) findPublicAddress
  25.272 +{
  25.273 +    IPAddress *addr = nil;
  25.274 +    MYPortMapper *mapper = [[self alloc] initWithNullMapping];
  25.275 +    if( [mapper waitTillOpened] )
  25.276 +        addr = [mapper.publicAddress retain];
  25.277 +    [mapper close];
  25.278 +    [mapper release];
  25.279 +    return [addr autorelease];
  25.280 +}
  25.281 +
  25.282 +
  25.283 +@end
  25.284 +
  25.285 +
  25.286 +/*
  25.287 + Copyright (c) 2008-2009, Jens Alfke <jens@mooseyard.com>. All rights reserved.
  25.288 + 
  25.289 + Redistribution and use in source and binary forms, with or without modification, are permitted
  25.290 + provided that the following conditions are met:
  25.291 + 
  25.292 + * Redistributions of source code must retain the above copyright notice, this list of conditions
  25.293 + and the following disclaimer.
  25.294 + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
  25.295 + and the following disclaimer in the documentation and/or other materials provided with the
  25.296 + distribution.
  25.297 + 
  25.298 + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
  25.299 + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
  25.300 + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
  25.301 + BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  25.302 + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
  25.303 +  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
  25.304 + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
  25.305 + THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25.306 + */
    26.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    26.2 +++ b/PortMapper/PortMapperTest.m	Wed Apr 22 16:45:39 2009 -0700
    26.3 @@ -0,0 +1,111 @@
    26.4 +//  PortMapperTest.m
    26.5 +//  MYNetwork
    26.6 +//
    26.7 +//  Created by Jens Alfke on 1/4/08.
    26.8 +//  Copyright 2008 Jens Alfke. All rights reserved.
    26.9 +//
   26.10 +
   26.11 +
   26.12 +
   26.13 +#import "MYPortMapper.h"
   26.14 +#import "IPAddress.h"
   26.15 +#import "Test.h"
   26.16 +#import "Logging.h"
   26.17 +
   26.18 +#if DEBUG
   26.19 +
   26.20 +
   26.21 +/** A trivial class that just demonstrates how to create a MYPortMapper and listen for changes. */
   26.22 +@interface MYPortMapperTest : NSObject
   26.23 +{
   26.24 +    MYPortMapper *_mapper;
   26.25 +}
   26.26 +
   26.27 +@end
   26.28 +
   26.29 +
   26.30 +@implementation MYPortMapperTest
   26.31 +
   26.32 +
   26.33 +- (id) init
   26.34 +{
   26.35 +    self = [super init];
   26.36 +    if( self ) {
   26.37 +        // Create MYPortMapper. This example doesn't open a real socket; just pretend that there's
   26.38 +        // already a TCP socket listening on port 8080. To experiment, you could turn on Web
   26.39 +        // Sharing, then change this port number to 80 -- that will make your computer's local
   26.40 +        // Apache web server reachable from the outside world while this program is running.
   26.41 +        _mapper = [[MYPortMapper alloc] initWithLocalPort: 80];
   26.42 +        
   26.43 +        // Optionally, request a public port number.
   26.44 +        // The NAT is free to ignore this and return a random number instead.
   26.45 +        _mapper.desiredPublicPort = 22222;
   26.46 +        
   26.47 +        // Now open the mapping (asynchronously):
   26.48 +        if( [_mapper open] ) {
   26.49 +            Log(@"Opening port mapping...");
   26.50 +            // Now listen for notifications to find out when the mapping opens, fails, or changes:
   26.51 +            [[NSNotificationCenter defaultCenter] addObserver: self 
   26.52 +                                                     selector: @selector(portMappingChanged:) 
   26.53 +                                                         name: MYPortMapperChangedNotification 
   26.54 +                                                       object: _mapper];
   26.55 +        } else {
   26.56 +            // MYPortMapper failed -- this is unlikely, but be graceful:
   26.57 +            Log(@"!! Error: MYPortMapper wouldn't start: %i",_mapper.error);
   26.58 +            [self release];
   26.59 +            return nil;
   26.60 +        }
   26.61 +    }
   26.62 +    return self;
   26.63 +}
   26.64 +
   26.65 +
   26.66 +- (void) portMappingChanged: (NSNotification*)n
   26.67 +{
   26.68 +    // This is where we get notified that the mapping was created, or that no mapping exists,
   26.69 +    // or that mapping failed.
   26.70 +    if( _mapper.error )
   26.71 +        Log(@"!! MYPortMapper error %i", _mapper.error);
   26.72 +    else {
   26.73 +        NSString *message = @"";
   26.74 +        if( !_mapper.isMapped )
   26.75 +            message = @" (no address translation!)";
   26.76 +        Log(@"** Public address:port is %@%@", _mapper.publicAddress, message);
   26.77 +        Log(@"    local address:port is %@", _mapper.localAddress);
   26.78 +    }
   26.79 +}
   26.80 +
   26.81 +
   26.82 +- (void) dealloc
   26.83 +{
   26.84 +    [_mapper close];
   26.85 +    [_mapper release];
   26.86 +    [super dealloc];
   26.87 +}
   26.88 +
   26.89 +
   26.90 +@end
   26.91 +
   26.92 +
   26.93 +
   26.94 +TestCase(MYPortMapper) {
   26.95 +    
   26.96 +    EnableLogTo(PortMapper,YES);
   26.97 +    // Here's how to simply obtain your local and public address(es):
   26.98 +    IPAddress *addr = [IPAddress localAddress];
   26.99 +    Log(@"** Local address is %@%@ ...getting public addr...", 
  26.100 +        addr, (addr.isPrivate ?@" (private)" :@""));
  26.101 +    addr = [MYPortMapper findPublicAddress];
  26.102 +    Log(@"** Public address is %@", addr);
  26.103 +
  26.104 +    // Start up the test class to create a mapping:
  26.105 +    MYPortMapperTest *test = [[MYPortMapperTest alloc] init];
  26.106 +    
  26.107 +    // Now let the runloop run forever...
  26.108 +    Log(@"Running the runloop forever...");
  26.109 +    [[NSRunLoop currentRunLoop] run];
  26.110 +        
  26.111 +    [test release];
  26.112 +}
  26.113 +
  26.114 +#endif DEBUG
    27.1 --- a/TCP/TCPConnection.h	Tue Dec 02 22:42:56 2008 -0800
    27.2 +++ b/TCP/TCPConnection.h	Wed Apr 22 16:45:39 2009 -0700
    27.3 @@ -127,6 +127,7 @@
    27.4      settings say to check the peer's certificate.
    27.5      This happens, if at all, after the -connectionDidOpen: call. */
    27.6  - (BOOL) connection: (TCPConnection*)connection authorizeSSLPeer: (SecCertificateRef)peerCert;
    27.7 -/** Called after the connection closes. */
    27.8 +/** Called after the connection closes.
    27.9 +    You can check the connection's error property to see if it was normal or abnormal. */
   27.10  - (void) connectionDidClose: (TCPConnection*)connection;
   27.11  @end
    28.1 --- a/TCP/TCPConnection.m	Tue Dec 02 22:42:56 2008 -0800
    28.2 +++ b/TCP/TCPConnection.m	Wed Apr 22 16:45:39 2009 -0700
    28.3 @@ -14,7 +14,7 @@
    28.4  #import "ExceptionUtils.h"
    28.5  
    28.6  
    28.7 -#if TARGET_OS_IPHONE && TARGET_OS_EMBEDDED
    28.8 +#if TARGET_OS_IPHONE && !defined(__SEC_TYPES__)
    28.9  // SecureTransport.h is missing on iPhone, with its SSL constants:
   28.10  enum{
   28.11      errSSLClosedAbort 			= -9806,	/* connection closed via error */
   28.12 @@ -348,7 +348,7 @@
   28.13                      allow = NO; // Server MUST have a cert!
   28.14                  else {
   28.15                      SecCertificateRef cert = certs.count ?(SecCertificateRef)[certs objectAtIndex:0] :NULL;
   28.16 -                    LogTo(TCP,@"%@: Peer cert = %@",self,cert);
   28.17 +                    LogTo(TCP,@"%@: Peer cert = %@",self,[TCPEndpoint describeCert: cert]);
   28.18                      if( [_delegate respondsToSelector: @selector(connection:authorizeSSLPeer:)] )
   28.19                          allow = [_delegate connection: self authorizeSSLPeer: cert];
   28.20                  }
    29.1 --- a/TCP/TCPEndpoint.h	Tue Dec 02 22:42:56 2008 -0800
    29.2 +++ b/TCP/TCPEndpoint.h	Wed Apr 22 16:45:39 2009 -0700
    29.3 @@ -7,6 +7,7 @@
    29.4  //
    29.5  
    29.6  #import <Foundation/Foundation.h>
    29.7 +#import <Security/SecBase.h>
    29.8  #if TARGET_OS_IPHONE
    29.9  #include <CFNetwork/CFSocketStream.h>
   29.10  #else
   29.11 @@ -15,10 +16,26 @@
   29.12  
   29.13  
   29.14  // SSL properties:
   29.15 +
   29.16 +/** This defines the SSL identity to be used by this endpoint.
   29.17 +    The value is an NSArray (or CFArray) whose first item must be a SecIdentityRef;
   29.18 +    optionally, it can also contain SecCertificateRefs for supporting certificates in the
   29.19 +    validation chain. */
   29.20  #define kTCPPropertySSLCertificates  ((NSString*)kCFStreamSSLCertificates)
   29.21 +
   29.22 +/** If set to YES, the connection will accept self-signed certificates from the peer,
   29.23 +    or any certificate chain that terminates in an unrecognized root. */
   29.24  #define kTCPPropertySSLAllowsAnyRoot ((NSString*)kCFStreamSSLAllowsAnyRoot)
   29.25  
   29.26 -extern NSString* const kTCPPropertySSLClientSideAuthentication;    // value is TCPAuthenticate enum
   29.27 +/** This sets the hostname that the peer's certificate must have.
   29.28 +    (The default value is the hostname, if any, that the connection was opened with.)
   29.29 +    Setting a value of [NSNull null] completely disables host-name checking. */
   29.30 +#define kTCPPropertySSLPeerName      ((NSString*)kCFStreamSSLPeerName)
   29.31 +
   29.32 +/** Specifies whether the client (the peer that opened the connection) will use a certificate.
   29.33 +    The value is a TCPAuthenticate enum value wrapped in an NSNumber. */
   29.34 +extern NSString* const kTCPPropertySSLClientSideAuthentication;
   29.35 +
   29.36  typedef enum {
   29.37  	kTCPNeverAuthenticate,			/* skip client authentication */
   29.38  	kTCPAlwaysAuthenticate,         /* require it */
   29.39 @@ -46,6 +63,10 @@
   29.40  - (void) setSSLProperty: (id)value 
   29.41                   forKey: (NSString*)key;
   29.42  
   29.43 +/** High-level setup for secure P2P connections. Uses the given identity for SSL,
   29.44 +    requires peers to use SSL, turns off root checking and peer-name checking. */
   29.45 +- (void) setPeerToPeerIdentity: (SecIdentityRef)identity;
   29.46 +
   29.47  //protected:
   29.48  - (void) tellDelegate: (SEL)selector withObject: (id)param;
   29.49  
    30.1 --- a/TCP/TCPEndpoint.m	Tue Dec 02 22:42:56 2008 -0800
    30.2 +++ b/TCP/TCPEndpoint.m	Wed Apr 22 16:45:39 2009 -0700
    30.3 @@ -7,8 +7,10 @@
    30.4  //
    30.5  
    30.6  #import "TCPEndpoint.h"
    30.7 -
    30.8 +#import "Test.h"
    30.9 +#import "CollectionUtils.h"
   30.10  #import "ExceptionUtils.h"
   30.11 +#import <Security/Security.h>
   30.12  
   30.13  
   30.14  NSString* const kTCPPropertySSLClientSideAuthentication = @"kTCPPropertySSLClientSideAuthentication";
   30.15 @@ -47,6 +49,15 @@
   30.16  - (NSString*) securityLevel                 {return [_sslProperties objectForKey: (id)kCFStreamSSLLevel];}
   30.17  - (void) setSecurityLevel: (NSString*)level {[self setSSLProperty: level forKey: (id)kCFStreamSSLLevel];}
   30.18  
   30.19 +- (void) setPeerToPeerIdentity: (SecIdentityRef)identity {
   30.20 +    Assert(identity);
   30.21 +    self.SSLProperties = $mdict(
   30.22 +             {(id)kCFStreamSSLLevel, NSStreamSocketSecurityLevelTLSv1},
   30.23 +             {kTCPPropertySSLCertificates, $array((id)identity)},
   30.24 +             {kTCPPropertySSLAllowsAnyRoot, $true},
   30.25 +             {kTCPPropertySSLPeerName, [NSNull null]},
   30.26 +             {kTCPPropertySSLClientSideAuthentication, $object(kTCPAlwaysAuthenticate)});
   30.27 +}
   30.28  
   30.29  - (void) tellDelegate: (SEL)selector withObject: (id)param
   30.30  {
   30.31 @@ -58,6 +69,37 @@
   30.32  }
   30.33  
   30.34  
   30.35 ++ (NSString*) describeCert: (SecCertificateRef)cert {
   30.36 +    if (!cert)
   30.37 +        return @"(null)";
   30.38 +    NSString *desc;
   30.39 +#if TARGET_OS_IPHONE && !defined(__SEC_TYPES__)
   30.40 +    CFStringRef summary = NULL;
   30.41 +    SecCertificateCopySubjectSummary(cert);
   30.42 +    desc = $sprintf(@"Certificate[%@]", summary);
   30.43 +    if(summary) CFRelease(summary);
   30.44 +#else
   30.45 +    CFStringRef name=NULL;
   30.46 +    CFArrayRef emails=NULL;
   30.47 +    SecCertificateCopyCommonName(cert, &name);
   30.48 +    SecCertificateCopyEmailAddresses(cert, &emails);
   30.49 +    desc = $sprintf(@"Certificate[\"%@\", <%@>]",
   30.50 +                              name, [(NSArray*)emails componentsJoinedByString: @">, <"]);
   30.51 +    if(name) CFRelease(name);
   30.52 +    if(emails) CFRelease(emails);
   30.53 +#endif
   30.54 +    return desc;
   30.55 +}
   30.56 +
   30.57 ++ (NSString*) describeIdentity: (SecIdentityRef)identity {
   30.58 +    if (!identity)
   30.59 +        return @"(null)";
   30.60 +    SecCertificateRef cert;
   30.61 +    SecIdentityCopyCertificate(identity, &cert);
   30.62 +    return $sprintf(@"Identity[%@]", [self describeCert: cert]);
   30.63 +}
   30.64 +
   30.65 +
   30.66  @end
   30.67  
   30.68  
    31.1 --- a/TCP/TCPListener.m	Tue Dec 02 22:42:56 2008 -0800
    31.2 +++ b/TCP/TCPListener.m	Wed Apr 22 16:45:39 2009 -0700
    31.3 @@ -156,10 +156,13 @@
    31.4          addr6.sin6_port = htons(_port);
    31.5          memcpy(&(addr6.sin6_addr), &in6addr_any, sizeof(addr6.sin6_addr));
    31.6          
    31.7 -        _ipv6socket = [self _openProtocol: PF_INET6 address: (struct sockaddr*)&addr6 error: outError];
    31.8 +        NSError *error;
    31.9 +        _ipv6socket = [self _openProtocol: PF_INET6 address: (struct sockaddr*)&addr6 error: &error];
   31.10          if( ! _ipv6socket ) {
   31.11              _ipv4socket = closeSocket(_ipv4socket);
   31.12 -            return [self _failedToOpen: *outError];
   31.13 +            [self _failedToOpen: error];
   31.14 +            if (outError) *outError = error;
   31.15 +            return NO;
   31.16          }
   31.17      }
   31.18      
    32.1 --- a/TCP/TCPStream.m	Tue Dec 02 22:42:56 2008 -0800
    32.2 +++ b/TCP/TCPStream.m	Wed Apr 22 16:45:39 2009 -0700
    32.3 @@ -96,7 +96,7 @@
    32.4  - (void) open
    32.5  {
    32.6      Assert(_stream);
    32.7 -    AssertEq(_stream.streamStatus,NSStreamStatusNotOpen);
    32.8 +    AssertEq(_stream.streamStatus,(NSStreamStatus)NSStreamStatusNotOpen);
    32.9      LogTo(TCP,@"Opening %@",self);
   32.10      [_stream open];
   32.11  }
    33.1 --- a/TCP/TCP_Internal.h	Tue Dec 02 22:42:56 2008 -0800
    33.2 +++ b/TCP/TCP_Internal.h	Wed Apr 22 16:45:39 2009 -0700
    33.3 @@ -30,3 +30,8 @@
    33.4  - (void) _unclose;
    33.5  @end
    33.6  
    33.7 +
    33.8 +@interface TCPEndpoint ()
    33.9 ++ (NSString*) describeCert: (SecCertificateRef)cert;
   33.10 ++ (NSString*) describeIdentity: (SecIdentityRef)identity;
   33.11 +@end
    34.1 --- a/iPhone/Classes/MyViewController.m	Tue Dec 02 22:42:56 2008 -0800
    34.2 +++ b/iPhone/Classes/MyViewController.m	Wed Apr 22 16:45:39 2009 -0700
    34.3 @@ -1,49 +1,3 @@
    34.4 -/*
    34.5 -
    34.6 -File: MyViewController.m
    34.7 -Abstract: A view controller responsible for managing the Hello World view.
    34.8 -
    34.9 -Version: 1.7
   34.10 -
   34.11 -Disclaimer: IMPORTANT:  This Apple software is supplied to you by Apple Inc.
   34.12 -("Apple") in consideration of your agreement to the following terms, and your
   34.13 -use, installation, modification or redistribution of this Apple software
   34.14 -constitutes acceptance of these terms.  If you do not agree with these terms,
   34.15 -please do not use, install, modify or redistribute this Apple software.
   34.16 -
   34.17 -In consideration of your agreement to abide by the following terms, and subject
   34.18 -to these terms, Apple grants you a personal, non-exclusive license, under
   34.19 -Apple's copyrights in this original Apple software (the "Apple Software"), to
   34.20 -use, reproduce, modify and redistribute the Apple Software, with or without
   34.21 -modifications, in source and/or binary forms; provided that if you redistribute
   34.22 -the Apple Software in its entirety and without modifications, you must retain
   34.23 -this notice and the following text and disclaimers in all such redistributions
   34.24 -of the Apple Software.
   34.25 -Neither the name, trademarks, service marks or logos of Apple Inc. may be used
   34.26 -to endorse or promote products derived from the Apple Software without specific
   34.27 -prior written permission from Apple.  Except as expressly stated in this notice,
   34.28 -no other rights or licenses, express or implied, are granted by Apple herein,
   34.29 -including but not limited to any patent rights that may be infringed by your
   34.30 -derivative works or by other works in which the Apple Software may be
   34.31 -incorporated.
   34.32 -
   34.33 -The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
   34.34 -WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
   34.35 -WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   34.36 -PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
   34.37 -COMBINATION WITH YOUR PRODUCTS.
   34.38 -
   34.39 -IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
   34.40 -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
   34.41 -GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   34.42 -ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR
   34.43 -DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF
   34.44 -CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
   34.45 -APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   34.46 -
   34.47 -Copyright (C) 2008 Apple Inc. All Rights Reserved.
   34.48 -
   34.49 -*/
   34.50  
   34.51  #import "MyViewController.h"
   34.52  #import "BLIP.h"
    35.1 --- a/iPhone/main.m	Tue Dec 02 22:42:56 2008 -0800
    35.2 +++ b/iPhone/main.m	Wed Apr 22 16:45:39 2009 -0700
    35.3 @@ -46,9 +46,11 @@
    35.4  */
    35.5  
    35.6  #import <UIKit/UIKit.h>
    35.7 +#import "Test.h"
    35.8  
    35.9  int main(int argc, char *argv[])
   35.10  {
   35.11 +    RunTestCases(argc,(const char**)argv);
   35.12      NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
   35.13      int retVal = UIApplicationMain(argc, argv, nil, nil);
   35.14      [pool release];