server: Add accept_into_socket to accept into an initialized socket.
authorMike Kaplinskiy <mike.kaplinskiy@gmail.com>
Sun, 29 Aug 2010 22:09:53 +0000 (18:09 -0400)
committerAlexandre Julliard <julliard@winehq.org>
Tue, 31 Aug 2010 12:23:49 +0000 (14:23 +0200)
include/wine/server_protocol.h
server/fd.c
server/protocol.def
server/request.h
server/sock.c
server/trace.c

index 0c43ecf6d03f8612b559f41c264a97cabfa94601..a86712489755328c06cd9c6e1a07a6e7682707d4 100644 (file)
@@ -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 */
index 9111a657e91a4ea86b88ceea8aa0419c638f9b7b..f9a769e13576970ec92a1b42063e441a45e3c434 100644 (file)
@@ -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)
     {
index 5f1a8f999505fd5c0039569fc153dd329269e913..00a1d9291e81b2b3cdc2b490e14c0fcd366483b6 100644 (file)
@@ -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 */
index 7897673bb272aa7b730d552aa77f8b25dc350cc7..1e6b0a2d5a1c20349d26129bc69bb49e33a836fd 100644 (file)
@@ -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 );
index 7e1cd7e3fe50696128273e88467c442589a8d675..886872d60a16c3afa80248754d11c6bcac57dc1f 100644 (file)
@@ -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)
 {
index 944d939cb84c6dc52207bebc53e994f6a0b229b5..977828bbfa798cc31e6cd0fb20976ee9b96e84df 100644 (file)
@@ -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",