From e3532cd018cd6b2084441704ad4e02cdb4916d31 Mon Sep 17 00:00:00 2001 From: Scott Lindeneau Date: Mon, 1 Sep 2008 03:59:02 +0900 Subject: [PATCH] Implements register_socket_listener and DECL_HANDLER(register_socker_listner) To: wine-patches sock.c: register_socket_listener sets up and maintains lists of dependent sockets. register_socket_listner queues a FILE_READ_DATA async request on the listening socket. register_socket_listener takes two socket handles and the necessary information to setup an async request complete with callback information. The two socket handles correspond to a listening socket and an accepting handle. It also queues a FILE_READ_DATA async on the listening socket. This function provides the setup for acceptex in the wineserver. The wineserver is responsible for accepting a connection from a listening socket onto an accepting socket BEFORE it wakes up any async read requests. If the wineserver does not do this before passing control back to the user thread in the dll race conditions exist between the user threads and the wineserver thread. For this reason we maintain a second list of pending connections and dependent connections. --- include/wine/server_protocol.h | 20 ++++++++++- server/protocol.def | 9 +++++ server/request.h | 2 + server/sock.c | 77 ++++++++++++++++++++++++++++++++++++++-- server/trace.c | 12 ++++++ 5 files changed, 116 insertions(+), 4 deletions(-) diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index e4f1378..e0f5cb1 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -1132,6 +1132,21 @@ struct unlock_file_reply +struct register_socket_listener_request +{ + struct request_header __header; + obj_handle_t lhandle; + obj_handle_t ahandle; + int count; + async_data_t async; +}; +struct register_socket_listener_reply +{ + struct reply_header __header; +}; + + + struct create_socket_request { struct request_header __header; @@ -4327,6 +4342,7 @@ enum request REQ_flush_file, REQ_lock_file, REQ_unlock_file, + REQ_register_socket_listener, REQ_create_socket, REQ_accept_socket, REQ_set_socket_event, @@ -4567,6 +4583,7 @@ union generic_request struct flush_file_request flush_file_request; struct lock_file_request lock_file_request; struct unlock_file_request unlock_file_request; + struct register_socket_listener_request register_socket_listener_request; struct create_socket_request create_socket_request; struct accept_socket_request accept_socket_request; struct set_socket_event_request set_socket_event_request; @@ -4805,6 +4822,7 @@ union generic_reply struct flush_file_reply flush_file_reply; struct lock_file_reply lock_file_reply; struct unlock_file_reply unlock_file_reply; + struct register_socket_listener_reply register_socket_listener_reply; struct create_socket_reply create_socket_reply; struct accept_socket_reply accept_socket_reply; struct set_socket_event_reply set_socket_event_reply; @@ -4999,6 +5017,6 @@ union generic_reply struct add_fd_completion_reply add_fd_completion_reply; }; -#define SERVER_PROTOCOL_VERSION 346 +#define SERVER_PROTOCOL_VERSION 347 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */ diff --git a/server/protocol.def b/server/protocol.def index 185ec64..25f6193 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -934,6 +934,15 @@ enum server_fd_type @END +/* Register a socket listener */ +@REQ(register_socket_listener) + obj_handle_t lhandle; /* handle to the listening socket */ + obj_handle_t ahandle; /* handle to the accepting socket */ + int count; /* count - usually # of bytes to be read/written */ + async_data_t async; /* async I/O parameters */ +@END + + /* Create a socket */ @REQ(create_socket) unsigned int access; /* wanted access rights */ diff --git a/server/request.h b/server/request.h index 00bdcaf..3104216 100644 --- a/server/request.h +++ b/server/request.h @@ -152,6 +152,7 @@ DECL_HANDLER(get_handle_fd); DECL_HANDLER(flush_file); DECL_HANDLER(lock_file); DECL_HANDLER(unlock_file); +DECL_HANDLER(register_socket_listener); DECL_HANDLER(create_socket); DECL_HANDLER(accept_socket); DECL_HANDLER(set_socket_event); @@ -391,6 +392,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] = (req_handler)req_flush_file, (req_handler)req_lock_file, (req_handler)req_unlock_file, + (req_handler)req_register_socket_listener, (req_handler)req_create_socket, (req_handler)req_accept_socket, (req_handler)req_set_socket_event, diff --git a/server/sock.c b/server/sock.c index 913aeab..7243bb6 100644 --- a/server/sock.c +++ b/server/sock.c @@ -65,6 +65,13 @@ #define USE_WS_PREFIX #include "winsock2.h" +struct sock_list /* list of sockets */ +{ + struct sock* sock; /* associated socket sock* */ + obj_handle_t shandle; /* associated socket handle */ + struct list entry; /* list entry */ +}; + struct sock { struct object obj; /* object header */ @@ -85,6 +92,7 @@ struct sock 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 */ + struct sock_list slist; /* list of sockets that is associated with this socket */ }; static void sock_dump( struct object *obj, int verbose ); @@ -353,7 +361,6 @@ static void sock_poll_event( struct fd *fd, int event ) { char dummy; int nr; - /* Linux 2.4 doesn't report POLLHUP if only one side of the socket * has been closed, so we need to check for it explicitly here */ nr = recv( get_unix_fd( fd ), &dummy, 1, MSG_PEEK ); @@ -616,6 +623,7 @@ static struct object *create_socket( int family, int type, int protocol, unsigne sock->deferred = NULL; sock->read_q = NULL; sock->write_q = NULL; + list_init(&sock->slist.entry); if (!(sock->fd = create_anonymous_fd( &sock_fd_ops, sockfd, &sock->obj, (flags & WSA_FLAG_OVERLAPPED) ? 0 : FILE_SYNCHRONOUS_IO_NONALERT ))) { @@ -652,7 +660,7 @@ static struct sock *accept_socket_obj( struct sock *sock, struct sock *acceptsoc sock_set_error(); return NULL; } - + if(!acceptsock) { acceptsock = alloc_object( &sock_ops ); @@ -693,7 +701,6 @@ static struct sock *accept_socket_obj( struct sock *sock, struct sock *acceptsoc sock->pmask &= ~FD_ACCEPT; sock->hmask &= ~FD_ACCEPT; sock_reselect( sock ); - release_object( sock ); return acceptsock; } /* accept a socket (creates a new fd) */ @@ -717,6 +724,8 @@ static struct sock *accept_socket( obj_handle_t handle, obj_handle_t ahandle ) ret = accept_socket_obj( sock, acceptsock ); if( ret != NULL) { + if(ahandle == NULL) + list_init(&ret->slist.entry); ret->wparam = ahandle; } if( acceptsock ) @@ -725,6 +734,50 @@ static struct sock *accept_socket( obj_handle_t handle, obj_handle_t ahandle ) return ret; } +/* registers a listening socket for an accepting socket */ +static void register_listening_socket( obj_handle_t lhandle, obj_handle_t ahandle ) +{ + struct sock *listen; + struct sock *accept; + struct sock_list *lnew; + struct sock_list *anew; + listen = (struct sock *)get_handle_obj( current->process, lhandle, FILE_WRITE_ATTRIBUTES, &sock_ops ); + accept = (struct sock *)get_handle_obj( current->process, ahandle, FILE_WRITE_ATTRIBUTES, &sock_ops ); + + if ( listen == NULL || accept == NULL ) + { + release_object( listen ); + release_object( accept ); + set_error( STATUS_INVALID_PARAMETER ); + return; + } + + lnew = (struct sock_list*) mem_alloc( sizeof(struct sock_list) ); + anew = (struct sock_list*) mem_alloc( sizeof(struct sock_list) ); + + if( lnew == NULL || anew == NULL ) + { + if( lnew ) + free(lnew); + if( anew ) + free(anew); + release_object( listen ); + release_object( accept ); + set_error( STATUS_NO_MEMORY ); + } + + list_init(&lnew->entry); + list_init(&anew->entry); + lnew->sock = accept; + lnew->shandle = ahandle; + anew->sock = listen; + anew->shandle = lhandle; + list_add_tail(&listen->slist.entry,&lnew->entry); /* add accepting socket onto listening socket list */ + list_add_tail(&accept->slist.entry,&anew->entry); /* add listening socket onto accepting socket list */ + release_object( listen ); + release_object( accept ); +} + /* set the last error depending on errno */ static int sock_get_error( int err ) { @@ -798,6 +851,24 @@ static void sock_set_error(void) set_error( sock_get_error( errno ) ); } +/* register socket listener */ +DECL_HANDLER(register_socket_listener) +{ + struct sock *sock; + struct fd *fd; + + register_listening_socket( req->lhandle, req->ahandle ); /* register the sockets */ + + /* The listener gets the async request queued is only read_data */ + if ((sock = (struct sock *)get_handle_obj( current->process, req->lhandle, FILE_WRITE_ATTRIBUTES, &sock_ops ))) + { + fd = sock->fd; + /* register the async request locatable by the accepting handle */ + if (get_unix_fd( fd ) != -1) + sock_queue_async_l( fd, &req->async, FILE_READ_DATA, req->count, req->ahandle ); + release_object( sock ); + } +} /* create a socket */ DECL_HANDLER(create_socket) diff --git a/server/trace.c b/server/trace.c index 3775fb1..165dc32 100644 --- a/server/trace.c +++ b/server/trace.c @@ -1380,6 +1380,15 @@ static void dump_unlock_file_request( const struct unlock_file_request *req ) dump_file_pos( &req->count ); } +static void dump_register_socket_listener_request( const struct register_socket_listener_request *req ) +{ + fprintf( stderr, " lhandle=%p,", req->lhandle ); + fprintf( stderr, " ahandle=%p,", req->ahandle ); + fprintf( stderr, " count=%d,", req->count ); + fprintf( stderr, " async=" ); + dump_async_data( &req->async ); +} + static void dump_create_socket_request( const struct create_socket_request *req ) { fprintf( stderr, " access=%08x,", req->access ); @@ -3826,6 +3835,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_flush_file_request, (dump_func)dump_lock_file_request, (dump_func)dump_unlock_file_request, + (dump_func)dump_register_socket_listener_request, (dump_func)dump_create_socket_request, (dump_func)dump_accept_socket_request, (dump_func)dump_set_socket_event_request, @@ -4062,6 +4072,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_flush_file_reply, (dump_func)dump_lock_file_reply, (dump_func)0, + (dump_func)0, (dump_func)dump_create_socket_reply, (dump_func)dump_accept_socket_reply, (dump_func)0, @@ -4298,6 +4309,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = { "flush_file", "lock_file", "unlock_file", + "register_socket_listener", "create_socket", "accept_socket", "set_socket_event", -- 1.5.4.3