PATCH: accept-deferred.diff
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.
The current CVS implementation of WSAAccept is wrong in this respect. This patch fixes this. Furthermore, it includes a trivial implementation of WSAConnect().
Patch against: CVS 2002-04-12.
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 TMP/wine/dlls/winsock/socket.c MW/wine/dlls/winsock/socket.c --- TMP/wine/dlls/winsock/socket.c Tue Apr 9 13:29:12 2002 +++ MW/wine/dlls/winsock/socket.c Fri Apr 12 14:50:50 2002 @@ -1140,6 +1140,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 ) + WARN ("unsupported parameters!"); + return WS_connect ( s, name, namelen ); +} + + +/*********************************************************************** * getpeername (WS2_32.5) */ int WINAPI WS_getpeername(SOCKET s, struct WS_sockaddr *name, int *namelen) @@ -3420,7 +3433,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, dwCallbackD ata %ld\n", s, addr, addrlen, lpfnCondition, dwCallbackData);
@@ -3451,7 +3464,14 @@ 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 ); + } + SERVER_END_REQ; return SOCKET_ERROR; case CF_REJECT: WS_closesocket(cs); diff -ruNX ignore TMP/wine/dlls/winsock/ws2_32.spec MW/wine/dlls/winsock/ws2_32.spec --- TMP/wine/dlls/winsock/ws2_32.spec Mon Apr 8 10:56:59 2002 +++ MW/wine/dlls/winsock/ws2_32.spec Fri Apr 12 14:52:57 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 TMP/wine/include/wine/server_protocol.h MW/wine/include/wine/server_protocol.h --- TMP/wine/include/wine/server_protocol.h Mon Apr 8 10:56:59 2002 +++ MW/wine/include/wine/server_protocol.h Fri Apr 12 14:25:47 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 TMP/wine/server/protocol.def MW/wine/server/protocol.def --- TMP/wine/server/protocol.def Mon Apr 8 10:56:59 2002 +++ MW/wine/server/protocol.def Fri Apr 12 14:18:38 2002 @@ -746,6 +746,10 @@ unsigned int cstate; /* status bits to clear */ @END
+@REQ(set_socket_deferred) + handle_t handle; /* handle to the socket */ + handle_t deferred; /* handle to the socket for which accept() is deferred */ +@END
/* Allocate a console (only used by a console renderer) */ @REQ(alloc_console) diff -ruNX ignore TMP/wine/server/request.h MW/wine/server/request.h --- TMP/wine/server/request.h Fri Apr 5 12:21:25 2002 +++ MW/wine/server/request.h Fri Apr 12 14:16:35 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 TMP/wine/server/sock.c MW/wine/server/sock.c --- TMP/wine/server/sock.c Tue Apr 2 16:51:51 2002 +++ MW/wine/server/sock.c Fri Apr 12 14:24:35 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 */ + handle_t 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 ) + close_handle ( current->process, sock->deferred, NULL ); + if ( sock->flags & WSA_FLAG_OVERLAPPED ) { destroy_async_queue ( &sock->read_q ); @@ -394,18 +398,19 @@ sock->window = 0; sock->message = 0; sock->wparam = 0; - sock_reselect( sock ); - clear_error(); + sock->deferred = 0; 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; }
/* accept a socket (creates a new fd) */ -static struct sock *accept_socket( handle_t handle ) +static struct sock *accept_socket( handle_t handle, handle_t *accept_handle, unsigned int access, int inherit ) { struct sock *acceptsock; struct sock *sock; @@ -417,42 +422,52 @@ 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; - } + if ( sock->deferred ) { + acceptsock = (struct sock*)get_handle_obj( current->process, sock->deferred, + GENERIC_READ|GENERIC_WRITE|SYNCHRONIZE,&sock_ops ); + *accept_handle = sock->deferred; + sock->deferred = 0; + } 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; - if ( acceptsock->flags & WSA_FLAG_OVERLAPPED ) - { - init_async_queue ( &acceptsock->read_q ); - init_async_queue ( &acceptsock->write_q ); + /* 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 ); + } + *accept_handle = alloc_handle( current->process, &acceptsock->obj, access, inherit ); }
clear_error(); @@ -552,9 +567,8 @@ struct sock *sock;
reply->handle = 0; - if ((sock = accept_socket( req->lhandle )) != NULL) + if ( (sock = accept_socket( req->lhandle, &reply->handle, req->access, req->inherit )) != NULL ) { - reply->handle = alloc_handle( current->process, &sock->obj, req->access, req->inherit ); sock->wparam = reply->handle; /* wparam for message is the socket handle */ sock_reselect( sock ); release_object( &sock->obj ); @@ -645,4 +659,27 @@ sock->state &= ~req->cstate; sock_reselect( sock ); release_object( &sock->obj ); +} + +DECL_HANDLER(set_socket_deferred) +{ + struct sock *sock; + + sock=(struct sock*)get_handle_obj( current->process,req->handle, + GENERIC_READ|GENERIC_WRITE|SYNCHRONIZE,&sock_ops ); + if (!sock) + { + set_error ( WSAENOTSOCK ); + return; + } + sock->deferred = req->deferred; + /* duplicate_handle ( current->process, req->deferred, current->process, + GENERIC_READ|GENERIC_WRITE|SYNCHRONIZE, TRUE, 0 ); */ + if ( !sock->deferred ) + { + release_object ( sock ); + set_error ( WSAENOTSOCK ); + return; + } + release_object ( sock ); } diff -ruNX ignore TMP/wine/server/trace.c MW/wine/server/trace.c --- TMP/wine/server/trace.c Mon Apr 8 10:56:59 2002 +++ MW/wine/server/trace.c Fri Apr 12 14:16:35 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",