diff options
Diffstat (limited to 'pflocal/socket.c')
-rw-r--r-- | pflocal/socket.c | 74 |
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 */; } } |