macosx compatibility fixes

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@23215 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Richard Frith-MacDonald 2006-08-08 13:31:50 +00:00
parent aa1ecf7e6e
commit 3156b070fe
5 changed files with 261 additions and 198 deletions

View file

@ -1,9 +1,13 @@
2006-08-07 Richard Frith-Macdonald <rfm@gnu.org>
2006-08-08 Richard Frith-Macdonald <rfm@gnu.org>
* 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 <greg_casamento@yahoo.com>

View file

@ -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

View file

@ -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 <GSStreamListener>)_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];

View file

@ -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];
}

View file

@ -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];
}