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, | 
