From 73afb3f5883624cf4afb6532e70981ee2e0c0d29 Mon Sep 17 00:00:00 2001
From: Mike Kaplinskiy <mike.kaplinskiy@gmail.com>
Date: Sun, 12 Jul 2009 15:44:07 -0400
Subject: server+ws2: change accept_socket to accept into an initialized socket

---
 dlls/ws2_32/socket.c |   54 ++++++++++++++++++++---
 server/protocol.def  |    5 +--
 server/sock.c        |  117 ++++++++++++++++++++++++++------------------------
 3 files changed, 109 insertions(+), 67 deletions(-)

diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c
index 464e890..b1c55c4 100644
--- a/dlls/ws2_32/socket.c
+++ b/dlls/ws2_32/socket.c
@@ -1356,17 +1356,54 @@ static int WS2_register_async_shutdown( SOCKET s, int type )
 SOCKET WINAPI WS_accept(SOCKET s, struct WS_sockaddr *addr,
                                  int *addrlen32)
 {
-    SOCKET as;
+    NTSTATUS status;
+    SOCKET as = INVALID_SOCKET;
     BOOL is_blocking;
 
     TRACE("socket %04lx\n", s );
     is_blocking = _is_blocking(s);
 
+    {
+        int af, type, protocol;
+        DWORD flags;
+        
+        SERVER_START_REQ( get_socket_type )
+        {
+            req->handle   = wine_server_obj_handle( SOCKET2HANDLE(s) );
+            set_error( status = wine_server_call( req ) );
+            af = reply->family;
+            type = reply->type;
+            protocol = reply->protocol;
+            flags = reply->flags;
+        }
+        SERVER_END_REQ;
+        
+        if (status) 
+            goto err;
+
+        /* Can't use socket() since these are UNIX properties */
+        SERVER_START_REQ( create_socket )
+        {
+            req->family     = af;
+            req->type       = type;
+            req->protocol   = protocol;
+            req->access     = GENERIC_READ|GENERIC_WRITE|SYNCHRONIZE;
+            req->attributes = OBJ_INHERIT;
+            req->flags      = flags;
+            set_error( wine_server_call( req ) );
+            as = HANDLE2SOCKET( wine_server_ptr_handle( reply->handle ));
+        }
+        SERVER_END_REQ;
+        
+        if (!as)
+            goto err;
+    }
+
     do {
         if (is_blocking)
         {
             int fd = get_sock_fd( s, FILE_READ_DATA, NULL );
-            if (fd == -1) return INVALID_SOCKET;
+            if (fd == -1) goto err;
             /* block here */
             do_block(fd, POLLIN, -1);
             _sync_sock_state(s); /* let wineserver notice connection */
@@ -1378,18 +1415,21 @@ SOCKET WINAPI WS_accept(SOCKET s, struct WS_sockaddr *addr,
         SERVER_START_REQ( accept_socket )
         {
             req->lhandle    = wine_server_obj_handle( SOCKET2HANDLE(s) );
-            req->access     = GENERIC_READ|GENERIC_WRITE|SYNCHRONIZE;
-            req->attributes = OBJ_INHERIT;
-            set_error( wine_server_call( req ) );
-            as = HANDLE2SOCKET( wine_server_ptr_handle( reply->handle ));
+            req->ahandle    = wine_server_obj_handle( SOCKET2HANDLE(as) );
+            status = wine_server_call( req );
+            set_error( status );
         }
         SERVER_END_REQ;
-        if (as)
+        if (!status)
         {
+            wine_server_clear_cache( SOCKET2HANDLE(as) );
             if (addr) WS_getpeername(as, addr, addrlen32);
             return as;
         }
     } while (is_blocking);
+
+err:
+    if (as && as != INVALID_SOCKET) WS_closesocket( as );
     return INVALID_SOCKET;
 }
 
diff --git a/server/protocol.def b/server/protocol.def
index 0267fb2..70e1c99 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -1041,10 +1041,7 @@ enum server_fd_type
 /* Accept a socket */
 @REQ(accept_socket)
     obj_handle_t lhandle;       /* handle to the listening socket */
-    unsigned int access;        /* wanted access rights */
-    unsigned int attributes;    /* object attributes */
-@REPLY
-    obj_handle_t handle;        /* handle to the new socket */
+    obj_handle_t ahandle;       /* handle to the accepting socket */
 @END
 
 
diff --git a/server/sock.c b/server/sock.c
index 156a4ac..f38f6a7 100644
--- a/server/sock.c
+++ b/server/sock.c
@@ -622,21 +622,19 @@ static struct object *create_socket( int family, int type, int protocol, unsigne
     return &sock->obj;
 }
 
-/* accept a socket (creates a new fd) */
-static struct sock *accept_socket( obj_handle_t handle )
+/* accept a socket */
+static int accept_socket( struct sock *sock, struct sock *acceptsock )
 {
-    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;
-
+    int acceptfd;
+    struct fd *newfd;
+    struct sockaddr saddr;
+    
     if ( sock->deferred )
     {
-        acceptsock = sock->deferred;
+        acceptfd = get_unix_fd(sock->deferred->fd);
+        make_fd_pseudo(sock->deferred->fd);
+
+        release_object( sock->deferred );
         sock->deferred = NULL;
     }
     else
@@ -648,53 +646,50 @@ static struct sock *accept_socket( obj_handle_t handle )
          */
         unsigned int slen = sizeof(saddr);
         acceptfd = accept( get_unix_fd(sock->fd), &saddr, &slen);
-        if (acceptfd==-1)
+        if (acceptfd == -1)
         {
             sock_set_error();
-            release_object( sock );
-            return NULL;
-        }
-        if (!(acceptsock = alloc_object( &sock_ops )))
-        {
-            close( acceptfd );
-            release_object( sock );
-            return NULL;
+            return FALSE;
         }
 
-        /* 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;
-        if (!(acceptsock->fd = create_anonymous_fd( &sock_fd_ops, acceptfd, &acceptsock->obj,
-                                                    get_fd_options( sock->fd ) )))
-        {
-            release_object( acceptsock );
-            release_object( sock );
-            return NULL;
-        }
     }
+
+    /* FIXME: Move the bulk of this into SO_UPDATE_ACCEPT_CONTEXT, as per AcceptEx */
+    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;
+    if (!(newfd = create_anonymous_fd( &sock_fd_ops, acceptfd, &acceptsock->obj,
+                                                get_fd_options( sock->fd ) )))
+    {
+        close( acceptfd );
+        return FALSE;
+    }
+
+    if ( acceptsock->fd )
+        release_object( acceptsock->fd );
+    acceptsock->fd = newfd;
+
     clear_error();
     sock->pmask &= ~FD_ACCEPT;
     sock->hmask &= ~FD_ACCEPT;
     sock_reselect( sock );
-    release_object( sock );
-    return acceptsock;
+    return TRUE;
 }
 
 /* set the last error depending on errno */
@@ -786,16 +781,26 @@ DECL_HANDLER(create_socket)
 /* accept a socket */
 DECL_HANDLER(accept_socket)
 {
-    struct sock *sock;
-
-    reply->handle = 0;
-    if ((sock = accept_socket( req->lhandle )) != NULL)
+    struct sock *sock, *acceptsock;
+    
+    if (!(sock = (struct sock *)get_handle_obj( current->process, req->lhandle,
+                                                FILE_READ_ATTRIBUTES|FILE_WRITE_ATTRIBUTES|FILE_READ_DATA, &sock_ops))) 
+        return;
+    if (!(acceptsock = (struct sock *)get_handle_obj( current->process, req->ahandle,
+                                                FILE_READ_ATTRIBUTES|FILE_WRITE_ATTRIBUTES, &sock_ops))) 
+    {
+        release_object( sock );
+        return;
+    }
+    
+    if (accept_socket( sock, acceptsock ))
     {
-        reply->handle = alloc_handle( current->process, &sock->obj, req->access, req->attributes );
-        sock->wparam = reply->handle;  /* wparam for message is the socket handle */
+        sock->wparam = req->ahandle;  /* wparam for message is the socket handle */
         sock_reselect( sock );
-        release_object( &sock->obj );
     }
+
+    release_object( acceptsock );
+    release_object( sock );
 }
 
 /* get a socket's init details */
-- 
1.6.3.3

