More documentation.
5 // Created by Jens Alfke on 5/10/08.
6 // Copyright 2008 Jens Alfke. All rights reserved.
10 #import "TCP_Internal.h"
16 extern const CFStringRef _kCFStreamPropertySSLClientSideAuthentication; // in CFNetwork
18 static NSError* fixStreamError( NSError *error );
21 @implementation TCPStream
24 - (id) initWithConnection: (TCPConnection*)conn stream: (NSStream*)stream
28 _conn = [conn retain];
29 _stream = [stream retain];
30 _stream.delegate = self;
31 [_stream scheduleInRunLoop: [NSRunLoop currentRunLoop] forMode: NSRunLoopCommonModes];
32 LogTo(TCPVerbose,@"%@ initialized; status=%i", self,_stream.streamStatus);
40 LogTo(TCP,@"DEALLOC %@",self);
47 - (id) propertyForKey: (CFStringRef)cfStreamProperty
49 return nil; // abstract -- overridden by TCPReader and TCPWriter
52 - (void) setProperty: (id)value forKey: (CFStringRef)cfStreamProperty
53 { // abstract -- overridden by TCPReader and TCPWriter
61 - (NSString*) securityLevel {return [_stream propertyForKey: NSStreamSocketSecurityLevelKey];}
63 - (NSDictionary*) SSLProperties {return [self propertyForKey: kCFStreamPropertySSLSettings];}
65 - (void) setSSLProperties: (NSDictionary*)p
67 LogTo(TCPVerbose,@"%@ SSL settings := %@",self,p);
68 [self setProperty: p forKey: kCFStreamPropertySSLSettings];
70 id clientAuth = [p objectForKey: kTCPPropertySSLClientSideAuthentication];
72 [self setProperty: clientAuth forKey: _kCFStreamPropertySSLClientSideAuthentication];
75 - (NSArray*) peerSSLCerts
78 return [self propertyForKey: kCFStreamPropertySSLPeerCertificates];
83 #pragma mark OPENING/CLOSING:
89 AssertEq(_stream.streamStatus,NSStreamStatusNotOpen);
90 LogTo(TCP,@"Opening %@",self);
98 LogTo(TCP,@"Disconnect %@",self);
99 _stream.delegate = nil;
101 setObj(&_stream,nil);
113 LogTo(TCP,@"Closing %@",self);
114 [[self retain] autorelease]; // don't let myself be dealloced in the midst of this
115 [_conn _streamClosed: self]; // have to do this before disconnect
124 NSStreamStatus status = _stream.streamStatus;
125 return status >= NSStreamStatusOpen && status < NSStreamStatusAtEnd;
130 return NO; // abstract
136 [_conn _streamOpened: self];
152 [self _gotError: [NSError errorWithDomain: NSPOSIXErrorDomain code: ECONNRESET userInfo: nil]];
155 [_conn _streamGotEOF: self];
161 - (BOOL) _gotError: (NSError*)error
163 [_conn _stream: self gotError: fixStreamError(error)];
169 NSError *error = _stream.streamError;
171 error = [NSError errorWithDomain: NSPOSIXErrorDomain code: EIO userInfo: nil]; //fallback
172 return [self _gotError: error];
176 - (void) stream: (NSStream*)stream handleEvent: (NSStreamEvent)streamEvent
178 [[self retain] autorelease];
179 switch(streamEvent) {
180 case NSStreamEventOpenCompleted:
181 LogTo(TCPVerbose,@"%@ opened",self);
184 case NSStreamEventHasBytesAvailable:
185 if( ! [_conn _streamPeerCertAvailable: self] )
187 LogTo(TCPVerbose,@"%@ can read",self);
190 case NSStreamEventHasSpaceAvailable:
191 if( ! [_conn _streamPeerCertAvailable: self] )
193 LogTo(TCPVerbose,@"%@ can write",self);
196 case NSStreamEventErrorOccurred:
197 LogTo(TCPVerbose,@"%@ got error",self);
200 case NSStreamEventEndEncountered:
201 LogTo(TCPVerbose,@"%@ got EOF",self);
205 Warn(@"%@: unknown NSStreamEvent %i",self,streamEvent);
209 // If I was previously asked to close, try again in case I'm no longer busy
220 @implementation TCPReader
223 - (TCPWriter*) writer
229 - (id) propertyForKey: (CFStringRef)cfStreamProperty
231 CFTypeRef value = CFReadStreamCopyProperty((CFReadStreamRef)_stream,cfStreamProperty);
232 return [(id)CFMakeCollectable(value) autorelease];
235 - (void) setProperty: (id)value forKey: (CFStringRef)cfStreamProperty
237 if( ! CFReadStreamSetProperty((CFReadStreamRef)_stream,cfStreamProperty,(CFTypeRef)value) )
238 Warn(@"%@ didn't accept property '%@'", self,cfStreamProperty);
242 - (NSInteger) read: (void*)dst maxLength: (NSUInteger)maxLength
244 NSInteger bytesRead = [(NSInputStream*)_stream read:dst maxLength: maxLength];
256 static NSError* fixStreamError( NSError *error )
258 // NSStream incorrectly returns SSL errors without the correct error domain:
259 if( $equal(error.domain,@"NSUnknownErrorDomain") ) {
260 int code = error.code;
261 if( -9899 <= code && code <= -9800 ) {
262 NSMutableDictionary *userInfo = error.userInfo.mutableCopy;
263 if( ! [userInfo objectForKey: NSLocalizedFailureReasonErrorKey] ) {
264 // look up error message:
265 NSBundle *secBundle = [NSBundle bundleWithPath: @"/System/Library/Frameworks/Security.framework"];
266 NSString *message = [secBundle localizedStringForKey: $sprintf(@"%i",code)
268 table: @"SecErrorMessages"];
270 if( ! userInfo ) userInfo = $mdict();
271 [userInfo setObject: message forKey: NSLocalizedFailureReasonErrorKey];
274 error = [NSError errorWithDomain: NSStreamSocketSSLErrorDomain
275 code: code userInfo: userInfo];
277 Warn(@"NSStream returned error with unknown domain: %@",error);
283 Copyright (c) 2008, Jens Alfke <jens@mooseyard.com>. All rights reserved.
285 Redistribution and use in source and binary forms, with or without modification, are permitted
286 provided that the following conditions are met:
288 * Redistributions of source code must retain the above copyright notice, this list of conditions
289 and the following disclaimer.
290 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
291 and the following disclaimer in the documentation and/or other materials provided with the
294 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
295 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
296 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
297 BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
298 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
299 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
300 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
301 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.