summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLuiz Augusto von Dentz <luiz.dentz@openbossa.org>2007-06-11 23:26:24 +0000
committerLuiz Augusto von Dentz <luiz.dentz@openbossa.org>2007-06-11 23:26:24 +0000
commitddf8edc54d666f9b6f75f28b6db5375e2f0982a8 (patch)
treebad9fa1f3bfc769d89ad4b91b49fd3e5968f7190
parent1ec7d98bba8eaf18c7024123d7b9196f4bf7aefc (diff)
Fix file descriptor passing.
-rw-r--r--audio/headset.c5
-rw-r--r--audio/ipc.h2
-rw-r--r--audio/pcm_bluetooth.c79
-rw-r--r--audio/unix.c79
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,