diff --git a/dlls/winsock/socket.c b/dlls/winsock/socket.c index dd5dfc021f9..29cbc6c1e0f 100644 --- a/dlls/winsock/socket.c +++ b/dlls/winsock/socket.c @@ -1138,6 +1138,19 @@ INT16 WINAPI WINSOCK_connect16(SOCKET16 s, struct WS_sockaddr *name, INT16 namel return (INT16)WS_connect( s, name, namelen ); } +/*********************************************************************** + * 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) */ @@ -3419,7 +3432,7 @@ SOCKET WINAPI WSAAccept( SOCKET s, struct WS_sockaddr *addr, LPINT addrlen, 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 @@ SOCKET WINAPI WSAAccept( SOCKET s, struct WS_sockaddr *addr, LPINT addrlen, 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 --git a/dlls/winsock/ws2_32.spec b/dlls/winsock/ws2_32.spec index 34dfceea76f..81e0952db7a 100644 --- a/dlls/winsock/ws2_32.spec +++ b/dlls/winsock/ws2_32.spec @@ -42,7 +42,7 @@ debug_channels (winsock) 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 --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 5f778d3e2b6..7241164382d 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -1001,6 +1001,16 @@ struct enable_socket_event_reply 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 @@ enum request 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 @@ union generic_request 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 @@ union generic_reply 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 @@ union generic_reply 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 --git a/server/protocol.def b/server/protocol.def index ba96ea7f660..e15147071e6 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -746,6 +746,10 @@ enum fd_type 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 --git a/server/request.h b/server/request.h index 99bba362098..f14b26efa89 100644 --- a/server/request.h +++ b/server/request.h @@ -152,6 +152,7 @@ DECL_HANDLER(accept_socket); 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 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] = (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 --git a/server/sock.c b/server/sock.c index 3d1e13969aa..d9c0be71825 100644 --- a/server/sock.c +++ b/server/sock.c @@ -72,6 +72,7 @@ struct sock 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 @@ static void sock_destroy( struct object *obj ) /* 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 @@ static struct object *create_socket( int family, int type, int protocol, unsigne 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 @@ static struct sock *accept_socket( handle_t handle ) 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; @@ -646,3 +658,26 @@ DECL_HANDLER(enable_socket_event) 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 --git a/server/trace.c b/server/trace.c index 00eb57d0d1c..b577e7125b4 100644 --- a/server/trace.c +++ b/server/trace.c @@ -943,6 +943,12 @@ static void dump_enable_socket_event_request( const struct enable_socket_event_r 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 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = { (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 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { (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 @@ static const char * const req_names[REQ_NB_REQUESTS] = { "set_socket_event", "get_socket_event", "enable_socket_event", + "set_socket_deferred", "alloc_console", "free_console", "get_console_renderer_events",