* fhandler_socket.cc (fhandler_socket::evaluate_events): Handle the

FD_CLOSE event specially when called from accept.  Explain why.
	(fhandler_socket::shutdown): Fake success on not-connected socket and
	trigger socket event if the read side of a socket is affected.  Explain
	why.
	* poll.cc (poll): Check for saw_shutdown_read on sockets to generate
	POLLHUP as well.
This commit is contained in:
Corinna Vinschen 2011-04-18 11:44:17 +00:00
parent 7c8126eb3e
commit 0077cd1016
3 changed files with 57 additions and 19 deletions

View File

@ -1,3 +1,13 @@
2011-04-18 Corinna Vinschen <corinna@vinschen.de>
* fhandler_socket.cc (fhandler_socket::evaluate_events): Handle the
FD_CLOSE event specially when called from accept. Explain why.
(fhandler_socket::shutdown): Fake success on not-connected socket and
trigger socket event if the read side of a socket is affected. Explain
why.
* poll.cc (poll): Check for saw_shutdown_read on sockets to generate
POLLHUP as well.
2011-04-18 Corinna Vinschen <corinna@vinschen.de>
* Fix various copyrights.

View File

@ -596,6 +596,15 @@ fhandler_socket::evaluate_events (const long event_mask, long &events,
wsock_events->events &= ~FD_CONNECT;
wsock_events->connect_errorcode = 0;
}
/* This test makes the accept function behave as on Linux when
accept is called on a socket for which shutdown for the read side
has been called. The second half of this code is in the shutdown
method. See there for more info. */
if ((event_mask & FD_ACCEPT) && (events & FD_CLOSE))
{
WSASetLastError (WSAEINVAL);
ret = SOCKET_ERROR;
}
if (erase)
wsock_events->events &= ~(events & ~(FD_WRITE | FD_CLOSE));
}
@ -1659,22 +1668,37 @@ fhandler_socket::shutdown (int how)
{
int res = ::shutdown (get_socket (), how);
if (res)
/* Linux allows to call shutdown for any socket, even if it's not connected.
This also disables to call accept on this socket, if shutdown has been
called with the SHUT_RD or SHUT_RDWR parameter. In contrast, Winsock
only allows to call shutdown on a connected socket. The accept function
is in no way affected. So, what we do here is to fake success, and to
change the event settings so that an FD_CLOSE event is triggered for the
calling Cygwin function. The evaluate_events method handles the call
from accept specially to generate a Linux-compatible behaviour. */
if (res && WSAGetLastError () != WSAENOTCONN)
set_winsock_errno ();
else
switch (how)
{
case SHUT_RD:
saw_shutdown_read (true);
break;
case SHUT_WR:
saw_shutdown_write (true);
break;
case SHUT_RDWR:
saw_shutdown_read (true);
saw_shutdown_write (true);
break;
}
{
res = 0;
switch (how)
{
case SHUT_RD:
saw_shutdown_read (true);
wsock_events->events |= FD_CLOSE;
SetEvent (wsock_evt);
break;
case SHUT_WR:
saw_shutdown_write (true);
break;
case SHUT_RDWR:
saw_shutdown_read (true);
saw_shutdown_write (true);
wsock_events->events |= FD_CLOSE;
SetEvent (wsock_evt);
break;
}
}
return res;
}

View File

@ -1,7 +1,7 @@
/* poll.cc. Implements poll(2) via usage of select(2) call.
Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
Red Hat, Inc.
Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
2011 Red Hat, Inc.
This file is part of Cygwin.
@ -84,12 +84,16 @@ poll (struct pollfd *fds, nfds_t nfds, int timeout)
{
if (fds[i].fd >= 0)
{
if (cygheap->fdtab.not_open (fds[i].fd))
fhandler_socket *sock;
/* Check if the descriptor has been closed, or if shutdown for the
read side has been called on a socket. */
if (cygheap->fdtab.not_open (fds[i].fd)
|| ((sock = cygheap->fdtab[fds[i].fd]->is_socket ())
&& sock->saw_shutdown_read ()))
fds[i].revents = POLLHUP;
else
{
fhandler_socket *sock;
if (FD_ISSET(fds[i].fd, read_fds))
/* This should be sufficient for sockets, too. Using
MSG_PEEK, as before, can be considered dangerous at