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