This patch introduces a new socket for QEMU, called multi-client-socket. This
socket allows multiple QEMU instances to communicate by sharing messages
and file descriptors.
A socket can be instantiated with the following parameters:
-object multi-socket-backend,id=,path=,listen=
If listen is set, the socket will act as a listener and register new
clients.
This patch is a follow-up to "[RFC PATCH 0/8] Towards an Heterogeneous QEMU":
https://lists.gnu.org/archive/html/qemu-devel/2015-10/msg00171.html
This work has been sponsored by Huawei Technologies Duesseldorf GmbH.
Signed-off-by: Baptiste Reynal
---
backends/Makefile.objs | 2 +
backends/multi-socket.c | 355
include/qemu/multi-socket.h | 124
3 files changed, 481 insertions(+)
create mode 100644 backends/multi-socket.c
create mode 100644 include/qemu/multi-socket.h
diff --git a/backends/Makefile.objs b/backends/Makefile.objs
index 31a3a89..689eac3 100644
--- a/backends/Makefile.objs
+++ b/backends/Makefile.objs
@@ -9,3 +9,5 @@ common-obj-$(CONFIG_TPM) += tpm.o
common-obj-y += hostmem.o hostmem-ram.o
common-obj-$(CONFIG_LINUX) += hostmem-file.o
+
+common-obj-y += multi-socket.o
diff --git a/backends/multi-socket.c b/backends/multi-socket.c
new file mode 100644
index 000..2cfbb50
--- /dev/null
+++ b/backends/multi-socket.c
@@ -0,0 +1,355 @@
+/*
+ * QEMU Multi Client socket
+ *
+ * Copyright (C) 2015 - Virtual Open Systems
+ *
+ * Author: Baptiste Reynal
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ */
+
+#include "qemu/multi-socket.h"
+#include "qemu/error-report.h"
+
+typedef struct MSHandler MSHandler;
+typedef struct MSRegHandler MSRegHandler;
+
+struct MSHandler {
+char *name;
+void (*read)(MSClient *client, const char *message, void *opaque);
+void *opaque;
+
+QLIST_ENTRY(MSHandler) next;
+};
+
+struct MSRegHandler {
+void (*reg)(MSClient *client, void *opaque);
+void *opaque;
+
+QLIST_ENTRY(MSRegHandler) next;
+};
+
+static void multi_socket_get_fds(MSClient *client, struct msghdr msg)
+{
+struct cmsghdr *cmsg;
+
+/* process fds */
+for (cmsg = CMSG_FIRSTHDR(); cmsg; cmsg = CMSG_NXTHDR(, cmsg)) {
+int fd_size;
+
+if (cmsg->cmsg_len < CMSG_LEN(sizeof(int)) ||
+cmsg->cmsg_level != SOL_SOCKET ||
+cmsg->cmsg_type != SCM_RIGHTS) {
+continue;
+}
+
+fd_size = cmsg->cmsg_len - CMSG_LEN(0);
+
+if (!fd_size) {
+continue;
+}
+
+g_free(client->rcvfds);
+
+client->rcvfds_num = fd_size / sizeof(int);
+client->rcvfds = g_malloc(fd_size);
+memcpy(client->rcvfds, CMSG_DATA(cmsg), fd_size);
+}
+}
+
+static gboolean
+multi_socket_read_handler(GIOChannel *channel, GIOCondition cond, void *opaque)
+{
+MSClient *client = (MSClient *) opaque;
+MSBackend *backend = client->backend;
+
+char message[BUFFER_SIZE];
+struct MSHandler *h;
+
+struct msghdr msg = { NULL, };
+struct iovec iov[1];
+union {
+struct cmsghdr cmsg;
+char control[CMSG_SPACE(sizeof(int) * MAX_FDS)];
+} msg_control;
+int flags = 0;
+ssize_t ret;
+
+iov[0].iov_base = message;
+iov[0].iov_len = BUFFER_SIZE;
+
+msg.msg_iov = iov;
+msg.msg_iovlen = 1;
+msg.msg_control = _control;
+msg.msg_controllen = sizeof(msg_control);
+
+ret = recvmsg(client->fd, , flags);
+
+if (ret > 0) {
+multi_socket_get_fds(client, msg);
+
+/* handler callback */
+QLIST_FOREACH(h, >handlers, next) {
+if (!strncmp(h->name, message, strlen(h->name))) {
+h->read(client, message + strlen(h->name) + 1, h->opaque);
+return TRUE;
+}
+}
+error_report("Unrecognized message: %s", message);
+}
+
+return FALSE;
+}
+
+void multi_socket_add_reg_handler(MSBackend *backend,
+void (*reg)(MSClient *client, void *opaque), void *opaque)
+{
+struct MSRegHandler *h;
+
+h = g_malloc(sizeof(struct MSRegHandler));
+
+h->reg = reg;
+h->opaque = opaque;
+
+QLIST_INSERT_HEAD(>reg_handlers, h, next);
+}
+
+void multi_socket_add_handler(MSBackend *backend,
+const char *name,
+void (*read)(MSClient *c, const char *message, void *opaque),
+void *opaque)
+{
+struct MSHandler *h;
+
+/* check that the handler name is not taken */
+QLIST_FOREACH(h, >handlers, next) {
+if (!strcmp(h->name, name)) {
+error_report("Handler %s already exists", name);
+return;
+}
+}
+
+h = g_malloc(sizeof(struct MSHandler));
+
+h->name = g_strdup(name);
+h->read = read;
+h->opaque = opaque;
+
+QLIST_INSERT_HEAD(>handlers, h, next);
+}
+
+static void