[suggested PATCH] POLLHUP handling, non-STREAM sockets

Martin Wilck Martin.Wilck at Fujitsu-Siemens.com
Wed Jun 26 06:33:34 CDT 2002


Summary:

        Check POLLHUP semantics at remote shutdown when wineserver is started.
        Fix socket state handling and event handling for non-STREAM sockets.

Status: Compiles, not tested
        (I couldn't get the tests to run, see my previous email).

Modified files:
        server: sock.c
                main.c

Index: server/main.c
===================================================================
RCS file: /home/wine/wine/server/main.c,v
retrieving revision 1.25
diff -u -r1.25 main.c
--- server/main.c	20 Jun 2002 23:21:28 -0000	1.25
+++ server/main.c	26 Jun 2002 11:22:13 -0000
@@ -35,6 +35,7 @@
 int debug_level = 0;
 int master_socket_timeout = 3;  /* master socket timeout in seconds, default is 3 s */
 const char *server_argv0;
+extern void server_sock_init (void);
 
 /* parse-line args */
 /* FIXME: should probably use getopt, and add a (more complete?) help option */
@@ -111,6 +112,7 @@
 {
     parse_args( argc, argv );
     signal_init();
+    server_sock_init();
     open_master_socket();
     setvbuf( stderr, NULL, _IOLBF, 0 );
 
Index: server/sock.c
===================================================================
RCS file: /home/wine/wine/server/sock.c,v
retrieving revision 1.36
diff -u -r1.36 sock.c
--- server/sock.c	21 Jun 2002 19:06:28 -0000	1.36
+++ server/sock.c	26 Jun 2002 11:22:13 -0000
@@ -67,6 +67,8 @@
     unsigned int        hmask;       /* held (blocked) events */
     unsigned int        pmask;       /* pending events */
     unsigned int        flags;       /* socket flags */
+    unsigned short      type;        /* socket type */
+    unsigned short      family;      /* socket family */
     struct event       *event;       /* event object */
     user_handle_t       window;      /* window to send the message to */
     unsigned int        message;     /* message to send */
@@ -124,6 +126,62 @@
     6, 7, 8, 9  /* leftovers */
 };
 
+/* Flags that make sense only for SOCK_STREAM sockets */
+#define STREAM_FLAG_MASK ((unsigned int) (FD_CONNECT | FD_ACCEPT | FD_WINE_LISTENING | FD_WINE_CONNECTED))
+
+typedef enum {
+    SOCK_SHUTDOWN_ERROR = -1,
+    SOCK_SHUTDOWN_EOF = 0,
+    SOCK_SHUTDOWN_POLLHUP = 1
+} sock_shutdown_t;
+
+static sock_shutdown_t sock_shutdown_type = SOCK_SHUTDOWN_ERROR;
+
+static sock_shutdown_t sock_check_pollhup (void)
+{
+    sock_shutdown_t ret = SOCK_SHUTDOWN_ERROR;
+    int fd[2], n;
+    struct pollfd pfd;
+    char dummy;
+
+    if ( socketpair ( AF_UNIX, SOCK_STREAM, 0, fd ) ) goto out;
+    if ( shutdown ( fd[0], 1 ) ) goto out;
+
+    pfd.fd = fd[1];
+    pfd.events = POLLIN;
+    pfd.revents = 0;
+
+    n = poll ( &pfd, 1, 0 );
+    if ( n != 1 ) goto out; /* error or timeout */
+    if ( pfd.revents & POLLHUP )
+        ret = SOCK_SHUTDOWN_POLLHUP;
+    else if ( pfd.revents & POLLIN &&
+              read ( fd[1], &dummy, 1 ) == 0 )
+        ret = SOCK_SHUTDOWN_EOF;
+
+out:
+    close ( fd[0] );
+    close ( fd[1] );
+    return ret;
+}
+
+void server_sock_init (void)
+{
+    sock_shutdown_type = sock_check_pollhup ();
+
+    switch ( sock_shutdown_type )
+    {
+    case SOCK_SHUTDOWN_EOF:
+        if (debug_level) fprintf ( stderr, "server_sock_init: shutdown() causes EOF\n" );
+        break;
+    case SOCK_SHUTDOWN_POLLHUP:
+        if (debug_level) fprintf ( stderr, "server_sock_init: shutdown() causes POLLHUP\n" );
+        break;
+    default:
+        fprintf ( stderr, "server_sock_init: ERROR in sock_check_pollhup()\n" );
+        sock_shutdown_type = SOCK_SHUTDOWN_EOF;
+    }
+}
 
 static int sock_reselect( struct sock *sock )
 {
@@ -222,7 +280,7 @@
 static void sock_poll_event( struct object *obj, int event )
 {
     struct sock *sock = (struct sock *)obj;
-    int empty_recv = 0;
+    int hangup_seen = 0;
 
     assert( sock->obj.ops == &sock_ops );
     if (debug_level)
@@ -270,7 +328,7 @@
     } else
     {
         /* normal data flow */
-        if (event & POLLIN)
+        if ( sock->type == SOCK_STREAM && ( event & POLLIN ) )
         {
             char dummy;
             int nr;
@@ -288,7 +346,7 @@
                     fprintf(stderr, "socket %d is readable\n", sock->obj.fd );
             }
             else if ( nr == 0 )
-                empty_recv = 1;
+                hangup_seen = 1;
             else
             {
                 /* EAGAIN can happen if an async recv() falls between the server's poll()
@@ -304,7 +362,19 @@
             }
 
         }
-        else if (event & POLLHUP) empty_recv = 1;
+        else if ( sock_shutdown_type == SOCK_SHUTDOWN_POLLHUP && (event & POLLHUP) )
+        {
+            hangup_seen = 1;
+        }
+        else if ( event & POLLIN ) /* POLLIN for non-stream socket */
+        {
+            sock->pmask |= FD_READ;
+            sock->hmask |= (FD_READ|FD_CLOSE);
+            sock->errors[FD_READ_BIT] = 0;
+            if (debug_level)
+                fprintf(stderr, "socket %d is readable\n", sock->obj.fd );
+
+        }
 
         if (event & POLLOUT)
         {
@@ -323,12 +393,12 @@
                 fprintf(stderr, "socket %d got OOB data\n", sock->obj.fd);
         }
         /* According to WS2 specs, FD_CLOSE is only delivered when there is
-           no more data to be read (i.e. empty_recv = 1) */
-        else if ( empty_recv && (sock->state & (FD_READ|FD_WRITE) ))
+           no more data to be read (i.e. hangup_seen = 1) */
+        else if ( hangup_seen && (sock->state & (FD_READ|FD_WRITE) ))
         {
             sock->errors[FD_CLOSE_BIT] = sock_error( sock->obj.fd );
-            if ( event & POLLERR)
-                 sock->state &= ~(FD_WINE_CONNECTED|FD_WRITE);
+            if ( (event & POLLERR) || ( sock_shutdown_type == SOCK_SHUTDOWN_EOF && (event & POLLHUP) ))
+                sock->state &= ~(FD_WINE_CONNECTED|FD_WRITE);
             sock->pmask |= FD_CLOSE;
             sock->hmask |= FD_CLOSE;
             if (debug_level)
@@ -390,8 +460,8 @@
         ev |= POLLIN | POLLPRI;
     if (mask & FD_WRITE || (sock->flags & WSA_FLAG_OVERLAPPED && IS_READY (sock->write_q)))
         ev |= POLLOUT;
-    /* We use POLLIN with 0 bytes recv() as FD_CLOSE indication. */
-    if (sock->mask & ~sock->hmask & FD_CLOSE)
+    /* We use POLLIN with 0 bytes recv() as FD_CLOSE indication for stream sockets. */
+    if ( sock->type == SOCK_STREAM && ( sock->mask & ~sock->hmask & FD_CLOSE) )
         ev |= POLLIN;
 
     return ev;
@@ -526,6 +596,8 @@
     sock->hmask   = 0;
     sock->pmask   = 0;
     sock->flags   = flags;
+    sock->type    = type;
+    sock->family  = family;
     sock->event   = NULL;
     sock->window  = 0;
     sock->message = 0;
@@ -586,6 +658,8 @@
         acceptsock->mask    = sock->mask;
         acceptsock->hmask   = 0;
         acceptsock->pmask   = 0;
+        acceptsock->type    = sock->type;
+        acceptsock->family  = sock->family;
         acceptsock->event   = NULL;
         acceptsock->window  = sock->window;
         acceptsock->message = sock->message;
@@ -794,6 +868,7 @@
         sock->hmask &= ~FD_CLOSE;
     sock->state |= req->sstate;
     sock->state &= ~req->cstate;
+    if ( sock->type != SOCK_STREAM ) sock->state &= ~STREAM_FLAG_MASK;
 
     pollev = sock_reselect( sock );
     if ( pollev ) sock_try_event ( sock, pollev );
-- 
Martin Wilck                Phone: +49 5251 8 15113
Fujitsu Siemens Computers   Fax:   +49 5251 8 20409
Heinz-Nixdorf-Ring 1	    mailto:Martin.Wilck at Fujitsu-Siemens.com
D-33106 Paderborn           http://www.fujitsu-siemens.com/primergy








More information about the wine-devel mailing list