server: Always treat POLLHUP as a hangup, just special case checking TCP sockets.

This commit is contained in:
Mike Kaplinskiy 2010-05-13 16:41:58 -04:00 committed by Alexandre Julliard
parent 861989596f
commit d03fe9d4ec
1 changed files with 16 additions and 21 deletions

View File

@ -329,6 +329,10 @@ static void sock_poll_event( struct fd *fd, int event )
assert( sock->obj.ops == &sock_ops ); assert( sock->obj.ops == &sock_ops );
if (debug_level) if (debug_level)
fprintf(stderr, "socket %p select event: %x\n", sock, event); fprintf(stderr, "socket %p select event: %x\n", sock, event);
/* we may change event later, remove from loop here */
if (event & (POLLERR|POLLHUP)) set_fd_events( sock->fd, -1 );
if (sock->state & FD_CONNECT) if (sock->state & FD_CONNECT)
{ {
/* connecting */ /* connecting */
@ -382,28 +386,25 @@ static void sock_poll_event( struct fd *fd, int event )
* has been closed, so we need to check for it explicitly here */ * has been closed, so we need to check for it explicitly here */
nr = recv( get_unix_fd( fd ), &dummy, 1, MSG_PEEK ); nr = recv( get_unix_fd( fd ), &dummy, 1, MSG_PEEK );
if ( nr == 0 ) if ( nr == 0 )
{
hangup_seen = 1; hangup_seen = 1;
event &= ~POLLIN;
}
else if ( nr < 0 ) else if ( nr < 0 )
{ {
event &= ~POLLIN;
/* EAGAIN can happen if an async recv() falls between the server's poll() /* EAGAIN can happen if an async recv() falls between the server's poll()
call and the invocation of this routine */ call and the invocation of this routine */
if ( errno == EAGAIN ) if ( errno != EAGAIN )
event &= ~POLLIN;
else
{ {
if ( debug_level ) if ( debug_level )
fprintf( stderr, "recv error on socket %p: %d\n", sock, errno ); fprintf( stderr, "recv error on socket %p: %d\n", sock, errno );
event = POLLERR; event |= POLLERR;
} }
} }
}
else if ( sock_shutdown_type == SOCK_SHUTDOWN_POLLHUP && (event & POLLHUP) )
{
hangup_seen = 1;
} }
if ( event & POLLIN && !hangup_seen ) if ( event & POLLIN )
{ {
sock->pmask |= FD_READ; sock->pmask |= FD_READ;
sock->hmask |= FD_READ; sock->hmask |= FD_READ;
@ -429,9 +430,7 @@ static void sock_poll_event( struct fd *fd, int event )
fprintf(stderr, "socket %p got OOB data\n", sock); fprintf(stderr, "socket %p got OOB data\n", sock);
} }
/* According to WS2 specs, FD_CLOSE is only delivered when there is if ( (hangup_seen || event & (POLLHUP|POLLERR)) && (sock->state & (FD_READ|FD_WRITE)) )
no more data to be read (i.e. hangup_seen = 1) */
if ( hangup_seen && (sock->state & (FD_READ|FD_WRITE) ))
{ {
sock->errors[FD_CLOSE_BIT] = sock_error( fd ); sock->errors[FD_CLOSE_BIT] = sock_error( fd );
if ( (event & POLLERR) || ( sock_shutdown_type == SOCK_SHUTDOWN_EOF && (event & POLLHUP) )) if ( (event & POLLERR) || ( sock_shutdown_type == SOCK_SHUTDOWN_EOF && (event & POLLHUP) ))
@ -444,16 +443,10 @@ static void sock_poll_event( struct fd *fd, int event )
fprintf(stderr, "socket %p aborted by error %d, event: %x - removing from select loop\n", fprintf(stderr, "socket %p aborted by error %d, event: %x - removing from select loop\n",
sock, sock->errors[FD_CLOSE_BIT], event); sock, sock->errors[FD_CLOSE_BIT], event);
} }
}
if ( event & (POLLERR|POLLHUP) ) if (hangup_seen)
{ event |= POLLHUP;
if ( debug_level )
fprintf( stderr, "removing socket %p from select loop\n", sock );
set_fd_events( sock->fd, -1 );
} }
else
sock_reselect( sock );
/* wake up anyone waiting for whatever just happened */ /* wake up anyone waiting for whatever just happened */
if ( sock->pmask & sock->mask || sock->flags & WSA_FLAG_OVERLAPPED ) sock_wake_up( sock, event ); if ( sock->pmask & sock->mask || sock->flags & WSA_FLAG_OVERLAPPED ) sock_wake_up( sock, event );
@ -461,6 +454,8 @@ static void sock_poll_event( struct fd *fd, int event )
/* if anyone is stupid enough to wait on the socket object itself, /* if anyone is stupid enough to wait on the socket object itself,
* maybe we should wake them up too, just in case? */ * maybe we should wake them up too, just in case? */
wake_up( &sock->obj, 0 ); wake_up( &sock->obj, 0 );
sock_reselect( sock );
} }
static void sock_dump( struct object *obj, int verbose ) static void sock_dump( struct object *obj, int verbose )