diff options
author | Luiz Augusto von Dentz <luiz.dentz@openbossa.org> | 2007-06-11 23:26:24 +0000 |
---|---|---|
committer | Luiz Augusto von Dentz <luiz.dentz@openbossa.org> | 2007-06-11 23:26:24 +0000 |
commit | ddf8edc54d666f9b6f75f28b6db5375e2f0982a8 (patch) | |
tree | bad9fa1f3bfc769d89ad4b91b49fd3e5968f7190 | |
parent | 1ec7d98bba8eaf18c7024123d7b9196f4bf7aefc (diff) |
Fix file descriptor passing.
-rw-r--r-- | audio/headset.c | 5 | ||||
-rw-r--r-- | audio/ipc.h | 2 | ||||
-rw-r--r-- | audio/pcm_bluetooth.c | 79 | ||||
-rw-r--r-- | audio/unix.c | 79 |
4 files changed, 127 insertions, 38 deletions
diff --git a/audio/headset.c b/audio/headset.c index ae7a32cc..2d398324 100644 --- a/audio/headset.c +++ b/audio/headset.c @@ -421,6 +421,7 @@ static gboolean sco_connect_cb(GIOChannel *chan, GIOCondition cond, debug("SCO socket opened for headset %s", device->object_path); + info("SCO fd=%d", sk); hs->sco = chan; hs->pending_connect->io = NULL; @@ -435,6 +436,8 @@ static gboolean sco_connect_cb(GIOChannel *chan, GIOCondition cond, pending_connect_free(hs->pending_connect); hs->pending_connect = NULL; + fcntl(sk, F_SETFL, 0); + hs->state = HEADSET_STATE_PLAYING; dbus_connection_emit_signal(connection, device->object_path, AUDIO_HEADSET_INTERFACE, @@ -1436,7 +1439,7 @@ static DBusHandlerResult hs_play(DBusConnection *conn, DBusMessage *msg, } debug("SCO connect in progress"); - g_io_add_watch(c->io, G_IO_OUT | G_IO_NVAL, + g_io_add_watch(c->io, G_IO_OUT | G_IO_NVAL | G_IO_ERR | G_IO_HUP, (GIOFunc) sco_connect_cb, device); } else { debug("SCO connect succeeded with first try"); diff --git a/audio/ipc.h b/audio/ipc.h index 0cd9e620..409abfda 100644 --- a/audio/ipc.h +++ b/audio/ipc.h @@ -25,7 +25,7 @@ #define IPC_TYPE_CONNECT 0x0001 -#define IPC_SOCKET_NAME "/org/bluez/audio" +#define IPC_SOCKET_NAME "\0/org/bluez/audio" #ifndef UNIX_PATH_MAX #define UNIX_PATH_MAX 108 diff --git a/audio/pcm_bluetooth.c b/audio/pcm_bluetooth.c index 26b7ad2c..10182993 100644 --- a/audio/pcm_bluetooth.c +++ b/audio/pcm_bluetooth.c @@ -118,7 +118,7 @@ static int bluetooth_hw_params(snd_pcm_ioplug_t *io, snd_pcm_hw_params_t *params int opt_name; DBG("fd = %d, period_count = %d", cfg.fd, period_count); - + opt_name = (io->stream == SND_PCM_STREAM_PLAYBACK) ? SCO_TXBUFS : SCO_RXBUFS; @@ -142,6 +142,7 @@ static int bluetooth_hw_params(snd_pcm_ioplug_t *io, snd_pcm_hw_params_t *params sizeof(period_count)) == 0) return 0; + SNDERR("%s (%d)", strerror(errno), errno); SNDERR("Unable to set number of SCO buffers: please upgrade your " "kernel!"); @@ -318,6 +319,51 @@ static int bluetooth_hw_constraint(snd_pcm_ioplug_t *io) return 0; } +static int bluetooth_recvmsg_fd(struct bluetooth_data *data) +{ + char cmsg_b[CMSG_SPACE(sizeof(int))]; + struct ipc_packet pkt; + int err, ret; + struct iovec iov = { + .iov_base = &pkt, + .iov_len = sizeof(pkt) + }; + struct msghdr msgh = { + .msg_name = 0, + .msg_namelen = 0, + .msg_iov = &iov, + .msg_iovlen = 1, + .msg_control = &cmsg_b, + .msg_controllen = CMSG_LEN(sizeof(int)), + .msg_flags = 0 + }; + + ret = recvmsg(data->sock, &msgh, 0); + + if (ret < 0) { + err = errno; + SNDERR("Unable to receive fd: %s (%d)", strerror(err), err); + return -err; + } + + if(pkt.type == PKT_TYPE_CFG_RSP) { + struct cmsghdr *cmsg; + /* Receive auxiliary data in msgh */ + for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL; + cmsg = CMSG_NXTHDR(&msgh,cmsg)) { + if (cmsg->cmsg_level == SOL_SOCKET + && cmsg->cmsg_type == SCM_RIGHTS) + data->cfg.fd = (*(int *) CMSG_DATA(cmsg)); + DBG("fd = %d", data->cfg.fd); + return 0; + } + } + else + SNDERR("Unexpected packet type received: type = %d", pkt.type); + + return -EINVAL; +} + static int bluetooth_cfg(struct bluetooth_data *data) { int ret, len = sizeof(struct ipc_packet) + sizeof(struct ipc_data_cfg); @@ -396,7 +442,13 @@ static int bluetooth_cfg(struct bluetooth_data *data) goto done; } - ret = 0; + if ((ret = bluetooth_recvmsg_fd(data)) < 0) + goto done; + + /* It is possible there is some outstanding + data in the pipe - we have to empty it */ + while(recv(data->cfg.fd, data->buffer, data->cfg.pkt_len, + MSG_DONTWAIT) > 0); done: free(pkt); @@ -406,7 +458,9 @@ done: static int bluetooth_init(struct bluetooth_data *data) { int sk, err, id; - struct sockaddr_un addr; + struct sockaddr_un addr = { + AF_UNIX, IPC_SOCKET_NAME + }; if (!data) return -EINVAL; @@ -417,30 +471,13 @@ static int bluetooth_init(struct bluetooth_data *data) id = abs(getpid() * rand()); - sk = socket(PF_LOCAL, SOCK_DGRAM, 0); + sk = socket(PF_LOCAL, SOCK_STREAM, 0); if (sk < 0) { err = -errno; SNDERR("Can't open socket"); return -errno; } - memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - snprintf(addr.sun_path + 1, UNIX_PATH_MAX - 2, "%s/%d", - IPC_SOCKET_NAME, id); - - DBG("Binding address: %s", addr.sun_path + 1); - if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - err = -errno; - SNDERR("Can't bind socket"); - close(sk); - return err; - } - - memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - snprintf(addr.sun_path + 1, UNIX_PATH_MAX - 2, "%s", IPC_SOCKET_NAME); - DBG("Connecting to address: %s", addr.sun_path + 1); if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { err = -errno; diff --git a/audio/unix.c b/audio/unix.c index 76650b75..00f146be 100644 --- a/audio/unix.c +++ b/audio/unix.c @@ -26,13 +26,13 @@ #endif #include <stdio.h> +#include <sys/socket.h> +#include <sys/un.h> #include <stdlib.h> #include <errno.h> #include <unistd.h> #include <stdint.h> #include <assert.h> -#include <sys/socket.h> -#include <sys/un.h> #include <glib.h> @@ -44,13 +44,46 @@ static int unix_sock = -1; +/* Pass file descriptor through local domain sockets (AF_LOCAL, formerly AF_UNIX) +and the sendmsg() system call with the cmsg_type field of a "struct cmsghdr" set +to SCM_RIGHTS and the data being an integer value equal to the handle of the +file descriptor to be passed.*/ +static int unix_sendmsg_fd(int sock, int fd, struct ipc_packet *pkt) +{ + char cmsg_b[CMSG_SPACE(sizeof(int))]; + struct cmsghdr *cmsg; + struct iovec iov = { + .iov_base = pkt, + .iov_len = sizeof(struct ipc_packet) + }; + + struct msghdr msgh = { + .msg_name = 0, + .msg_namelen = 0, + .msg_iov = &iov, + .msg_iovlen = 1, + .msg_control = &cmsg_b, + .msg_controllen = CMSG_LEN(sizeof(int)), + .msg_flags = 0 + }; + + cmsg = CMSG_FIRSTHDR(&msgh); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(sizeof(int)); + /* Initialize the payload */ + (*(int *)CMSG_DATA(cmsg)) = fd; + + return sendmsg(sock, &msgh, MSG_NOSIGNAL); +} + static gboolean unix_event(GIOChannel *chan, GIOCondition cond, gpointer data) { struct sockaddr_un addr; socklen_t addrlen; struct ipc_packet *pkt; struct ipc_data_cfg *cfg; - int sk, len; + int sk, clisk, len; debug("chan %p cond %td data %p", chan, cond, data); @@ -69,7 +102,8 @@ static gboolean unix_event(GIOChannel *chan, GIOCondition cond, gpointer data) len = sizeof(struct ipc_packet) + sizeof(struct ipc_data_cfg); pkt = g_malloc0(len); - len = recvfrom(sk, pkt, len, 0, (struct sockaddr *) &addr, &addrlen); + clisk = accept(sk, (struct sockaddr *) &addr, &addrlen); + len = recv(clisk, pkt, len, 0); debug("path %s len %d", addr.sun_path + 1, len); @@ -79,18 +113,30 @@ static gboolean unix_event(GIOChannel *chan, GIOCondition cond, gpointer data) cfg = (struct ipc_data_cfg *) pkt->data; + memset(cfg, 0, sizeof(struct ipc_data_cfg)); if (manager_get_device(pkt->role, cfg) < 0) cfg->fd = -1; + info("fd=%d, fd_opt=%u, channels=%u, pkt_len=%u, sample_size=%u," + "rate=%u", cfg->fd, cfg->fd_opt, cfg->channels, + cfg->pkt_len, cfg->sample_size, cfg->rate); + pkt->type = PKT_TYPE_CFG_RSP; pkt->length = sizeof(struct ipc_data_cfg); pkt->error = PKT_ERROR_NONE; - len = sendto(sk, pkt, len, 0, (struct sockaddr *) &addr, addrlen); + len = send(clisk, pkt, len, 0); if (len < 0) info("Error %s(%d)", strerror(errno), errno); - info("%d bytes sent", len); + + if (cfg->fd != -1) { + len = unix_sendmsg_fd(clisk, cfg->fd, pkt); + if (len < 0) + info("Error %s(%d)", strerror(errno), errno); + info("%d bytes sent", len); + } + break; case PKT_TYPE_STATUS_REQ: info("Package PKT_TYPE_STATUS_REQ"); @@ -101,25 +147,26 @@ static gboolean unix_event(GIOChannel *chan, GIOCondition cond, gpointer data) } g_free(pkt); + close(clisk); return TRUE; } int unix_init(void) { GIOChannel *io; - struct sockaddr_un addr; - int sk; + struct sockaddr_un addr = { + AF_UNIX, IPC_SOCKET_NAME + }; + + int sk, err; - sk = socket(PF_LOCAL, SOCK_DGRAM, 0); + sk = socket(PF_LOCAL, SOCK_STREAM, 0); if (sk < 0) { - error("Can't create unix socket: %s (%d)", strerror(errno), errno); - return -1; + err = errno; + error("Can't create unix socket: %s (%d)", strerror(err), err); + return -err; } - memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - snprintf(addr.sun_path + 1, UNIX_PATH_MAX - 2, "%s", IPC_SOCKET_NAME); - if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { error("Can't bind unix socket: %s (%d)", strerror(errno), errno); close(sk); @@ -130,6 +177,8 @@ int unix_init(void) unix_sock = sk; + listen(sk, 1); + io = g_io_channel_unix_new(sk); g_io_add_watch(io, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, |