From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1MNs2p-00056S-3X for qemu-devel@nongnu.org; Mon, 06 Jul 2009 13:31:59 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1MNs2k-00053t-K3 for qemu-devel@nongnu.org; Mon, 06 Jul 2009 13:31:58 -0400 Received: from [199.232.76.173] (port=57353 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1MNs2k-00053d-9X for qemu-devel@nongnu.org; Mon, 06 Jul 2009 13:31:54 -0400 Received: from mx2.redhat.com ([66.187.237.31]:60263) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1MNs2j-0000KN-Et for qemu-devel@nongnu.org; Mon, 06 Jul 2009 13:31:54 -0400 Received: from int-mx2.corp.redhat.com (int-mx2.corp.redhat.com [172.16.27.26]) by mx2.redhat.com (8.13.8/8.13.8) with ESMTP id n66HVqVu001739 for ; Mon, 6 Jul 2009 13:31:52 -0400 Received: from ns3.rdu.redhat.com (ns3.rdu.redhat.com [10.11.255.199]) by int-mx2.corp.redhat.com (8.13.1/8.13.1) with ESMTP id n66HVpPF022918 for ; Mon, 6 Jul 2009 13:31:52 -0400 Received: from [IPv6:::1] (sebastian-int.corp.redhat.com [172.16.52.221]) by ns3.rdu.redhat.com (8.13.8/8.13.8) with ESMTP id n66HVoa0003150 for ; Mon, 6 Jul 2009 13:31:51 -0400 From: Mark McLoughlin In-Reply-To: <1246901456.12086.21.camel@blaa> References: <1246901401.12086.20.camel@blaa> <1246901456.12086.21.camel@blaa> Content-Type: text/plain Date: Mon, 06 Jul 2009 18:31:35 +0100 Message-Id: <1246901495.12086.22.camel@blaa> Mime-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: [Qemu-devel] [PATCH 2/3] Add SCM_RIGHTS support to unix socket character devices Reply-To: Mark McLoughlin List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel If a file descriptor is passed via a message with SCM_RIGHTS ancillary data on a unix socket, store the file descriptor for use in the chr_read() handler. Close the file descriptor if it was not used. The qemu_chr_get_msgfd() and monitor_get_msgfd() APIs provide access to any passed descriptor. Signed-off-by: Mark McLoughlin --- monitor.c | 5 +++++ monitor.h | 1 + qemu-char.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ qemu-char.h | 2 ++ 4 files changed, 58 insertions(+), 0 deletions(-) diff --git a/monitor.c b/monitor.c index bad79fe..f61f43d 100644 --- a/monitor.c +++ b/monitor.c @@ -2981,6 +2981,11 @@ static void monitor_read(void *opaque, const uint8_t *buf, int size) cur_mon = old_mon; } +int monitor_get_msgfd(Monitor *mon) +{ + return qemu_chr_get_msgfd(mon->chr); +} + static void monitor_command_cb(Monitor *mon, const char *cmdline, void *opaque) { monitor_suspend(mon); diff --git a/monitor.h b/monitor.h index 13e8cc7..af97a86 100644 --- a/monitor.h +++ b/monitor.h @@ -19,6 +19,7 @@ void monitor_resume(Monitor *mon); void monitor_read_bdrv_key_start(Monitor *mon, BlockDriverState *bs, BlockDriverCompletionFunc *completion_cb, void *opaque); +int monitor_get_msgfd(Monitor *mon); void monitor_vprintf(Monitor *mon, const char *fmt, va_list ap); void monitor_printf(Monitor *mon, const char *fmt, ...) diff --git a/qemu-char.c b/qemu-char.c index e0d7220..f06a614 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -168,6 +168,11 @@ void qemu_chr_read(CharDriverState *s, uint8_t *buf, int len) s->chr_read(s->handler_opaque, buf, len); } +int qemu_chr_get_msgfd(CharDriverState *s) +{ + return s->get_msgfd ? s->get_msgfd(s) : -1; +} + void qemu_chr_accept_input(CharDriverState *s) { if (s->chr_accept_input) @@ -1832,6 +1837,7 @@ typedef struct { int do_telnetopt; int do_nodelay; int is_unix; + int msgfd; } TCPCharDriver; static void tcp_chr_accept(void *opaque); @@ -1907,12 +1913,46 @@ static void tcp_chr_process_IAC_bytes(CharDriverState *chr, *size = j; } +static int tcp_get_msgfd(CharDriverState *chr) +{ + TCPCharDriver *s = chr->opaque; + + return s->msgfd; +} + +static void unix_process_msgfd(CharDriverState *chr, struct msghdr *msg) +{ + TCPCharDriver *s = chr->opaque; + struct cmsghdr *cmsg; + + for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) { + int fd; + + if (cmsg->cmsg_len != CMSG_LEN(sizeof(int)) || + cmsg->cmsg_level != SOL_SOCKET || + cmsg->cmsg_type != SCM_RIGHTS) + continue; + + fd = *((int *)CMSG_DATA(cmsg)); + if (fd < 0) + continue; + + if (s->msgfd != -1) + close(s->msgfd); + s->msgfd = fd; + } +} + static void tcp_chr_read(void *opaque) { CharDriverState *chr = opaque; TCPCharDriver *s = chr->opaque; struct msghdr msg = { 0, }; struct iovec iov[1]; + union { + struct cmsghdr cmsg; + char control[CMSG_SPACE(sizeof(int))]; + } msg_control; uint8_t buf[1024]; int len, size; @@ -1928,6 +1968,8 @@ static void tcp_chr_read(void *opaque) msg.msg_iov = iov; msg.msg_iovlen = 1; + msg.msg_control = &msg_control; + msg.msg_controllen = sizeof(msg_control); size = recvmsg(s->fd, &msg, 0); if (size == 0) { @@ -1940,10 +1982,16 @@ static void tcp_chr_read(void *opaque) closesocket(s->fd); s->fd = -1; } else if (size > 0) { + if (s->is_unix) + unix_process_msgfd(chr, &msg); if (s->do_telnetopt) tcp_chr_process_IAC_bytes(chr, s, buf, &size); if (size > 0) qemu_chr_read(chr, buf, size); + if (s->msgfd != -1) { + close(s->msgfd); + s->msgfd = -1; + } } } @@ -2105,12 +2153,14 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str, s->connected = 0; s->fd = -1; s->listen_fd = -1; + s->msgfd = -1; s->is_unix = is_unix; s->do_nodelay = do_nodelay && !is_unix; chr->opaque = s; chr->chr_write = tcp_chr_write; chr->chr_close = tcp_chr_close; + chr->get_msgfd = tcp_get_msgfd; if (is_listen) { s->listen_fd = fd; diff --git a/qemu-char.h b/qemu-char.h index e1aa8db..77d4eda 100644 --- a/qemu-char.h +++ b/qemu-char.h @@ -51,6 +51,7 @@ struct CharDriverState { int (*chr_write)(struct CharDriverState *s, const uint8_t *buf, int len); void (*chr_update_read_handler)(struct CharDriverState *s); int (*chr_ioctl)(struct CharDriverState *s, int cmd, void *arg); + int (*get_msgfd)(struct CharDriverState *s); IOEventHandler *chr_event; IOCanRWHandler *chr_can_read; IOReadHandler *chr_read; @@ -81,6 +82,7 @@ void qemu_chr_reset(CharDriverState *s); void qemu_chr_initial_reset(void); int qemu_chr_can_read(CharDriverState *s); void qemu_chr_read(CharDriverState *s, uint8_t *buf, int len); +int qemu_chr_get_msgfd(CharDriverState *s); void qemu_chr_accept_input(CharDriverState *s); void qemu_chr_info(Monitor *mon); -- 1.6.2.5