Misc. tweaks made while porting Chatty to use MYNetwork.
authorJens Alfke <jens@mooseyard.com>
Sun May 24 15:03:39 2009 -0700 (2009-05-24)
changeset 4920cccc7c26ee
parent 48 2b4ad2067074
child 50 63baa74c903f
child 51 de59ce19f42e
Misc. tweaks made while porting Chatty to use MYNetwork.
* Allow -[BLIPConnection sendRequest:] to re-send an already-sent or received request.
* Allow use of the basic -init method for BLIPConnection.
* Some new convenience factory methods.
* Broke dependencies on Security.framework out into new TCPEndpoint+Certs.m source file, so client apps aren't forced to link against Security.
BLIP/BLIPConnection.m
BLIP/BLIPRequest.h
BLIP/BLIPRequest.m
Bonjour/MYBonjourService.h
IPAddress.h
IPAddress.m
MYNetwork-iPhone.xcodeproj/project.pbxproj
MYNetwork.xcodeproj/project.pbxproj
TCP/TCPConnection.m
TCP/TCPEndpoint+Certs.m
TCP/TCPEndpoint.m
TCP/TCPListener.m
     1.1 --- a/BLIP/BLIPConnection.m	Sat May 16 14:24:06 2009 -0700
     1.2 +++ b/BLIP/BLIPConnection.m	Sun May 24 15:03:39 2009 -0700
     1.3 @@ -121,6 +121,12 @@
     1.4  
     1.5  - (BLIPResponse*) sendRequest: (BLIPRequest*)request
     1.6  {
     1.7 +    if (!request.isMine || request.sent) {
     1.8 +        // This was an incoming request that I'm being asked to forward or echo;
     1.9 +        // or it's an outgoing request being sent to multiple connections.
    1.10 +        // Since a particular BLIPRequest can only be sent once, make a copy of it to send:
    1.11 +        request = [[request mutableCopy] autorelease];
    1.12 +    }
    1.13      BLIPConnection *itsConnection = request.connection;
    1.14      if( itsConnection==nil )
    1.15          request.connection = self;
    1.16 @@ -187,9 +193,9 @@
    1.17  #pragma mark -
    1.18  @implementation BLIPListener
    1.19  
    1.20 -- (id) initWithPort: (UInt16)port
    1.21 +- (id) init
    1.22  {
    1.23 -    self = [super initWithPort: port];
    1.24 +    self = [super init];
    1.25      if (self != nil) {
    1.26          self.connectionClass = [BLIPConnection class];
    1.27      }
     2.1 --- a/BLIP/BLIPRequest.h	Sat May 16 14:24:06 2009 -0700
     2.2 +++ b/BLIP/BLIPRequest.h	Sun May 24 15:03:39 2009 -0700
     2.3 @@ -11,7 +11,7 @@
     2.4  
     2.5  
     2.6  /** A Request, or initiating message, in the <a href=".#blipdesc">BLIP</a> protocol. */
     2.7 -@interface BLIPRequest : BLIPMessage
     2.8 +@interface BLIPRequest : BLIPMessage <NSMutableCopying>
     2.9  {
    2.10      @private
    2.11      BLIPResponse *_response;
    2.12 @@ -25,6 +25,10 @@
    2.13  + (BLIPRequest*) requestWithBody: (NSData*)body;
    2.14  
    2.15  /** Creates an outgoing request.
    2.16 +    This is just like requestWithBody: except that you supply a string. */
    2.17 ++ (BLIPRequest*) requestWithBodyString: (NSString*)bodyString;
    2.18 +
    2.19 +/** Creates an outgoing request.
    2.20      The body or properties may be nil.
    2.21      The request is not associated with any BLIPConnection yet, so you must either set its
    2.22      connection property before calling -send, or pass the request as a parameter to
     3.1 --- a/BLIP/BLIPRequest.m	Sat May 16 14:24:06 2009 -0700
     3.2 +++ b/BLIP/BLIPRequest.m	Sun May 24 15:03:39 2009 -0700
     3.3 @@ -44,12 +44,27 @@
     3.4      return [[[self alloc] _initWithConnection: nil body: body properties: nil] autorelease];
     3.5  }
     3.6  
     3.7 ++ (BLIPRequest*) requestWithBodyString: (NSString*)bodyString {
     3.8 +    return [self requestWithBody: [bodyString dataUsingEncoding: NSUTF8StringEncoding]];
     3.9 +}
    3.10 +
    3.11  + (BLIPRequest*) requestWithBody: (NSData*)body
    3.12                        properties: (NSDictionary*)properties
    3.13  {
    3.14      return [[[self alloc] _initWithConnection: nil body: body properties: properties] autorelease];
    3.15  }
    3.16  
    3.17 +- (id)mutableCopyWithZone:(NSZone *)zone
    3.18 +{
    3.19 +    Assert(self.complete);
    3.20 +    BLIPRequest *copy = [[self class] requestWithBody: self.body 
    3.21 +                                           properties: self.properties.allProperties];
    3.22 +    copy.compressed = self.compressed;
    3.23 +    copy.urgent = self.urgent;
    3.24 +    copy.noReply = self.noReply;
    3.25 +    return [copy retain];
    3.26 +}
    3.27 +
    3.28  
    3.29  - (void) dealloc
    3.30  {
     4.1 --- a/Bonjour/MYBonjourService.h	Sat May 16 14:24:06 2009 -0700
     4.2 +++ b/Bonjour/MYBonjourService.h	Sun May 24 15:03:39 2009 -0700
     4.3 @@ -7,7 +7,6 @@
     4.4  //
     4.5  
     4.6  #import "MYDNSService.h"
     4.7 -#import "ConcurrentOperation.h"
     4.8  @class MYBonjourQuery, MYAddressLookup;
     4.9  
    4.10  
     5.1 --- a/IPAddress.h	Sat May 16 14:24:06 2009 -0700
     5.2 +++ b/IPAddress.h	Sun May 24 15:03:39 2009 -0700
     5.3 @@ -25,6 +25,12 @@
     5.4      be returned instead. */
     5.5  - (id) initWithHostname: (NSString*)hostname port: (UInt16)port;
     5.6  
     5.7 +/** Creates an IPAddress from a host name (which may be a DNS name or dotted-quad numeric form)
     5.8 +    and port number.
     5.9 +    If the hostname is not in dotted-quad form, an instance of the subclass HostAddress will
    5.10 +    be returned instead. */
    5.11 ++ (IPAddress*) addressWithHostname: (NSString*)hostname port: (UInt16)port;
    5.12 +
    5.13  /** Initializes an IPAddress from a raw IPv4 address (in network byte order, i.e. big-endian)
    5.14      and port number (in native byte order) */
    5.15  - (id) initWithIPv4: (UInt32)ipv4 port: (UInt16)port;
     6.1 --- a/IPAddress.m	Sat May 16 14:24:06 2009 -0700
     6.2 +++ b/IPAddress.m	Sun May 24 15:03:39 2009 -0700
     6.3 @@ -56,6 +56,11 @@
     6.4      return self;
     6.5  }
     6.6  
     6.7 ++ (IPAddress*) addressWithHostname: (NSString*)hostname port: (UInt16)port
     6.8 +{
     6.9 +    return [[[self alloc] initWithHostname: hostname port: port] autorelease];
    6.10 +}
    6.11 +
    6.12  
    6.13  - (id) initWithIPv4: (UInt32)ipv4 port: (UInt16)port
    6.14  {
     7.1 --- a/MYNetwork-iPhone.xcodeproj/project.pbxproj	Sat May 16 14:24:06 2009 -0700
     7.2 +++ b/MYNetwork-iPhone.xcodeproj/project.pbxproj	Sun May 24 15:03:39 2009 -0700
     7.3 @@ -41,6 +41,7 @@
     7.4  		278C1B2F0F9F865800954AE1 /* PortMapperTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 278C1B2D0F9F865800954AE1 /* PortMapperTest.m */; };
     7.5  		278C1B350F9F86A100954AE1 /* MYUtilities_Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 278C1B330F9F86A100954AE1 /* MYUtilities_Debug.xcconfig */; };
     7.6  		278C1B360F9F86A100954AE1 /* MYUtilities_Release.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 278C1B340F9F86A100954AE1 /* MYUtilities_Release.xcconfig */; };
     7.7 +		27C6A22B0FC5D92000EFF2A7 /* TCPEndpoint+Certs.m in Sources */ = {isa = PBXBuildFile; fileRef = 27C6A22A0FC5D92000EFF2A7 /* TCPEndpoint+Certs.m */; };
     7.8  		27D915BF0FA8EABC002B0DEC /* MYDNSService.m in Sources */ = {isa = PBXBuildFile; fileRef = 27D915BC0FA8EABC002B0DEC /* MYDNSService.m */; };
     7.9  		27D915C00FA8EABC002B0DEC /* MYAddressLookup.m in Sources */ = {isa = PBXBuildFile; fileRef = 27D915BE0FA8EABC002B0DEC /* MYAddressLookup.m */; };
    7.10  		27D915C90FA8EAD0002B0DEC /* MYBonjourBrowser.m in Sources */ = {isa = PBXBuildFile; fileRef = 27D915C20FA8EAD0002B0DEC /* MYBonjourBrowser.m */; };
    7.11 @@ -147,6 +148,7 @@
    7.12  		278C1B2D0F9F865800954AE1 /* PortMapperTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PortMapperTest.m; sourceTree = "<group>"; };
    7.13  		278C1B330F9F86A100954AE1 /* MYUtilities_Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = MYUtilities_Debug.xcconfig; sourceTree = "<group>"; };
    7.14  		278C1B340F9F86A100954AE1 /* MYUtilities_Release.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = MYUtilities_Release.xcconfig; sourceTree = "<group>"; };
    7.15 +		27C6A22A0FC5D92000EFF2A7 /* TCPEndpoint+Certs.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "TCPEndpoint+Certs.m"; sourceTree = "<group>"; };
    7.16  		27D915BB0FA8EABC002B0DEC /* MYDNSService.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MYDNSService.h; path = PortMapper/MYDNSService.h; sourceTree = "<group>"; };
    7.17  		27D915BC0FA8EABC002B0DEC /* MYDNSService.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MYDNSService.m; path = PortMapper/MYDNSService.m; sourceTree = "<group>"; };
    7.18  		27D915BD0FA8EABC002B0DEC /* MYAddressLookup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MYAddressLookup.h; path = Bonjour/MYAddressLookup.h; sourceTree = "<group>"; };
    7.19 @@ -233,6 +235,7 @@
    7.20  				270E9AA50EE61113003F17CA /* TCPConnection.m */,
    7.21  				270E9AA60EE61113003F17CA /* TCPEndpoint.h */,
    7.22  				270E9AA70EE61113003F17CA /* TCPEndpoint.m */,
    7.23 +				27C6A22A0FC5D92000EFF2A7 /* TCPEndpoint+Certs.m */,
    7.24  				270E9AA80EE61113003F17CA /* TCPListener.h */,
    7.25  				270E9AA90EE61113003F17CA /* TCPListener.m */,
    7.26  				270E9AAA0EE61113003F17CA /* TCPStream.h */,
    7.27 @@ -519,6 +522,7 @@
    7.28  				27D915CB0FA8EAD0002B0DEC /* MYBonjourQuery.m in Sources */,
    7.29  				27D915CC0FA8EAD0002B0DEC /* MYBonjourRegistration.m in Sources */,
    7.30  				384A72B70FB0062C006A0B19 /* ConcurrentOperation.m in Sources */,
    7.31 +				27C6A22B0FC5D92000EFF2A7 /* TCPEndpoint+Certs.m in Sources */,
    7.32  			);
    7.33  			runOnlyForDeploymentPostprocessing = 0;
    7.34  		};
     8.1 --- a/MYNetwork.xcodeproj/project.pbxproj	Sat May 16 14:24:06 2009 -0700
     8.2 +++ b/MYNetwork.xcodeproj/project.pbxproj	Sun May 24 15:03:39 2009 -0700
     8.3 @@ -25,6 +25,9 @@
     8.4  		270461470DE491A6003D9D3F /* Target.m in Sources */ = {isa = PBXBuildFile; fileRef = 270461460DE491A6003D9D3F /* Target.m */; };
     8.5  		270461890DE49634003D9D3F /* CollectionUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 270461870DE49634003D9D3F /* CollectionUtils.m */; };
     8.6  		2706F1D90F9D3EF300292CCF /* SecurityInterface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2706F1D80F9D3EF300292CCF /* SecurityInterface.framework */; };
     8.7 +		27375DFB0FC9FB5C0033F8F5 /* TCPEndpoint+Certs.m in Sources */ = {isa = PBXBuildFile; fileRef = 27375DFA0FC9FB5C0033F8F5 /* TCPEndpoint+Certs.m */; };
     8.8 +		27375DFC0FC9FB5C0033F8F5 /* TCPEndpoint+Certs.m in Sources */ = {isa = PBXBuildFile; fileRef = 27375DFA0FC9FB5C0033F8F5 /* TCPEndpoint+Certs.m */; };
     8.9 +		27375DFD0FC9FB5C0033F8F5 /* TCPEndpoint+Certs.m in Sources */ = {isa = PBXBuildFile; fileRef = 27375DFA0FC9FB5C0033F8F5 /* TCPEndpoint+Certs.m */; };
    8.10  		273B457B0FA681EE00276298 /* MYBonjourRegistration.h in Headers */ = {isa = PBXBuildFile; fileRef = 273B45790FA681EE00276298 /* MYBonjourRegistration.h */; };
    8.11  		273B457C0FA681EE00276298 /* MYBonjourRegistration.m in Sources */ = {isa = PBXBuildFile; fileRef = 273B457A0FA681EE00276298 /* MYBonjourRegistration.m */; };
    8.12  		273B457D0FA681EE00276298 /* MYBonjourRegistration.m in Sources */ = {isa = PBXBuildFile; fileRef = 273B457A0FA681EE00276298 /* MYBonjourRegistration.m */; };
    8.13 @@ -168,6 +171,7 @@
    8.14  		270462C10DE4A64B003D9D3F /* MYUtilitiesTest_main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYUtilitiesTest_main.m; sourceTree = "<group>"; };
    8.15  		270462C30DE4A65B003D9D3F /* BLIP Overview.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = "BLIP Overview.txt"; path = "BLIP/BLIP Overview.txt"; sourceTree = "<group>"; wrapsLines = 1; };
    8.16  		2706F1D80F9D3EF300292CCF /* SecurityInterface.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SecurityInterface.framework; path = System/Library/Frameworks/SecurityInterface.framework; sourceTree = SDKROOT; };
    8.17 +		27375DFA0FC9FB5C0033F8F5 /* TCPEndpoint+Certs.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "TCPEndpoint+Certs.m"; sourceTree = "<group>"; };
    8.18  		273B45790FA681EE00276298 /* MYBonjourRegistration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYBonjourRegistration.h; sourceTree = "<group>"; };
    8.19  		273B457A0FA681EE00276298 /* MYBonjourRegistration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYBonjourRegistration.m; sourceTree = "<group>"; };
    8.20  		274122DD0F9CDD1600F21842 /* MYUtilities_Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = MYUtilities_Debug.xcconfig; sourceTree = "<group>"; };
    8.21 @@ -337,6 +341,7 @@
    8.22  				2704610A0DE49030003D9D3F /* TCPConnection.m */,
    8.23  				2704610B0DE49030003D9D3F /* TCPEndpoint.h */,
    8.24  				2704610C0DE49030003D9D3F /* TCPEndpoint.m */,
    8.25 +				27375DFA0FC9FB5C0033F8F5 /* TCPEndpoint+Certs.m */,
    8.26  				2704610D0DE49030003D9D3F /* TCPListener.h */,
    8.27  				2704610E0DE49030003D9D3F /* TCPListener.m */,
    8.28  				2704610F0DE49030003D9D3F /* TCPStream.h */,
    8.29 @@ -561,6 +566,7 @@
    8.30  			buildActionMask = 2147483647;
    8.31  			files = (
    8.32  				279DDCD10F9E38DD00D75D91 /* BLIPEchoClient.m in Sources */,
    8.33 +				27375DFC0FC9FB5C0033F8F5 /* TCPEndpoint+Certs.m in Sources */,
    8.34  			);
    8.35  			runOnlyForDeploymentPostprocessing = 0;
    8.36  		};
    8.37 @@ -569,6 +575,7 @@
    8.38  			buildActionMask = 2147483647;
    8.39  			files = (
    8.40  				277905240DE9E5BC00C6D295 /* BLIPEchoServer.m in Sources */,
    8.41 +				27375DFD0FC9FB5C0033F8F5 /* TCPEndpoint+Certs.m in Sources */,
    8.42  			);
    8.43  			runOnlyForDeploymentPostprocessing = 0;
    8.44  		};
    8.45 @@ -641,6 +648,7 @@
    8.46  				2780F43A0FA28F4400C0FB83 /* MYBonjourQuery.m in Sources */,
    8.47  				2780F4A30FA2C59000C0FB83 /* MYAddressLookup.m in Sources */,
    8.48  				273B457D0FA681EE00276298 /* MYBonjourRegistration.m in Sources */,
    8.49 +				27375DFB0FC9FB5C0033F8F5 /* TCPEndpoint+Certs.m in Sources */,
    8.50  			);
    8.51  			runOnlyForDeploymentPostprocessing = 0;
    8.52  		};
     9.1 --- a/TCP/TCPConnection.m	Sat May 16 14:24:06 2009 -0700
     9.2 +++ b/TCP/TCPConnection.m	Sun May 24 15:03:39 2009 -0700
     9.3 @@ -361,7 +361,8 @@
     9.4                      allow = NO; // Server MUST have a cert!
     9.5                  else {
     9.6                      SecCertificateRef cert = certs.count ?(SecCertificateRef)[certs objectAtIndex:0] :NULL;
     9.7 -                    LogTo(TCP,@"%@: Peer cert = %@",self,[TCPEndpoint describeCert: cert]);
     9.8 +                    if ([TCPEndpoint respondsToSelector: @selector(describeCert:)])
     9.9 +                        LogTo(TCP,@"%@: Peer cert = %@",self,[TCPEndpoint describeCert: cert]);
    9.10                      if( [_delegate respondsToSelector: @selector(connection:authorizeSSLPeer:)] )
    9.11                          allow = [_delegate connection: self authorizeSSLPeer: cert];
    9.12                  }
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/TCP/TCPEndpoint+Certs.m	Sun May 24 15:03:39 2009 -0700
    10.3 @@ -0,0 +1,53 @@
    10.4 +//
    10.5 +//  TCPEndpoint+Certs.m
    10.6 +//  MYNetwork-iPhone
    10.7 +//
    10.8 +//  Created by Jens Alfke on 5/21/09.
    10.9 +//  Copyright 2009 Jens Alfke. All rights reserved.
   10.10 +//
   10.11 +
   10.12 +#import "TCPEndpoint.h"
   10.13 +#import "CollectionUtils.h"
   10.14 +#import <Security/Security.h>
   10.15 +
   10.16 +
   10.17 +/** These are some optional category methods for TCPEndpoint for dumping info about certificates.
   10.18 +    They're useful if you're working with SSL connections, but they do link against the Security
   10.19 +    framework, so they're moved into this extra file that you can choose to compile into your
   10.20 +    project or not.
   10.21 +*/
   10.22 +@implementation TCPEndpoint (Certificates)
   10.23 +
   10.24 +
   10.25 ++ (NSString*) describeCert: (SecCertificateRef)cert {
   10.26 +    if (!cert)
   10.27 +        return @"(null)";
   10.28 +    NSString *desc;
   10.29 +#if TARGET_OS_IPHONE && !defined(__SEC_TYPES__)
   10.30 +    CFStringRef summary = NULL;
   10.31 +    SecCertificateCopySubjectSummary(cert);
   10.32 +    desc = $sprintf(@"Certificate[%@]", summary);
   10.33 +    if(summary) CFRelease(summary);
   10.34 +#else
   10.35 +    CFStringRef name=NULL;
   10.36 +    CFArrayRef emails=NULL;
   10.37 +    SecCertificateCopyCommonName(cert, &name);
   10.38 +    SecCertificateCopyEmailAddresses(cert, &emails);
   10.39 +    desc = $sprintf(@"Certificate[\"%@\", <%@>]",
   10.40 +                    name, [(NSArray*)emails componentsJoinedByString: @">, <"]);
   10.41 +    if(name) CFRelease(name);
   10.42 +    if(emails) CFRelease(emails);
   10.43 +#endif
   10.44 +    return desc;
   10.45 +}
   10.46 +
   10.47 ++ (NSString*) describeIdentity: (SecIdentityRef)identity {
   10.48 +    if (!identity)
   10.49 +        return @"(null)";
   10.50 +    SecCertificateRef cert;
   10.51 +    SecIdentityCopyCertificate(identity, &cert);
   10.52 +    return $sprintf(@"Identity[%@]", [self describeCert: cert]);
   10.53 +}
   10.54 +
   10.55 +
   10.56 +@end
    11.1 --- a/TCP/TCPEndpoint.m	Sat May 16 14:24:06 2009 -0700
    11.2 +++ b/TCP/TCPEndpoint.m	Sun May 24 15:03:39 2009 -0700
    11.3 @@ -69,37 +69,6 @@
    11.4  }
    11.5  
    11.6  
    11.7 -+ (NSString*) describeCert: (SecCertificateRef)cert {
    11.8 -    if (!cert)
    11.9 -        return @"(null)";
   11.10 -    NSString *desc;
   11.11 -#if TARGET_OS_IPHONE && !defined(__SEC_TYPES__)
   11.12 -    CFStringRef summary = NULL;
   11.13 -    SecCertificateCopySubjectSummary(cert);
   11.14 -    desc = $sprintf(@"Certificate[%@]", summary);
   11.15 -    if(summary) CFRelease(summary);
   11.16 -#else
   11.17 -    CFStringRef name=NULL;
   11.18 -    CFArrayRef emails=NULL;
   11.19 -    SecCertificateCopyCommonName(cert, &name);
   11.20 -    SecCertificateCopyEmailAddresses(cert, &emails);
   11.21 -    desc = $sprintf(@"Certificate[\"%@\", <%@>]",
   11.22 -                              name, [(NSArray*)emails componentsJoinedByString: @">, <"]);
   11.23 -    if(name) CFRelease(name);
   11.24 -    if(emails) CFRelease(emails);
   11.25 -#endif
   11.26 -    return desc;
   11.27 -}
   11.28 -
   11.29 -+ (NSString*) describeIdentity: (SecIdentityRef)identity {
   11.30 -    if (!identity)
   11.31 -        return @"(null)";
   11.32 -    SecCertificateRef cert;
   11.33 -    SecIdentityCopyCertificate(identity, &cert);
   11.34 -    return $sprintf(@"Identity[%@]", [self describeCert: cert]);
   11.35 -}
   11.36 -
   11.37 -
   11.38  @end
   11.39  
   11.40  
    12.1 --- a/TCP/TCPListener.m	Sat May 16 14:24:06 2009 -0700
    12.2 +++ b/TCP/TCPListener.m	Sun May 24 15:03:39 2009 -0700
    12.3 @@ -34,9 +34,19 @@
    12.4  @implementation TCPListener
    12.5  
    12.6  
    12.7 +- (id) init
    12.8 +{
    12.9 +    self = [super init];
   12.10 +    if (self != nil) {
   12.11 +        _connectionClass = [TCPConnection class];
   12.12 +    }
   12.13 +    return self;
   12.14 +}
   12.15 +
   12.16 +
   12.17  - (id) initWithPort: (UInt16)port
   12.18  {
   12.19 -    self = [super init];
   12.20 +    self = [self init];
   12.21      if (self != nil) {
   12.22          _port = port;
   12.23      }