diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 0c43ecf6d03..a8671248975 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -1344,6 +1344,20 @@ struct accept_socket_reply +struct accept_into_socket_request +{ + struct request_header __header; + obj_handle_t lhandle; + obj_handle_t ahandle; + char __pad_20[4]; +}; +struct accept_into_socket_reply +{ + struct reply_header __header; +}; + + + struct set_socket_event_request { struct request_header __header; @@ -4791,6 +4805,7 @@ enum request REQ_unlock_file, REQ_create_socket, REQ_accept_socket, + REQ_accept_into_socket, REQ_set_socket_event, REQ_get_socket_event, REQ_enable_socket_event, @@ -5040,6 +5055,7 @@ union generic_request struct unlock_file_request unlock_file_request; struct create_socket_request create_socket_request; struct accept_socket_request accept_socket_request; + struct accept_into_socket_request accept_into_socket_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; @@ -5287,6 +5303,7 @@ union generic_reply struct unlock_file_reply unlock_file_reply; struct create_socket_reply create_socket_reply; struct accept_socket_reply accept_socket_reply; + struct accept_into_socket_reply accept_into_socket_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; @@ -5487,6 +5504,6 @@ union generic_reply struct set_cursor_reply set_cursor_reply; }; -#define SERVER_PROTOCOL_VERSION 403 +#define SERVER_PROTOCOL_VERSION 404 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */ diff --git a/server/fd.c b/server/fd.c index 9111a657e91..f9a769e1357 100644 --- a/server/fd.c +++ b/server/fd.c @@ -1599,32 +1599,20 @@ struct fd *alloc_pseudo_fd( const struct fd_ops *fd_user_ops, struct object *use /* duplicate an fd object for a different user */ struct fd *dup_fd_object( struct fd *orig, unsigned int access, unsigned int sharing, unsigned int options ) { - struct fd *fd = alloc_object( &fd_ops ); + struct fd *fd = alloc_fd_object(); if (!fd) return NULL; - fd->fd_ops = NULL; - fd->user = NULL; - fd->inode = NULL; - fd->closed = NULL; fd->access = access; fd->options = options; fd->sharing = sharing; - fd->unix_fd = -1; fd->cacheable = orig->cacheable; - fd->signaled = 0; - fd->fs_locks = 0; - fd->poll_index = -1; - fd->read_q = NULL; - fd->write_q = NULL; - fd->wait_q = NULL; - fd->completion = NULL; - list_init( &fd->inode_entry ); - list_init( &fd->locks ); - if (!(fd->unix_name = mem_alloc( strlen(orig->unix_name) + 1 ))) goto failed; - strcpy( fd->unix_name, orig->unix_name ); - if ((fd->poll_index = add_poll_user( fd )) == -1) goto failed; + if (orig->unix_name) + { + if (!(fd->unix_name = mem_alloc( strlen(orig->unix_name) + 1 ))) goto failed; + strcpy( fd->unix_name, orig->unix_name ); + } if (orig->inode) { diff --git a/server/protocol.def b/server/protocol.def index 5f1a8f99950..00a1d9291e8 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1089,6 +1089,13 @@ enum server_fd_type @END +/* Accept into an initialized socket */ +@REQ(accept_into_socket) + obj_handle_t lhandle; /* handle to the listening socket */ + obj_handle_t ahandle; /* handle to the accepting socket */ +@END + + /* Set socket event parameters */ @REQ(set_socket_event) obj_handle_t handle; /* handle to the socket */ diff --git a/server/request.h b/server/request.h index 7897673bb27..1e6b0a2d5a1 100644 --- a/server/request.h +++ b/server/request.h @@ -155,6 +155,7 @@ DECL_HANDLER(lock_file); DECL_HANDLER(unlock_file); DECL_HANDLER(create_socket); DECL_HANDLER(accept_socket); +DECL_HANDLER(accept_into_socket); DECL_HANDLER(set_socket_event); DECL_HANDLER(get_socket_event); DECL_HANDLER(enable_socket_event); @@ -403,6 +404,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] = (req_handler)req_unlock_file, (req_handler)req_create_socket, (req_handler)req_accept_socket, + (req_handler)req_accept_into_socket, (req_handler)req_set_socket_event, (req_handler)req_get_socket_event, (req_handler)req_enable_socket_event, @@ -924,6 +926,9 @@ C_ASSERT( FIELD_OFFSET(struct accept_socket_request, attributes) == 20 ); C_ASSERT( sizeof(struct accept_socket_request) == 24 ); C_ASSERT( FIELD_OFFSET(struct accept_socket_reply, handle) == 8 ); C_ASSERT( sizeof(struct accept_socket_reply) == 16 ); +C_ASSERT( FIELD_OFFSET(struct accept_into_socket_request, lhandle) == 12 ); +C_ASSERT( FIELD_OFFSET(struct accept_into_socket_request, ahandle) == 16 ); +C_ASSERT( sizeof(struct accept_into_socket_request) == 24 ); C_ASSERT( FIELD_OFFSET(struct set_socket_event_request, handle) == 12 ); C_ASSERT( FIELD_OFFSET(struct set_socket_event_request, mask) == 16 ); C_ASSERT( FIELD_OFFSET(struct set_socket_event_request, event) == 20 ); diff --git a/server/sock.c b/server/sock.c index 7e1cd7e3fe5..886872d60a1 100644 --- a/server/sock.c +++ b/server/sock.c @@ -605,6 +605,26 @@ static void sock_destroy( struct object *obj ) } } +static void init_sock(struct sock *sock) +{ + sock->state = 0; + sock->mask = 0; + sock->hmask = 0; + sock->pmask = 0; + sock->polling = 0; + sock->flags = 0; + sock->type = 0; + sock->family = 0; + sock->event = NULL; + sock->window = 0; + sock->message = 0; + sock->wparam = 0; + sock->deferred = NULL; + sock->read_q = NULL; + sock->write_q = NULL; + memset( sock->errors, 0, sizeof(sock->errors) ); +} + /* create a new and unconnected socket */ static struct object *create_socket( int family, int type, int protocol, unsigned int flags ) { @@ -625,22 +645,12 @@ static struct object *create_socket( int family, int type, int protocol, unsigne close( sockfd ); return NULL; } - sock->state = (type != SOCK_STREAM) ? (FD_READ|FD_WRITE) : 0; - sock->mask = 0; - sock->hmask = 0; - sock->pmask = 0; - sock->polling = 0; - sock->flags = flags; - sock->type = type; - sock->family = family; - sock->event = NULL; - sock->window = 0; - sock->message = 0; - sock->wparam = 0; - sock->deferred = NULL; - sock->read_q = NULL; - sock->write_q = NULL; - memset( sock->errors, 0, sizeof(sock->errors) ); + init_sock( sock ); + sock->state = (type != SOCK_STREAM) ? (FD_READ|FD_WRITE) : 0; + sock->flags = flags; + sock->type = type; + sock->family = family; + if (!(sock->fd = create_anonymous_fd( &sock_fd_ops, sockfd, &sock->obj, (flags & WSA_FLAG_OVERLAPPED) ? 0 : FILE_SYNCHRONOUS_IO_NONALERT ))) { @@ -652,17 +662,38 @@ static struct object *create_socket( int family, int type, int protocol, unsigne return &sock->obj; } +/* accepts a socket and inits it */ +static int accept_new_fd( struct sock *sock ) +{ + + /* 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. + */ + int acceptfd; + struct sockaddr saddr; + unsigned int slen = sizeof(saddr); + acceptfd = accept( get_unix_fd(sock->fd), &saddr, &slen); + if (acceptfd == -1) + { + sock_set_error(); + return acceptfd; + } + + fcntl(acceptfd, F_SETFL, O_NONBLOCK); /* make socket nonblocking */ + return acceptfd; +} + /* accept a socket (creates a new fd) */ static struct sock *accept_socket( obj_handle_t handle ) { struct sock *acceptsock; struct sock *sock; int acceptfd; - struct sockaddr saddr; sock = (struct sock *)get_handle_obj( current->process, handle, FILE_READ_DATA, &sock_ops ); if (!sock) - return NULL; + return NULL; if ( sock->deferred ) { @@ -671,16 +702,8 @@ static struct sock *accept_socket( obj_handle_t handle ) } 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. - */ - unsigned int slen = sizeof(saddr); - acceptfd = accept( get_unix_fd(sock->fd), &saddr, &slen); - if (acceptfd==-1) + if ((acceptfd = accept_new_fd( sock )) == -1) { - sock_set_error(); release_object( sock ); return NULL; } @@ -691,27 +714,18 @@ static struct sock *accept_socket( obj_handle_t handle ) return NULL; } + init_sock( acceptsock ); /* newly created socket gets the same properties of the listening socket */ - fcntl(acceptfd, F_SETFL, O_NONBLOCK); /* make socket nonblocking */ 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->polling = 0; acceptsock->type = sock->type; acceptsock->family = sock->family; - 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 = NULL; - acceptsock->read_q = NULL; - acceptsock->write_q = NULL; - memset( acceptsock->errors, 0, sizeof(acceptsock->errors) ); if (!(acceptsock->fd = create_anonymous_fd( &sock_fd_ops, acceptfd, &acceptsock->obj, get_fd_options( sock->fd ) ))) { @@ -728,6 +742,54 @@ static struct sock *accept_socket( obj_handle_t handle ) return acceptsock; } +static int accept_into_socket( struct sock *sock, struct sock *acceptsock ) +{ + int acceptfd; + struct fd *newfd; + if ( sock->deferred ) + { + newfd = dup_fd_object( sock->deferred->fd, 0, 0, + get_fd_options( acceptsock->fd ) ); + if ( !newfd ) + return FALSE; + + set_fd_user( newfd, &sock_fd_ops, &acceptsock->obj ); + + release_object( sock->deferred ); + sock->deferred = NULL; + } + else + { + if ((acceptfd = accept_new_fd( sock )) == -1) + return FALSE; + + if (!(newfd = create_anonymous_fd( &sock_fd_ops, acceptfd, &acceptsock->obj, + get_fd_options( acceptsock->fd ) ))) + { + close( acceptfd ); + return FALSE; + } + } + + acceptsock->state |= FD_WINE_CONNECTED|FD_READ|FD_WRITE; + acceptsock->hmask = 0; + acceptsock->pmask = 0; + acceptsock->polling = 0; + acceptsock->type = sock->type; + acceptsock->family = sock->family; + acceptsock->wparam = 0; + acceptsock->deferred = NULL; + if (acceptsock->fd) release_object( acceptsock->fd ); + acceptsock->fd = newfd; + + clear_error(); + sock->pmask &= ~FD_ACCEPT; + sock->hmask &= ~FD_ACCEPT; + sock_reselect( sock ); + + return TRUE; +} + /* set the last error depending on errno */ static int sock_get_error( int err ) { @@ -877,6 +939,32 @@ DECL_HANDLER(accept_socket) } } +/* accept a socket into an initialized socket */ +DECL_HANDLER(accept_into_socket) +{ + struct sock *sock, *acceptsock; + const int all_attributes = FILE_READ_ATTRIBUTES|FILE_WRITE_ATTRIBUTES|FILE_READ_DATA; + + if (!(sock = (struct sock *)get_handle_obj( current->process, req->lhandle, + all_attributes, &sock_ops))) + return; + + if (!(acceptsock = (struct sock *)get_handle_obj( current->process, req->ahandle, + all_attributes, &sock_ops))) + { + release_object( sock ); + return; + } + + if (accept_into_socket( sock, acceptsock )) + { + acceptsock->wparam = req->ahandle; /* wparam for message is the socket handle */ + sock_reselect( acceptsock ); + } + release_object( acceptsock ); + release_object( sock ); +} + /* set socket event parameters */ DECL_HANDLER(set_socket_event) { diff --git a/server/trace.c b/server/trace.c index 944d939cb84..977828bbfa7 100644 --- a/server/trace.c +++ b/server/trace.c @@ -1539,6 +1539,12 @@ static void dump_accept_socket_reply( const struct accept_socket_reply *req ) fprintf( stderr, " handle=%04x", req->handle ); } +static void dump_accept_into_socket_request( const struct accept_into_socket_request *req ) +{ + fprintf( stderr, " lhandle=%04x", req->lhandle ); + fprintf( stderr, ", ahandle=%04x", req->ahandle ); +} + static void dump_set_socket_event_request( const struct set_socket_event_request *req ) { fprintf( stderr, " handle=%04x", req->handle ); @@ -3874,6 +3880,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_unlock_file_request, (dump_func)dump_create_socket_request, (dump_func)dump_accept_socket_request, + (dump_func)dump_accept_into_socket_request, (dump_func)dump_set_socket_event_request, (dump_func)dump_get_socket_event_request, (dump_func)dump_enable_socket_event_request, @@ -4120,6 +4127,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_create_socket_reply, (dump_func)dump_accept_socket_reply, NULL, + NULL, (dump_func)dump_get_socket_event_reply, NULL, NULL, @@ -4364,6 +4372,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = { "unlock_file", "create_socket", "accept_socket", + "accept_into_socket", "set_socket_event", "get_socket_event", "enable_socket_event",