From 85ada8322a6f066ef9c48e9db80d37fcbfdfbe84 Mon Sep 17 00:00:00 2001 From: rfm Date: Tue, 8 Aug 2006 13:31:50 +0000 Subject: [PATCH] macosx compatibility fixes git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@23215 72102866-910b-0410-8b05-ffd578937521 --- ChangeLog | 8 +- Source/GSStream.h | 6 + Source/GSStream.m | 53 +++++- Source/unix/NSStream.m | 36 ++-- Source/win32/NSStreamWin32.m | 356 ++++++++++++++++++----------------- 5 files changed, 261 insertions(+), 198 deletions(-) diff --git a/ChangeLog b/ChangeLog index d813c1f2a..3d0535472 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,9 +1,13 @@ -2006-08-07 Richard Frith-Macdonald +2006-08-08 Richard Frith-Macdonald + * Source/GSStream.h: + * Source/GSStream.m: * Source/win32/NSStreamWin32.m: * Source/unix/NSStream.m: - If a connection attampt fails, propogate error to sibling stream so + If a connection attempt fails, propagate error to sibling stream so both streams in the pair get a failure. + Try to make behavior of socket streams MacOs-X like, avoiding repeated + notifications of events. 2006-08-07 00:13-EDT Gregory John Casamento diff --git a/Source/GSStream.h b/Source/GSStream.h index dd8833aa4..fb9f9adb2 100644 --- a/Source/GSStream.h +++ b/Source/GSStream.h @@ -68,6 +68,7 @@ id _delegate; /* Delegate controls operation. */\ NSMutableDictionary *_properties; /* storage for properties */\ BOOL _delegateValid;/* whether the delegate responds*/\ + BOOL _unhandledData; /* no read/write since event */\ NSError *_lastError; /* last error occured */\ NSStreamStatus _currentStatus;/* current status */\ NSMutableArray *_modes; /* currently scheduled modes. */\ @@ -121,6 +122,11 @@ IVARS * record an error based on errno */ - (void) _recordError; + +/** + * say whether there is unahdnled data for the stream. + */ +- (BOOL) _unhandledData; @end @interface GSInputStream : NSInputStream diff --git a/Source/GSStream.m b/Source/GSStream.m index 494e57eb3..22dec229c 100644 --- a/Source/GSStream.m +++ b/Source/GSStream.m @@ -318,6 +318,10 @@ static RunLoopEventType typeForStream(NSStream *aStream) { } +- (BOOL) _unhandledData +{ + return NO; +} @end @implementation GSStream (Private) @@ -351,7 +355,17 @@ static RunLoopEventType typeForStream(NSStream *aStream) - (void) _sendEvent: (NSStreamEvent)event { - if (_delegateValid) + if (event == NSStreamEventHasSpaceAvailable + || event == NSStreamEventHasBytesAvailable) + { + /* If we have a data event, we mark the stream as having unhandled + * data (so we can refrain from triggering again) until a read or + * write operation (as approriate) has been performed. + */ + _unhandledData = YES; + _unhandledData = YES; + } + if (_delegateValid == YES) { [(id )_delegate stream: self handleEvent: event]; } @@ -372,6 +386,38 @@ static RunLoopEventType typeForStream(NSStream *aStream) } } +- (BOOL) _unhandledData +{ + return _unhandledData; +} + +- (BOOL) runLoopShouldBlock: (BOOL*)trigger +{ + if (_unhandledData == YES + || _currentStatus == NSStreamStatusError) + { + /* If we have an unhandled data event, we should not watch for more + * or trigger until the appropriate rad or write has been done. + * If an error has occurred, we should not watch for any events at all. + */ + *trigger = NO; + return NO; + } + else if (_loopID == (void*)self) + { + /* If _loopID is the receiver, the stream is not receiving external + * input, so it must trigger an event when the loop runs and must not + * block the loop from running. + */ + *trigger = YES; + return NO; + } + else + { + *trigger = YES; + return YES; + } +} @end @implementation GSInputStream @@ -432,6 +478,7 @@ static RunLoopEventType typeForStream(NSStream *aStream) unsigned long dataSize = [_data length]; unsigned long copySize; + _unhandledData = NO; NSAssert(dataSize >= _pointer, @"Buffer overflow!"); if (len + _pointer > dataSize) { @@ -482,8 +529,7 @@ static RunLoopEventType typeForStream(NSStream *aStream) BOOL av = [self hasBytesAvailable]; NSStreamEvent myEvent = av ? NSStreamEventHasBytesAvailable : NSStreamEventEndEncountered; - NSStreamStatus myStatus = av ? NSStreamStatusReading : - NSStreamStatusAtEnd; + NSStreamStatus myStatus = av ? NSStreamStatusOpen : NSStreamStatusAtEnd; [self _setStatus: myStatus]; [self _sendEvent: myEvent]; @@ -523,6 +569,7 @@ static RunLoopEventType typeForStream(NSStream *aStream) - (int) write: (const uint8_t *)buffer maxLength: (unsigned int)len { + _unhandledData = NO; if (_fixedSize) { unsigned long dataLen = [_data length]; diff --git a/Source/unix/NSStream.m b/Source/unix/NSStream.m index 48c47e8a7..34a9b5de2 100644 --- a/Source/unix/NSStream.m +++ b/Source/unix/NSStream.m @@ -297,6 +297,7 @@ static void setNonblocking(int fd) { int readLen; + _unhandledData = NO; readLen = read((intptr_t)_loopID, buffer, len); if (readLen < 0 && errno != EAGAIN && errno != EINTR) [self _recordError]; @@ -353,15 +354,6 @@ static void setNonblocking(int fd) [super close]; } -- (void) _dispatch -{ - NSStreamEvent myEvent; - - [self _setStatus: NSStreamStatusReading]; - myEvent = NSStreamEventHasBytesAvailable; - [self _sendEvent: myEvent]; -} - @end @implementation GSSocketInputStream @@ -472,6 +464,7 @@ static void setNonblocking(int fd) { int readLen; + _unhandledData = NO; readLen = read((intptr_t)_loopID, buffer, len); if (readLen < 0 && errno != EAGAIN && errno != EINTR) [self _recordError]; @@ -507,7 +500,8 @@ static void setNonblocking(int fd) { [_runloop removeStream: self mode: [_modes objectAtIndex: i]]; } - result = getsockopt((intptr_t)_loopID, SOL_SOCKET, SO_ERROR, &error, &len); + result + = getsockopt((intptr_t)_loopID, SOL_SOCKET, SO_ERROR, &error, &len); if (result >= 0 && !error) { // finish up the opening @@ -530,7 +524,7 @@ static void setNonblocking(int fd) } else { - [self _setStatus: NSStreamStatusReading]; + [self _setStatus: NSStreamStatusOpen]; myEvent = NSStreamEventHasBytesAvailable; } [self _sendEvent: myEvent]; @@ -666,6 +660,8 @@ static void setNonblocking(int fd) - (int) write: (const uint8_t *)buffer maxLength: (unsigned int)len { int writeLen; + + _unhandledData = NO; writeLen = write((intptr_t)_loopID, buffer, len); if (writeLen < 0 && errno != EAGAIN && errno != EINTR) [self _recordError]; @@ -720,15 +716,6 @@ static void setNonblocking(int fd) return [super propertyForKey: key]; } -- (void) _dispatch -{ - NSStreamEvent myEvent; - - [self _setStatus: NSStreamStatusWriting]; - myEvent = NSStreamEventHasSpaceAvailable; - [self _sendEvent: myEvent]; -} - @end @implementation GSSocketOutputStream @@ -776,6 +763,8 @@ static void setNonblocking(int fd) - (int) write: (const uint8_t *)buffer maxLength: (unsigned int)len { int writeLen; + + _unhandledData = NO; writeLen = write((intptr_t)_loopID, buffer, len); if (writeLen < 0 && errno != EAGAIN && errno != EINTR) [self _recordError]; @@ -868,7 +857,8 @@ static void setNonblocking(int fd) { [_runloop removeStream: self mode: [_modes objectAtIndex: i]]; } - result = getsockopt((intptr_t)_loopID, SOL_SOCKET, SO_ERROR, &error, &len); + result + = getsockopt((intptr_t)_loopID, SOL_SOCKET, SO_ERROR, &error, &len); if (result >= 0 && !error) { // finish up the opening myEvent = NSStreamEventOpenCompleted; @@ -890,7 +880,7 @@ static void setNonblocking(int fd) } else { - [self _setStatus: NSStreamStatusWriting]; + [self _setStatus: NSStreamStatusOpen]; myEvent = NSStreamEventHasSpaceAvailable; } [self _sendEvent: myEvent]; @@ -1411,7 +1401,7 @@ static void setNonblocking(int fd) { NSStreamEvent myEvent; - [self _setStatus: NSStreamStatusReading]; + [self _setStatus: NSStreamStatusOpen]; myEvent = NSStreamEventHasBytesAvailable; [self _sendEvent: myEvent]; } diff --git a/Source/win32/NSStreamWin32.m b/Source/win32/NSStreamWin32.m index d7dab8e3d..cdc8ce11c 100644 --- a/Source/win32/NSStreamWin32.m +++ b/Source/win32/NSStreamWin32.m @@ -324,6 +324,7 @@ static void setNonblocking(SOCKET fd) { DWORD readLen; + _unhandledData = NO; if (ReadFile((HANDLE)_loopID, buffer, len, &readLen, NULL) == 0) { [self _recordError]; @@ -342,7 +343,7 @@ static void setNonblocking(SOCKET fd) BOOL av = [self hasBytesAvailable]; NSStreamEvent myEvent = av ? NSStreamEventHasBytesAvailable : NSStreamEventEndEncountered; - NSStreamStatus myStatus = av ? NSStreamStatusReading : + NSStreamStatus myStatus = av ? NSStreamStatusOpen : NSStreamStatusAtEnd; [self _setStatus: myStatus]; @@ -502,6 +503,7 @@ static void setNonblocking(SOCKET fd) { NSStreamStatus myStatus = [self streamStatus]; + _unhandledData = NO; if (myStatus == NSStreamStatusReading) { myStatus = [self _check]; @@ -587,6 +589,11 @@ static void setNonblocking(SOCKET fd) { NSStreamStatus myStatus = [self streamStatus]; + if (_unhandledData == YES || myStatus == NSStreamStatusError) + { + *trigger = NO; + return NO; + } *trigger = YES; if (myStatus == NSStreamStatusReading) { @@ -712,19 +719,28 @@ static void setNonblocking(SOCKET fd) { int readLen; + _unhandledData = NO; readLen = recv(_sock, buffer, len, 0); if (readLen == SOCKET_ERROR) { errno = WSAGetLastError(); if (errno == WSAEINPROGRESS || errno == WSAEWOULDBLOCK) - [self _setStatus: NSStreamStatusReading]; + { + [self _setStatus: NSStreamStatusReading]; + } else if (errno != WSAEINTR) - [self _recordError]; + { + [self _recordError]; + } } else if (readLen == 0) - [self _setStatus: NSStreamStatusAtEnd]; + { + [self _setStatus: NSStreamStatusAtEnd]; + } else - [self _setStatus: NSStreamStatusOpen]; + { + [self _setStatus: NSStreamStatusOpen]; + } return readLen; } @@ -742,98 +758,95 @@ static void setNonblocking(SOCKET fd) - (void) _dispatch { - NSStreamStatus myStatus; - WSANETWORKEVENTS ocurredEvents; - int error, getReturn; - unsigned len = sizeof(error); - - /* - * it is possible the stream is closed yet recieving event because - * of not closed sibling - */ if ([self streamStatus] == NSStreamStatusClosed) { + /* + * It is possible the stream is closed yet recieving event because + * of not closed sibling + */ NSAssert([_sibling streamStatus] != NSStreamStatusClosed, - @"Received event for closed stream"); + @"Received event for closed stream"); [_sibling _dispatch]; - return; - } - - if (WSAEnumNetworkEvents(_sock, _loopID, &ocurredEvents) == SOCKET_ERROR) - { - errno = WSAGetLastError(); - [self _recordError]; - } - else if ([self streamStatus] == NSStreamStatusOpening) - { - unsigned i = [_modes count]; - - while (i-- > 0) - { - [_runloop removeStream: self mode: [_modes objectAtIndex: i]]; - } - getReturn = getsockopt(_sock, SOL_SOCKET, SO_ERROR, - (char*)&error, &len); - - if (getReturn >= 0 && !error - && (ocurredEvents.lNetworkEvents & FD_CONNECT)) - { // finish up the opening - ocurredEvents.lNetworkEvents ^= FD_CONNECT; - _passive = YES; - [self open]; - [self _sendEvent: NSStreamEventOpenCompleted]; - // notify sibling - if (_sibling) - { - [_sibling open]; - [_sibling _sendEvent: NSStreamEventOpenCompleted]; - } - } - else // must be an error - { - if (error) - errno = error; - [self _recordError]; - if (_sibling) - { - [_sibling _recordError]; - [_sibling _sendEvent: NSStreamEventOpenCompleted]; - } - } } else { - if (ocurredEvents.lNetworkEvents & FD_READ) - { - ocurredEvents.lNetworkEvents ^= FD_READ; - [self _setStatus: NSStreamStatusOpen]; - } - if ((ocurredEvents.lNetworkEvents & FD_WRITE) - && (_sibling && [_sibling _isOpened])) - { - ocurredEvents.lNetworkEvents ^= FD_WRITE; - [_sibling _setStatus: NSStreamStatusOpen]; - } - } + WSANETWORKEVENTS events; + int error = 0; + int getReturn = -1; - myStatus = [self streamStatus]; - switch (myStatus) - { - case NSStreamStatusError: + if (WSAEnumNetworkEvents(_sock, _loopID, &events) == SOCKET_ERROR) { + error = WSAGetLastError(); + } +else NSLog(@"EVENTS:%x", events.lNetworkEvents); + + if ([self streamStatus] == NSStreamStatusOpening) + { + unsigned i = [_modes count]; + + while (i-- > 0) + { + [_runloop removeStream: self mode: [_modes objectAtIndex: i]]; + } + if (error == 0) + { + unsigned len = sizeof(error); + + getReturn = getsockopt(_sock, SOL_SOCKET, SO_ERROR, + (char*)&error, &len); + } + + if (getReturn >= 0 && error == 0 + && (events.lNetworkEvents & FD_CONNECT)) + { // finish up the opening + _passive = YES; + [self open]; + // notify sibling + if (_sibling) + { + [_sibling open]; + [_sibling _sendEvent: NSStreamEventOpenCompleted]; + } + [self _sendEvent: NSStreamEventOpenCompleted]; + } + } + + if (error != 0) + { + errno = error; + [self _recordError]; + [_sibling _recordError]; [self _sendEvent: NSStreamEventErrorOccurred]; - break; + [_sibling _sendEvent: NSStreamEventErrorOccurred]; } - case NSStreamStatusOpen: + else { - [self _sendEvent: NSStreamEventHasBytesAvailable]; - break; + if (events.lNetworkEvents & FD_WRITE) + { + [_sibling _setStatus: NSStreamStatusOpen]; + [_sibling _sendEvent: NSStreamEventHasSpaceAvailable]; + } + if (events.lNetworkEvents & FD_READ) + { + [self _setStatus: NSStreamStatusOpen]; + [self _sendEvent: NSStreamEventHasBytesAvailable]; + } + if (events.lNetworkEvents & FD_CLOSE) + { + [_sibling _setStatus: NSStreamStatusAtEnd]; + [_sibling _sendEvent: NSStreamEventEndEncountered]; + while ([self streamStatus] == NSStreamStatusOpen + && _unhandledData == NO) + { + [self _sendEvent: NSStreamEventHasBytesAvailable]; + } + if ([self streamStatus] == NSStreamStatusAtEnd) + { + [self _sendEvent: NSStreamEventEndEncountered]; + } + } } - default: - break; } - if (_sibling && [_sibling _isOpened]) - [_sibling _dispatch]; } @end @@ -871,12 +884,6 @@ static void setNonblocking(SOCKET fd) @implementation GSFileOutputStream -- (void) close -{ - if (CloseHandle((HANDLE)_loopID) == 0) - [self _recordError]; - [super close]; -} - (void) dealloc { @@ -947,6 +954,7 @@ static void setNonblocking(SOCKET fd) { DWORD writeLen; + _unhandledData = NO; if (_shouldAppend == YES) { SetFilePointer((HANDLE)_loopID, 0, 0, FILE_END); @@ -1061,6 +1069,7 @@ static void setNonblocking(SOCKET fd) { NSStreamStatus myStatus = [self streamStatus]; + _unhandledData = NO; if (len < 0) { return -1; @@ -1152,6 +1161,11 @@ static void setNonblocking(SOCKET fd) { NSStreamStatus myStatus = [self streamStatus]; + if (_unhandledData == YES || myStatus == NSStreamStatusError) + { + *trigger = NO; + return NO; + } *trigger = YES; if (myStatus == NSStreamStatusWriting) { @@ -1218,6 +1232,7 @@ static void setNonblocking(SOCKET fd) { int writeLen; + _unhandledData = NO; writeLen = send(_sock, buffer, len, 0); if (writeLen == SOCKET_ERROR) { @@ -1304,96 +1319,97 @@ static void setNonblocking(SOCKET fd) - (void) _dispatch { - NSStreamStatus myStatus; - WSANETWORKEVENTS ocurredEvents; - int error, getReturn; - unsigned len = sizeof(error); - - /* - * it is possible the stream is closed yet recieving event - * because of not closed sibling - */ if ([self streamStatus] == NSStreamStatusClosed) { + /* + * It is possible the stream is closed yet recieving event because + * of not closed sibling + */ NSAssert([_sibling streamStatus] != NSStreamStatusClosed, @"Received event for closed stream"); [_sibling _dispatch]; - return; - } - - if (WSAEnumNetworkEvents(_sock, _loopID, &ocurredEvents) == SOCKET_ERROR) - { - errno = WSAGetLastError(); - [self _recordError]; - } - else if ([self streamStatus] == NSStreamStatusOpening) - { - unsigned i = [_modes count]; - - while (i-- > 0) - { - [_runloop removeStream: self mode: [_modes objectAtIndex: i]]; - } - getReturn = getsockopt(_sock, SOL_SOCKET, SO_ERROR, - (char*)&error, &len); - - if (getReturn >= 0 && !error - && (ocurredEvents.lNetworkEvents & FD_CONNECT)) - { // finish up the opening - ocurredEvents.lNetworkEvents ^= FD_CONNECT; - _passive = YES; - [self open]; - // notify sibling - if (_sibling) - { - [_sibling open]; - [_sibling _sendEvent: NSStreamEventOpenCompleted]; - } - } - else // must be an error - { - if (error) - errno = error; - [self _recordError]; - if (_sibling) - { - [_sibling _recordError]; - [_sibling _sendEvent: NSStreamEventOpenCompleted]; - } - } } else { - if ((ocurredEvents.lNetworkEvents & FD_READ) && - (_sibling && [_sibling _isOpened])) - { - ocurredEvents.lNetworkEvents ^= FD_READ; - [_sibling _setStatus: NSStreamStatusOpen]; - } - if (ocurredEvents.lNetworkEvents & FD_WRITE) - { - ocurredEvents.lNetworkEvents ^= FD_WRITE; - [self _setStatus: NSStreamStatusOpen]; - } - } - myStatus = [self streamStatus]; - switch (myStatus) - { - case NSStreamStatusError: + WSANETWORKEVENTS events; + int error = 0; + int getReturn = -1; + + if (WSAEnumNetworkEvents(_sock, _loopID, &events) == SOCKET_ERROR) { + error = WSAGetLastError(); + } +else NSLog(@"EVENTS:%x", events.lNetworkEvents); + + if ([self streamStatus] == NSStreamStatusOpening) + { + unsigned i = [_modes count]; + + while (i-- > 0) + { + [_runloop removeStream: self mode: [_modes objectAtIndex: i]]; + } + + if (error == 0) + { + unsigned len = sizeof(error); + + getReturn = getsockopt(_sock, SOL_SOCKET, SO_ERROR, + (char*)&error, &len); + } + + if (getReturn >= 0 && error == 0 + && (events.lNetworkEvents & FD_CONNECT)) + { // finish up the opening + events.lNetworkEvents ^= FD_CONNECT; + _passive = YES; + [self open]; + // notify sibling + if (_sibling) + { + [_sibling open]; + [_sibling _sendEvent: NSStreamEventOpenCompleted]; + } + [self _sendEvent: NSStreamEventOpenCompleted]; + } + } + + if (error != 0) + { + errno = error; + [self _recordError]; + [_sibling _recordError]; [self _sendEvent: NSStreamEventErrorOccurred]; - break; + [_sibling _sendEvent: NSStreamEventErrorOccurred]; } - case NSStreamStatusOpen: + else { - [self _sendEvent: NSStreamEventHasSpaceAvailable]; - break; + if (events.lNetworkEvents & FD_WRITE) + { + [self _setStatus: NSStreamStatusOpen]; + [self _sendEvent: NSStreamEventHasSpaceAvailable]; + } + if (events.lNetworkEvents & FD_READ) + { + [_sibling _setStatus: NSStreamStatusOpen]; + [_sibling _sendEvent: NSStreamEventHasBytesAvailable]; + } + if (events.lNetworkEvents & FD_CLOSE) + { + [self _setStatus: NSStreamStatusAtEnd]; + [self _sendEvent: NSStreamEventEndEncountered]; + while ([_sibling streamStatus] == NSStreamStatusOpen + && [_sibling _unhandledData] == NO) + { + [_sibling _sendEvent: NSStreamEventHasBytesAvailable]; + } + if ([_sibling streamStatus] == NSStreamStatusAtEnd) + { + [_sibling _sendEvent: NSStreamEventEndEncountered]; + } + } } - default: - break; } - if (_sibling && [_sibling _isOpened]) - [_sibling _dispatch]; } @end @@ -1788,7 +1804,7 @@ static void setNonblocking(SOCKET fd) return 0; } -#define SOCKET_BACKLOG 5 +#define SOCKET_BACKLOG 255 - (void) open { @@ -1860,17 +1876,17 @@ static void setNonblocking(SOCKET fd) - (void) _dispatch { - WSANETWORKEVENTS ocurredEvents; + WSANETWORKEVENTS events; - if (WSAEnumNetworkEvents(_sock, _loopID, &ocurredEvents) == SOCKET_ERROR) + if (WSAEnumNetworkEvents(_sock, _loopID, &events) == SOCKET_ERROR) { errno = WSAGetLastError(); [self _recordError]; [self _sendEvent: NSStreamEventErrorOccurred]; } - else if (ocurredEvents.lNetworkEvents & FD_ACCEPT) + else if (events.lNetworkEvents & FD_ACCEPT) { - ocurredEvents.lNetworkEvents ^= FD_ACCEPT; + events.lNetworkEvents ^= FD_ACCEPT; [self _setStatus: NSStreamStatusReading]; [self _sendEvent: NSStreamEventHasBytesAvailable]; }