/* * Grouch.app Copyright (C) 2006 Andy Sveikauskas * ------------------------------------------------------------------------ * This program is free software under the GNU General Public License * -- * Implementation of sockets using NSStream. Used only on Mac OS. * However, latest GNUstep does support this. */ #import #ifdef USE_NSSTREAM #import #import #import #import #import #import #import #import #import #import @implementation GrouchSocketMac + socketForHost:(NSString*)host atPort:(int)port withRunLoop:(NSRunLoop*)loop forSocket:(GrouchSocket*)sock { GrouchSocketMac *r = [self alloc]; NS_DURING [r initForHost:host atPort:port withRunLoop:loop forSocket:sock]; NS_HANDLER [r release]; [localException raise]; NS_ENDHANDLER return r; } - initForHost:(NSString*)str atPort:(int)port withRunLoop:(NSRunLoop*)loop forSocket:(GrouchSocket*)s { [super init]; writeThreadLive = NO; fd = s; NS_DURING [NSStream getStreamsToHost:[NSHost hostWithName:str] port:port inputStream:&in outputStream:&out]; [in retain]; [out retain]; [in setDelegate:self]; [out setDelegate:self]; if( loop && [loop isKindOfClass:[GrouchRunLoopHack class]] ) { NSInvocation *call; SEL sel = @selector(_startReadThread); call = [NSInvocation invocationWithMethodSignature: [self methodSignatureForSelector:sel]]; [call setTarget:self]; [call setSelector:sel]; [call retainArguments]; [(GrouchRunLoopHack*)loop addInvocation:call]; } else [in scheduleInRunLoop:loop forMode:NSDefaultRunLoopMode]; [in open]; [out open]; NS_HANDLER [GrouchException raiseSocketExceptionForHost:str withReason:[localException reason]]; NS_ENDHANDLER if( loop && [loop isKindOfClass:[GrouchRunLoopHack class]] ) { [(GrouchRunLoopHack*)loop invalidate]; loop = nil; } return self; } - (void)dealloc { if(in) { NS_DURING [in close]; NS_HANDLER NS_ENDHANDLER [in release]; } if(out) { NS_DURING [out close]; NS_HANDLER NS_ENDHANDLER [out release]; } [super dealloc]; } - (int)write:(const void*)buf length:(int)len { return [out write:buf maxLength:len]; } - (int)read:(void *)buf length:(int)len { if( ![in hasBytesAvailable] ) return 0; return [in read:buf maxLength:len]; } - (BOOL)lastOperationWasError { return [in streamStatus] == NSStreamStatusError || [out streamStatus] == NSStreamStatusError; } - (void)_startReadThread { [in scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; } - (void)startWriteThread { if( !writeThreadLive ) { NSRunLoop *loop = [NSRunLoop currentRunLoop]; [out scheduleInRunLoop:loop forMode:NSDefaultRunLoopMode]; writeThreadLive = YES; } } - (void)setBlocking:(BOOL)b { } - (GrouchSocketEvent)pollSocketEvents { return 0; } - (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)ev { int r = 0; if( (ev&NSStreamEventHasBytesAvailable) ) r |= GrouchSocketEventIn; if( (ev&NSStreamEventHasSpaceAvailable) ) r |= GrouchSocketEventOut; if( (ev&(NSStreamEventErrorOccurred|NSStreamEventEndEncountered)) ) { r |= GrouchSocketEventError; [stream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; } [fd eventLoop:r]; if( writeThreadLive && ![fd outBufferSize] ) { NSString *mode = NSDefaultRunLoopMode; [out removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:mode]; writeThreadLive = NO; } } @end #endif