server: Add accept_into_socket to accept into an initialized socket.
diff --git a/server/fd.c b/server/fd.c
index 9111a65..f9a769e 100644
--- a/server/fd.c
+++ b/server/fd.c
@@ -1599,32 +1599,20 @@
/* 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 5f1a8f9..00a1d92 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -1089,6 +1089,13 @@
@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 7897673..1e6b0a2 100644
--- a/server/request.h
+++ b/server/request.h
@@ -155,6 +155,7 @@
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 @@
(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( 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 7e1cd7e..886872d 100644
--- a/server/sock.c
+++ b/server/sock.c
@@ -605,6 +605,26 @@
}
}
+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 @@
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 @@
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 @@
}
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 @@
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 @@
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 @@
}
}
+/* 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 944d939..977828b 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -1539,6 +1539,12 @@
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 @@
(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 @@
(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 @@
"unlock_file",
"create_socket",
"accept_socket",
+ "accept_into_socket",
"set_socket_event",
"get_socket_event",
"enable_socket_event",