From 4cf7b228777ce19df5403312629855f73c7d0d5a Mon Sep 17 00:00:00 2001
From: Mike Kaplinskiy <mike.kaplinskiy@gmail.com>
Date: Sun, 12 Jul 2009 15:45:01 -0400
Subject: server: Add register_accept_async to register async and save the async handle in the accepting socket

---
 server/protocol.def |    7 +++++
 server/sock.c       |   64 ++++++++++++++++++++++++++++++++++++++++++++------
 2 files changed, 63 insertions(+), 8 deletions(-)

diff --git a/server/protocol.def b/server/protocol.def
index 70e1c99..31f527a 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -1038,6 +1038,13 @@ enum server_fd_type
 @END
 
 
+/* Register an accept listener */
+@REQ(register_accept_async)
+    async_data_t async;         /* async I/O parameters */
+    obj_handle_t ahandle;       /* handle to the future accepting socket */
+@END
+
+
 /* Accept a socket */
 @REQ(accept_socket)
     obj_handle_t lhandle;       /* handle to the listening socket */
diff --git a/server/sock.c b/server/sock.c
index f38f6a7..dd81248 100644
--- a/server/sock.c
+++ b/server/sock.c
@@ -84,6 +84,7 @@ struct sock
     obj_handle_t        wparam;      /* message wparam (socket handle) */
     int                 errors[FD_MAX_EVENTS]; /* event errors */
     struct sock        *deferred;    /* socket that waits for a deferred accept */
+    struct async       *accept_req;  /* pending accept to this socket */
     struct async_queue *read_q;      /* queue for asynchronous reads */
     struct async_queue *write_q;     /* queue for asynchronous writes */
 };
@@ -475,7 +476,7 @@ static int sock_get_poll_events( struct fd *fd )
         return POLLOUT;
     if (sock->state & FD_WINE_LISTENING)
         /* listening, wait for readable */
-        return (sock->hmask & FD_ACCEPT) ? 0 : POLLIN;
+        return (!(sock->hmask & FD_ACCEPT) || async_waiting( sock->read_q )) ? POLLIN : 0;
 
     if (mask & FD_READ  || async_waiting( sock->read_q )) ev |= POLLIN | POLLPRI;
     if (mask & FD_WRITE || async_waiting( sock->write_q )) ev |= POLLOUT;
@@ -491,10 +492,11 @@ static enum server_fd_type sock_get_fd_type( struct fd *fd )
     return FD_TYPE_SOCKET;
 }
 
-static void sock_queue_async( struct fd *fd, const async_data_t *data, int type, int count )
+static struct async *_sock_queue_async( struct fd *fd, const async_data_t *data, int type, int count )
 {
     struct sock *sock = get_fd_user( fd );
     struct async_queue *queue;
+    struct async *async = NULL;
     int pollev;
 
     assert( sock->obj.ops == &sock_ops );
@@ -502,34 +504,39 @@ static void sock_queue_async( struct fd *fd, const async_data_t *data, int type,
     switch (type)
     {
     case ASYNC_TYPE_READ:
-        if (!sock->read_q && !(sock->read_q = create_async_queue( sock->fd ))) return;
+        if (!sock->read_q && !(sock->read_q = create_async_queue( sock->fd ))) return NULL;
         queue = sock->read_q;
         sock->hmask &= ~FD_CLOSE;
         break;
     case ASYNC_TYPE_WRITE:
-        if (!sock->write_q && !(sock->write_q = create_async_queue( sock->fd ))) return;
+        if (!sock->write_q && !(sock->write_q = create_async_queue( sock->fd ))) return NULL;
         queue = sock->write_q;
         break;
     default:
         set_error( STATUS_INVALID_PARAMETER );
-        return;
+        return NULL;
     }
 
-    if ( ( !( sock->state & FD_READ ) && type == ASYNC_TYPE_READ  ) ||
+    if ( ( !( sock->state & (FD_READ|FD_WINE_LISTENING) ) && type == ASYNC_TYPE_READ  ) ||
          ( !( sock->state & FD_WRITE ) && type == ASYNC_TYPE_WRITE ) )
     {
         set_error( STATUS_PIPE_DISCONNECTED );
     }
     else
     {
-        struct async *async;
-        if (!(async = create_async( current, queue, data ))) return;
+        if (!(async = create_async( current, queue, data ))) return NULL;
         release_object( async );
         set_error( STATUS_PENDING );
     }
 
     pollev = sock_reselect( sock );
     if ( pollev ) sock_try_event( sock, pollev );
+    return async;
+}
+
+static void sock_queue_async( struct fd *fd, const async_data_t *data, int type, int count )
+{
+    (void)_sock_queue_async( fd, data, type, count );
 }
 
 static void sock_reselect_async( struct fd *fd, struct async_queue *queue )
@@ -563,6 +570,11 @@ static void sock_destroy( struct object *obj )
 
     if ( sock->deferred )
         release_object( sock->deferred );
+    if ( sock->accept_req )
+    {
+        async_terminate( sock->accept_req, STATUS_HANDLES_CLOSED );
+        release_object( sock->accept_req );
+    }
 
     free_async_queue( sock->read_q );
     free_async_queue( sock->write_q );
@@ -609,6 +621,7 @@ static struct object *create_socket( int family, int type, int protocol, unsigne
     sock->message = 0;
     sock->wparam  = 0;
     sock->deferred = NULL;
+    sock->accept_req = NULL;
     sock->read_q  = NULL;
     sock->write_q = NULL;
     if (!(sock->fd = create_anonymous_fd( &sock_fd_ops, sockfd, &sock->obj,
@@ -685,6 +698,12 @@ static int accept_socket( struct sock *sock, struct sock *acceptsock )
         release_object( acceptsock->fd );
     acceptsock->fd = newfd;
 
+    if ( acceptsock->accept_req )
+    {
+        release_object( acceptsock->accept_req );
+        acceptsock->accept_req = NULL;
+    }
+
     clear_error();
     sock->pmask &= ~FD_ACCEPT;
     sock->hmask &= ~FD_ACCEPT;
@@ -937,3 +956,32 @@ DECL_HANDLER(set_socket_deferred)
     sock->deferred = acceptsock;
     release_object( sock );
 }
+
+DECL_HANDLER(register_accept_async)
+{
+    struct sock *sock, *acceptsock;
+    
+    sock = (struct sock *)get_handle_obj( current->process, req->async.handle, 
+                                          FILE_READ_ATTRIBUTES, &sock_ops );
+    if ( !sock )
+    {
+        set_error( WSAENOTSOCK );
+        return;
+    }
+    acceptsock = (struct sock *)get_handle_obj( current->process, req->ahandle, 
+                                                FILE_WRITE_ATTRIBUTES, &sock_ops );
+    if ( !acceptsock )
+    {
+        release_object( sock );
+        set_error( WSAENOTSOCK );
+        return;
+    }
+    
+    acceptsock->accept_req = 
+            _sock_queue_async(sock->fd, &req->async, ASYNC_TYPE_READ, 0);
+    if (acceptsock->accept_req)
+        acceptsock->accept_req = (struct async *) grab_object( acceptsock->accept_req );
+    
+    release_object( acceptsock );
+    release_object( sock );
+}
-- 
1.6.3.3

