summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pflocal/sock.c106
1 files changed, 89 insertions, 17 deletions
diff --git a/pflocal/sock.c b/pflocal/sock.c
index 968ec460..14936513 100644
--- a/pflocal/sock.c
+++ b/pflocal/sock.c
@@ -54,31 +54,103 @@ sock_aquire_write_pipe (struct sock *sock)
return pipe;
}
+/* ---------------------------------------------------------------- */
+
+/* Return a new socket with the given pipe ops in SOCK. */
error_t
-sock_create (int type, struct sock *result)
+sock_create (struct pipe_ops *pipe_ops, struct sock **sock)
{
static unsigned next_sock_id = 0;
- struct sock *sock = malloc (sizeof (struct sock));
+ struct sock *new = malloc (sizeof (struct sock));
- if (sock == NULL)
+ if (new == NULL)
return ENOMEM;
- sock->refs = 0;
- sock->read_pipe = sock->write_pipe = NULL;
- sock->id = next_sock_id++;
- bzero (&sock->change_time, sizeof (sock->change_time));
- mutex_init (&sock->lock);
+ new->refs = 0;
+ new->read_pipe = new->write_pipe = NULL;
+ new->id = next_sock_id++;
+ new->pipe_ops = pipe_ops;
+ new->listenq = NULL;
+ new->addr = NULL;
+ bzero (&new->change_time, sizeof (new->change_time));
+ mutex_init (&new->lock);
+
+ *sock = new;
+ return 0;
+}
+
+void
+sock_free (struct sock *sock)
+{
+
+}
+
+/* Return a new user port on SOCK, in PORT and PORT_TYPE. */
+error_t
+sock_create_port (struct sock *sock,
+ mach_port_t *port, mach_msg_type_name_t *port_type)
+{
+ struct sock_user *user =
+ port_allocate_port (sock_user_bucket,
+ sizeof (struct sock_user), sock_user_class);
+
+ if (!user)
+ return ENOMEM;
+
+ mutex_lock (&sock->lock);
+ sock->refs++;
+ mutex_unlock (&sock->lock);
+
+ user->sock = sock;
+
+ *port = ports_get_right (user);
+ *port_type = MACH_MSG_TYPE_MAKE_SEND;
+
+ return 0;
+}
+
+/* ---------------------------------------------------------------- */
- switch (type)
+/* 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;
+
+/* Connect together the previously unconnected sockets SOCK1 and SOCK2. */
+error_t
+sock_connect (struct sock *sock1, struct sock *sock2)
+{
+ if (sock1->pipe_ops != sock2->pipe_ops)
+ return EOPNOTSUPP; /* XXX?? */
+
+ mutex_lock (&connect_lock);
+ mutex_lock (&sock1->lock);
+ mutex_lock (&sock2->lock);
+
+ if (sock1->read_pipe || sock1->write_pipe
+ || sock2->read_pipe || sock2->write_pipe)
+ err = EISCONN;
+ else
{
- case SOCK_STREAM:
- sock->pipe_ops = stream_pipe_ops; break;
- case SOCK_DGRAM:
- sock->pipe_ops = dgram_pipe_ops; break;
- default:
- free (sock);
- return ESOCKTNOSUPPORT;
+ struct pipe *pipe1, *pipe2;
+ err = pipe_create (sock1, sock2, sock1->pipe_ops, &pipe1);
+ if (!err)
+ {
+ err = pipe_create (sock2, sock1, sock1->pipe_ops, &pipe2);
+ if (err)
+ pipe_free (pipe1);
+ }
+ if (!err)
+ {
+ sock1->write_pipe = sock2->read_pipe = pipe1;
+ sock2->write_pipe = sock1->read_pipe = pipe2;
+ }
}
- return 0;
+ mutex_unlock (&sock2->lock);
+ mutex_unlock (&sock1->lock);
+ mutex_unlock (&connect_lock);
+
+ return err;
}