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",