mirror of
https://github.com/gnustep/libs-base.git
synced 2025-05-31 00:30:53 +00:00
add comments about the horrible working of winsock event handling.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@23240 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
6b7b3c4906
commit
8236d09007
1 changed files with 82 additions and 13 deletions
|
@ -708,14 +708,23 @@ static void setNonblocking(SOCKET fd)
|
||||||
|
|
||||||
- (void) close
|
- (void) close
|
||||||
{
|
{
|
||||||
|
WSACloseEvent(_loopID);
|
||||||
// read shutdown is ignored, because the other side may shutdown first.
|
// read shutdown is ignored, because the other side may shutdown first.
|
||||||
if (_sibling && [_sibling streamStatus] != NSStreamStatusClosed)
|
if (_sibling && [_sibling streamStatus] != NSStreamStatusClosed)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
* Windows only permits a single event to be associated with a socket
|
||||||
|
* at any time, but the runloop system only allows an event handle to
|
||||||
|
* be added to the loop once, and we have two streams for each socket.
|
||||||
|
* So we use two events, one for each stream, and when one stream is
|
||||||
|
* closed, we must call WSAEventSelect to ensure that the event handle
|
||||||
|
* of the sibling is used to signal events from now on.
|
||||||
|
*/
|
||||||
|
WSAEventSelect(_sock, [_sibling _loopID], FD_ALL_EVENTS);
|
||||||
shutdown(_sock, SD_RECEIVE);
|
shutdown(_sock, SD_RECEIVE);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
WSACloseEvent(_loopID);
|
|
||||||
closesocket(_sock);
|
closesocket(_sock);
|
||||||
}
|
}
|
||||||
[super close];
|
[super close];
|
||||||
|
@ -766,6 +775,13 @@ static void setNonblocking(SOCKET fd)
|
||||||
|
|
||||||
- (void) _dispatch
|
- (void) _dispatch
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
* Windows only permits a single event to be associated with a socket
|
||||||
|
* at any time, but the runloop system only allows an event handle to
|
||||||
|
* be added to the loop once, and we have two streams for each socket.
|
||||||
|
* So we use two events, one for each stream, and the _dispatch method
|
||||||
|
* must handle things for both streams.
|
||||||
|
*/
|
||||||
if ([self streamStatus] == NSStreamStatusClosed)
|
if ([self streamStatus] == NSStreamStatusClosed)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
@ -786,7 +802,7 @@ static void setNonblocking(SOCKET fd)
|
||||||
{
|
{
|
||||||
error = WSAGetLastError();
|
error = WSAGetLastError();
|
||||||
}
|
}
|
||||||
//else NSLog(@"EVENTS 0x%x", events.lNetworkEvents);
|
//else NSLog(@"EVENTS 0x%x on %p", events.lNetworkEvents, self);
|
||||||
|
|
||||||
if ([self streamStatus] == NSStreamStatusOpening)
|
if ([self streamStatus] == NSStreamStatusOpening)
|
||||||
{
|
{
|
||||||
|
@ -849,13 +865,21 @@ static void setNonblocking(SOCKET fd)
|
||||||
}
|
}
|
||||||
if (events.lNetworkEvents & FD_CLOSE)
|
if (events.lNetworkEvents & FD_CLOSE)
|
||||||
{
|
{
|
||||||
[_sibling _setStatus: NSStreamStatusAtEnd];
|
if ([_sibling _isOpened])
|
||||||
[_sibling _sendEvent: NSStreamEventEndEncountered];
|
{
|
||||||
|
[_sibling _setStatus: NSStreamStatusAtEnd];
|
||||||
|
[_sibling _sendEvent: NSStreamEventEndEncountered];
|
||||||
|
}
|
||||||
while ([self hasBytesAvailable]
|
while ([self hasBytesAvailable]
|
||||||
&& _unhandledData == NO)
|
&& _unhandledData == NO)
|
||||||
{
|
{
|
||||||
[self _sendEvent: NSStreamEventHasBytesAvailable];
|
[self _sendEvent: NSStreamEventHasBytesAvailable];
|
||||||
}
|
}
|
||||||
|
if ([self _isOpened])
|
||||||
|
{
|
||||||
|
[self _setStatus: NSStreamStatusAtEnd];
|
||||||
|
[self _sendEvent: NSStreamEventEndEncountered];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1340,13 +1364,22 @@ static void setNonblocking(SOCKET fd)
|
||||||
// shutdown may fail (broken pipe). Record it.
|
// shutdown may fail (broken pipe). Record it.
|
||||||
int closeReturn;
|
int closeReturn;
|
||||||
|
|
||||||
|
WSACloseEvent(_loopID);
|
||||||
if (_sibling && [_sibling streamStatus] != NSStreamStatusClosed)
|
if (_sibling && [_sibling streamStatus] != NSStreamStatusClosed)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
* Windows only permits a single event to be associated with a socket
|
||||||
|
* at any time, but the runloop system only allows an event handle to
|
||||||
|
* be added to the loop once, and we have two streams for each socket.
|
||||||
|
* So we use two events, one for each stream, and when one stream is
|
||||||
|
* closed, we must call WSAEventSelect to ensure that the event handle
|
||||||
|
* of the sibling is used to signal events from now on.
|
||||||
|
*/
|
||||||
|
WSAEventSelect(_sock, [_sibling _loopID], FD_ALL_EVENTS);
|
||||||
closeReturn = shutdown(_sock, SD_SEND);
|
closeReturn = shutdown(_sock, SD_SEND);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
WSACloseEvent(_loopID);
|
|
||||||
closeReturn = closesocket(_sock);
|
closeReturn = closesocket(_sock);
|
||||||
}
|
}
|
||||||
if (closeReturn < 0)
|
if (closeReturn < 0)
|
||||||
|
@ -1359,6 +1392,13 @@ static void setNonblocking(SOCKET fd)
|
||||||
|
|
||||||
- (void) _dispatch
|
- (void) _dispatch
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
* Windows only permits a single event to be associated with a socket
|
||||||
|
* at any time, but the runloop system only allows an event handle to
|
||||||
|
* be added to the loop once, and we have two streams for each socket.
|
||||||
|
* So we use two events, one for each stream, and the _dispatch method
|
||||||
|
* must handle things for both streams.
|
||||||
|
*/
|
||||||
if ([self streamStatus] == NSStreamStatusClosed)
|
if ([self streamStatus] == NSStreamStatusClosed)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
@ -1379,7 +1419,7 @@ static void setNonblocking(SOCKET fd)
|
||||||
{
|
{
|
||||||
error = WSAGetLastError();
|
error = WSAGetLastError();
|
||||||
}
|
}
|
||||||
//else NSLog(@"EVENTS 0x%x", events.lNetworkEvents);
|
//else NSLog(@"EVENTS 0x%x on %p", events.lNetworkEvents, self);
|
||||||
|
|
||||||
if ([self streamStatus] == NSStreamStatusOpening)
|
if ([self streamStatus] == NSStreamStatusOpening)
|
||||||
{
|
{
|
||||||
|
@ -1451,6 +1491,11 @@ static void setNonblocking(SOCKET fd)
|
||||||
{
|
{
|
||||||
[_sibling _sendEvent: NSStreamEventHasBytesAvailable];
|
[_sibling _sendEvent: NSStreamEventHasBytesAvailable];
|
||||||
}
|
}
|
||||||
|
if ([_sibling _isOpened])
|
||||||
|
{
|
||||||
|
[_sibling _setStatus: NSStreamStatusAtEnd];
|
||||||
|
[_sibling _sendEvent: NSStreamEventEndEncountered];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1505,20 +1550,33 @@ static void setNonblocking(SOCKET fd)
|
||||||
GSSocketInputStream *ins = nil;
|
GSSocketInputStream *ins = nil;
|
||||||
GSSocketOutputStream *outs = nil;
|
GSSocketOutputStream *outs = nil;
|
||||||
int sock;
|
int sock;
|
||||||
WSAEVENT event;
|
WSAEVENT ievent;
|
||||||
|
WSAEVENT oevent;
|
||||||
|
|
||||||
ins = AUTORELEASE([[GSInetInputStream alloc]
|
ins = AUTORELEASE([[GSInetInputStream alloc]
|
||||||
initToAddr: address port: port]);
|
initToAddr: address port: port]);
|
||||||
outs = AUTORELEASE([[GSInetOutputStream alloc]
|
outs = AUTORELEASE([[GSInetOutputStream alloc]
|
||||||
initToAddr: address port: port]);
|
initToAddr: address port: port]);
|
||||||
sock = socket(PF_INET, SOCK_STREAM, 0);
|
sock = socket(PF_INET, SOCK_STREAM, 0);
|
||||||
event = CreateEvent(NULL, NO, NO, NULL);
|
|
||||||
|
/*
|
||||||
|
* Windows only permits a single event to be associated with a socket
|
||||||
|
* at any time, but the runloop system only allows an event handle to
|
||||||
|
* be added to the loop once, and we have two streams.
|
||||||
|
* So we create two events, one for each stream, so that we can have
|
||||||
|
* both streams scheduled in the run loop, but we make sure that the
|
||||||
|
* _dispatch method in each stream actually handles things for both
|
||||||
|
* streams so that whichever stream gets signalled, the correct
|
||||||
|
* actions are taken.
|
||||||
|
*/
|
||||||
|
ievent = CreateEvent(NULL, NO, NO, NULL);
|
||||||
|
oevent = CreateEvent(NULL, NO, NO, NULL);
|
||||||
|
|
||||||
NSAssert(sock >= 0, @"Cannot open socket");
|
NSAssert(sock >= 0, @"Cannot open socket");
|
||||||
[ins setSock: sock];
|
[ins setSock: sock];
|
||||||
[outs setSock: sock];
|
[outs setSock: sock];
|
||||||
[ins setEvent: event];
|
[ins setEvent: ievent];
|
||||||
[outs setEvent: event];
|
[outs setEvent: oevent];
|
||||||
|
|
||||||
if (inputStream)
|
if (inputStream)
|
||||||
{
|
{
|
||||||
|
@ -1905,7 +1963,18 @@ static void setNonblocking(SOCKET fd)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
WSAEVENT event = CreateEvent(NULL, NO, NO, NULL);
|
/*
|
||||||
|
* Windows only permits a single event to be associated with a socket
|
||||||
|
* at any time, but the runloop system only allows an event handle to
|
||||||
|
* be added to the loop once, and we have two streams.
|
||||||
|
* So we create two events, one for each stream, so that we can have
|
||||||
|
* both streams scheduled in the run loop, but we make sure that the
|
||||||
|
* _dispatch method in each stream actually handles things for both
|
||||||
|
* streams so that whichever stream gets signalled, the correct
|
||||||
|
* actions are taken.
|
||||||
|
*/
|
||||||
|
WSAEVENT ievent = CreateEvent(NULL, NO, NO, NULL);
|
||||||
|
WSAEVENT oevent = CreateEvent(NULL, NO, NO, NULL);
|
||||||
// no need to connect again
|
// no need to connect again
|
||||||
[ins setPassive: YES];
|
[ins setPassive: YES];
|
||||||
[outs setPassive: YES];
|
[outs setPassive: YES];
|
||||||
|
@ -1913,8 +1982,8 @@ static void setNonblocking(SOCKET fd)
|
||||||
memcpy([outs peerAddr], [ins peerAddr], len);
|
memcpy([outs peerAddr], [ins peerAddr], len);
|
||||||
[ins setSock: acceptReturn];
|
[ins setSock: acceptReturn];
|
||||||
[outs setSock: acceptReturn];
|
[outs setSock: acceptReturn];
|
||||||
[ins setEvent: event];
|
[ins setEvent: ievent];
|
||||||
[outs setEvent: event];
|
[outs setEvent: oevent];
|
||||||
}
|
}
|
||||||
if (inputStream)
|
if (inputStream)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue