PATCH: deferred WSAAccept() (1 in series)

Martin Wilck Martin.Wilck at fujitsu-siemens.com
Tue Apr 23 12:54:48 CDT 2002


PATCH: accept-deferred.diff (improved)

Changed against http://www.winehq.com/hypermail/wine-patches/2002/04/0087.html:
        Use object pointer rather than handler in server code.

If a connection request is deferred in a call to WSAAccept(),
a subsequent accept()/WSAAccept() call must return the
previously deferred connection rather than a new one.
Otherwise the peer will wait forever on the socket returned by connect().

The current CVS implementation of WSAAccept is wrong in this respect.
This patch fixes this. Furthermore, it includes a trivial implementation
of WSAConnect().

BUGS: The peer still does not see the same behaviour as under Windows if
      a deferred connection request is eventually rejected.
      (Windows: connection refused, Wine: first accepted, then closed).
      The Linux accept() system call semantics prevent a completely analogous
      behaviour.

Patch against: CVS 2002-04-23.

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

diff -ruNX ignore CVS/wine/dlls/winsock/socket.c TMP/wine/dlls/winsock/socket.c
--- CVS/wine/dlls/winsock/socket.c	Thu Apr 18 10:29:55 2002
+++ TMP/wine/dlls/winsock/socket.c	Mon Apr 22 10:52:43 2002
@@ -1139,6 +1139,19 @@
 }

 /***********************************************************************
+ *              WSAConnect             (WS2_32.30)
+ */
+int WINAPI WSAConnect ( SOCKET s, const struct WS_sockaddr* name, int namelen,
+                        LPWSABUF lpCallerData, LPWSABUF lpCalleeData,
+                        LPQOS lpSQOS, LPQOS lpGQOS )
+{
+    if ( lpCallerData || lpCalleeData || lpSQOS || lpGQOS )
+        FIXME ("unsupported parameters!\n");
+    return WS_connect ( s, name, namelen );
+}
+
+
+/***********************************************************************
  *		getpeername		(WS2_32.5)
  */
 int WINAPI WS_getpeername(SOCKET s, struct WS_sockaddr *name, int *namelen)
@@ -3419,7 +3432,7 @@
        SOCKET cs;
        SOCKADDR src_addr, dst_addr;

-       TRACE("Socket  %ui, sockaddr %p, addrlen %p, fnCondition %p, dwCallbackD ata %ld\n",
+       TRACE("Socket  %u, sockaddr %p, addrlen %p, fnCondition %p, dwCallbackData %ld\n",
                s, addr, addrlen, lpfnCondition, dwCallbackData);


@@ -3450,7 +3463,17 @@
                                addr = memcpy(addr, &src_addr, (*addrlen > size) ?  size : *addrlen );
                        return cs;
                case CF_DEFER:
-                       SetLastError(WSATRY_AGAIN);
+                       SERVER_START_REQ ( set_socket_deferred )
+                       {
+                           req->handle = s;
+                           req->deferred = cs;
+                           if ( !wine_server_call_err ( req ) )
+                           {
+                               SetLastError ( WSATRY_AGAIN );
+                               CloseHandle ( cs );
+                           }
+                       }
+                       SERVER_END_REQ;
                        return SOCKET_ERROR;
                case CF_REJECT:
                        WS_closesocket(cs);
diff -ruNX ignore CVS/wine/dlls/winsock/ws2_32.spec TMP/wine/dlls/winsock/ws2_32.spec
--- CVS/wine/dlls/winsock/ws2_32.spec	Tue Apr 16 11:29:41 2002
+++ TMP/wine/dlls/winsock/ws2_32.spec	Mon Apr 22 10:52:43 2002
@@ -42,7 +42,7 @@
 27  stub     WSAAddressToStringA
 28  stub     WSAAddressToStringW
 29  stdcall  WSACloseEvent(long) WSACloseEvent
-30  stub     WSAConnect
+30  stdcall  WSAConnect(long ptr long ptr ptr ptr ptr) WSAConnect
 31  stdcall  WSACreateEvent ()  WSACreateEvent
 32  stub     WSADuplicateSocketA
 33  stub     WSADuplicateSocketW
diff -ruNX ignore CVS/wine/include/wine/server_protocol.h TMP/wine/include/wine/server_protocol.h
--- CVS/wine/include/wine/server_protocol.h	Tue Apr 16 11:29:41 2002
+++ TMP/wine/include/wine/server_protocol.h	Mon Apr 22 10:52:43 2002
@@ -1001,6 +1001,16 @@
     struct reply_header __header;
 };

+struct set_socket_deferred_request
+{
+    struct request_header __header;
+    handle_t     handle;
+    handle_t     deferred;
+};
+struct set_socket_deferred_reply
+{
+    struct reply_header __header;
+};


 struct alloc_console_request
@@ -2758,6 +2768,7 @@
     REQ_set_socket_event,
     REQ_get_socket_event,
     REQ_enable_socket_event,
+    REQ_set_socket_deferred,
     REQ_alloc_console,
     REQ_free_console,
     REQ_get_console_renderer_events,
@@ -2919,6 +2930,7 @@
     struct set_socket_event_request set_socket_event_request;
     struct get_socket_event_request get_socket_event_request;
     struct enable_socket_event_request enable_socket_event_request;
+    struct set_socket_deferred_request set_socket_deferred_request;
     struct alloc_console_request alloc_console_request;
     struct free_console_request free_console_request;
     struct get_console_renderer_events_request get_console_renderer_events_request;
@@ -3078,6 +3090,7 @@
     struct set_socket_event_reply set_socket_event_reply;
     struct get_socket_event_reply get_socket_event_reply;
     struct enable_socket_event_reply enable_socket_event_reply;
+    struct set_socket_deferred_reply set_socket_deferred_reply;
     struct alloc_console_reply alloc_console_reply;
     struct free_console_reply free_console_reply;
     struct get_console_renderer_events_reply get_console_renderer_events_reply;
@@ -3183,6 +3196,6 @@
     struct get_window_properties_reply get_window_properties_reply;
 };

-#define SERVER_PROTOCOL_VERSION 78
+#define SERVER_PROTOCOL_VERSION 79

 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */
diff -ruNX ignore CVS/wine/server/protocol.def TMP/wine/server/protocol.def
--- CVS/wine/server/protocol.def	Tue Apr 16 11:29:41 2002
+++ TMP/wine/server/protocol.def	Mon Apr 22 10:52:43 2002
@@ -746,6 +746,10 @@
     unsigned int cstate;        /* status bits to clear */
 @END

+ at REQ(set_socket_deferred)
+    handle_t     handle;        /* handle to the socket */
+    handle_t     deferred;      /* handle to the socket for which accept() is deferred */
+ at END

 /* Allocate a console (only used by a console renderer) */
 @REQ(alloc_console)
diff -ruNX ignore CVS/wine/server/request.h TMP/wine/server/request.h
--- CVS/wine/server/request.h	Tue Apr 16 11:29:41 2002
+++ TMP/wine/server/request.h	Mon Apr 22 10:52:43 2002
@@ -152,6 +152,7 @@
 DECL_HANDLER(set_socket_event);
 DECL_HANDLER(get_socket_event);
 DECL_HANDLER(enable_socket_event);
+DECL_HANDLER(set_socket_deferred);
 DECL_HANDLER(alloc_console);
 DECL_HANDLER(free_console);
 DECL_HANDLER(get_console_renderer_events);
@@ -312,6 +313,7 @@
     (req_handler)req_set_socket_event,
     (req_handler)req_get_socket_event,
     (req_handler)req_enable_socket_event,
+    (req_handler)req_set_socket_deferred,
     (req_handler)req_alloc_console,
     (req_handler)req_free_console,
     (req_handler)req_get_console_renderer_events,
diff -ruNX ignore CVS/wine/server/sock.c TMP/wine/server/sock.c
--- CVS/wine/server/sock.c	Tue Apr 16 11:29:41 2002
+++ TMP/wine/server/sock.c	Mon Apr 22 10:52:43 2002
@@ -72,6 +72,7 @@
     unsigned int        message;     /* message to send */
     unsigned int        wparam;      /* message wparam (socket handle) */
     int                 errors[FD_MAX_EVENTS]; /* event errors */
+    struct sock*        deferred;    /* socket that waits for a deferred accept */
     struct async_queue  read_q;      /* Queue for asynchronous reads */
     struct async_queue  write_q;     /* Queue for asynchronous writes */
 };
@@ -361,6 +362,9 @@

     /* FIXME: special socket shutdown stuff? */

+    if ( sock->deferred )
+        release_object ( sock->deferred );
+
     if ( sock->flags & WSA_FLAG_OVERLAPPED )
     {
         destroy_async_queue ( &sock->read_q );
@@ -394,13 +398,14 @@
     sock->window  = 0;
     sock->message = 0;
     sock->wparam  = 0;
-    sock_reselect( sock );
-    clear_error();
+    sock->deferred = NULL;
     if (sock->flags & WSA_FLAG_OVERLAPPED)
     {
         init_async_queue (&sock->read_q);
         init_async_queue (&sock->write_q);
     }
+    sock_reselect( sock );
+    clear_error();
     return &sock->obj;
 }

@@ -417,44 +422,51 @@
                                       GENERIC_READ|GENERIC_WRITE|SYNCHRONIZE,&sock_ops);
     if (!sock)
     	return NULL;
-    /* Try to accept(2). We can't be safe that this an already connected socket
-     * or that accept() is allowed on it. In those cases we will get -1/errno
-     * return.
-     */
-    slen = sizeof(saddr);
-    acceptfd = accept(sock->obj.fd,&saddr,&slen);
-    if (acceptfd==-1) {
-    	sock_set_error();
-        release_object( sock );
-	return NULL;
-    }
-    if (!(acceptsock = alloc_object( &sock_ops, -1 )))
-    {
-        release_object( sock );
-        return NULL;
-    }

-    /* newly created socket gets the same properties of the listening socket */
-    fcntl(acceptfd, F_SETFL, O_NONBLOCK); /* make socket nonblocking */
-    acceptsock->obj.fd = acceptfd;
-    acceptsock->state  = FD_WINE_CONNECTED|FD_READ|FD_WRITE;
-    if (sock->state & FD_WINE_NONBLOCKING)
-        acceptsock->state |= FD_WINE_NONBLOCKING;
-    acceptsock->mask    = sock->mask;
-    acceptsock->hmask   = 0;
-    acceptsock->pmask   = 0;
-    acceptsock->event   = NULL;
-    acceptsock->window  = sock->window;
-    acceptsock->message = sock->message;
-    acceptsock->wparam  = 0;
-    if (sock->event) acceptsock->event = (struct event *)grab_object( sock->event );
-    acceptsock->flags = sock->flags;
-    if ( acceptsock->flags & WSA_FLAG_OVERLAPPED )
-    {
-	init_async_queue ( &acceptsock->read_q );
-	init_async_queue ( &acceptsock->write_q );
-    }
+    if ( sock->deferred ) {
+        acceptsock = sock->deferred;
+        sock->deferred = NULL;
+    } else {
+
+        /* Try to accept(2). We can't be safe that this an already connected socket
+         * or that accept() is allowed on it. In those cases we will get -1/errno
+         * return.
+         */
+        slen = sizeof(saddr);
+        acceptfd = accept(sock->obj.fd,&saddr,&slen);
+        if (acceptfd==-1) {
+            sock_set_error();
+            release_object( sock );
+            return NULL;
+        }
+        if (!(acceptsock = alloc_object( &sock_ops, -1 )))
+        {
+            release_object( sock );
+            return NULL;
+        }

+        /* newly created socket gets the same properties of the listening socket */
+        fcntl(acceptfd, F_SETFL, O_NONBLOCK); /* make socket nonblocking */
+        acceptsock->obj.fd = acceptfd;
+        acceptsock->state  = FD_WINE_CONNECTED|FD_READ|FD_WRITE;
+        if (sock->state & FD_WINE_NONBLOCKING)
+            acceptsock->state |= FD_WINE_NONBLOCKING;
+        acceptsock->mask    = sock->mask;
+        acceptsock->hmask   = 0;
+        acceptsock->pmask   = 0;
+        acceptsock->event   = NULL;
+        acceptsock->window  = sock->window;
+        acceptsock->message = sock->message;
+        acceptsock->wparam  = 0;
+        if (sock->event) acceptsock->event = (struct event *)grab_object( sock->event );
+        acceptsock->flags = sock->flags;
+        acceptsock->deferred = 0;
+        if ( acceptsock->flags & WSA_FLAG_OVERLAPPED )
+        {
+            init_async_queue ( &acceptsock->read_q );
+            init_async_queue ( &acceptsock->write_q );
+        }
+    }
     clear_error();
     sock->pmask &= ~FD_ACCEPT;
     sock->hmask &= ~FD_ACCEPT;
@@ -645,4 +657,27 @@
     sock->state &= ~req->cstate;
     sock_reselect( sock );
     release_object( &sock->obj );
+}
+
+DECL_HANDLER(set_socket_deferred)
+{
+    struct sock *sock, *acceptsock;
+
+    sock=(struct sock*)get_handle_obj( current->process,req->handle,
+                                       GENERIC_READ|GENERIC_WRITE|SYNCHRONIZE,&sock_ops );
+    if ( !sock )
+    {
+        set_error ( WSAENOTSOCK );
+        return;
+    }
+    acceptsock = (struct sock*)get_handle_obj( current->process,req->deferred,
+                                               GENERIC_READ|GENERIC_WRITE|SYNCHRONIZE,&sock_ops );
+    if ( !acceptsock )
+    {
+        release_object ( sock );
+        set_error ( WSAENOTSOCK );
+        return;
+    }
+    sock->deferred = acceptsock;
+    release_object ( sock );
 }
diff -ruNX ignore CVS/wine/server/trace.c TMP/wine/server/trace.c
--- CVS/wine/server/trace.c	Tue Apr 16 11:29:41 2002
+++ TMP/wine/server/trace.c	Mon Apr 22 10:52:43 2002
@@ -943,6 +943,12 @@
     fprintf( stderr, " cstate=%08x", req->cstate );
 }

+static void dump_set_socket_deferred_request( const struct set_socket_deferred_request *req )
+{
+    fprintf( stderr, " handle=%d,", req->handle );
+    fprintf( stderr, " deferred=%d", req->deferred );
+}
+
 static void dump_alloc_console_request( const struct alloc_console_request *req )
 {
     fprintf( stderr, " access=%08x,", req->access );
@@ -2215,6 +2221,7 @@
     (dump_func)dump_set_socket_event_request,
     (dump_func)dump_get_socket_event_request,
     (dump_func)dump_enable_socket_event_request,
+    (dump_func)dump_set_socket_deferred_request,
     (dump_func)dump_alloc_console_request,
     (dump_func)dump_free_console_request,
     (dump_func)dump_get_console_renderer_events_request,
@@ -2372,6 +2379,7 @@
     (dump_func)0,
     (dump_func)dump_get_socket_event_reply,
     (dump_func)0,
+    (dump_func)0,
     (dump_func)dump_alloc_console_reply,
     (dump_func)0,
     (dump_func)dump_get_console_renderer_events_reply,
@@ -2529,6 +2537,7 @@
     "set_socket_event",
     "get_socket_event",
     "enable_socket_event",
+    "set_socket_deferred",
     "alloc_console",
     "free_console",
     "get_console_renderer_events",
Binary files CVS/wine/wine and TMP/wine/wine differ






More information about the wine-patches mailing list