summaryrefslogtreecommitdiff
path: root/pflocal/socket.c
diff options
context:
space:
mode:
authorNeal H. Walfield <neal@walfield.org>2005-05-17 10:31:09 +0100
committerThomas Schwinge <thomas@codesourcery.com>2012-07-26 12:32:47 +0200
commitd74fad98ca037a539de873a92c033d3d0364fca7 (patch)
treef04330df5addf1b5a83e0e7d32b91637306cf9fa /pflocal/socket.c
parentb4d90f14926247f087a719462a7c61e794afa489 (diff)
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.
Diffstat (limited to 'pflocal/socket.c')
-rw-r--r--pflocal/socket.c74
1 files changed, 38 insertions, 36 deletions
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 <miles@gnu.ai.mit.edu>
@@ -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 */;
}
}