# HG changeset patch # User Jens Alfke # Date 1240443939 25200 # Node ID cb9cdf247239f338d763d84ce33364b52d7e1244 # Parent a4875607a3a054971a5314188b179a8dfdfb90e5 * Added MYBonjourBrowser and MYBonjourService. * Added MYPortMapper. * Added -[TCPEndpoint setPeerToPeerIdentity:]. * Created a static-library target. diff -r a4875607a3a0 -r cb9cdf247239 BLIP/BLIP.h --- a/BLIP/BLIP.h Tue Dec 02 22:42:56 2008 -0800 +++ b/BLIP/BLIP.h Wed Apr 22 16:45:39 2009 -0700 @@ -3,7 +3,7 @@ // MYNetwork // // Created by Jens Alfke on 5/24/08. -// Copyright 2008 __MyCompanyName__. All rights reserved. +// Copyright 2008 Jens Alfke. All rights reserved. // #import "BLIPConnection.h" diff -r a4875607a3a0 -r cb9cdf247239 BLIP/BLIPConnection.h --- a/BLIP/BLIPConnection.h Tue Dec 02 22:42:56 2008 -0800 +++ b/BLIP/BLIPConnection.h Wed Apr 22 16:45:39 2009 -0700 @@ -19,6 +19,7 @@ Most of the API is inherited from TCPConnection. */ @interface BLIPConnection : TCPConnection { + @private BLIPDispatcher *_dispatcher; BOOL _blipClosing; } diff -r a4875607a3a0 -r cb9cdf247239 BLIP/BLIPDispatcher.h --- a/BLIP/BLIPDispatcher.h Tue Dec 02 22:42:56 2008 -0800 +++ b/BLIP/BLIPDispatcher.h Wed Apr 22 16:45:39 2009 -0700 @@ -25,6 +25,7 @@ request based on property values. */ @interface BLIPDispatcher : NSObject { + @private NSMutableArray *_predicates, *_targets; BLIPDispatcher *_parent; } diff -r a4875607a3a0 -r cb9cdf247239 BLIP/BLIPMessage.h --- a/BLIP/BLIPMessage.h Tue Dec 02 22:42:56 2008 -0800 +++ b/BLIP/BLIPMessage.h Wed Apr 22 16:45:39 2009 -0700 @@ -36,6 +36,7 @@ /** Abstract superclass for BLIP requests and responses. */ @interface BLIPMessage : NSObject { + @protected BLIPConnection *_connection; UInt16 _flags; UInt32 _number; diff -r a4875607a3a0 -r cb9cdf247239 BLIP/BLIPProperties.h --- a/BLIP/BLIPProperties.h Tue Dec 02 22:42:56 2008 -0800 +++ b/BLIP/BLIPProperties.h Wed Apr 22 16:45:39 2009 -0700 @@ -45,6 +45,7 @@ /** Mutable subclass of BLIPProperties, used for creating new instances. */ @interface BLIPMutableProperties : BLIPProperties { + @private NSMutableDictionary *_properties; } diff -r a4875607a3a0 -r cb9cdf247239 BLIP/BLIPProperties.m --- a/BLIP/BLIPProperties.m Tue Dec 02 22:42:56 2008 -0800 +++ b/BLIP/BLIPProperties.m Wed Apr 22 16:45:39 2009 -0700 @@ -69,7 +69,7 @@ else props = [BLIPProperties properties]; - *usedLength = props ?length :-1; + *usedLength = props ?(ssize_t)length :-1; return props; } @@ -132,7 +132,7 @@ goto fail; // The data consists of consecutive NUL-terminated strings, alternating key/value: - unsigned capacity = 0; + int capacity = 0; const char *end = bytes+length; for( const char *str=bytes; str < end; str += strlen(str)+1, _nStrings++ ) { if( _nStrings >= capacity ) { @@ -285,7 +285,7 @@ static void appendStr( NSMutableData *data, NSString *str ) { const char *utf8 = [str UTF8String]; size_t size = strlen(utf8)+1; - for( int i=0; i -#endif +#import +#import + +@interface TCPEndpoint () ++ (NSString*) describeCert: (SecCertificateRef)cert; ++ (NSString*) describeIdentity: (SecIdentityRef)identity; +@end #define kListenerHost @"localhost" @@ -31,20 +34,41 @@ #define kNBatchedMessages 20 #define kUseCompression YES #define kUrgentEvery 4 -#define kClientRequiresSSL NO -#define kClientUsesSSLCert NO -#define kListenerRequiresSSL NO -#define kListenerRequiresClientCert NO #define kListenerCloseAfter 50 #define kClientAcceptCloseRequest YES +#define kListenerUsesSSL YES // Does the listener (server) use an SSL connection? +#define kListenerRequiresClientCert YES // Does the listener require clients to have an SSL cert? +#define kClientRequiresSSL YES // Does the client require the listener to use SSL? +#define kClientUsesSSLCert YES // Does the client use an SSL cert? + + +static SecIdentityRef ChooseIdentity( NSString *prompt ) { + NSMutableArray *identities = [NSMutableArray array]; + SecKeychainRef kc; + SecKeychainCopyDefault(&kc); + SecIdentitySearchRef search; + SecIdentitySearchCreate(kc, CSSM_KEYUSE_ANY, &search); + SecIdentityRef identity; + while (SecIdentitySearchCopyNext(search, &identity) == noErr) + [identities addObject: (id)identity]; + Log(@"Found %u identities -- prompting '%@'", identities.count, prompt); + if (identities.count > 0) { + SFChooseIdentityPanel *panel = [SFChooseIdentityPanel sharedChooseIdentityPanel]; + if ([panel runModalForIdentities: identities message: prompt] == NSOKButton) { + Log(@"Using SSL identity: %@", panel.identity); + return panel.identity; + } + } + return NULL; +} static SecIdentityRef GetClientIdentity(void) { - return NULL; // Make this return a valid identity to test client-side certs + return ChooseIdentity(@"Choose an identity for the BLIP Client Test:"); } static SecIdentityRef GetListenerIdentity(void) { - return NULL; // Make this return a valid identity to test client-side certs + return ChooseIdentity(@"Choose an identity for the BLIP Listener Test:"); } @@ -75,15 +99,11 @@ [self release]; return nil; } - if( kClientRequiresSSL ) { - _conn.SSLProperties = $mdict({kTCPPropertySSLAllowsAnyRoot, $true}); - if( kClientUsesSSLCert ) { - SecIdentityRef clientIdentity = GetClientIdentity(); - if( clientIdentity ) { - [_conn setSSLProperty: $array((id)clientIdentity) - forKey: kTCPPropertySSLCertificates]; - } - } + if( kClientUsesSSLCert ) { + [_conn setPeerToPeerIdentity: GetClientIdentity()]; + } else if( kClientRequiresSSL ) { + _conn.SSLProperties = $mdict({kTCPPropertySSLAllowsAnyRoot, $true}, + {(id)kCFStreamSSLPeerName, [NSNull null]}); } _conn.delegate = self; Log(@"** Opening connection..."); @@ -148,22 +168,20 @@ } - (BOOL) connection: (TCPConnection*)connection authorizeSSLPeer: (SecCertificateRef)peerCert { -#if HAVE_KEYCHAIN_FRAMEWORK - Certificate *cert = peerCert ?[Certificate certificateWithCertificateRef: peerCert] :nil; - Log(@"** %@ authorizeSSLPeer: %@",self,cert); -#else - Log(@"** %@ authorizeSSLPeer: %@",self,peerCert); -#endif + Log(@"** %@ authorizeSSLPeer: %@",self, [TCPEndpoint describeCert:peerCert]); return peerCert != nil; } - (void) connection: (TCPConnection*)connection failedToOpen: (NSError*)error { - Log(@"** %@ failedToOpen: %@",connection,error); + Warn(@"** %@ failedToOpen: %@",connection,error); CFRunLoopStop(CFRunLoopGetCurrent()); } - (void) connectionDidClose: (TCPConnection*)connection { - Log(@"** %@ didClose",connection); + if (connection.error) + Warn(@"** %@ didClose: %@", connection,connection.error); + else + Log(@"** %@ didClose", connection); setObj(&_conn,nil); [NSObject cancelPreviousPerformRequestsWithTarget: self]; CFRunLoopStop(CFRunLoopGetCurrent()); @@ -188,7 +206,7 @@ const UInt8 *bytes = body.bytes; for( size_t i=0; iCFBundleExecutable ${EXECUTABLE_NAME} CFBundleIdentifier - com.yourcompany.${PRODUCT_NAME:identifier} + com.mooseyard.BLIPEchoClient CFBundleInfoDictionaryVersion 6.0 CFBundlePackageType diff -r a4875607a3a0 -r cb9cdf247239 BLIP/Demo/BLIPEchoClient.h --- a/BLIP/Demo/BLIPEchoClient.h Tue Dec 02 22:42:56 2008 -0800 +++ b/BLIP/Demo/BLIPEchoClient.h Wed Apr 22 16:45:39 2009 -0700 @@ -9,23 +9,24 @@ // #import -@class BLIPConnection; +#import "BLIPConnection.h" +@class MYBonjourBrowser; -@interface BLIPEchoClient : NSObject +@interface BLIPEchoClient : NSObject { IBOutlet NSTextField * inputField; IBOutlet NSTextField * responseField; IBOutlet NSTableView * serverTableView; - NSNetServiceBrowser * _serviceBrowser; - NSMutableArray * _serviceList; - + MYBonjourBrowser * _serviceBrowser; BLIPConnection *_connection; } -@property (readonly) NSMutableArray *serviceList; +@property (readonly) MYBonjourBrowser *serviceBrowser; +@property (readonly) NSArray *serviceList; +- (IBAction)serverClicked:(id)sender; - (IBAction)sendText:(id)sender; @end diff -r a4875607a3a0 -r cb9cdf247239 BLIP/Demo/BLIPEchoClient.m --- a/BLIP/Demo/BLIPEchoClient.m Tue Dec 02 22:42:56 2008 -0800 +++ b/BLIP/Demo/BLIPEchoClient.m Wed Apr 22 16:45:39 2009 -0700 @@ -9,44 +9,36 @@ // #import "BLIPEchoClient.h" -#import "BLIP.h" +#import "MYBonjourBrowser.h" +#import "MYBonjourService.h" +#import "CollectionUtils.h" +#import "MYNetwork.h" #import "Target.h" @implementation BLIPEchoClient -@synthesize serviceList=_serviceList; - (void)awakeFromNib { - _serviceBrowser = [[NSNetServiceBrowser alloc] init]; - _serviceList = [[NSMutableArray alloc] init]; - [_serviceBrowser setDelegate:self]; - - [_serviceBrowser searchForServicesOfType:@"_blipecho._tcp." inDomain:@""]; + [self.serviceBrowser start]; } -#pragma mark - -#pragma mark NSNetServiceBrowser delegate methods - -// We broadcast the willChangeValueForKey: and didChangeValueForKey: for the NSTableView binding to work. - -- (void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didFindService:(NSNetService *)aNetService moreComing:(BOOL)moreComing { - if (![_serviceList containsObject:aNetService]) { - [self willChangeValueForKey:@"serviceList"]; - [_serviceList addObject:aNetService]; - [self didChangeValueForKey:@"serviceList"]; - } +- (MYBonjourBrowser*) serviceBrowser { + if (!_serviceBrowser) + _serviceBrowser = [[MYBonjourBrowser alloc] initWithServiceType: @"_blipecho._tcp."]; + return _serviceBrowser; } -- (void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didRemoveService:(NSNetService *)aNetService moreComing:(BOOL)moreComing { - if ([_serviceList containsObject:aNetService]) { - [self willChangeValueForKey:@"serviceList"]; - [_serviceList removeObject:aNetService]; - [self didChangeValueForKey:@"serviceList"]; - } +- (NSArray*) serviceList { + return [_serviceBrowser.services.allObjects sortedArrayUsingSelector: @selector(compare:)]; } ++ (NSArray*) keyPathsForValuesAffectingServiceList { + return $array(@"serviceBrowser.services"); +} + + #pragma mark - #pragma mark BLIPConnection support @@ -54,9 +46,10 @@ - (void)openConnection: (NSNetService*)service { _connection = [[BLIPConnection alloc] initToNetService: service]; - if( _connection ) + if( _connection ) { + _connection.delegate = self; [_connection open]; - else + } else NSBeep(); } @@ -64,10 +57,35 @@ - (void)closeConnection { [_connection close]; - [_connection release]; - _connection = nil; } +/** Called after the connection successfully opens. */ +- (void) connectionDidOpen: (TCPConnection*)connection { + if (connection==_connection) { + [inputField setEnabled: YES]; + [responseField setEnabled: YES]; + [inputField.window makeFirstResponder: inputField]; + } +} + +/** Called after the connection fails to open due to an error. */ +- (void) connection: (TCPConnection*)connection failedToOpen: (NSError*)error { + [serverTableView.window presentError: error]; +} + +/** Called after the connection closes. */ +- (void) connectionDidClose: (TCPConnection*)connection { + if (connection==_connection) { + if (connection.error) + [serverTableView.window presentError: connection.error]; + [_connection release]; + _connection = nil; + [inputField setEnabled: NO]; + [responseField setEnabled: NO]; + } +} + + #pragma mark - #pragma mark GUI action methods @@ -77,7 +95,7 @@ [self closeConnection]; if (-1 != selectedRow) - [self openConnection: [_serviceList objectAtIndex:selectedRow]]; + [self openConnection: [[self.serviceList objectAtIndex:selectedRow] netService]]; } /* Send a BLIP request containing the string in the textfield */ @@ -86,7 +104,11 @@ BLIPRequest *r = [_connection request]; r.bodyString = [sender stringValue]; BLIPResponse *response = [r send]; - response.onComplete = $target(self,gotResponse:); + if (response) { + response.onComplete = $target(self,gotResponse:); + [inputField setStringValue: @""]; + } else + NSBeep(); } /* Receive the response to the BLIP request, and put its contents into the response field */ @@ -100,5 +122,6 @@ int main(int argc, char *argv[]) { + //RunTestCases(argc,(const char**)argv); return NSApplicationMain(argc, (const char **) argv); } diff -r a4875607a3a0 -r cb9cdf247239 BLIP/Demo/BLIPEchoClient.xib --- a/BLIP/Demo/BLIPEchoClient.xib Tue Dec 02 22:42:56 2008 -0800 +++ b/BLIP/Demo/BLIPEchoClient.xib Wed Apr 22 16:45:39 2009 -0700 @@ -1,20 +1,29 @@ - + 1050 - 9C7010 - 658 - 949.26 - 352.00 + 9G55 + 677 + 949.43 + 353.00 YES - + YES com.apple.InterfaceBuilder.CocoaPlugin + + YES + + YES + + + YES + + YES @@ -38,6 +47,7 @@ View + {3.40282e+38, 3.40282e+38} {213, 107} @@ -217,7 +227,7 @@ YES - -1804468671 + -1267597759 272630784 @@ -244,7 +254,7 @@ YES - -2072904127 + -1536033215 272630784 @@ -1880,7 +1890,6 @@ 208.IBPluginDependency 208.ImportedFromIB2 21.IBEditorWindowLastContentRect - 21.IBPluginDependency 21.IBWindowTemplateEditedContentRect 21.ImportedFromIB2 21.NSWindowTemplate.visibleAtLaunch @@ -1894,11 +1903,18 @@ 213.ImportedFromIB2 214.IBPluginDependency 214.ImportedFromIB2 + 228.IBPluginDependency + 229.IBPluginDependency 23.IBPluginDependency 23.ImportedFromIB2 + 230.IBPluginDependency + 231.IBPluginDependency 231.IBShouldRemoveOnLegacySave + 232.IBPluginDependency 232.IBShouldRemoveOnLegacySave + 233.IBPluginDependency 233.IBShouldRemoveOnLegacySave + 234.IBPluginDependency 234.IBShouldRemoveOnLegacySave 24.IBPluginDependency 24.ImportedFromIB2 @@ -2040,9 +2056,8 @@ com.apple.InterfaceBuilder.CocoaPlugin - {{108, 555}, {529, 256}} - com.apple.InterfaceBuilder.CocoaPlugin - {{108, 555}, {529, 256}} + {{82, 548}, {529, 256}} + {{82, 548}, {529, 256}} @@ -2056,10 +2071,17 @@ com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin @@ -2129,8 +2151,17 @@ BLIPEchoClient NSObject - sendText: - id + YES + + YES + sendText: + serverClicked: + + + YES + id + id + YES @@ -2162,6 +2193,7 @@ FirstResponder + NSObject IBUserSource @@ -2170,7 +2202,7 @@ 0 - + ../../MYNetwork.xcodeproj 3 diff -r a4875607a3a0 -r cb9cdf247239 BLIP/Demo/BLIPEchoServer.m --- a/BLIP/Demo/BLIPEchoServer.m Tue Dec 02 22:42:56 2008 -0800 +++ b/BLIP/Demo/BLIPEchoServer.m Wed Apr 22 16:45:39 2009 -0700 @@ -7,7 +7,7 @@ // #import "BLIPEchoServer.h" -#import "BLIP.h" +#import "MYNetwork.h" @implementation BLIPEchoServer diff -r a4875607a3a0 -r cb9cdf247239 Bonjour/MYBonjourBrowser.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Bonjour/MYBonjourBrowser.h Wed Apr 22 16:45:39 2009 -0700 @@ -0,0 +1,52 @@ +// +// MYBonjourBrowser.h +// MYNetwork +// +// Created by Jens Alfke on 1/22/08. +// Copyright 2008 Jens Alfke. All rights reserved. +// + +#import + + +/** Searches for Bonjour services of a specific type. */ +@interface MYBonjourBrowser : NSObject +{ + @private + NSString *_serviceType; + NSNetServiceBrowser *_browser; + BOOL _browsing; + NSError *_error; + Class _serviceClass; + NSMutableSet *_services, *_addServices, *_rmvServices; +} + +/** Initializes a new BonjourBrowser. + Call -start to begin browsing. + @param serviceType The name of the service type to look for, e.g. "_http._tcp". */ +- (id) initWithServiceType: (NSString*)serviceType; + +/** Starts browsing. This is asynchronous, so nothing will happen immediately. */ +- (void) start; + +/** Stops browsing. */ +- (void) stop; + +/** Is the browser currently browsing? */ +@property (readonly) BOOL browsing; + +/** The current error status, if any. + This is KV-observable. */ +@property (readonly,retain) NSError* error; + +/** The set of currently found services. These are instances of the serviceClass, + which is BonjourService by default. + This is KV-observable. */ +@property (readonly) NSSet *services; + +/** The class of objects to create to represent services. + The default value is [BonjourService class]; you can change this, but only + to a subclass of that. */ +@property Class serviceClass; + +@end diff -r a4875607a3a0 -r cb9cdf247239 Bonjour/MYBonjourBrowser.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Bonjour/MYBonjourBrowser.m Wed Apr 22 16:45:39 2009 -0700 @@ -0,0 +1,239 @@ +// +// MYBonjourBrowser.m +// MYNetwork +// +// Created by Jens Alfke on 1/22/08. +// Copyright 2008 Jens Alfke. All rights reserved. +// + +#import "MYBonjourBrowser.h" +#import "MYBonjourService.h" +#import "Test.h" +#import "Logging.h" + + +@interface MYBonjourBrowser () +@property BOOL browsing; +@property (retain) NSError* error; +@end + + +@implementation MYBonjourBrowser + + +- (id) initWithServiceType: (NSString*)serviceType +{ + Assert(serviceType); + self = [super init]; + if (self != nil) { + _serviceType = [serviceType copy]; + _browser = [[NSNetServiceBrowser alloc] init]; + _browser.delegate = self; + _services = [[NSMutableSet alloc] init]; + _addServices = [[NSMutableSet alloc] init]; + _rmvServices = [[NSMutableSet alloc] init]; + _serviceClass = [MYBonjourService class]; + } + return self; +} + + +- (void) dealloc +{ + LogTo(Bonjour,@"DEALLOC BonjourBrowser"); + [_browser stop]; + _browser.delegate = nil; + [_browser release]; + [_serviceType release]; + [_error release]; + [_services release]; + [_addServices release]; + [_rmvServices release]; + [super dealloc]; +} + + +@synthesize browsing=_browsing, error=_error, services=_services, serviceClass=_serviceClass; + + +- (void) start +{ + [_browser searchForServicesOfType: _serviceType inDomain: @"local."]; +} + +- (void) stop +{ + [_browser stop]; +} + + +- (void)netServiceBrowserWillSearch:(NSNetServiceBrowser *)netServiceBrowser +{ + LogTo(Bonjour,@"%@ started browsing",self); + self.browsing = YES; +} + +- (void)netServiceBrowserDidStopSearch:(NSNetServiceBrowser *)netServiceBrowser +{ + LogTo(Bonjour,@"%@ stopped browsing",self); + self.browsing = NO; +} + +- (void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser + didNotSearch:(NSDictionary *)errorDict +{ + NSString *domain = [errorDict objectForKey: NSNetServicesErrorDomain]; + int err = [[errorDict objectForKey: NSNetServicesErrorCode] intValue]; + self.error = [NSError errorWithDomain: domain code: err userInfo: nil]; + LogTo(Bonjour,@"%@ got error: ",self,self.error); + self.browsing = NO; +} + + +- (void) _updateServiceList +{ + if( _rmvServices.count ) { + [self willChangeValueForKey: @"services" + withSetMutation: NSKeyValueMinusSetMutation + usingObjects: _rmvServices]; + [_services minusSet: _rmvServices]; + [self didChangeValueForKey: @"services" + withSetMutation: NSKeyValueMinusSetMutation + usingObjects: _rmvServices]; + [_rmvServices makeObjectsPerformSelector: @selector(removed)]; + [_rmvServices removeAllObjects]; + } + if( _addServices.count ) { + [_addServices makeObjectsPerformSelector: @selector(added)]; + [self willChangeValueForKey: @"services" + withSetMutation: NSKeyValueUnionSetMutation + usingObjects: _addServices]; + [_services unionSet: _addServices]; + [self didChangeValueForKey: @"services" + withSetMutation: NSKeyValueUnionSetMutation + usingObjects: _addServices]; + [_addServices removeAllObjects]; + } +} + + +- (void) _handleService: (NSNetService*)netService + addTo: (NSMutableSet*)addTo + removeFrom: (NSMutableSet*)removeFrom + moreComing: (BOOL)moreComing +{ + // Wrap the NSNetService in a BonjourService, using an existing instance if possible: + MYBonjourService *service = [[_serviceClass alloc] initWithNetService: netService]; + MYBonjourService *existingService = [_services member: service]; + if( existingService ) { + [service release]; + service = [existingService retain]; + } + + if( [removeFrom containsObject: service] ) + [removeFrom removeObject: service]; + else + [addTo addObject: service]; + [service release]; + if( ! moreComing ) + [self _updateServiceList]; +} + +- (void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser + didFindService:(NSNetService *)netService + moreComing:(BOOL)moreComing +{ + //LogTo(Bonjour,@"Add service %@",netService); + [self _handleService: netService addTo: _addServices removeFrom: _rmvServices moreComing: moreComing]; +} + +- (void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser + didRemoveService:(NSNetService *)netService + moreComing:(BOOL)moreComing +{ + //LogTo(Bonjour,@"Remove service %@",netService); + [self _handleService: netService addTo: _rmvServices removeFrom: _addServices moreComing: moreComing]; +} + + +@end + + + +#pragma mark - +#pragma mark TESTING: + +@interface BonjourTester : NSObject +{ + MYBonjourBrowser *_browser; +} +@end + +@implementation BonjourTester + +- (id) init +{ + self = [super init]; + if (self != nil) { + _browser = [[MYBonjourBrowser alloc] initWithServiceType: @"_http._tcp"]; + [_browser addObserver: self forKeyPath: @"services" options: NSKeyValueObservingOptionNew context: NULL]; + [_browser addObserver: self forKeyPath: @"browsing" options: NSKeyValueObservingOptionNew context: NULL]; + [_browser start]; + } + return self; +} + +- (void) dealloc +{ + [_browser stop]; + [_browser removeObserver: self forKeyPath: @"services"]; + [_browser removeObserver: self forKeyPath: @"browsing"]; + [_browser release]; + [super dealloc]; +} + +- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context +{ + LogTo(Bonjour,@"Observed change in %@: %@",keyPath,change); + if( $equal(keyPath,@"services") ) { + if( [[change objectForKey: NSKeyValueChangeKindKey] intValue]==NSKeyValueChangeInsertion ) { + NSSet *newServices = [change objectForKey: NSKeyValueChangeNewKey]; + for( MYBonjourService *service in newServices ) { + LogTo(Bonjour,@" --> %@ : TXT=%@", service,service.txtRecord); + } + } + } +} + +@end + +TestCase(Bonjour) { + [NSRunLoop currentRunLoop]; // create runloop + BonjourTester *tester = [[BonjourTester alloc] init]; + [[NSRunLoop currentRunLoop] runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 15]]; + [tester release]; +} + + + +/* + Copyright (c) 2008-2009, Jens Alfke . All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, are permitted + provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions + and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions + and the following disclaimer in the documentation and/or other materials provided with the + distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI- + BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ diff -r a4875607a3a0 -r cb9cdf247239 Bonjour/MYBonjourService.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Bonjour/MYBonjourService.h Wed Apr 22 16:45:39 2009 -0700 @@ -0,0 +1,70 @@ +// +// MYBonjourService.h +// MYNetwork +// +// Created by Jens Alfke on 1/22/08. +// Copyright 2008 Jens Alfke. All rights reserved. +// + +#import +#import "ConcurrentOperation.h" +@class MYBonjourResolveOperation; + + +/** Represents a Bonjour service discovered by a BonjourBrowser. */ +@interface MYBonjourService : NSObject +{ + @private + NSNetService *_netService; + NSDictionary *_txtRecord; + NSSet *_addresses; + CFAbsoluteTime _addressesExpireAt; + MYBonjourResolveOperation *_resolveOp; +} + +/** The service's name. */ +@property (readonly) NSString *name; + +/** The service's metadata dictionary, from its DNS TXT record */ +@property (readonly,copy) NSDictionary *txtRecord; + +/** A convenience to access a single property from the TXT record. */ +- (NSString*) txtStringForKey: (NSString*)key; + +/** Returns a set of IPAddress objects; may be the empty set if address resolution failed, + or nil if addresses have not been resolved yet (or expired). + In the latter case, call -resolve and wait for the returned Operation to finish. */ +@property (readonly,copy) NSSet* addresses; + +/** Starts looking up the IP address(es) of this service. + @return The NSOperation representing the lookup; you can observe this to see when it + completes, or you can observe the service's 'addresses' property. */ +- (MYBonjourResolveOperation*) resolve; + +/** The underlying NSNetSerice object. */ +@property (readonly) NSNetService *netService; + + +// Protected methods, for subclass use only: + +- (id) initWithNetService: (NSNetService*)netService; + +// (for subclasses to override, but not call): +- (void) added; +- (void) removed; +- (void) txtRecordChanged; + +@end + + + +@interface MYBonjourResolveOperation : ConcurrentOperation +{ + MYBonjourService *_service; + NSSet *_addresses; +} + +@property (readonly) MYBonjourService *service; +@property (readonly,retain) NSSet *addresses; + +@end diff -r a4875607a3a0 -r cb9cdf247239 Bonjour/MYBonjourService.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Bonjour/MYBonjourService.m Wed Apr 22 16:45:39 2009 -0700 @@ -0,0 +1,251 @@ +// +// MYBonjourService.m +// MYNetwork +// +// Created by Jens Alfke on 1/22/08. +// Copyright 2008 Jens Alfke. All rights reserved. +// + +#import "MYBonjourService.h" +#import "IPAddress.h" +#import "ConcurrentOperation.h" +#import "Test.h" +#import "Logging.h" + + +NSString* const kBonjourServiceResolvedAddressesNotification = @"BonjourServiceResolvedAddresses"; + + +@interface MYBonjourService () +@property (copy) NSSet* addresses; +@end + +@interface MYBonjourResolveOperation () +@property (assign) MYBonjourService *service; +@property (retain) NSSet *addresses; +@end + + + +@implementation MYBonjourService + + +- (id) initWithNetService: (NSNetService*)netService +{ + self = [super init]; + if (self != nil) { + _netService = [netService retain]; + _netService.delegate = self; + } + return self; +} + +- (void) dealloc +{ + Log(@"DEALLOC %@",self); + _netService.delegate = nil; + [_netService release]; + [_txtRecord release]; + [_addresses release]; + [super dealloc]; +} + + +- (NSString*) description +{ + return $sprintf(@"%@['%@'.%@%@]", self.class,self.name,_netService.type,_netService.domain); +} + + +- (NSComparisonResult) compare: (id)obj +{ + return [self.name caseInsensitiveCompare: [obj name]]; +} + + +- (NSNetService*) netService {return _netService;} +- (BOOL) isEqual: (id)obj {return [obj isKindOfClass: [MYBonjourService class]] && [_netService isEqual: [obj netService]];} +- (NSUInteger) hash {return _netService.hash;} +- (NSString*) name {return _netService.name;} + + +- (void) added +{ + LogTo(Bonjour,@"Added %@",_netService); +} + +- (void) removed +{ + LogTo(Bonjour,@"Removed %@",_netService); + [_netService stopMonitoring]; + _netService.delegate = nil; + + if( _resolveOp ) { + [_resolveOp cancel]; + [_resolveOp release]; + _resolveOp = nil; + } +} + + +#pragma mark - +#pragma mark TXT RECORD: + + +- (NSDictionary*) txtRecord +{ + [_netService startMonitoring]; + return _txtRecord; +} + +- (void) txtRecordChanged +{ + // no-op (this is here for subclassers to override) +} + +- (NSString*) txtStringForKey: (NSString*)key +{ + NSData *value = [self.txtRecord objectForKey: key]; + if( ! value ) + return nil; + if( ! [value isKindOfClass: [NSData class]] ) { + Warn(@"TXT dictionary has unexpected value type: %@",value.class); + return nil; + } + NSString *str = [[NSString alloc] initWithData: value encoding: NSUTF8StringEncoding]; + if( ! str ) + str = [[NSString alloc] initWithData: value encoding: NSWindowsCP1252StringEncoding]; + return [str autorelease]; +} + + +- (void)netService:(NSNetService *)sender didUpdateTXTRecordData:(NSData *)data +{ + NSDictionary *txtDict = [NSNetService dictionaryFromTXTRecordData: data]; + if( ! $equal(txtDict,_txtRecord) ) { + LogTo(Bonjour,@"%@ got TXT record (%u bytes)",self,data.length); + [self willChangeValueForKey: @"txtRecord"]; + setObj(&_txtRecord,txtDict); + [self didChangeValueForKey: @"txtRecord"]; + [self txtRecordChanged]; + } +} + + +#pragma mark - +#pragma mark ADDRESS RESOLUTION: + + +#define kAddressResolveTimeout 10.0 +#define kAddressExpirationInterval 60.0 +#define kAddressErrorRetryInterval 5.0 + + +- (NSSet*) addresses +{ + if( _addresses && CFAbsoluteTimeGetCurrent() >= _addressesExpireAt ) { + setObj(&_addresses,nil); // eww, toss 'em and get new ones + [self resolve]; + } + return _addresses; +} + + +- (MYBonjourResolveOperation*) resolve +{ + if( ! _resolveOp ) { + LogTo(Bonjour,@"Resolving %@",self); + _resolveOp = [[MYBonjourResolveOperation alloc] init]; + _resolveOp.service = self; + [_resolveOp start]; + Assert(_netService); + Assert(_netService.delegate=self); + [_netService resolveWithTimeout: kAddressResolveTimeout]; + } + return _resolveOp; +} + +- (void) setAddresses: (NSSet*)addresses +{ + setObj(&_addresses,addresses); +} + + +- (void) _finishedResolving: (NSSet*)addresses expireIn: (NSTimeInterval)expirationInterval +{ + _addressesExpireAt = CFAbsoluteTimeGetCurrent() + expirationInterval; + self.addresses = addresses; + _resolveOp.addresses = addresses; + [_resolveOp finish]; + [_resolveOp release]; + _resolveOp = nil; +} + + +- (void)netServiceDidResolveAddress:(NSNetService *)sender +{ + // Convert the raw sockaddrs into IPAddress objects: + NSMutableSet *addresses = [NSMutableSet setWithCapacity: 2]; + for( NSData *rawAddr in _netService.addresses ) { + IPAddress *addr = [[IPAddress alloc] initWithSockAddr: rawAddr.bytes]; + if( addr ) { + [addresses addObject: addr]; + [addr release]; + } + } + LogTo(Bonjour,@"Resolved %@: %@",self,addresses); + [self _finishedResolving: addresses expireIn: kAddressExpirationInterval]; +} + +- (void)netService:(NSNetService *)sender didNotResolve:(NSDictionary *)errorDict +{ + LogTo(Bonjour,@"Error resolving %@ -- %@",self,errorDict); + [self _finishedResolving: [NSArray array] expireIn: kAddressErrorRetryInterval]; +} + +- (void)netServiceDidStop:(NSNetService *)sender +{ + LogTo(Bonjour,@"Resolve stopped for %@",self); + [self _finishedResolving: [NSArray array] expireIn: kAddressErrorRetryInterval]; +} + + +@end + + + + +@implementation MYBonjourResolveOperation + +@synthesize service=_service, addresses=_addresses; + +- (void) dealloc +{ + [_addresses release]; + [super dealloc]; +} + +@end + + +/* + Copyright (c) 2008-2009, Jens Alfke . All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, are permitted + provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions + and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions + and the following disclaimer in the documentation and/or other materials provided with the + distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI- + BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ diff -r a4875607a3a0 -r cb9cdf247239 IPAddress.h --- a/IPAddress.h Tue Dec 02 22:42:56 2008 -0800 +++ b/IPAddress.h Wed Apr 22 16:45:39 2009 -0700 @@ -35,6 +35,10 @@ /** Initializes an IPAddress from a BSD struct sockaddr. */ - (id) initWithSockAddr: (const struct sockaddr*)sockaddr; +/** Returns the IP address of this host (plus the specified port number). + If multiple network interfaces are active, the main one's address is returned. */ ++ (IPAddress*) localAddressWithPort: (UInt16)port; + /** Returns the IP address of this host (with a port number of zero). If multiple network interfaces are active, the main one's address is returned. */ + (IPAddress*) localAddress; diff -r a4875607a3a0 -r cb9cdf247239 IPAddress.m --- a/IPAddress.m Tue Dec 02 22:42:56 2008 -0800 +++ b/IPAddress.m Wed Apr 22 16:45:39 2009 -0700 @@ -160,7 +160,7 @@ } -+ (IPAddress*) localAddress ++ (IPAddress*) localAddressWithPort: (UInt16)port { // getifaddrs returns a linked list of interface entries; // find the first active non-loopback interface with IPv4: @@ -179,7 +179,12 @@ } freeifaddrs(interfaces); } - return [[[self alloc] initWithIPv4: address] autorelease]; + return [[[self alloc] initWithIPv4: address port: port] autorelease]; +} + ++ (IPAddress*) localAddress +{ + return [self localAddressWithPort: 0]; } @@ -339,7 +344,7 @@ TestCase(IPAddress) { RequireTestCase(CollectionUtils); IPAddress *addr = [[IPAddress alloc] initWithIPv4: htonl(0x0A0001FE) port: 8080]; - CAssertEq(addr.ipv4,htonl(0x0A0001FE)); + CAssertEq(addr.ipv4,(UInt32)htonl(0x0A0001FE)); CAssertEq(addr.port,8080); CAssertEqual(addr.hostname,@"10.0.1.254"); CAssertEqual(addr.description,@"10.0.1.254:8080"); @@ -347,7 +352,7 @@ addr = [[IPAddress alloc] initWithHostname: @"66.66.0.255" port: 123]; CAssertEq(addr.class,[IPAddress class]); - CAssertEq(addr.ipv4,htonl(0x424200FF)); + CAssertEq(addr.ipv4,(UInt32)htonl(0x424200FF)); CAssertEq(addr.port,123); CAssertEqual(addr.hostname,@"66.66.0.255"); CAssertEqual(addr.description,@"66.66.0.255:123"); @@ -355,8 +360,8 @@ addr = [[IPAddress alloc] initWithHostname: @"www.apple.com" port: 80]; CAssertEq(addr.class,[HostAddress class]); - Log(@"www.apple.com = 0x%08X", addr.ipv4); - CAssertEq(addr.ipv4,htonl(0x1195A00A)); + Log(@"www.apple.com = %@ [0x%08X]", addr.ipv4name, ntohl(addr.ipv4)); + CAssertEq(addr.ipv4,(UInt32)htonl(0x11FBC820)); CAssertEq(addr.port,80); CAssertEqual(addr.hostname,@"www.apple.com"); CAssertEqual(addr.description,@"www.apple.com:80"); diff -r a4875607a3a0 -r cb9cdf247239 MYNetwork-iPhone.xcodeproj/project.pbxproj --- a/MYNetwork-iPhone.xcodeproj/project.pbxproj Tue Dec 02 22:42:56 2008 -0800 +++ b/MYNetwork-iPhone.xcodeproj/project.pbxproj Wed Apr 22 16:45:39 2009 -0700 @@ -36,6 +36,11 @@ 270E9B9A0EE64B45003F17CA /* Icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 270E9B970EE64B45003F17CA /* Icon.png */; }; 270E9BA10EE64B4E003F17CA /* HelloWorldAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 270E9B9E0EE64B4E003F17CA /* HelloWorldAppDelegate.m */; }; 270E9BA20EE64B4E003F17CA /* MyViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 270E9BA00EE64B4E003F17CA /* MyViewController.m */; }; + 2777C78D0F75E141007F8D30 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2777C78C0F75E141007F8D30 /* Security.framework */; }; + 278C1B2E0F9F865800954AE1 /* MYPortMapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 278C1B2C0F9F865800954AE1 /* MYPortMapper.m */; }; + 278C1B2F0F9F865800954AE1 /* PortMapperTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 278C1B2D0F9F865800954AE1 /* PortMapperTest.m */; }; + 278C1B350F9F86A100954AE1 /* MYUtilities_Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 278C1B330F9F86A100954AE1 /* MYUtilities_Debug.xcconfig */; }; + 278C1B360F9F86A100954AE1 /* MYUtilities_Release.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 278C1B340F9F86A100954AE1 /* MYUtilities_Release.xcconfig */; }; 280E754F0DD40C5E005A515E /* MainWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 280E754C0DD40C5E005A515E /* MainWindow.xib */; }; /* End PBXBuildFile section */ @@ -96,6 +101,12 @@ 270E9B9E0EE64B4E003F17CA /* HelloWorldAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HelloWorldAppDelegate.m; sourceTree = ""; }; 270E9B9F0EE64B4E003F17CA /* MyViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MyViewController.h; sourceTree = ""; }; 270E9BA00EE64B4E003F17CA /* MyViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MyViewController.m; sourceTree = ""; }; + 2777C78C0F75E141007F8D30 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; + 278C1B2B0F9F865800954AE1 /* MYPortMapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYPortMapper.h; sourceTree = ""; }; + 278C1B2C0F9F865800954AE1 /* MYPortMapper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYPortMapper.m; sourceTree = ""; }; + 278C1B2D0F9F865800954AE1 /* PortMapperTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PortMapperTest.m; sourceTree = ""; }; + 278C1B330F9F86A100954AE1 /* MYUtilities_Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = MYUtilities_Debug.xcconfig; sourceTree = ""; }; + 278C1B340F9F86A100954AE1 /* MYUtilities_Release.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = MYUtilities_Release.xcconfig; sourceTree = ""; }; 280E754C0DD40C5E005A515E /* MainWindow.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MainWindow.xib; sourceTree = ""; }; 29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = iPhone/main.m; sourceTree = ""; }; 8D1107310486CEB800E47090 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -110,6 +121,7 @@ 1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */, 270E9AE90EE61167003F17CA /* libz.dylib in Frameworks */, 270E9B4F0EE63F8F003F17CA /* CFNetwork.framework in Frameworks */, + 2777C78D0F75E141007F8D30 /* Security.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -141,6 +153,7 @@ 270E9AA20EE61113003F17CA /* IPAddress.m */, 270E9AA30EE61113003F17CA /* TCP */, 270E9AAF0EE61113003F17CA /* BLIP */, + 278C1B2A0F9F865800954AE1 /* PortMapper */, ); name = MYNetwork; sourceTree = ""; @@ -201,6 +214,8 @@ 270E9AD70EE6111A003F17CA /* Target.m */, 270E9AD80EE6111A003F17CA /* Test.h */, 270E9AD90EE6111A003F17CA /* Test.m */, + 278C1B330F9F86A100954AE1 /* MYUtilities_Debug.xcconfig */, + 278C1B340F9F86A100954AE1 /* MYUtilities_Release.xcconfig */, 270E9ADA0EE6111A003F17CA /* GoogleToolboxSubset */, ); name = MYUtilities; @@ -228,6 +243,16 @@ path = Classes; sourceTree = ""; }; + 278C1B2A0F9F865800954AE1 /* PortMapper */ = { + isa = PBXGroup; + children = ( + 278C1B2B0F9F865800954AE1 /* MYPortMapper.h */, + 278C1B2C0F9F865800954AE1 /* MYPortMapper.m */, + 278C1B2D0F9F865800954AE1 /* PortMapperTest.m */, + ); + path = PortMapper; + sourceTree = ""; + }; 29B97314FDCFA39411CA2CEA /* CustomTemplate */ = { isa = PBXGroup; children = ( @@ -237,6 +262,7 @@ 29B97315FDCFA39411CA2CEA /* Other Sources */, 29B97323FDCFA39411CA2CEA /* Frameworks */, 19C28FACFE9D520D11CA2CBB /* Products */, + 2777C78C0F75E141007F8D30 /* Security.framework */, ); name = CustomTemplate; sourceTree = ""; @@ -325,6 +351,8 @@ 270E9B950EE64B3C003F17CA /* HelloWorld.xib in Resources */, 270E9B990EE64B45003F17CA /* Default.png in Resources */, 270E9B9A0EE64B45003F17CA /* Icon.png in Resources */, + 278C1B350F9F86A100954AE1 /* MYUtilities_Debug.xcconfig in Resources */, + 278C1B360F9F86A100954AE1 /* MYUtilities_Release.xcconfig in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -357,6 +385,8 @@ 270E9AE40EE6111A003F17CA /* GTMNSData+zlib.m in Sources */, 270E9BA10EE64B4E003F17CA /* HelloWorldAppDelegate.m in Sources */, 270E9BA20EE64B4E003F17CA /* MyViewController.m in Sources */, + 278C1B2E0F9F865800954AE1 /* MYPortMapper.m in Sources */, + 278C1B2F0F9F865800954AE1 /* PortMapperTest.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -366,56 +396,37 @@ 1D6058940D05DD3E006BFB54 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer: Jens Alfke"; - COPY_PHASE_STRIP = NO; - GCC_DYNAMIC_NO_PIC = NO; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = iPhone/MYNetwork_iPhone_Prefix.pch; INFOPLIST_FILE = iPhone/Info.plist; PRODUCT_NAME = BLIPEcho; - PROVISIONING_PROFILE = "166C8314-D005-438F-841B-B20D42F71712"; }; name = Debug; }; 1D6058950D05DD3E006BFB54 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer: Jens Alfke"; - COPY_PHASE_STRIP = YES; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = iPhone/MYNetwork_iPhone_Prefix.pch; INFOPLIST_FILE = iPhone/Info.plist; PRODUCT_NAME = BLIPEcho; - PROVISIONING_PROFILE = "166C8314-D005-438F-841B-B20D42F71712"; }; name = Release; }; C01FCF4F08A954540054247B /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 278C1B330F9F86A100954AE1 /* MYUtilities_Debug.xcconfig */; buildSettings = { ARCHS = "$(ARCHS_STANDARD_32_BIT)"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - GCC_C_LANGUAGE_STANDARD = c99; - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_UNUSED_VARIABLE = YES; + EXCLUDED_RECURSIVE_SEARCH_PATH_SUBDIRECTORIES = "*.nib *.lproj *.framework *.gch *.xcode* (*) CVS .svn .hg"; ONLY_ACTIVE_ARCH = YES; - PREBINDING = NO; SDKROOT = iphonesimulator2.0; }; name = Debug; }; C01FCF5008A954540054247B /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 278C1B340F9F86A100954AE1 /* MYUtilities_Release.xcconfig */; buildSettings = { ARCHS = "$(ARCHS_STANDARD_32_BIT)"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - GCC_C_LANGUAGE_STANDARD = c99; - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - PREBINDING = NO; SDKROOT = iphonesimulator2.0; }; name = Release; diff -r a4875607a3a0 -r cb9cdf247239 MYNetwork.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MYNetwork.h Wed Apr 22 16:45:39 2009 -0700 @@ -0,0 +1,14 @@ +/* + * MYNetwork.h + * MYNetwork + * + * Created by Jens Alfke on 4/21/09. + * Copyright 2009 Jens Alfke. All rights reserved. + * + */ + +#import "BLIP.h" +#import "MYBonjourBrowser.h" +#import "MYBonjourService.h" +#import "IPAddress.h" +#import "MYPortMapper.h" diff -r a4875607a3a0 -r cb9cdf247239 MYNetwork.xcodeproj/project.pbxproj --- a/MYNetwork.xcodeproj/project.pbxproj Tue Dec 02 22:42:56 2008 -0800 +++ b/MYNetwork.xcodeproj/project.pbxproj Wed Apr 22 16:45:39 2009 -0700 @@ -24,60 +24,74 @@ 270461370DE4918D003D9D3F /* ExceptionUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 270461350DE4918D003D9D3F /* ExceptionUtils.m */; }; 270461470DE491A6003D9D3F /* Target.m in Sources */ = {isa = PBXBuildFile; fileRef = 270461460DE491A6003D9D3F /* Target.m */; }; 270461890DE49634003D9D3F /* CollectionUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 270461870DE49634003D9D3F /* CollectionUtils.m */; }; - 2704618C0DE49652003D9D3F /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2704618B0DE49652003D9D3F /* libz.dylib */; }; - 270461920DE4975D003D9D3F /* CoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 270461910DE4975C003D9D3F /* CoreServices.framework */; }; - 277904330DE91DE600C6D295 /* BLIPConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = 270460F40DE49030003D9D3F /* BLIPConnection.m */; }; - 277904340DE91DE700C6D295 /* BLIPDispatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 270460F60DE49030003D9D3F /* BLIPDispatcher.m */; }; - 277904350DE91DE800C6D295 /* BLIPEchoClient.m in Sources */ = {isa = PBXBuildFile; fileRef = 277903E90DE8F08100C6D295 /* BLIPEchoClient.m */; }; - 277904370DE91DEB00C6D295 /* BLIPMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = 270460F90DE49030003D9D3F /* BLIPMessage.m */; }; - 277904380DE91DEC00C6D295 /* BLIPProperties.m in Sources */ = {isa = PBXBuildFile; fileRef = 270460FB0DE49030003D9D3F /* BLIPProperties.m */; }; - 277904390DE91DEE00C6D295 /* BLIPReader.m in Sources */ = {isa = PBXBuildFile; fileRef = 270460FD0DE49030003D9D3F /* BLIPReader.m */; }; - 2779043A0DE91DEF00C6D295 /* BLIPRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 27D5EC060DE5FEDE00CD84FA /* BLIPRequest.m */; }; - 2779043C0DE91DF100C6D295 /* BLIPWriter.m in Sources */ = {isa = PBXBuildFile; fileRef = 270461000DE49030003D9D3F /* BLIPWriter.m */; }; - 2779043D0DE91DF300C6D295 /* IPAddress.m in Sources */ = {isa = PBXBuildFile; fileRef = 270461020DE49030003D9D3F /* IPAddress.m */; }; - 2779043E0DE91DF500C6D295 /* TCPConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = 2704610A0DE49030003D9D3F /* TCPConnection.m */; }; - 2779043F0DE91DF800C6D295 /* TCPEndpoint.m in Sources */ = {isa = PBXBuildFile; fileRef = 2704610C0DE49030003D9D3F /* TCPEndpoint.m */; }; - 277904400DE91DF900C6D295 /* TCPListener.m in Sources */ = {isa = PBXBuildFile; fileRef = 2704610E0DE49030003D9D3F /* TCPListener.m */; }; - 277904410DE91DFA00C6D295 /* TCPStream.m in Sources */ = {isa = PBXBuildFile; fileRef = 270461100DE49030003D9D3F /* TCPStream.m */; }; - 277904420DE91DFC00C6D295 /* TCPWriter.m in Sources */ = {isa = PBXBuildFile; fileRef = 270461120DE49030003D9D3F /* TCPWriter.m */; }; - 277904440DE91E3500C6D295 /* CollectionUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 270461870DE49634003D9D3F /* CollectionUtils.m */; }; - 277904450DE91E3600C6D295 /* ExceptionUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 270461350DE4918D003D9D3F /* ExceptionUtils.m */; }; - 277904460DE91E3700C6D295 /* Logging.m in Sources */ = {isa = PBXBuildFile; fileRef = 2704612A0DE49088003D9D3F /* Logging.m */; }; - 277904480DE91E3900C6D295 /* Target.m in Sources */ = {isa = PBXBuildFile; fileRef = 270461460DE491A6003D9D3F /* Target.m */; }; - 277904490DE91E3A00C6D295 /* Test.m in Sources */ = {isa = PBXBuildFile; fileRef = 270461280DE49088003D9D3F /* Test.m */; }; + 2706F1D90F9D3EF300292CCF /* SecurityInterface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2706F1D80F9D3EF300292CCF /* SecurityInterface.framework */; }; + 2777C9110F7602A7007F8D30 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2777C9100F7602A7007F8D30 /* Security.framework */; }; 2779048B0DE9204300C6D295 /* BLIPEchoClient.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2779048A0DE9204300C6D295 /* BLIPEchoClient.xib */; }; - 277905110DE9E5BC00C6D295 /* BLIPConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = 270460F40DE49030003D9D3F /* BLIPConnection.m */; }; - 277905120DE9E5BC00C6D295 /* BLIPDispatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 270460F60DE49030003D9D3F /* BLIPDispatcher.m */; }; - 277905130DE9E5BC00C6D295 /* BLIPMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = 270460F90DE49030003D9D3F /* BLIPMessage.m */; }; - 277905140DE9E5BC00C6D295 /* BLIPProperties.m in Sources */ = {isa = PBXBuildFile; fileRef = 270460FB0DE49030003D9D3F /* BLIPProperties.m */; }; - 277905150DE9E5BC00C6D295 /* BLIPReader.m in Sources */ = {isa = PBXBuildFile; fileRef = 270460FD0DE49030003D9D3F /* BLIPReader.m */; }; - 277905160DE9E5BC00C6D295 /* BLIPWriter.m in Sources */ = {isa = PBXBuildFile; fileRef = 270461000DE49030003D9D3F /* BLIPWriter.m */; }; - 277905170DE9E5BC00C6D295 /* IPAddress.m in Sources */ = {isa = PBXBuildFile; fileRef = 270461020DE49030003D9D3F /* IPAddress.m */; }; - 277905180DE9E5BC00C6D295 /* TCPConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = 2704610A0DE49030003D9D3F /* TCPConnection.m */; }; - 277905190DE9E5BC00C6D295 /* TCPEndpoint.m in Sources */ = {isa = PBXBuildFile; fileRef = 2704610C0DE49030003D9D3F /* TCPEndpoint.m */; }; - 2779051A0DE9E5BC00C6D295 /* TCPListener.m in Sources */ = {isa = PBXBuildFile; fileRef = 2704610E0DE49030003D9D3F /* TCPListener.m */; }; - 2779051B0DE9E5BC00C6D295 /* TCPStream.m in Sources */ = {isa = PBXBuildFile; fileRef = 270461100DE49030003D9D3F /* TCPStream.m */; }; - 2779051C0DE9E5BC00C6D295 /* TCPWriter.m in Sources */ = {isa = PBXBuildFile; fileRef = 270461120DE49030003D9D3F /* TCPWriter.m */; }; - 2779051D0DE9E5BC00C6D295 /* Test.m in Sources */ = {isa = PBXBuildFile; fileRef = 270461280DE49088003D9D3F /* Test.m */; }; - 2779051E0DE9E5BC00C6D295 /* Logging.m in Sources */ = {isa = PBXBuildFile; fileRef = 2704612A0DE49088003D9D3F /* Logging.m */; }; - 2779051F0DE9E5BC00C6D295 /* ExceptionUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 270461350DE4918D003D9D3F /* ExceptionUtils.m */; }; - 277905200DE9E5BC00C6D295 /* Target.m in Sources */ = {isa = PBXBuildFile; fileRef = 270461460DE491A6003D9D3F /* Target.m */; }; - 277905220DE9E5BC00C6D295 /* CollectionUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 270461870DE49634003D9D3F /* CollectionUtils.m */; }; - 277905230DE9E5BC00C6D295 /* BLIPRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 27D5EC060DE5FEDE00CD84FA /* BLIPRequest.m */; }; 277905240DE9E5BC00C6D295 /* BLIPEchoServer.m in Sources */ = {isa = PBXBuildFile; fileRef = 277903D60DE8EE4800C6D295 /* BLIPEchoServer.m */; }; - 277905260DE9E5BC00C6D295 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08FB779EFE84155DC02AAC07 /* Foundation.framework */; }; - 277905270DE9E5BC00C6D295 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2704618B0DE49652003D9D3F /* libz.dylib */; }; - 277905280DE9E5BC00C6D295 /* CoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 270461910DE4975C003D9D3F /* CoreServices.framework */; }; 277905300DE9ED9100C6D295 /* MYUtilitiesTest_main.m in Sources */ = {isa = PBXBuildFile; fileRef = 270462C10DE4A64B003D9D3F /* MYUtilitiesTest_main.m */; }; 2779053B0DE9EDAA00C6D295 /* BLIPTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 270460FE0DE49030003D9D3F /* BLIPTest.m */; }; - 277ECFBC0E2A73A100D756BB /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2704618B0DE49652003D9D3F /* libz.dylib */; }; + 278C1A3D0F9F687800954AE1 /* PortMapperTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 278C1A340F9F687800954AE1 /* PortMapperTest.m */; }; + 278C1A3E0F9F687800954AE1 /* MYPortMapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 278C1A360F9F687800954AE1 /* MYPortMapper.m */; }; + 278C1BA60F9F92EA00954AE1 /* MYBonjourBrowser.m in Sources */ = {isa = PBXBuildFile; fileRef = 278C1B9F0F9F92EA00954AE1 /* MYBonjourBrowser.m */; }; + 278C1BA70F9F92EA00954AE1 /* MYBonjourService.m in Sources */ = {isa = PBXBuildFile; fileRef = 278C1BA10F9F92EA00954AE1 /* MYBonjourService.m */; }; + 278C1BB90F9F975700954AE1 /* ConcurrentOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 278C1BB60F9F975700954AE1 /* ConcurrentOperation.m */; }; + 279DDA590F9E2DFA00D75D91 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 279DD99E0F9E290500D75D91 /* Foundation.framework */; }; + 279DDAE00F9E2E0F00D75D91 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 279DD99E0F9E290500D75D91 /* Foundation.framework */; }; + 279DDC4E0F9E2E2700D75D91 /* CoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 279DD9B30F9E296E00D75D91 /* CoreServices.framework */; }; + 279DDC520F9E2E3A00D75D91 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 279DD9B10F9E296200D75D91 /* libz.dylib */; }; + 279DDC970F9E2EF400D75D91 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 279DD99E0F9E290500D75D91 /* Foundation.framework */; }; + 279DDC9B0F9E2F2A00D75D91 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 279DDC9A0F9E2F2A00D75D91 /* AppKit.framework */; }; + 279DDCD10F9E38DD00D75D91 /* BLIPEchoClient.m in Sources */ = {isa = PBXBuildFile; fileRef = 277903E90DE8F08100C6D295 /* BLIPEchoClient.m */; }; + 279E8FA10F9FDD2600608D8D /* BLIPConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = 270460F40DE49030003D9D3F /* BLIPConnection.m */; }; + 279E8FA20F9FDD2600608D8D /* BLIPDispatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 270460F60DE49030003D9D3F /* BLIPDispatcher.m */; }; + 279E8FA30F9FDD2600608D8D /* BLIPMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = 270460F90DE49030003D9D3F /* BLIPMessage.m */; }; + 279E8FA40F9FDD2600608D8D /* BLIPProperties.m in Sources */ = {isa = PBXBuildFile; fileRef = 270460FB0DE49030003D9D3F /* BLIPProperties.m */; }; + 279E8FA50F9FDD2600608D8D /* BLIPReader.m in Sources */ = {isa = PBXBuildFile; fileRef = 270460FD0DE49030003D9D3F /* BLIPReader.m */; }; + 279E8FA60F9FDD2600608D8D /* BLIPRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 27D5EC060DE5FEDE00CD84FA /* BLIPRequest.m */; }; + 279E8FA70F9FDD2600608D8D /* BLIPWriter.m in Sources */ = {isa = PBXBuildFile; fileRef = 270461000DE49030003D9D3F /* BLIPWriter.m */; }; + 279E8FA80F9FDD2600608D8D /* IPAddress.m in Sources */ = {isa = PBXBuildFile; fileRef = 270461020DE49030003D9D3F /* IPAddress.m */; }; + 279E8FA90F9FDD2600608D8D /* TCPConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = 2704610A0DE49030003D9D3F /* TCPConnection.m */; }; + 279E8FAA0F9FDD2600608D8D /* TCPEndpoint.m in Sources */ = {isa = PBXBuildFile; fileRef = 2704610C0DE49030003D9D3F /* TCPEndpoint.m */; }; + 279E8FAB0F9FDD2600608D8D /* TCPListener.m in Sources */ = {isa = PBXBuildFile; fileRef = 2704610E0DE49030003D9D3F /* TCPListener.m */; }; + 279E8FAC0F9FDD2600608D8D /* TCPStream.m in Sources */ = {isa = PBXBuildFile; fileRef = 270461100DE49030003D9D3F /* TCPStream.m */; }; + 279E8FAD0F9FDD2600608D8D /* TCPWriter.m in Sources */ = {isa = PBXBuildFile; fileRef = 270461120DE49030003D9D3F /* TCPWriter.m */; }; + 279E8FAE0F9FDD2600608D8D /* CollectionUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 270461870DE49634003D9D3F /* CollectionUtils.m */; }; + 279E8FAF0F9FDD2600608D8D /* ExceptionUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 270461350DE4918D003D9D3F /* ExceptionUtils.m */; }; + 279E8FB00F9FDD2600608D8D /* GTMNSData+zlib.m in Sources */ = {isa = PBXBuildFile; fileRef = 27E0DBEF0DF3450F00E7F648 /* GTMNSData+zlib.m */; }; + 279E8FB10F9FDD2600608D8D /* Logging.m in Sources */ = {isa = PBXBuildFile; fileRef = 2704612A0DE49088003D9D3F /* Logging.m */; }; + 279E8FB20F9FDD2600608D8D /* Target.m in Sources */ = {isa = PBXBuildFile; fileRef = 270461460DE491A6003D9D3F /* Target.m */; }; + 279E8FB30F9FDD2600608D8D /* Test.m in Sources */ = {isa = PBXBuildFile; fileRef = 270461280DE49088003D9D3F /* Test.m */; }; + 279E8FB40F9FDD2600608D8D /* PortMapperTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 278C1A340F9F687800954AE1 /* PortMapperTest.m */; }; + 279E8FB50F9FDD2600608D8D /* MYPortMapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 278C1A360F9F687800954AE1 /* MYPortMapper.m */; }; + 279E8FB60F9FDD2600608D8D /* MYBonjourBrowser.m in Sources */ = {isa = PBXBuildFile; fileRef = 278C1B9F0F9F92EA00954AE1 /* MYBonjourBrowser.m */; }; + 279E8FB70F9FDD2600608D8D /* MYBonjourService.m in Sources */ = {isa = PBXBuildFile; fileRef = 278C1BA10F9F92EA00954AE1 /* MYBonjourService.m */; }; + 279E8FB80F9FDD2600608D8D /* ConcurrentOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 278C1BB60F9F975700954AE1 /* ConcurrentOperation.m */; }; + 279E8FD70F9FDDE900608D8D /* libMYNetwork.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 279E8F9E0F9FDD0800608D8D /* libMYNetwork.a */; }; + 279E8FEF0F9FDE5A00608D8D /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2777C9100F7602A7007F8D30 /* Security.framework */; }; + 279E8FFA0F9FDEEB00608D8D /* libMYNetwork.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 279E8F9E0F9FDD0800608D8D /* libMYNetwork.a */; }; + 279E8FFC0F9FDEFB00608D8D /* CoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 279DD9B30F9E296E00D75D91 /* CoreServices.framework */; }; + 279E8FFE0F9FDF0600608D8D /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2777C9100F7602A7007F8D30 /* Security.framework */; }; 27D5EC070DE5FEDE00CD84FA /* BLIPRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 27D5EC060DE5FEDE00CD84FA /* BLIPRequest.m */; }; - 27E0DBF00DF3450F00E7F648 /* GTMNSData+zlib.m in Sources */ = {isa = PBXBuildFile; fileRef = 27E0DBEF0DF3450F00E7F648 /* GTMNSData+zlib.m */; }; 27E0DBF10DF3450F00E7F648 /* GTMNSData+zlib.m in Sources */ = {isa = PBXBuildFile; fileRef = 27E0DBEF0DF3450F00E7F648 /* GTMNSData+zlib.m */; }; - 27E0DBF20DF3450F00E7F648 /* GTMNSData+zlib.m in Sources */ = {isa = PBXBuildFile; fileRef = 27E0DBEF0DF3450F00E7F648 /* GTMNSData+zlib.m */; }; - 8DD76F9C0486AA7600D96B5E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08FB779EFE84155DC02AAC07 /* Foundation.framework */; }; /* End PBXBuildFile section */ +/* Begin PBXContainerItemProxy section */ + 279E8FD50F9FDDD900608D8D /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 279E8F9D0F9FDD0800608D8D /* Library */; + remoteInfo = Library; + }; + 279E8FF80F9FDECD00608D8D /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 279E8F9D0F9FDD0800608D8D /* Library */; + remoteInfo = Library; + }; +/* End PBXContainerItemProxy section */ + /* Begin PBXCopyFilesBuildPhase section */ 277905290DE9E5BC00C6D295 /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; @@ -100,7 +114,6 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 08FB779EFE84155DC02AAC07 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = ""; }; 270460F30DE49030003D9D3F /* BLIPConnection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BLIPConnection.h; sourceTree = ""; }; 270460F40DE49030003D9D3F /* BLIPConnection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BLIPConnection.m; sourceTree = ""; }; 270460F50DE49030003D9D3F /* BLIPDispatcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BLIPDispatcher.h; sourceTree = ""; }; @@ -112,7 +125,7 @@ 270460FB0DE49030003D9D3F /* BLIPProperties.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BLIPProperties.m; sourceTree = ""; }; 270460FC0DE49030003D9D3F /* BLIPReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BLIPReader.h; sourceTree = ""; }; 270460FD0DE49030003D9D3F /* BLIPReader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BLIPReader.m; sourceTree = ""; }; - 270460FE0DE49030003D9D3F /* BLIPTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BLIPTest.m; path = BLIP/BLIPTest.m; sourceTree = ""; }; + 270460FE0DE49030003D9D3F /* BLIPTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BLIPTest.m; path = ../BLIPTest.m; sourceTree = ""; }; 270460FF0DE49030003D9D3F /* BLIPWriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BLIPWriter.h; sourceTree = ""; }; 270461000DE49030003D9D3F /* BLIPWriter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BLIPWriter.m; sourceTree = ""; }; 270461010DE49030003D9D3F /* IPAddress.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IPAddress.h; sourceTree = ""; }; @@ -139,11 +152,13 @@ 270461720DE49340003D9D3F /* MYNetwork */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = MYNetwork; sourceTree = BUILT_PRODUCTS_DIR; }; 270461870DE49634003D9D3F /* CollectionUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CollectionUtils.m; sourceTree = ""; }; 270461880DE49634003D9D3F /* CollectionUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CollectionUtils.h; sourceTree = ""; }; - 2704618B0DE49652003D9D3F /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = /usr/lib/libz.dylib; sourceTree = ""; }; - 270461910DE4975C003D9D3F /* CoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreServices.framework; path = /System/Library/Frameworks/CoreServices.framework; sourceTree = ""; }; 270462C00DE4A639003D9D3F /* MYUtilities_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYUtilities_Prefix.pch; sourceTree = ""; }; 270462C10DE4A64B003D9D3F /* MYUtilitiesTest_main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYUtilitiesTest_main.m; sourceTree = ""; }; 270462C30DE4A65B003D9D3F /* BLIP Overview.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = "BLIP Overview.txt"; path = "BLIP/BLIP Overview.txt"; sourceTree = ""; wrapsLines = 1; }; + 2706F1D80F9D3EF300292CCF /* SecurityInterface.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SecurityInterface.framework; path = System/Library/Frameworks/SecurityInterface.framework; sourceTree = SDKROOT; }; + 274122DD0F9CDD1600F21842 /* MYUtilities_Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = MYUtilities_Debug.xcconfig; sourceTree = ""; }; + 274122DE0F9CDD1600F21842 /* MYUtilities_Release.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = MYUtilities_Release.xcconfig; sourceTree = ""; }; + 2777C9100F7602A7007F8D30 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; 277903830DE8C2DD00C6D295 /* maindocs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = maindocs.h; sourceTree = ""; wrapsLines = 1; }; 277903D50DE8EE4800C6D295 /* BLIPEchoServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BLIPEchoServer.h; sourceTree = ""; }; 277903D60DE8EE4800C6D295 /* BLIPEchoServer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BLIPEchoServer.m; sourceTree = ""; }; @@ -154,6 +169,21 @@ 277904280DE91C7900C6D295 /* BLIP Echo Client-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "BLIP Echo Client-Info.plist"; sourceTree = ""; }; 2779048A0DE9204300C6D295 /* BLIPEchoClient.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = BLIPEchoClient.xib; sourceTree = ""; }; 2779052D0DE9E5BC00C6D295 /* BLIPEchoServer */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = BLIPEchoServer; sourceTree = BUILT_PRODUCTS_DIR; }; + 278C1A340F9F687800954AE1 /* PortMapperTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PortMapperTest.m; sourceTree = ""; }; + 278C1A350F9F687800954AE1 /* MYPortMapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYPortMapper.h; sourceTree = ""; }; + 278C1A360F9F687800954AE1 /* MYPortMapper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYPortMapper.m; sourceTree = ""; }; + 278C1B9E0F9F92EA00954AE1 /* MYBonjourBrowser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYBonjourBrowser.h; sourceTree = ""; }; + 278C1B9F0F9F92EA00954AE1 /* MYBonjourBrowser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYBonjourBrowser.m; sourceTree = ""; }; + 278C1BA00F9F92EA00954AE1 /* MYBonjourService.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYBonjourService.h; sourceTree = ""; }; + 278C1BA10F9F92EA00954AE1 /* MYBonjourService.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYBonjourService.m; sourceTree = ""; }; + 278C1BB50F9F975700954AE1 /* ConcurrentOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConcurrentOperation.h; sourceTree = ""; }; + 278C1BB60F9F975700954AE1 /* ConcurrentOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ConcurrentOperation.m; sourceTree = ""; }; + 279DD99E0F9E290500D75D91 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + 279DD9B10F9E296200D75D91 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; }; + 279DD9B30F9E296E00D75D91 /* CoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreServices.framework; path = System/Library/Frameworks/CoreServices.framework; sourceTree = SDKROOT; }; + 279DDC9A0F9E2F2A00D75D91 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; + 279DDCCB0F9E381500D75D91 /* MYNetwork.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYNetwork.h; sourceTree = ""; }; + 279E8F9E0F9FDD0800608D8D /* libMYNetwork.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libMYNetwork.a; sourceTree = BUILT_PRODUCTS_DIR; }; 27D5EC050DE5FEDE00CD84FA /* BLIPRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BLIPRequest.h; sourceTree = ""; }; 27D5EC060DE5FEDE00CD84FA /* BLIPRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BLIPRequest.m; sourceTree = ""; }; 27E0DBED0DF3450F00E7F648 /* GTMDefines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GTMDefines.h; sourceTree = ""; }; @@ -166,7 +196,10 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 277ECFBC0E2A73A100D756BB /* libz.dylib in Frameworks */, + 279DDC970F9E2EF400D75D91 /* Foundation.framework in Frameworks */, + 279DDC9B0F9E2F2A00D75D91 /* AppKit.framework in Frameworks */, + 279E8FD70F9FDDE900608D8D /* libMYNetwork.a in Frameworks */, + 279E8FEF0F9FDE5A00608D8D /* Security.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -174,9 +207,17 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 277905260DE9E5BC00C6D295 /* Foundation.framework in Frameworks */, - 277905270DE9E5BC00C6D295 /* libz.dylib in Frameworks */, - 277905280DE9E5BC00C6D295 /* CoreServices.framework in Frameworks */, + 279DDAE00F9E2E0F00D75D91 /* Foundation.framework in Frameworks */, + 279E8FFA0F9FDEEB00608D8D /* libMYNetwork.a in Frameworks */, + 279E8FFC0F9FDEFB00608D8D /* CoreServices.framework in Frameworks */, + 279E8FFE0F9FDF0600608D8D /* Security.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 279E8F9C0F9FDD0800608D8D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( ); runOnlyForDeploymentPostprocessing = 0; }; @@ -184,9 +225,11 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 8DD76F9C0486AA7600D96B5E /* Foundation.framework in Frameworks */, - 2704618C0DE49652003D9D3F /* libz.dylib in Frameworks */, - 270461920DE4975D003D9D3F /* CoreServices.framework in Frameworks */, + 2777C9110F7602A7007F8D30 /* Security.framework in Frameworks */, + 2706F1D90F9D3EF300292CCF /* SecurityInterface.framework in Frameworks */, + 279DDA590F9E2DFA00D75D91 /* Foundation.framework in Frameworks */, + 279DDC4E0F9E2E2700D75D91 /* CoreServices.framework in Frameworks */, + 279DDC520F9E2E3A00D75D91 /* libz.dylib in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -200,7 +243,6 @@ 277903830DE8C2DD00C6D295 /* maindocs.h */, 270460F00DE49030003D9D3F /* MYNetwork */, 270461220DE49055003D9D3F /* MYUtilities */, - 270460FE0DE49030003D9D3F /* BLIPTest.m */, 277903E70DE8F05F00C6D295 /* Demo */, 08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */, 1AB674ADFE9D54B511CA2CBB /* Products */, @@ -211,9 +253,12 @@ 08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */ = { isa = PBXGroup; children = ( - 270461910DE4975C003D9D3F /* CoreServices.framework */, - 08FB779EFE84155DC02AAC07 /* Foundation.framework */, - 2704618B0DE49652003D9D3F /* libz.dylib */, + 279DDC9A0F9E2F2A00D75D91 /* AppKit.framework */, + 279DD9B30F9E296E00D75D91 /* CoreServices.framework */, + 279DD99E0F9E290500D75D91 /* Foundation.framework */, + 2777C9100F7602A7007F8D30 /* Security.framework */, + 2706F1D80F9D3EF300292CCF /* SecurityInterface.framework */, + 279DD9B10F9E296200D75D91 /* libz.dylib */, ); name = "External Frameworks and Libraries"; sourceTree = ""; @@ -224,6 +269,7 @@ 270461720DE49340003D9D3F /* MYNetwork */, 277904260DE91C7900C6D295 /* BLIP Echo Client.app */, 2779052D0DE9E5BC00C6D295 /* BLIPEchoServer */, + 279E8F9E0F9FDD0800608D8D /* libMYNetwork.a */, ); name = Products; sourceTree = ""; @@ -231,10 +277,13 @@ 270460F00DE49030003D9D3F /* MYNetwork */ = { isa = PBXGroup; children = ( + 279DDCCB0F9E381500D75D91 /* MYNetwork.h */, 270461010DE49030003D9D3F /* IPAddress.h */, 270461020DE49030003D9D3F /* IPAddress.m */, 270461070DE49030003D9D3F /* TCP */, + 278C1A320F9F687800954AE1 /* PortMapper */, 270460F10DE49030003D9D3F /* BLIP */, + 278C1B9D0F9F92D600954AE1 /* Bonjour */, ); name = MYNetwork; sourceTree = ""; @@ -283,6 +332,8 @@ 270461220DE49055003D9D3F /* MYUtilities */ = { isa = PBXGroup; children = ( + 278C1BB50F9F975700954AE1 /* ConcurrentOperation.h */, + 278C1BB60F9F975700954AE1 /* ConcurrentOperation.m */, 270462C10DE4A64B003D9D3F /* MYUtilitiesTest_main.m */, 270462C00DE4A639003D9D3F /* MYUtilities_Prefix.pch */, 270461880DE49634003D9D3F /* CollectionUtils.h */, @@ -295,6 +346,8 @@ 270461460DE491A6003D9D3F /* Target.m */, 270461290DE49088003D9D3F /* Test.h */, 270461280DE49088003D9D3F /* Test.m */, + 274122DD0F9CDD1600F21842 /* MYUtilities_Debug.xcconfig */, + 274122DE0F9CDD1600F21842 /* MYUtilities_Release.xcconfig */, 27E0DBEC0DF3450F00E7F648 /* GoogleToolboxSubset */, ); name = MYUtilities; @@ -304,6 +357,7 @@ 277903E70DE8F05F00C6D295 /* Demo */ = { isa = PBXGroup; children = ( + 270460FE0DE49030003D9D3F /* BLIPTest.m */, 277903D50DE8EE4800C6D295 /* BLIPEchoServer.h */, 277903D60DE8EE4800C6D295 /* BLIPEchoServer.m */, 277903E80DE8F08100C6D295 /* BLIPEchoClient.h */, @@ -315,6 +369,27 @@ path = BLIP/Demo; sourceTree = ""; }; + 278C1A320F9F687800954AE1 /* PortMapper */ = { + isa = PBXGroup; + children = ( + 278C1A350F9F687800954AE1 /* MYPortMapper.h */, + 278C1A360F9F687800954AE1 /* MYPortMapper.m */, + 278C1A340F9F687800954AE1 /* PortMapperTest.m */, + ); + path = PortMapper; + sourceTree = ""; + }; + 278C1B9D0F9F92D600954AE1 /* Bonjour */ = { + isa = PBXGroup; + children = ( + 278C1B9E0F9F92EA00954AE1 /* MYBonjourBrowser.h */, + 278C1B9F0F9F92EA00954AE1 /* MYBonjourBrowser.m */, + 278C1BA00F9F92EA00954AE1 /* MYBonjourService.h */, + 278C1BA10F9F92EA00954AE1 /* MYBonjourService.m */, + ); + path = Bonjour; + sourceTree = ""; + }; 27E0DBEC0DF3450F00E7F648 /* GoogleToolboxSubset */ = { isa = PBXGroup; children = ( @@ -327,6 +402,16 @@ }; /* End PBXGroup section */ +/* Begin PBXHeadersBuildPhase section */ + 279E8F9A0F9FDD0800608D8D /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + /* Begin PBXNativeTarget section */ 277904250DE91C7900C6D295 /* BLIP Echo Client */ = { isa = PBXNativeTarget; @@ -339,6 +424,7 @@ buildRules = ( ); dependencies = ( + 279E8FD60F9FDDD900608D8D /* PBXTargetDependency */, ); name = "BLIP Echo Client"; productName = "BLIP Echo Client"; @@ -356,6 +442,7 @@ buildRules = ( ); dependencies = ( + 279E8FF90F9FDECD00608D8D /* PBXTargetDependency */, ); name = "BLIP Echo Server"; productInstallPath = "$(HOME)/bin"; @@ -363,9 +450,26 @@ productReference = 2779052D0DE9E5BC00C6D295 /* BLIPEchoServer */; productType = "com.apple.product-type.tool"; }; - 8DD76F960486AA7600D96B5E /* MYNetwork */ = { + 279E8F9D0F9FDD0800608D8D /* Library */ = { isa = PBXNativeTarget; - buildConfigurationList = 1DEB927408733DD40010E9CD /* Build configuration list for PBXNativeTarget "MYNetwork" */; + buildConfigurationList = 279E8FCC0F9FDD8900608D8D /* Build configuration list for PBXNativeTarget "Library" */; + buildPhases = ( + 279E8F9A0F9FDD0800608D8D /* Headers */, + 279E8F9B0F9FDD0800608D8D /* Sources */, + 279E8F9C0F9FDD0800608D8D /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Library; + productName = Library; + productReference = 279E8F9E0F9FDD0800608D8D /* libMYNetwork.a */; + productType = "com.apple.product-type.library.static"; + }; + 8DD76F960486AA7600D96B5E /* SelfTest */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1DEB927408733DD40010E9CD /* Build configuration list for PBXNativeTarget "SelfTest" */; buildPhases = ( 8DD76F990486AA7600D96B5E /* Sources */, 8DD76F9B0486AA7600D96B5E /* Frameworks */, @@ -375,7 +479,7 @@ ); dependencies = ( ); - name = MYNetwork; + name = SelfTest; productInstallPath = "$(HOME)/bin"; productName = MYNetwork; productReference = 270461720DE49340003D9D3F /* MYNetwork */; @@ -393,7 +497,8 @@ projectDirPath = ""; projectRoot = ""; targets = ( - 8DD76F960486AA7600D96B5E /* MYNetwork */, + 279E8F9D0F9FDD0800608D8D /* Library */, + 8DD76F960486AA7600D96B5E /* SelfTest */, 277904250DE91C7900C6D295 /* BLIP Echo Client */, 2779050F0DE9E5BC00C6D295 /* BLIP Echo Server */, ); @@ -416,26 +521,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 277904330DE91DE600C6D295 /* BLIPConnection.m in Sources */, - 277904340DE91DE700C6D295 /* BLIPDispatcher.m in Sources */, - 277904350DE91DE800C6D295 /* BLIPEchoClient.m in Sources */, - 277904370DE91DEB00C6D295 /* BLIPMessage.m in Sources */, - 277904380DE91DEC00C6D295 /* BLIPProperties.m in Sources */, - 277904390DE91DEE00C6D295 /* BLIPReader.m in Sources */, - 2779043A0DE91DEF00C6D295 /* BLIPRequest.m in Sources */, - 2779043C0DE91DF100C6D295 /* BLIPWriter.m in Sources */, - 2779043D0DE91DF300C6D295 /* IPAddress.m in Sources */, - 2779043E0DE91DF500C6D295 /* TCPConnection.m in Sources */, - 2779043F0DE91DF800C6D295 /* TCPEndpoint.m in Sources */, - 277904400DE91DF900C6D295 /* TCPListener.m in Sources */, - 277904410DE91DFA00C6D295 /* TCPStream.m in Sources */, - 277904420DE91DFC00C6D295 /* TCPWriter.m in Sources */, - 277904440DE91E3500C6D295 /* CollectionUtils.m in Sources */, - 277904450DE91E3600C6D295 /* ExceptionUtils.m in Sources */, - 277904460DE91E3700C6D295 /* Logging.m in Sources */, - 277904480DE91E3900C6D295 /* Target.m in Sources */, - 277904490DE91E3A00C6D295 /* Test.m in Sources */, - 27E0DBF00DF3450F00E7F648 /* GTMNSData+zlib.m in Sources */, + 279DDCD10F9E38DD00D75D91 /* BLIPEchoClient.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -443,26 +529,38 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 277905110DE9E5BC00C6D295 /* BLIPConnection.m in Sources */, - 277905120DE9E5BC00C6D295 /* BLIPDispatcher.m in Sources */, - 277905130DE9E5BC00C6D295 /* BLIPMessage.m in Sources */, - 277905140DE9E5BC00C6D295 /* BLIPProperties.m in Sources */, - 277905150DE9E5BC00C6D295 /* BLIPReader.m in Sources */, - 277905160DE9E5BC00C6D295 /* BLIPWriter.m in Sources */, - 277905170DE9E5BC00C6D295 /* IPAddress.m in Sources */, - 277905180DE9E5BC00C6D295 /* TCPConnection.m in Sources */, - 277905190DE9E5BC00C6D295 /* TCPEndpoint.m in Sources */, - 2779051A0DE9E5BC00C6D295 /* TCPListener.m in Sources */, - 2779051B0DE9E5BC00C6D295 /* TCPStream.m in Sources */, - 2779051C0DE9E5BC00C6D295 /* TCPWriter.m in Sources */, - 2779051D0DE9E5BC00C6D295 /* Test.m in Sources */, - 2779051E0DE9E5BC00C6D295 /* Logging.m in Sources */, - 2779051F0DE9E5BC00C6D295 /* ExceptionUtils.m in Sources */, - 277905200DE9E5BC00C6D295 /* Target.m in Sources */, - 277905220DE9E5BC00C6D295 /* CollectionUtils.m in Sources */, - 277905230DE9E5BC00C6D295 /* BLIPRequest.m in Sources */, 277905240DE9E5BC00C6D295 /* BLIPEchoServer.m in Sources */, - 27E0DBF20DF3450F00E7F648 /* GTMNSData+zlib.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 279E8F9B0F9FDD0800608D8D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 279E8FA10F9FDD2600608D8D /* BLIPConnection.m in Sources */, + 279E8FA20F9FDD2600608D8D /* BLIPDispatcher.m in Sources */, + 279E8FA30F9FDD2600608D8D /* BLIPMessage.m in Sources */, + 279E8FA40F9FDD2600608D8D /* BLIPProperties.m in Sources */, + 279E8FA50F9FDD2600608D8D /* BLIPReader.m in Sources */, + 279E8FA60F9FDD2600608D8D /* BLIPRequest.m in Sources */, + 279E8FA70F9FDD2600608D8D /* BLIPWriter.m in Sources */, + 279E8FA80F9FDD2600608D8D /* IPAddress.m in Sources */, + 279E8FA90F9FDD2600608D8D /* TCPConnection.m in Sources */, + 279E8FAA0F9FDD2600608D8D /* TCPEndpoint.m in Sources */, + 279E8FAB0F9FDD2600608D8D /* TCPListener.m in Sources */, + 279E8FAC0F9FDD2600608D8D /* TCPStream.m in Sources */, + 279E8FAD0F9FDD2600608D8D /* TCPWriter.m in Sources */, + 279E8FAE0F9FDD2600608D8D /* CollectionUtils.m in Sources */, + 279E8FAF0F9FDD2600608D8D /* ExceptionUtils.m in Sources */, + 279E8FB00F9FDD2600608D8D /* GTMNSData+zlib.m in Sources */, + 279E8FB10F9FDD2600608D8D /* Logging.m in Sources */, + 279E8FB20F9FDD2600608D8D /* Target.m in Sources */, + 279E8FB30F9FDD2600608D8D /* Test.m in Sources */, + 279E8FB40F9FDD2600608D8D /* PortMapperTest.m in Sources */, + 279E8FB50F9FDD2600608D8D /* MYPortMapper.m in Sources */, + 279E8FB60F9FDD2600608D8D /* MYBonjourBrowser.m in Sources */, + 279E8FB70F9FDD2600608D8D /* MYBonjourService.m in Sources */, + 279E8FB80F9FDD2600608D8D /* ConcurrentOperation.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -491,26 +589,33 @@ 277905300DE9ED9100C6D295 /* MYUtilitiesTest_main.m in Sources */, 2779053B0DE9EDAA00C6D295 /* BLIPTest.m in Sources */, 27E0DBF10DF3450F00E7F648 /* GTMNSData+zlib.m in Sources */, + 278C1A3D0F9F687800954AE1 /* PortMapperTest.m in Sources */, + 278C1A3E0F9F687800954AE1 /* MYPortMapper.m in Sources */, + 278C1BA60F9F92EA00954AE1 /* MYBonjourBrowser.m in Sources */, + 278C1BA70F9F92EA00954AE1 /* MYBonjourService.m in Sources */, + 278C1BB90F9F975700954AE1 /* ConcurrentOperation.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ +/* Begin PBXTargetDependency section */ + 279E8FD60F9FDDD900608D8D /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 279E8F9D0F9FDD0800608D8D /* Library */; + targetProxy = 279E8FD50F9FDDD900608D8D /* PBXContainerItemProxy */; + }; + 279E8FF90F9FDECD00608D8D /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 279E8F9D0F9FDD0800608D8D /* Library */; + targetProxy = 279E8FF80F9FDECD00608D8D /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + /* Begin XCBuildConfiguration section */ 1DEB927508733DD40010E9CD /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - COPY_PHASE_STRIP = NO; - GCC_C_LANGUAGE_STANDARD = c99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_ENABLE_FIX_AND_CONTINUE = YES; - GCC_MODEL_TUNING = G5; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = ../MYUtilities/MYUtilities_Prefix.pch; - GCC_PREPROCESSOR_DEFINITIONS = DEBUG; - INSTALL_PATH = /usr/local/bin; PRODUCT_NAME = MYNetwork; }; name = Debug; @@ -518,68 +623,31 @@ 1DEB927608733DD40010E9CD /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - GCC_C_LANGUAGE_STANDARD = c99; - GCC_MODEL_TUNING = G5; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = ../MYUtilities/MYUtilities_Prefix.pch; - INSTALL_PATH = /usr/local/bin; PRODUCT_NAME = MYNetwork; }; name = Release; }; 1DEB927908733DD40010E9CD /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 274122DD0F9CDD1600F21842 /* MYUtilities_Debug.xcconfig */; buildSettings = { - ARCHS = "$(ARCHS_STANDARD_32_BIT)"; - GCC_C_LANGUAGE_STANDARD = c99; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = DEBUG; - GCC_TREAT_WARNINGS_AS_ERRORS = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - ONLY_ACTIVE_ARCH = YES; - PREBINDING = NO; SDKROOT = macosx10.5; - WARNING_CFLAGS = "-Wall"; }; name = Debug; }; 1DEB927A08733DD40010E9CD /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 274122DE0F9CDD1600F21842 /* MYUtilities_Release.xcconfig */; buildSettings = { - ARCHS = "$(ARCHS_STANDARD_32_BIT)"; - GCC_C_LANGUAGE_STANDARD = c99; - GCC_TREAT_WARNINGS_AS_ERRORS = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - PREBINDING = NO; SDKROOT = macosx10.5; - WARNING_CFLAGS = "-Wall"; }; name = Release; }; 277904290DE91C7A00C6D295 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - COPY_PHASE_STRIP = NO; - GCC_DYNAMIC_NO_PIC = NO; - GCC_ENABLE_FIX_AND_CONTINUE = YES; - GCC_MODEL_TUNING = G5; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/AppKit.framework/Headers/AppKit.h"; INFOPLIST_FILE = "BLIP/Demo/BLIP Echo Client-Info.plist"; INSTALL_PATH = "$(HOME)/Applications"; - OTHER_LDFLAGS = ( - "-framework", - Foundation, - "-framework", - AppKit, - ); - PREBINDING = NO; PRODUCT_NAME = "BLIP Echo Client"; }; name = Debug; @@ -587,41 +655,15 @@ 2779042A0DE91C7A00C6D295 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - COPY_PHASE_STRIP = YES; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - GCC_ENABLE_FIX_AND_CONTINUE = NO; - GCC_MODEL_TUNING = G5; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/AppKit.framework/Headers/AppKit.h"; INFOPLIST_FILE = "BLIP/Demo/BLIP Echo Client-Info.plist"; INSTALL_PATH = "$(HOME)/Applications"; - OTHER_LDFLAGS = ( - "-framework", - Foundation, - "-framework", - AppKit, - ); - PREBINDING = NO; PRODUCT_NAME = "BLIP Echo Client"; - ZERO_LINK = NO; }; name = Release; }; 2779052B0DE9E5BC00C6D295 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - COPY_PHASE_STRIP = NO; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_ENABLE_FIX_AND_CONTINUE = YES; - GCC_MODEL_TUNING = G5; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = ../MYUtilities/MYUtilities_Prefix.pch; - GCC_PREPROCESSOR_DEFINITIONS = DEBUG; - INSTALL_PATH = /usr/local/bin; PRODUCT_NAME = BLIPEchoServer; }; name = Debug; @@ -629,21 +671,30 @@ 2779052C0DE9E5BC00C6D295 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_MODEL_TUNING = G5; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = MYNetwork_Prefix.pch; - INSTALL_PATH = /usr/local/bin; PRODUCT_NAME = BLIPEchoServer; }; name = Release; }; + 279E8F9F0F9FDD0900608D8D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + INSTALL_PATH = /usr/local/lib; + PRODUCT_NAME = MYNetwork; + }; + name = Debug; + }; + 279E8FA00F9FDD0900608D8D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + INSTALL_PATH = /usr/local/lib; + PRODUCT_NAME = MYNetwork; + }; + name = Release; + }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ - 1DEB927408733DD40010E9CD /* Build configuration list for PBXNativeTarget "MYNetwork" */ = { + 1DEB927408733DD40010E9CD /* Build configuration list for PBXNativeTarget "SelfTest" */ = { isa = XCConfigurationList; buildConfigurations = ( 1DEB927508733DD40010E9CD /* Debug */, @@ -679,6 +730,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 279E8FCC0F9FDD8900608D8D /* Build configuration list for PBXNativeTarget "Library" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 279E8F9F0F9FDD0900608D8D /* Debug */, + 279E8FA00F9FDD0900608D8D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; /* End XCConfigurationList section */ }; rootObject = 08FB7793FE84155DC02AAC07 /* Project object */; diff -r a4875607a3a0 -r cb9cdf247239 PortMapper/MYPortMapper.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/PortMapper/MYPortMapper.h Wed Apr 22 16:45:39 2009 -0700 @@ -0,0 +1,119 @@ +// +// MYPortMapper.m +// MYNetwork +// +// Created by Jens Alfke on 1/4/08. +// Copyright 2008 Jens Alfke. All rights reserved. +// + +#import +#import +@class IPAddress; + + +/* MYPortMapper attempts to make a particular network port on this computer publicly reachable + for incoming connections, by "opening a hole" through a Network Address Translator + (NAT) or firewall that may be in between the computer and the public Internet. + + The port mapping may fail if: + * the NAT/router/firewall does not support either the UPnP or NAT-PMP protocols; + * the device doesn't implement the protocols correctly (this happens); + * the network administrator has disabled port-mapping; + * there is a second layer of NAT/firewall (this happens in some ISP networks.) + + The PortMapper is asynchronous. It will take a nonzero amount of time to set up the + mapping, and the mapping may change in the future as the network configuration changes. + To be informed of changes, either use key-value observing to watch the "error" and + "publicAddress" properties, or observe the MYPortMapperChangedNotification. + + Typical usage is to: + * Start a network service that listens for incoming connections on a port + * Open a MYPortMapper + * When the MYPortMapper reports the public address and port of the mapping, you somehow + notify other peers of that address and port, so they can connect to you. + * When the MYPortMapper reports changes, you (somehow) notify peers of the changes. + * When closing the network service, close the MYPortMapper object too. +*/ +@interface MYPortMapper : NSObject +{ + UInt16 _localPort, _desiredPublicPort; + BOOL _mapTCP, _mapUDP; + SInt32 _error; + void* /*DNSServiceRef*/ _service; // Typed void* to avoid having to #include + CFSocketRef _socket; + CFRunLoopSourceRef _socketSource; + IPAddress *_publicAddress, *_localAddress; +} + +/** Initializes a PortMapper that will map the given local (private) port. + By default it will map TCP and not UDP, and will not suggest a desired public port, + but this can be configured by setting properties before opening the PortMapper. */ +- (id) initWithLocalPort: (UInt16)localPort; + +/** Initializes a PortMapper that will not map any ports. + This is useful if you just want to find out your public IP address. + (For a simplified, but synchronous, convenience method for this, see + +findPublicAddress.) */ +- (id) initWithNullMapping; + +/** Should the TCP or UDP port, or both, be mapped? By default, TCP only. + These properties have no effect if changed while the PortMapper is open. */ +@property BOOL mapTCP, mapUDP; + +/** You can set this to the public port number you'd like to get. + It defaults to 0, which means "no preference". + This property has no effect if changed while the PortMapper is open. */ +@property UInt16 desiredPublicPort; + +/** Opens the PortMapper, using the current settings of the above properties. + Returns immediately; you can find out when the mapping is created or fails + by observing the error/publicAddress/publicPort properties, or by listening + for the PortMapperChangedNotification. + It's very unlikely that this call will fail (return NO). If it does, it + probably means that the mDNSResponder process isn't working. */ +- (BOOL) open; + +/** Blocks till the PortMapper finishes opening. Returns YES if it opened, NO on error. + It's not usually a good idea to use this, as it will lock up your application + until a response arrives from the NAT. Listen for asynchronous notifications instead. + If called when the PortMapper is closed, it will call -open for you. + If called when it's already open, it just returns YES. */ +- (BOOL) waitTillOpened; + +/** Closes the PortMapper, terminating any open port mapping. */ +- (void) close; + +/** The error status, a DNSServiceErrorType enum; nonzero if something went wrong. + The most likely error is kDNSServiceErr_NATPortMappingUnsupported (-65564). + This property is KV observable. */ +@property (readonly) SInt32 error; + +/** The known public IPv4 address/port, once it's been determined. + This property is KV observable. */ +@property (readonly,retain) IPAddress* publicAddress; + +/** The current local address/port, as of the time the port mapping was last updated. + The address part is of the main interface; the port is the specified local port. + This property is KV observable. */ +@property (readonly,retain) IPAddress* localAddress; + +/** Returns YES if a non-null port mapping is in effect: + that is, if the public address differs from the local one. */ +@property (readonly) BOOL isMapped; + + +// UTILITY CLASS METHOD: + +/** Determine the main interface's public IP address, without mapping any ports. + This method internally calls -waitTillOpened, so it may take a nontrivial amount + of time (and will crank the runloop while it waits.) + If you want to do this asynchronously, you should instead create a new + MYPortMapper instance using -initWithNullMapping. */ ++ (IPAddress*) findPublicAddress; + +@end + + +/** This notification is posted asynchronously when the status of a PortMapper + (its error, publicAddress or publicPort) changes. */ +extern NSString* const MYPortMapperChangedNotification; diff -r a4875607a3a0 -r cb9cdf247239 PortMapper/MYPortMapper.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/PortMapper/MYPortMapper.m Wed Apr 22 16:45:39 2009 -0700 @@ -0,0 +1,303 @@ +// +// MYPortMapper.m +// MYNetwork +// +// Created by Jens Alfke on 1/4/08. +// Copyright 2008 Jens Alfke. All rights reserved. +// + +#import "MYPortMapper.h" +#import "IPAddress.h" +#import "CollectionUtils.h" +#import "Logging.h" +#import "ExceptionUtils.h" + +#import +#import +#import +#import +#import +#import + + +NSString* const MYPortMapperChangedNotification = @"MYPortMapperChanged"; + + +@interface MYPortMapper () +// Redeclare these properties as settable, internally: +@property (readwrite) SInt32 error; +@property (retain) IPAddress* publicAddress, *localAddress; +// Private getter: +@property (readonly) void* _service; +- (void) priv_updateLocalAddress; +- (void) priv_disconnect; +@end + + +@implementation MYPortMapper + + +- (id) initWithLocalPort: (UInt16)localPort +{ + self = [super init]; + if (self != nil) { + _localPort = localPort; + _mapTCP = YES; + [self priv_updateLocalAddress]; + } + return self; +} + +- (id) initWithNullMapping +{ + // A PortMapper with no port or protocols will cause the DNSService to look up + // our public address without creating a mapping. + if ([self initWithLocalPort: 0]) { + _mapTCP = _mapUDP = NO; + } + return self; +} + + +- (void) dealloc +{ + if( _service ) + [self priv_disconnect]; + [_publicAddress release]; + [_localAddress release]; + [super dealloc]; +} + +- (void) finalize +{ + if( _service ) + [self priv_disconnect]; + [super finalize]; +} + + +@synthesize localAddress=_localAddress, publicAddress=_publicAddress, + error=_error, _service=_service, + mapTCP=_mapTCP, mapUDP=_mapUDP, + desiredPublicPort=_desiredPublicPort; + + +- (BOOL) isMapped +{ + return ! $equal(_publicAddress,_localAddress); +} + +- (void) priv_updateLocalAddress +{ + IPAddress *localAddress = [IPAddress localAddressWithPort: _localPort]; + if (!$equal(localAddress,_localAddress)) + self.localAddress = localAddress; +} + + +static IPAddress* makeIPAddr( UInt32 rawAddr, UInt16 port ) { + if (rawAddr) + return [[[IPAddress alloc] initWithIPv4: rawAddr port: port] autorelease]; + else + return nil; +} + +/** Called whenever the port mapping changes (see comment for callback, below.) */ +- (void) priv_portMapStatus: (DNSServiceErrorType)errorCode + publicAddress: (UInt32)rawPublicAddress + publicPort: (UInt16)publicPort +{ + LogTo(PortMapper,@"Callback got err %i, addr %08X:%hu", + errorCode, rawPublicAddress, publicPort); + if( errorCode==kDNSServiceErr_NoError ) { + if( rawPublicAddress==0 || (publicPort==0 && (_mapTCP || _mapUDP)) ) { + LogTo(PortMapper,@"(Callback reported no mapping available)"); + errorCode = kDNSServiceErr_NATPortMappingUnsupported; + } + } + if( errorCode != self.error ) + self.error = errorCode; + + [self priv_updateLocalAddress]; + IPAddress *publicAddress = makeIPAddr(rawPublicAddress,publicPort); + if (!$equal(publicAddress,_publicAddress)) + self.publicAddress = publicAddress; + + if( ! errorCode ) { + LogTo(PortMapper,@"Callback got %08X:%hu -> %@ (mapped=%i)", + rawPublicAddress,publicPort, self.publicAddress, self.isMapped); + } + [[NSNotificationCenter defaultCenter] postNotificationName: MYPortMapperChangedNotification + object: self]; +} + + +/** Asynchronous callback from DNSServiceNATPortMappingCreate. + This is invoked whenever the status of the port mapping changes. + All it does is dispatch to the object's priv_portMapStatus:publicAddress:publicPort: method. */ +static void portMapCallback ( + DNSServiceRef sdRef, + DNSServiceFlags flags, + uint32_t interfaceIndex, + DNSServiceErrorType errorCode, + uint32_t publicAddress, /* four byte IPv4 address in network byte order */ + DNSServiceProtocol protocol, + uint16_t privatePort, + uint16_t publicPort, /* may be different than the requested port */ + uint32_t ttl, /* may be different than the requested ttl */ + void *context + ) +{ + NSAutoreleasePool *pool = [NSAutoreleasePool new]; + @try{ + [(MYPortMapper*)context priv_portMapStatus: errorCode + publicAddress: publicAddress + publicPort: ntohs(publicPort)]; // port #s in network byte order! + }catchAndReport(@"PortMapper"); + [pool drain]; +} + + +/** CFSocket callback, informing us that _socket has data available, which means + that the DNS service has an incoming result to be processed. This will end up invoking + the portMapCallback. */ +static void serviceCallback(CFSocketRef s, + CFSocketCallBackType type, + CFDataRef address, const void *data, void *clientCallBackInfo) +{ + MYPortMapper *mapper = (MYPortMapper*)clientCallBackInfo; + DNSServiceRef service = mapper._service; + DNSServiceErrorType err = DNSServiceProcessResult(service); + if( err ) { + // An error here means the socket has failed and should be closed. + [mapper priv_portMapStatus: err publicAddress: 0 publicPort: 0]; + [mapper priv_disconnect]; + } +} + + + +- (BOOL) open +{ + NSAssert(!_service,@"Already open"); + // Create the DNSService: + DNSServiceProtocol protocols = 0; + if( _mapTCP ) protocols |= kDNSServiceProtocol_TCP; + if( _mapUDP ) protocols |= kDNSServiceProtocol_UDP; + self.error = DNSServiceNATPortMappingCreate((DNSServiceRef*)&_service, + 0 /*flags*/, + 0 /*interfaceIndex*/, + protocols, + htons(_localPort), + htons(_desiredPublicPort), + 0 /*ttl*/, + &portMapCallback, + self); + if( _error ) { + LogTo(PortMapper,@"Error %i creating port mapping",_error); + return NO; + } + + // Wrap a CFSocket around the service's socket: + CFSocketContext ctxt = { 0, self, CFRetain, CFRelease, NULL }; + _socket = CFSocketCreateWithNative(NULL, + DNSServiceRefSockFD(_service), + kCFSocketReadCallBack, + &serviceCallback, &ctxt); + if( _socket ) { + CFSocketSetSocketFlags(_socket, CFSocketGetSocketFlags(_socket) & ~kCFSocketCloseOnInvalidate); + // Attach the socket to the runloop so the serviceCallback will be invoked: + _socketSource = CFSocketCreateRunLoopSource(NULL, _socket, 0); + if( _socketSource ) + CFRunLoopAddSource(CFRunLoopGetCurrent(), _socketSource, kCFRunLoopCommonModes); + } + if( _socketSource ) { + LogTo(PortMapper,@"Opening"); + return YES; + } else { + Warn(@"Failed to open PortMapper"); + [self close]; + _error = kDNSServiceErr_Unknown; + return NO; + } +} + + +- (BOOL) waitTillOpened +{ + if( ! _socketSource ) + if( ! [self open] ) + return NO; + // Run the runloop until there's either an error or a result: + while( _error==0 && _publicAddress==nil ) + if( ! [[NSRunLoop currentRunLoop] runMode: NSDefaultRunLoopMode + beforeDate: [NSDate distantFuture]] ) + break; + return (_error==0); +} + + +// Close down, but _without_ clearing the 'error' property +- (void) priv_disconnect +{ + if( _socketSource ) { + CFRunLoopSourceInvalidate(_socketSource); + CFRelease(_socketSource); + _socketSource = NULL; + } + if( _socket ) { + CFSocketInvalidate(_socket); + CFRelease(_socket); + _socket = NULL; + } + if( _service ) { + LogTo(PortMapper,@"Deleting port mapping"); + DNSServiceRefDeallocate(_service); + _service = NULL; + self.publicAddress = nil; + } +} + +- (void) close +{ + [self priv_disconnect]; + self.error = 0; +} + + ++ (IPAddress*) findPublicAddress +{ + IPAddress *addr = nil; + MYPortMapper *mapper = [[self alloc] initWithNullMapping]; + if( [mapper waitTillOpened] ) + addr = [mapper.publicAddress retain]; + [mapper close]; + [mapper release]; + return [addr autorelease]; +} + + +@end + + +/* + Copyright (c) 2008-2009, Jens Alfke . All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, are permitted + provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions + and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions + and the following disclaimer in the documentation and/or other materials provided with the + distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI- + BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ diff -r a4875607a3a0 -r cb9cdf247239 PortMapper/PortMapperTest.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/PortMapper/PortMapperTest.m Wed Apr 22 16:45:39 2009 -0700 @@ -0,0 +1,111 @@ +// PortMapperTest.m +// MYNetwork +// +// Created by Jens Alfke on 1/4/08. +// Copyright 2008 Jens Alfke. All rights reserved. +// + + + +#import "MYPortMapper.h" +#import "IPAddress.h" +#import "Test.h" +#import "Logging.h" + +#if DEBUG + + +/** A trivial class that just demonstrates how to create a MYPortMapper and listen for changes. */ +@interface MYPortMapperTest : NSObject +{ + MYPortMapper *_mapper; +} + +@end + + +@implementation MYPortMapperTest + + +- (id) init +{ + self = [super init]; + if( self ) { + // Create MYPortMapper. This example doesn't open a real socket; just pretend that there's + // already a TCP socket listening on port 8080. To experiment, you could turn on Web + // Sharing, then change this port number to 80 -- that will make your computer's local + // Apache web server reachable from the outside world while this program is running. + _mapper = [[MYPortMapper alloc] initWithLocalPort: 80]; + + // Optionally, request a public port number. + // The NAT is free to ignore this and return a random number instead. + _mapper.desiredPublicPort = 22222; + + // Now open the mapping (asynchronously): + if( [_mapper open] ) { + Log(@"Opening port mapping..."); + // Now listen for notifications to find out when the mapping opens, fails, or changes: + [[NSNotificationCenter defaultCenter] addObserver: self + selector: @selector(portMappingChanged:) + name: MYPortMapperChangedNotification + object: _mapper]; + } else { + // MYPortMapper failed -- this is unlikely, but be graceful: + Log(@"!! Error: MYPortMapper wouldn't start: %i",_mapper.error); + [self release]; + return nil; + } + } + return self; +} + + +- (void) portMappingChanged: (NSNotification*)n +{ + // This is where we get notified that the mapping was created, or that no mapping exists, + // or that mapping failed. + if( _mapper.error ) + Log(@"!! MYPortMapper error %i", _mapper.error); + else { + NSString *message = @""; + if( !_mapper.isMapped ) + message = @" (no address translation!)"; + Log(@"** Public address:port is %@%@", _mapper.publicAddress, message); + Log(@" local address:port is %@", _mapper.localAddress); + } +} + + +- (void) dealloc +{ + [_mapper close]; + [_mapper release]; + [super dealloc]; +} + + +@end + + + +TestCase(MYPortMapper) { + + EnableLogTo(PortMapper,YES); + // Here's how to simply obtain your local and public address(es): + IPAddress *addr = [IPAddress localAddress]; + Log(@"** Local address is %@%@ ...getting public addr...", + addr, (addr.isPrivate ?@" (private)" :@"")); + addr = [MYPortMapper findPublicAddress]; + Log(@"** Public address is %@", addr); + + // Start up the test class to create a mapping: + MYPortMapperTest *test = [[MYPortMapperTest alloc] init]; + + // Now let the runloop run forever... + Log(@"Running the runloop forever..."); + [[NSRunLoop currentRunLoop] run]; + + [test release]; +} + +#endif DEBUG diff -r a4875607a3a0 -r cb9cdf247239 TCP/TCPConnection.h --- a/TCP/TCPConnection.h Tue Dec 02 22:42:56 2008 -0800 +++ b/TCP/TCPConnection.h Wed Apr 22 16:45:39 2009 -0700 @@ -127,6 +127,7 @@ settings say to check the peer's certificate. This happens, if at all, after the -connectionDidOpen: call. */ - (BOOL) connection: (TCPConnection*)connection authorizeSSLPeer: (SecCertificateRef)peerCert; -/** Called after the connection closes. */ +/** Called after the connection closes. + You can check the connection's error property to see if it was normal or abnormal. */ - (void) connectionDidClose: (TCPConnection*)connection; @end diff -r a4875607a3a0 -r cb9cdf247239 TCP/TCPConnection.m --- a/TCP/TCPConnection.m Tue Dec 02 22:42:56 2008 -0800 +++ b/TCP/TCPConnection.m Wed Apr 22 16:45:39 2009 -0700 @@ -14,7 +14,7 @@ #import "ExceptionUtils.h" -#if TARGET_OS_IPHONE && TARGET_OS_EMBEDDED +#if TARGET_OS_IPHONE && !defined(__SEC_TYPES__) // SecureTransport.h is missing on iPhone, with its SSL constants: enum{ errSSLClosedAbort = -9806, /* connection closed via error */ @@ -348,7 +348,7 @@ allow = NO; // Server MUST have a cert! else { SecCertificateRef cert = certs.count ?(SecCertificateRef)[certs objectAtIndex:0] :NULL; - LogTo(TCP,@"%@: Peer cert = %@",self,cert); + LogTo(TCP,@"%@: Peer cert = %@",self,[TCPEndpoint describeCert: cert]); if( [_delegate respondsToSelector: @selector(connection:authorizeSSLPeer:)] ) allow = [_delegate connection: self authorizeSSLPeer: cert]; } diff -r a4875607a3a0 -r cb9cdf247239 TCP/TCPEndpoint.h --- a/TCP/TCPEndpoint.h Tue Dec 02 22:42:56 2008 -0800 +++ b/TCP/TCPEndpoint.h Wed Apr 22 16:45:39 2009 -0700 @@ -7,6 +7,7 @@ // #import +#import #if TARGET_OS_IPHONE #include #else @@ -15,10 +16,26 @@ // SSL properties: + +/** This defines the SSL identity to be used by this endpoint. + The value is an NSArray (or CFArray) whose first item must be a SecIdentityRef; + optionally, it can also contain SecCertificateRefs for supporting certificates in the + validation chain. */ #define kTCPPropertySSLCertificates ((NSString*)kCFStreamSSLCertificates) + +/** If set to YES, the connection will accept self-signed certificates from the peer, + or any certificate chain that terminates in an unrecognized root. */ #define kTCPPropertySSLAllowsAnyRoot ((NSString*)kCFStreamSSLAllowsAnyRoot) -extern NSString* const kTCPPropertySSLClientSideAuthentication; // value is TCPAuthenticate enum +/** This sets the hostname that the peer's certificate must have. + (The default value is the hostname, if any, that the connection was opened with.) + Setting a value of [NSNull null] completely disables host-name checking. */ +#define kTCPPropertySSLPeerName ((NSString*)kCFStreamSSLPeerName) + +/** Specifies whether the client (the peer that opened the connection) will use a certificate. + The value is a TCPAuthenticate enum value wrapped in an NSNumber. */ +extern NSString* const kTCPPropertySSLClientSideAuthentication; + typedef enum { kTCPNeverAuthenticate, /* skip client authentication */ kTCPAlwaysAuthenticate, /* require it */ @@ -46,6 +63,10 @@ - (void) setSSLProperty: (id)value forKey: (NSString*)key; +/** High-level setup for secure P2P connections. Uses the given identity for SSL, + requires peers to use SSL, turns off root checking and peer-name checking. */ +- (void) setPeerToPeerIdentity: (SecIdentityRef)identity; + //protected: - (void) tellDelegate: (SEL)selector withObject: (id)param; diff -r a4875607a3a0 -r cb9cdf247239 TCP/TCPEndpoint.m --- a/TCP/TCPEndpoint.m Tue Dec 02 22:42:56 2008 -0800 +++ b/TCP/TCPEndpoint.m Wed Apr 22 16:45:39 2009 -0700 @@ -7,8 +7,10 @@ // #import "TCPEndpoint.h" - +#import "Test.h" +#import "CollectionUtils.h" #import "ExceptionUtils.h" +#import NSString* const kTCPPropertySSLClientSideAuthentication = @"kTCPPropertySSLClientSideAuthentication"; @@ -47,6 +49,15 @@ - (NSString*) securityLevel {return [_sslProperties objectForKey: (id)kCFStreamSSLLevel];} - (void) setSecurityLevel: (NSString*)level {[self setSSLProperty: level forKey: (id)kCFStreamSSLLevel];} +- (void) setPeerToPeerIdentity: (SecIdentityRef)identity { + Assert(identity); + self.SSLProperties = $mdict( + {(id)kCFStreamSSLLevel, NSStreamSocketSecurityLevelTLSv1}, + {kTCPPropertySSLCertificates, $array((id)identity)}, + {kTCPPropertySSLAllowsAnyRoot, $true}, + {kTCPPropertySSLPeerName, [NSNull null]}, + {kTCPPropertySSLClientSideAuthentication, $object(kTCPAlwaysAuthenticate)}); +} - (void) tellDelegate: (SEL)selector withObject: (id)param { @@ -58,6 +69,37 @@ } ++ (NSString*) describeCert: (SecCertificateRef)cert { + if (!cert) + return @"(null)"; + NSString *desc; +#if TARGET_OS_IPHONE && !defined(__SEC_TYPES__) + CFStringRef summary = NULL; + SecCertificateCopySubjectSummary(cert); + desc = $sprintf(@"Certificate[%@]", summary); + if(summary) CFRelease(summary); +#else + CFStringRef name=NULL; + CFArrayRef emails=NULL; + SecCertificateCopyCommonName(cert, &name); + SecCertificateCopyEmailAddresses(cert, &emails); + desc = $sprintf(@"Certificate[\"%@\", <%@>]", + name, [(NSArray*)emails componentsJoinedByString: @">, <"]); + if(name) CFRelease(name); + if(emails) CFRelease(emails); +#endif + return desc; +} + ++ (NSString*) describeIdentity: (SecIdentityRef)identity { + if (!identity) + return @"(null)"; + SecCertificateRef cert; + SecIdentityCopyCertificate(identity, &cert); + return $sprintf(@"Identity[%@]", [self describeCert: cert]); +} + + @end diff -r a4875607a3a0 -r cb9cdf247239 TCP/TCPListener.m --- a/TCP/TCPListener.m Tue Dec 02 22:42:56 2008 -0800 +++ b/TCP/TCPListener.m Wed Apr 22 16:45:39 2009 -0700 @@ -156,10 +156,13 @@ addr6.sin6_port = htons(_port); memcpy(&(addr6.sin6_addr), &in6addr_any, sizeof(addr6.sin6_addr)); - _ipv6socket = [self _openProtocol: PF_INET6 address: (struct sockaddr*)&addr6 error: outError]; + NSError *error; + _ipv6socket = [self _openProtocol: PF_INET6 address: (struct sockaddr*)&addr6 error: &error]; if( ! _ipv6socket ) { _ipv4socket = closeSocket(_ipv4socket); - return [self _failedToOpen: *outError]; + [self _failedToOpen: error]; + if (outError) *outError = error; + return NO; } } diff -r a4875607a3a0 -r cb9cdf247239 TCP/TCPStream.m --- a/TCP/TCPStream.m Tue Dec 02 22:42:56 2008 -0800 +++ b/TCP/TCPStream.m Wed Apr 22 16:45:39 2009 -0700 @@ -96,7 +96,7 @@ - (void) open { Assert(_stream); - AssertEq(_stream.streamStatus,NSStreamStatusNotOpen); + AssertEq(_stream.streamStatus,(NSStreamStatus)NSStreamStatusNotOpen); LogTo(TCP,@"Opening %@",self); [_stream open]; } diff -r a4875607a3a0 -r cb9cdf247239 TCP/TCP_Internal.h --- a/TCP/TCP_Internal.h Tue Dec 02 22:42:56 2008 -0800 +++ b/TCP/TCP_Internal.h Wed Apr 22 16:45:39 2009 -0700 @@ -30,3 +30,8 @@ - (void) _unclose; @end + +@interface TCPEndpoint () ++ (NSString*) describeCert: (SecCertificateRef)cert; ++ (NSString*) describeIdentity: (SecIdentityRef)identity; +@end diff -r a4875607a3a0 -r cb9cdf247239 iPhone/Classes/MyViewController.m --- a/iPhone/Classes/MyViewController.m Tue Dec 02 22:42:56 2008 -0800 +++ b/iPhone/Classes/MyViewController.m Wed Apr 22 16:45:39 2009 -0700 @@ -1,49 +1,3 @@ -/* - -File: MyViewController.m -Abstract: A view controller responsible for managing the Hello World view. - -Version: 1.7 - -Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc. -("Apple") in consideration of your agreement to the following terms, and your -use, installation, modification or redistribution of this Apple software -constitutes acceptance of these terms. If you do not agree with these terms, -please do not use, install, modify or redistribute this Apple software. - -In consideration of your agreement to abide by the following terms, and subject -to these terms, Apple grants you a personal, non-exclusive license, under -Apple's copyrights in this original Apple software (the "Apple Software"), to -use, reproduce, modify and redistribute the Apple Software, with or without -modifications, in source and/or binary forms; provided that if you redistribute -the Apple Software in its entirety and without modifications, you must retain -this notice and the following text and disclaimers in all such redistributions -of the Apple Software. -Neither the name, trademarks, service marks or logos of Apple Inc. may be used -to endorse or promote products derived from the Apple Software without specific -prior written permission from Apple. Except as expressly stated in this notice, -no other rights or licenses, express or implied, are granted by Apple herein, -including but not limited to any patent rights that may be infringed by your -derivative works or by other works in which the Apple Software may be -incorporated. - -The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO -WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED -WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN -COMBINATION WITH YOUR PRODUCTS. - -IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE -GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR -DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF -CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF -APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -Copyright (C) 2008 Apple Inc. All Rights Reserved. - -*/ #import "MyViewController.h" #import "BLIP.h" diff -r a4875607a3a0 -r cb9cdf247239 iPhone/main.m --- a/iPhone/main.m Tue Dec 02 22:42:56 2008 -0800 +++ b/iPhone/main.m Wed Apr 22 16:45:39 2009 -0700 @@ -46,9 +46,11 @@ */ #import +#import "Test.h" int main(int argc, char *argv[]) { + RunTestCases(argc,(const char**)argv); NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; int retVal = UIApplicationMain(argc, argv, nil, nil); [pool release];