summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pflocal/sock.c188
1 files changed, 111 insertions, 77 deletions
diff --git a/pflocal/sock.c b/pflocal/sock.c
index a95f77fd..056f632a 100644
--- a/pflocal/sock.c
+++ b/pflocal/sock.c
@@ -19,6 +19,11 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "pflocal.h"
+
+/* We hold this lock before we lock two sockets at once, to someone
+ else trying to lock the same two sockets in the reverse order, resulting
+ in a deadlock. */
+static struct mutex socket_pair_lock;
/* ---------------------------------------------------------------- */
@@ -35,7 +40,12 @@ sock_aquire_read_pipe (struct sock *sock, struct pipe **pipe)
*pipe = user->sock->read_pipe;
assert (*pipe); /* A socket always has a read pipe. */
- if (((*pipe)->flags & PIPE_BROKEN) && ! (sock->flags & SOCK_SHUTDOWN_READ))
+ if (((*pipe)->flags & PIPE_BROKEN)
+ && ! (sock->flags & SOCK_CONNECTED)
+ && ! (sock->flags & SOCK_SHUTDOWN_READ))
+ /* A broken pipe with no peer is not connected (only connection-oriented
+ sockets can have broken pipes. However this is not true if the
+ read-half has been explicitly shutdown [at least in netbsd]. */
err = ENOTCONN;
else
pipe_aquire (*pipe);
@@ -59,9 +69,10 @@ sock_aquire_write_pipe (struct sock *sock, struct pipe **pipe)
pipe_aquire (*pipe); /* Do this before unlocking the sock! */
else if (sock->flags & SOCK_SHUTDOWN_WRITE)
/* Writing on a socket with the write-half shutdown always acts as if the
- pipe we're broken, even if the socket isn't connected yet. */
+ pipe were broken, even if the socket isn't connected yet [at least in
+ netbsd]. */
err = EPIPE;
- else if (sock->pipe_class->flags & PIPE_CLASS_CONNECTIONLESS)
+ else if (sock->read_pipe->class->flags & PIPE_CLASS_CONNECTIONLESS)
/* Connectionless protocols give a different error when unconnected. */
err = EDESTADDRREQ;
else
@@ -118,6 +129,8 @@ sock_free (struct sock *sock)
/* But we must do the read pipe ourselves. */
pipe_release (sock->read_pipe);
+
+
free (sock);
}
@@ -173,31 +186,89 @@ sock_create_port (struct sock *sock, mach_port_t *port)
/* ---------------------------------------------------------------- */
-/* We hold this lock when we want to lock both sockets for a attach
- operation, to avoid another attach with the sockets reversed happening.
- Attach should be the only place trying to lock two sockets at once, so
- this should be safe... */
-static struct mutex connect_lock;
+/* Bind SOCK to ADDR. */
+error_t
+sock_bind (struct sock *sock, struct addr *addr)
+{
+ error_t err = 0;
-/* Connect together the previously unconnected sockets SOCK1 and SOCK2. */
+ mutex_lock (&sock->lock);
+ mutex_lock (&addr->lock);
+
+ if (addr && sock->addr)
+ err = EINVAL; /* SOCK already bound. */
+ else if (addr && addr->sock)
+ err = EADDRINUSE; /* Something else already bound ADDR. */
+ else if (addr)
+ addr->sock = sock; /* First binding for SOCK. */
+ else
+ sock->addr->sock = NULL; /* Unbinding SOCK. */
+
+ if (!err)
+ sock->addr = addr;
+
+ mutex_unlock (&addr->lock);
+ mutex_unlock (&sock->lock);
+
+ return err;
+}
+
+/* Returns SOCK's addr, fabricating one if necessary. SOCK should be
+ locked. */
+static struct addr *
+ensure_addr (struct sock *sock)
+{
+ if (! sock->addr)
+ {
+ addr_create (&sock->addr);
+ sock->addr->sock = sock;
+ }
+ return sock->addr;
+}
+
+/* Returns a send right to SOCK's address in ADDR_PORT. If SOCK doesn't
+ currently have an address, one is fabricated first. */
+error_t
+sock_get_addr_port (struct sock *sock, mach_port_t *addr_port)
+{
+ mutex_lock (&sock->lock);
+ *addr_port = ports_get_right (ensure_addr (sock));
+ mutex_unlock (&sock->lock);
+ return 0; /* XXX */
+}
+
+/* If SOCK is a connected socket, returns a send right to SOCK's peer's
+ address in ADDR_PORT. */
+error_t
+sock_get_write_addr_port (struct sock *sock, mach_port_t *addr_port)
+{
+ error_t err = 0;
+
+ mutex_lock (&sock->lock);
+ if (sock->write_addr)
+ *addr_port = ports_get_right (sock->write_addr);
+ else
+ err = ENOTCONN;
+ mutex_unlock (&sock->lock);
+
+ return err;
+}
+
+/* ---------------------------------------------------------------- */
+
+/* Connect SOCK1 and SOCK2. */
error_t
sock_connect (struct sock *sock1, struct sock *sock2)
{
error_t err = 0;
/* In the case of a connectionless protocol, an already-connected socket may
- be reconnected elsewhere, so we save the old write pipe for later
- disposal. */
+ be reconnected, so save the old destination for later disposal. */
struct pipe *old_sock1_write_pipe = NULL;
- struct pipe_class *pipe_class = sock1->read_pipe->pipe_class;
+ struct addr *old_sock1_write_addr = NULL;
+ struct pipe_class *pipe_class = sock1->read_pipe->class;
/* True if this protocol is a connectionless one. */
int connless = (pipe_class->flags & PIPE_CLASS_CONNECTIONLESS);
- int connected (struct sock *s)
- {
- /* A socket is considered connected if it has a write pipe or a
- non-broken read-pipe. */
- return s->write_pipe != NULL || ! (s->read_pipe->flags & PIPE_BROKEN);
- }
void connect (struct sock *wr, struct sock *rd)
{
if ((wr->flags & SOCK_SHUTDOWN_WRITE)
@@ -207,89 +278,52 @@ sock_connect (struct sock *sock1, struct sock *sock2)
pipe_aquire (pipe);
pipe->flags &= ~PIPE_BROKEN; /* Not yet... */
wr->write_pipe = pipe;
+ wr->write_addr = ensure_addr (rd);
+ ports_port_ref (wr->write_addr);
mutex_unlock (&pipe->lock);
}
}
- if (sock2->read_pipe->pipe_class != pipe_class)
+ if (sock2->read_pipe->class != pipe_class)
/* Incompatible socket types. */
return EOPNOTSUPP; /* XXX?? */
- mutex_lock (&connect_lock);
+ mutex_lock (&socket_pair_lock);
mutex_lock (&sock1->lock);
mutex_lock (&sock2->lock);
- if (!connless && (connected (sock1) || connected (sock2)))
+ if ((sock1->flags & SOCK_CONNECTED) || (sock2->flags & SOCK_CONNECTED))
+ /* An already-connected socket. */
err = EISCONN;
else
{
old_sock1_write_pipe = sock1->write_pipe;
+ old_sock1_write_addr = sock1->write_addr;
- /* We always try and make the forward connection. */
+ /* Always make the forward connection. */
connect (sock1, sock2);
- /* We only make the backward connection for connection-oriented
- protocols. */
- if (! (pipe_class->flags & PIPE_CLASS_CONNECTIONLESS))
- connect (sock2, sock1);
+ /* Only make the reverse for connection-oriented protocols. */
+ if (! connless)
+ {
+ connect (sock2, sock1);
+ sock1->flags |= SOCK_CONNECTED;
+ sock2->flags |= SOCK_CONNECTED;
+ }
}
mutex_unlock (&sock2->lock);
mutex_unlock (&sock1->lock);
- mutex_unlock (&connect_lock);
+ mutex_unlock (&socket_pair_lock);
if (old_sock1_write_pipe)
- /* Discard SOCK1's previous write pipe. */
- pipe_discard (old_sock1_write_pipe);
-
- return err;
-}
-
-/* ---------------------------------------------------------------- */
-
-/* Bind SOCK to ADDR. */
-error_t
-sock_bind (struct sock *sock, struct addr *addr)
-{
- error_t err;
-
- mutex_lock (&sock->lock);
-
- if (sock->addr)
- if (addr)
- err = EINVAL; /* Already bound. */
- else
- err = addr_set_sock (sock->addr, NULL);
- else
- if (addr)
- err = addr_set_sock (addr, sock);
-
- if (!err)
- sock->addr = addr;
-
- mutex_unlock (&sock->lock);
-
- return err;
-}
+ {
+ pipe_discard (old_sock1_write_pipe);
+ ports_port_deref (old_sock1_write_addr);
+ }
-/* Returns SOCK's address in ADDR. If SOCK doesn't currently have an
- address, one is fabricated first. */
-error_t
-sock_get_addr (struct sock *sock, struct addr **addr)
-{
- error_t err;
- mutex_lock (&sock->lock);
- if (sock->addr == NULL)
- err = addr_create (&sock->addr);
- *addr = sock->addr;
- mutex_unlock (&sock->lock);
return err;
}
-
-error_t
-sock_get_peer_addr (struct sock *sock, struct addr **addr)
-{
-}
/* ---------------------------------------------------------------- */
@@ -300,7 +334,7 @@ sock_shutdown (struct sock *sock, unsigned flags)
sock->flags |= flags;
- if (which & SOCK_SHUTDOWN_READ)
+ if (flags & SOCK_SHUTDOWN_READ)
/* Shutdown the read half. We keep the pipe around though. */
{
struct pipe *pipe = sock->read_pipe;
@@ -312,7 +346,7 @@ sock_shutdown (struct sock *sock, unsigned flags)
mutex_unlock (&pipe->lock);
}
- if (which & SOCK_SHUTDOWN_WRITE)
+ if (flags & SOCK_SHUTDOWN_WRITE)
/* Shutdown the write half. */
{
struct pipe *pipe = sock->write_pipe;