Added -[TCPConnection initToNetService:] to make it easier to use with Bonjour. This allowed me to simplify BLIPEchoClient quite a lot.
5 // Created by Jens Alfke on 5/10/08.
6 // Copyright 2008 Jens Alfke. All rights reserved.
10 #import "TCP_Internal.h"
17 extern const CFStringRef _kCFStreamPropertySSLClientSideAuthentication; // in CFNetwork
19 static NSError* fixStreamError( NSError *error );
22 @implementation TCPStream
25 - (id) initWithConnection: (TCPConnection*)conn stream: (NSStream*)stream
29 _conn = [conn retain];
30 _stream = [stream retain];
31 _stream.delegate = self;
32 [_stream scheduleInRunLoop: [NSRunLoop currentRunLoop] forMode: NSRunLoopCommonModes];
33 LogTo(TCPVerbose,@"%@ initialized; status=%i", self,_stream.streamStatus);
41 LogTo(TCP,@"DEALLOC %@",self);
48 - (id) propertyForKey: (CFStringRef)cfStreamProperty
50 return [_stream propertyForKey: (NSString*)cfStreamProperty];
53 - (void) setProperty: (id)value forKey: (CFStringRef)cfStreamProperty
55 if( ! [_stream setProperty: value forKey: (NSString*)cfStreamProperty] )
56 Warn(@"Failed to set property %@ on %@",cfStreamProperty,self);
60 - (IPAddress*) peerAddress
62 const CFSocketNativeHandle *socketPtr = [[self propertyForKey: kCFStreamPropertySocketNativeHandle] bytes];
63 return socketPtr ?[IPAddress addressOfSocket: *socketPtr] :nil;
71 - (NSString*) securityLevel {return [_stream propertyForKey: NSStreamSocketSecurityLevelKey];}
73 - (NSDictionary*) SSLProperties {return [self propertyForKey: kCFStreamPropertySSLSettings];}
75 - (void) setSSLProperties: (NSDictionary*)p
77 LogTo(TCPVerbose,@"%@ SSL settings := %@",self,p);
78 [self setProperty: p forKey: kCFStreamPropertySSLSettings];
80 id clientAuth = [p objectForKey: kTCPPropertySSLClientSideAuthentication];
82 [self setProperty: clientAuth forKey: _kCFStreamPropertySSLClientSideAuthentication];
85 - (NSArray*) peerSSLCerts
88 return [self propertyForKey: kCFStreamPropertySSLPeerCertificates];
93 #pragma mark OPENING/CLOSING:
99 AssertEq(_stream.streamStatus,NSStreamStatusNotOpen);
100 LogTo(TCP,@"Opening %@",self);
108 LogTo(TCP,@"Disconnect %@",self);
109 _stream.delegate = nil;
111 setObj(&_stream,nil);
123 LogTo(TCP,@"Closing %@",self);
124 [[self retain] autorelease]; // don't let myself be dealloced in the midst of this
125 [_conn _streamClosed: self]; // have to do this before disconnect
134 NSStreamStatus status = _stream.streamStatus;
135 return status >= NSStreamStatusOpen && status < NSStreamStatusAtEnd;
140 return NO; // abstract
146 [_conn _streamOpened: self];
162 [self _gotError: [NSError errorWithDomain: NSPOSIXErrorDomain code: ECONNRESET userInfo: nil]];
165 [_conn _streamGotEOF: self];
171 - (BOOL) _gotError: (NSError*)error
173 [_conn _stream: self gotError: fixStreamError(error)];
179 NSError *error = _stream.streamError;
181 error = [NSError errorWithDomain: NSPOSIXErrorDomain code: EIO userInfo: nil]; //fallback
182 return [self _gotError: error];
186 - (void) stream: (NSStream*)stream handleEvent: (NSStreamEvent)streamEvent
188 [[self retain] autorelease];
189 switch(streamEvent) {
190 case NSStreamEventOpenCompleted:
191 LogTo(TCPVerbose,@"%@ opened",self);
194 case NSStreamEventHasBytesAvailable:
195 if( ! [_conn _streamPeerCertAvailable: self] )
197 LogTo(TCPVerbose,@"%@ can read",self);
200 case NSStreamEventHasSpaceAvailable:
201 if( ! [_conn _streamPeerCertAvailable: self] )
203 LogTo(TCPVerbose,@"%@ can write",self);
206 case NSStreamEventErrorOccurred:
207 LogTo(TCPVerbose,@"%@ got error",self);
210 case NSStreamEventEndEncountered:
211 LogTo(TCPVerbose,@"%@ got EOF",self);
215 Warn(@"%@: unknown NSStreamEvent %i",self,streamEvent);
219 // If I was previously asked to close, try again in case I'm no longer busy
230 @implementation TCPReader
233 - (TCPWriter*) writer
238 - (NSInteger) read: (void*)dst maxLength: (NSUInteger)maxLength
240 NSInteger bytesRead = [(NSInputStream*)_stream read:dst maxLength: maxLength];
252 static NSError* fixStreamError( NSError *error )
254 // NSStream incorrectly returns SSL errors without the correct error domain:
255 if( $equal(error.domain,@"NSUnknownErrorDomain") ) {
256 int code = error.code;
257 if( -9899 <= code && code <= -9800 ) {
258 NSMutableDictionary *userInfo = error.userInfo.mutableCopy;
259 if( ! [userInfo objectForKey: NSLocalizedFailureReasonErrorKey] ) {
260 // look up error message:
261 NSBundle *secBundle = [NSBundle bundleWithPath: @"/System/Library/Frameworks/Security.framework"];
262 NSString *message = [secBundle localizedStringForKey: $sprintf(@"%i",code)
264 table: @"SecErrorMessages"];
266 if( ! userInfo ) userInfo = $mdict();
267 [userInfo setObject: message forKey: NSLocalizedFailureReasonErrorKey];
270 error = [NSError errorWithDomain: NSStreamSocketSSLErrorDomain
271 code: code userInfo: userInfo];
273 Warn(@"NSStream returned error with unknown domain: %@",error);
279 Copyright (c) 2008, Jens Alfke <jens@mooseyard.com>. All rights reserved.
281 Redistribution and use in source and binary forms, with or without modification, are permitted
282 provided that the following conditions are met:
284 * Redistributions of source code must retain the above copyright notice, this list of conditions
285 and the following disclaimer.
286 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
287 and the following disclaimer in the documentation and/or other materials provided with the
290 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
291 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
292 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
293 BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
294 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
295 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
296 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
297 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.