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",
On April 12, 2002 11:20 am, Martin Wilck wrote:
/***********************************************************************
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!");
^^^^ Shouldn't this be a FIXME instead?
On Fri, 12 Apr 2002, Dimitrie O. Paun wrote:
- if ( lpCallerData || lpCalleeData || lpSQOS || lpGQOS )
WARN ("unsupported parameters!");
^^^^
Shouldn't this be a FIXME instead?
I don't think so - there is little to fix on the part of wine. AFAICS the Linux network stack simply doesn't support passing of additional parameters along with a connection request.
I am not so sure about the QOS parameters, but that appears to be a secondary issue.
Martin
On April 15, 2002 09:38 am, Martin Wilck wrote:
On Fri, 12 Apr 2002, Dimitrie O. Paun wrote:
- if ( lpCallerData || lpCalleeData || lpSQOS || lpGQOS )
WARN ("unsupported parameters!");
^^^^
Shouldn't this be a FIXME instead?
I don't think so - there is little to fix on the part of wine. AFAICS the Linux network stack simply doesn't support passing of additional parameters along with a connection request.
But this is irrelevant. Wine is supposed to implement the Win32 API, whether we know how to do it or not (on some platforms) is another matter. But we should be vocal (i.e. FIXME :)) when we can not implement all the features, this way people will implement them in the future, even if this requires modifications to the kernel.
There are only few cases where WARN is the right answer. Most messages are either ERR, FIXME or TRACE.
Martin Wilck Martin.Wilck@fujitsu-siemens.com writes:
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.
You cannot store a handle to the deferred socket in the server, you must store a pointer to the object and allocate a handle when returning it to the application. Handles are only valid in one process so they cannot be part of a server object that is potentially shared between several processes.
On 17 Apr 2002, Alexandre Julliard wrote:
Martin Wilck Martin.Wilck@fujitsu-siemens.com writes:
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.
OK - I keep overlooking issues like that :( Thanks for spotting it. Martin