Patch: sock-shutdown.diff (9 in series)

Martin Wilck Martin.Wilck at fujitsu-siemens.com
Fri Apr 12 10:24:24 CDT 2002


Sorry I got the numbers wrong - there is no number 6 :-/

Patch: sock-shutdown.diff

On overlapped sockets, shutdown() must be done asynchronously too to avoid
premature closing of connections (necessary but unfortunately not sufficient).
This patch queues the shutdown request in the async queue. Moreover it sets
flags for the fd state to prevent calls to send() or recv() after the respective
connection of the socket was shut down.

Patch against: CVS 2002-04-12, with my sock-fd-type, sock-accept-deferred,
        async-winsock patches applied.

Modified files:
        dlls/winsock:   socket.c
        include/wine:   server_protocol.h
        include:        winsock.h
        server:         protocol.def, sock.c

diff -ruNX ignore TMP/wine/dlls/winsock/socket.c MW/wine/dlls/winsock/socket.c
--- TMP/wine/dlls/winsock/socket.c	Fri Apr 12 15:29:04 2002
+++ MW/wine/dlls/winsock/socket.c	Fri Apr 12 15:29:13 2002
@@ -2258,6 +2258,12 @@
     if ( fd == -1 )
         goto error;

+    if ( flags & FD_FLAG_SEND_SHUTDOWN )
+    {
+        err = WSAESHUTDOWN;
+        goto err_close;
+    }
+
     iovec = WS_ALLOC ( dwBufferCount * sizeof (struct iovec) );

     if ( !iovec )
@@ -2470,55 +2476,168 @@
     return (INT16)WS_setsockopt( s, (UINT16)level, optname, optval, optlen );
 }

+/***********************************************************************
+ *              WS2_async_shutdown      (INTERNAL)
+ *
+ * On overlapped sockets, shutdown() must be done asynchronously.
+ */
+static void WS2_async_shutdown ( async_private *as )
+{
+    ws2_async* wsa = (ws2_async*) as;
+    int err = 1;
+
+    TRACE ( "async %p %d\n", wsa, wsa->async.type );
+    switch ( wsa->async.type )
+    {
+    case ASYNC_TYPE_READ:
+        err = shutdown ( wsa->async.fd, 0 );
+        break;
+    case ASYNC_TYPE_WRITE:
+        err = shutdown ( wsa->async.fd, 1 );
+        break;
+    default:
+        WARN ("invalid type: %d\n", wsa->async.type );
+    }
+
+    if ( err )
+        wsa->overlapped->Internal = STATUS_UNSUCCESSFUL;
+    else
+        wsa->overlapped->Internal = STATUS_SUCCESS;
+}
+
+/***********************************************************************
+ *  WS2_register_async_shutdown         (INTERNAL)
+ */
+static int WS2_register_async_shutdown ( SOCKET s, int fd, int type )
+{
+    struct ws2_async *wsa;
+    int ret, err = WSAEFAULT;
+    DWORD dwflags = 0;
+    int len = 0;
+    LPWSAOVERLAPPED ovl = HeapAlloc (GetProcessHeap(), 0, sizeof ( WSAOVERLAPPED ));
+
+    TRACE ("s %d fd %d type %d\n", s, fd, type);
+    if (!ovl)
+        goto out;
+
+    ovl->hEvent = WSACreateEvent ();
+    if ( ovl->hEvent == WSA_INVALID_EVENT  )
+        goto out_free;
+
+    wsa = WS2_make_async ( s, fd, type, NULL, 0,
+                           &dwflags, NULL, &len, ovl, NULL );
+    if ( !wsa )
+        goto out_close;
+
+    /* Hack: this will cause ws2_async_cleanup() to free the overlapped structure */
+    wsa->user_overlapped = NULL;
+    wsa->async.func = WS2_async_shutdown;
+    if ( (ret = register_new_async ( &wsa->async )) )
+    {
+        err = RtlNtStatusToDosError ( ret );
+        ws2_async_cleanup ( &wsa->async );
+        goto out;
+    }
+    return 0;
+
+out_close:
+    WSACloseEvent ( ovl->hEvent );
+out_free:
+    HeapFree ( GetProcessHeap(), 0, ovl );
+out:
+    return err;
+}

 /***********************************************************************
  *		shutdown		(WS2_32.22)
  */
 int WINAPI WS_shutdown(SOCKET s, int how)
 {
-    int fd = _get_sock_fd(s);
+    int fd, fd0 = -1, fd1 = -1, flags, err = WSAENOTSOCK;
+    enum fd_type type;
+    unsigned int set_flags = 0, clear_flags = 0;

-    TRACE("socket %04x, how %i\n", s, how );
-    if (fd != -1)
-    {
-	    switch( how )
-	    {
-		case 0: /* drop receives */
-			_enable_event(s, 0, 0, FD_READ);
-#ifdef SHUT_RD
-			how = SHUT_RD;
-#endif
-			break;
+    fd = _get_sock_fd_type ( s, &type, &flags );
+    TRACE("socket %04x, how %i %d %d \n", s, how, type, flags );

-		case 1: /* drop sends */
-			_enable_event(s, 0, 0, FD_WRITE);
-#ifdef SHUT_WR
-			how = SHUT_WR;
-#endif
-			break;
+    if (fd == -1)
+        goto error;

-		case 2: /* drop all */
-#ifdef SHUT_RDWR
-			how = SHUT_RDWR;
-#endif
-		default:
-			WSAAsyncSelect( s, 0, 0, 0 );
-			break;
-	    }
+    if ( flags & FD_FLAG_OVERLAPPED ) {
+
+        switch ( how )
+        {
+        case SD_RECEIVE:
+            fd0 = fd;
+            set_flags |= FD_FLAG_RECV_SHUTDOWN;
+            clear_flags |= FD_READ;
+            break;
+        case SD_SEND:
+            fd1 = fd;
+            set_flags |= FD_FLAG_SEND_SHUTDOWN;
+            clear_flags |= FD_WRITE;
+            break;
+        case SD_BOTH:
+            fd0 = fd;
+            fd1 = _get_sock_fd ( s );
+            set_flags |= FD_FLAG_RECV_SHUTDOWN|FD_FLAG_SEND_SHUTDOWN;
+            clear_flags |= FD_READ|FD_WRITE;
+        default:
+            clear_flags |= FD_WINE_CONNECTED|FD_WINE_LISTENING;
+            WSAAsyncSelect( s, 0, 0, 0 );
+        }
+        _enable_event( s, 0, set_flags, clear_flags );

-	if (shutdown(fd, how) == 0)
-	{
-	    if( how > 1 )
-	    {
-		_enable_event(s, 0, 0, FD_WINE_CONNECTED|FD_WINE_LISTENING);
-	    }
-	    close(fd);
-	    return 0;
-	}
-	SetLastError(wsaErrno());
-	close(fd);
-    }
-    else SetLastError(WSAENOTSOCK);
+        if ( fd0 != -1 )
+        {
+            err = WS2_register_async_shutdown ( s, fd0, ASYNC_TYPE_READ );
+            if ( err )
+            {
+                close ( fd0 );
+                goto error;
+            }
+        }
+        if ( fd1 != -1 )
+        {
+            err = WS2_register_async_shutdown ( s, fd1, ASYNC_TYPE_WRITE );
+            if ( err )
+            {
+                close ( fd1 );
+                goto error;
+            }
+        }
+        return 0;
+    }
+    else /* non-overlapped mode */
+    {
+        switch( how )
+        {
+        case 0: /* drop receives */
+            _enable_event(s, 0, 0, FD_READ);
+            break;
+        case 1: /* drop sends */
+            _enable_event(s, 0, 0, FD_WRITE);
+            break;
+        case 2: /* drop all */
+        default:
+            WSAAsyncSelect( s, 0, 0, 0 );
+        break;
+        }
+
+        if ( shutdown( fd, how ) )
+        {
+            err = wsaErrno ();
+            close ( fd );
+            goto error;
+        }
+        if( how > 1 )
+            _enable_event(s, 0, 0, FD_WINE_CONNECTED|FD_WINE_LISTENING);
+        close(fd);
+        return 0;
+    }
+
+error:
+    WSASetLastError ( err );
     return SOCKET_ERROR;
 }

@@ -3707,9 +3826,12 @@
     TRACE ( "fd=%d, type=%d, flags=%x\n", fd, type, flags );

     if (fd == -1)
-    {
-        err = WSAENOTSOCK;
         goto error;
+
+    if ( flags & FD_FLAG_RECV_SHUTDOWN )
+    {
+        err = WSAESHUTDOWN;
+        goto err_close;
     }

     iovec = HeapAlloc ( GetProcessHeap(), 0, dwBufferCount * sizeof (struct iovec) );
@@ -3879,6 +4001,7 @@
                                SetLastError ( WSATRY_AGAIN );
                        }
                        SERVER_END_REQ;
+                       /* WS_closesocket ( cs ); */
                        return SOCKET_ERROR;
                case CF_REJECT:
                        WS_closesocket(cs);
diff -ruNX ignore TMP/wine/include/wine/server_protocol.h MW/wine/include/wine/server_protocol.h
--- TMP/wine/include/wine/server_protocol.h	Fri Apr 12 14:38:16 2002
+++ MW/wine/include/wine/server_protocol.h	Fri Apr 12 15:29:13 2002
@@ -796,6 +796,9 @@
 #define FD_FLAG_OVERLAPPED 0x01
 #define FD_FLAG_TIMEOUT    0x02

+#define FD_FLAG_RECV_SHUTDOWN      0x08000000
+#define FD_FLAG_SEND_SHUTDOWN      0x04000000
+#define FD_FLAG_SHUTDOWN_MASK      (FD_FLAG_RECV_SHUTDOWN|FD_FLAG_SEND_SHUTDOWN)


 struct set_file_pointer_request
@@ -3196,6 +3199,6 @@
     struct get_window_properties_reply get_window_properties_reply;
 };

-#define SERVER_PROTOCOL_VERSION 79
+#define SERVER_PROTOCOL_VERSION 80

 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */
diff -ruNX ignore TMP/wine/include/winsock.h MW/wine/include/winsock.h
--- TMP/wine/include/winsock.h	Tue Apr  2 16:51:40 2002
+++ MW/wine/include/winsock.h	Fri Apr 12 15:29:13 2002
@@ -728,6 +728,7 @@
 #define FD_CLOSE                   0x00000020

 /* internal per-socket flags */
+/* CAUTION: FD_FLAG_RECV_SHUTDOWN / FD_FLAG_SEND_SHUTDOWN (server/protocol.def) must fit into this mask */
 #ifdef __WINE__
 #define FD_WINE_LISTENING          0x10000000
 #define FD_WINE_NONBLOCKING        0x20000000
diff -ruNX ignore TMP/wine/server/protocol.def MW/wine/server/protocol.def
--- TMP/wine/server/protocol.def	Fri Apr 12 14:38:16 2002
+++ MW/wine/server/protocol.def	Fri Apr 12 15:29:13 2002
@@ -612,7 +612,10 @@
 };
 #define FD_FLAG_OVERLAPPED 0x01
 #define FD_FLAG_TIMEOUT    0x02
-
+/* These are only for sockets, but must work with ReadFile() etc., too */
+#define FD_FLAG_RECV_SHUTDOWN      0x08000000
+#define FD_FLAG_SEND_SHUTDOWN      0x04000000
+#define FD_FLAG_SHUTDOWN_MASK      (FD_FLAG_RECV_SHUTDOWN|FD_FLAG_SEND_SHUTDOWN)

 /* Set a file current position */
 @REQ(set_file_pointer)
diff -ruNX ignore TMP/wine/server/sock.c MW/wine/server/sock.c
--- TMP/wine/server/sock.c	Fri Apr 12 15:29:04 2002
+++ MW/wine/server/sock.c	Fri Apr 12 15:29:13 2002
@@ -230,7 +230,6 @@
         }
     } else
     {
-
         if ( sock->flags & WSA_FLAG_OVERLAPPED )
         {
             if( IS_READY(sock->read_q) && (POLLIN & event) )
@@ -243,25 +242,26 @@
                 if (debug_level) fprintf ( stderr, "activating write queue for socket %p\n", sock );
                 async_notify(sock->write_q.head, STATUS_ALERTED);
             }
-        }

-        /* normal data flow */
-        if (event & POLLIN)
-        {
-            char dummy;
+        } else {

             /* Linux 2.4 doesn't report POLLHUP if only one side of the socket
              * has been closed, so we need to check for it explicitly here */
-            if (!recv( sock->obj.fd, &dummy, 1, MSG_PEEK )) event = POLLHUP;
-            else
-            {
-                /* incoming data */
-                sock->pmask |= FD_READ;
-                sock->hmask |= FD_READ;
-                sock->errors[FD_READ_BIT] = 0;
-                if (debug_level)
-                    fprintf(stderr, "socket %d is readable\n", sock->obj.fd );
-            }
+            /* !!!! MW: do that only for non-overlapped sockets ??? */
+            char dummy;
+            if (!recv( sock->obj.fd, &dummy, 1, MSG_PEEK ))
+                event = POLLHUP;
+        }
+        /* normal data flow */
+        if (event & POLLIN)
+        {
+
+            /* incoming data */
+            sock->pmask |= FD_READ;
+            sock->hmask |= FD_READ;
+            sock->errors[FD_READ_BIT] = 0;
+            if (debug_level)
+                fprintf(stderr, "socket %d is readable\n", sock->obj.fd );
         }
         if (event & POLLOUT)
         {
@@ -371,8 +371,8 @@
         reply->index_low   = 0;
         reply->serial      = 0;
     }
-    *flags = 0;
-    if (sock->flags & WSA_FLAG_OVERLAPPED) *flags |= FD_FLAG_OVERLAPPED;
+    *flags = ( sock->state & FD_FLAG_SHUTDOWN_MASK );
+    if ( sock->flags & WSA_FLAG_OVERLAPPED ) *flags |= FD_FLAG_OVERLAPPED;
     return FD_TYPE_DEFAULT;
 }









More information about the wine-devel mailing list