From d74fad98ca037a539de873a92c033d3d0364fca7 Mon Sep 17 00:00:00 2001 From: "Neal H. Walfield" Date: Tue, 17 May 2005 10:31:09 +0100 Subject: pflocal: Handle non-blocking connect with no pending acceptors. * pflocal/connq.h (struct connq_request): Remove forward. (connq_listen): Wait for a request to be queued not until there is a connection attempt. Remove REQ parameter. Update callers. (connq_request_complete): Remove declaration. (connq_connect): Wait for a slot to queue a request not until there is an acceptor. Remove SOCK parameter. Update callers. (connq_connect_complete): New declaration. (connq_connect_cancel): New declaration. * pflocal/connq.c (struct connq): Remove fields noqueue, queue, length, head and tail. Add fields head, tail, count, max, connectors and num_connectors. That is, replace the circular buffer with a singly linked list. (qnext): Remove function. (struct connq_request): Remove field signal, lock, completed and err. Add field next. (connq_request_init): Rewrite according to new semantics. (connq_request_enqueue): New function. (connq_request_dequeue): New function. (connq_create): Update according to new semantics. (connq_destroy): Likewise. (connq_listen): Rewrite to not block until there is a connector but until there is a request in the queue. (connq_request_complete): Remove function. (connq_connect): Rewrite to not block until there is an acceptor but until there is space for a request. (connq_connect_complete): New function. (connq_connect_cancel): New function. (connq_compress): Remove dead code. (connq_set_length): Rewrite. * pflocal/socket.c (S_socket_connect): Create the server socket here... (S_socket_accept): ... not here. --- pflocal/socket.c | 74 +++++++++++++++++++++++++++++--------------------------- 1 file changed, 38 insertions(+), 36 deletions(-) (limited to 'pflocal/socket.c') diff --git a/pflocal/socket.c b/pflocal/socket.c index a0e5b1da..64a80a46 100644 --- a/pflocal/socket.c +++ b/pflocal/socket.c @@ -1,6 +1,6 @@ /* Socket-specific operations - Copyright (C) 1995, 2008, 2010 Free Software Foundation, Inc. + Copyright (C) 1995, 2008, 2010, 2012 Free Software Foundation, Inc. Written by Miles Bader @@ -112,7 +112,7 @@ S_socket_connect (struct sock_user *user, struct addr *addr) else if (sock->flags & SOCK_CONNECTED) /* SOCK_CONNECTED is only set for connection-oriented sockets, which can only ever connect once. [If we didn't do this test - here, it would eventually fail when it the listening socket + here, it would eventually fail when the listening socket tried to accept our connection request.] */ err = EISCONN; else @@ -120,16 +120,35 @@ S_socket_connect (struct sock_user *user, struct addr *addr) /* Assert that we're trying to connect, so anyone else trying to do so will fail with EALREADY. */ sock->connect_queue = cq; - mutex_unlock (&sock->lock); /* Unlock SOCK while waiting. */ + /* Unlock SOCK while waiting. */ + mutex_unlock (&sock->lock); - /* Try to connect. */ - err = connq_connect (cq, sock->flags & SOCK_NONBLOCK, sock); + err = connq_connect (peer->listen_queue, + sock->flags & SOCK_NONBLOCK); + if (!err) + { + struct sock *server; + + err = sock_clone (peer, &server); + if (!err) + { + err = sock_connect (sock, server); + if (!err) + connq_connect_complete (peer->listen_queue, server); + else + sock_free (server); + } - /* We can safely set CONNECT_QUEUE to NULL, as no one else can + mutex_lock (&sock->lock); + if (err) + connq_connect_cancel (peer->listen_queue); + } + + /* We must set CONNECT_QUEUE to NULL, as no one else can set it until we've done so. */ - mutex_lock (&sock->lock); sock->connect_queue = NULL; } + mutex_unlock (&sock->lock); } else @@ -159,42 +178,25 @@ S_socket_accept (struct sock_user *user, err = ensure_connq (sock); if (!err) { - struct connq_request *req; struct sock *peer_sock; - err = - connq_listen (sock->listen_queue, sock->flags & SOCK_NONBLOCK, - &req, &peer_sock); + err = connq_listen (sock->listen_queue, sock->flags & SOCK_NONBLOCK, + &peer_sock); if (!err) { - struct sock *conn_sock; - - err = sock_clone (sock, &conn_sock); + struct addr *peer_addr; + *port_type = MACH_MSG_TYPE_MAKE_SEND; + err = sock_create_port (peer_sock, port); + if (!err) + err = sock_get_addr (peer_sock, &peer_addr); if (!err) { - err = sock_connect (conn_sock, peer_sock); - if (!err) - { - struct addr *peer_addr; - *port_type = MACH_MSG_TYPE_MAKE_SEND; - err = sock_create_port (conn_sock, port); - if (!err) - err = sock_get_addr (peer_sock, &peer_addr); - if (!err) - { - *peer_addr_port = ports_get_right (peer_addr); - *peer_addr_port_type = MACH_MSG_TYPE_MAKE_SEND; - ports_port_deref (peer_addr); - } - else - /* TEAR DOWN THE CONNECTION XXX */; - } - if (err) - sock_free (conn_sock); + *peer_addr_port = ports_get_right (peer_addr); + *peer_addr_port_type = MACH_MSG_TYPE_MAKE_SEND; + ports_port_deref (peer_addr); } - - /* Communicate any error (or success) to the connecting thread. */ - connq_request_complete (req, err); + else + /* TEAR DOWN THE CONNECTION XXX */; } } -- cgit v1.2.3