]> xenbits.xensource.com Git - libvirt.git/commitdiff
Rename daemon main code
authorDaniel P. Berrange <berrange@redhat.com>
Wed, 16 Sep 2009 11:37:26 +0000 (12:37 +0100)
committerDaniel P. Berrange <berrange@redhat.com>
Mon, 21 Sep 2009 13:41:45 +0000 (14:41 +0100)
* daemon/qemud.c: Rename to daemon/libvirtd.c
* daemon/qemud.h: Rename to daemon/libvirtd.h
* daemon/Makefile.am, daemon/dispatch.h, daemon/mdns.c,
  daemon/remote.h: Update for renamed libvirtd.h file

daemon/Makefile.am
daemon/dispatch.h
daemon/libvirtd.c [new file with mode: 0644]
daemon/libvirtd.h [new file with mode: 0644]
daemon/mdns.c
daemon/qemud.c [deleted file]
daemon/qemud.h [deleted file]
daemon/remote.h

index 89c94b33066d85ef5d983f4665bcd299f670ab95..335fa859129450b3ca9d3ab38d4c9c48faddad9e 100644 (file)
@@ -2,7 +2,7 @@
 
 DAEMON_SOURCES =                                       \
                event.c event.h                         \
-               qemud.c qemud.h                         \
+               libvirtd.c libvirtd.h                   \
                remote.c remote.h                       \
                dispatch.c dispatch.h                   \
                remote_dispatch_prototypes.h            \
index 1d85df9a6b97742654084fe3e9b4932c55d1c5bb..30de65887bad96c9568f9b9e1e81a2fa91066107 100644 (file)
@@ -25,7 +25,7 @@
 #define __LIBVIRTD_DISPATCH_H__
 
 
-#include "qemud.h"
+#include "libvirtd.h"
 
 
 int
diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c
new file mode 100644 (file)
index 0000000..7a25648
--- /dev/null
@@ -0,0 +1,3015 @@
+/*
+ * libvirtd.c: daemon start of day, guest process & i/o management
+ *
+ * Copyright (C) 2006, 2007, 2008, 2009 Red Hat, Inc.
+ * Copyright (C) 2006 Daniel P. Berrange
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ *
+ * Author: Daniel P. Berrange <berrange@redhat.com>
+ */
+
+#include <config.h>
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/poll.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <syslog.h>
+#include <string.h>
+#include <errno.h>
+#include <getopt.h>
+#include <fnmatch.h>
+#include <grp.h>
+#include <signal.h>
+#include <netdb.h>
+
+#include "libvirt_internal.h"
+#include "virterror_internal.h"
+
+#define VIR_FROM_THIS VIR_FROM_QEMU
+
+#include "libvirtd.h"
+#include "dispatch.h"
+
+#include "util.h"
+#include "remote/remote_driver.h"
+#include "conf.h"
+#include "event.h"
+#include "memory.h"
+#ifdef HAVE_AVAHI
+#include "mdns.h"
+#endif
+
+#ifdef WITH_DRIVER_MODULES
+#include "driver.h"
+#else
+#ifdef WITH_QEMU
+#include "qemu/qemu_driver.h"
+#endif
+#ifdef WITH_LXC
+#include "lxc/lxc_driver.h"
+#endif
+#ifdef WITH_UML
+#include "uml/uml_driver.h"
+#endif
+#ifdef WITH_ONE
+#include "opennebula/one_driver.h"
+#endif
+#ifdef WITH_NETWORK
+#include "network/bridge_driver.h"
+#endif
+#ifdef WITH_NETCF
+#include "interface/netcf_driver.h"
+#endif
+#ifdef WITH_STORAGE_DIR
+#include "storage/storage_driver.h"
+#endif
+#ifdef WITH_NODE_DEVICES
+#include "node_device/node_device_driver.h"
+#endif
+#include "secret/secret_driver.h"
+#endif
+
+
+#ifdef __sun
+#include <ucred.h>
+#include <priv.h>
+
+#ifndef PRIV_VIRT_MANAGE
+#define PRIV_VIRT_MANAGE ((const char *)"virt_manage")
+#endif
+
+#ifndef PRIV_XVM_CONTROL
+#define PRIV_XVM_CONTROL ((const char *)"xvm_control")
+#endif
+
+#define PU_RESETGROUPS          0x0001  /* Remove supplemental groups */
+#define PU_CLEARLIMITSET        0x0008  /* L=0 */
+
+extern int __init_daemon_priv(int, uid_t, gid_t, ...);
+
+#define SYSTEM_UID 60
+
+static gid_t unix_sock_gid = 60; /* Not used */
+static int unix_sock_rw_mask = 0666;
+static int unix_sock_ro_mask = 0666;
+
+#else
+
+static gid_t unix_sock_gid = 0; /* Only root by default */
+static int unix_sock_rw_mask = 0700; /* Allow user only */
+static int unix_sock_ro_mask = 0777; /* Allow world */
+
+#endif /* __sun */
+
+static int godaemon = 0;        /* -d: Be a daemon */
+static int verbose = 0;         /* -v: Verbose mode */
+static int timeout = -1;        /* -t: Shutdown timeout */
+static int sigwrite = -1;       /* Signal handler pipe */
+static int ipsock = 0;          /* -l  Listen for TCP/IP */
+
+/* Defaults for configuration file elements */
+static int listen_tls = 1;
+static int listen_tcp = 0;
+static char *listen_addr  = (char *) LIBVIRTD_LISTEN_ADDR;
+static char *tls_port = (char *) LIBVIRTD_TLS_PORT;
+static char *tcp_port = (char *) LIBVIRTD_TCP_PORT;
+
+static char *unix_sock_dir = NULL;
+
+#if HAVE_POLKIT
+static int auth_unix_rw = REMOTE_AUTH_POLKIT;
+static int auth_unix_ro = REMOTE_AUTH_POLKIT;
+#else
+static int auth_unix_rw = REMOTE_AUTH_NONE;
+static int auth_unix_ro = REMOTE_AUTH_NONE;
+#endif /* HAVE_POLKIT */
+#if HAVE_SASL
+static int auth_tcp = REMOTE_AUTH_SASL;
+#else
+static int auth_tcp = REMOTE_AUTH_NONE;
+#endif
+static int auth_tls = REMOTE_AUTH_NONE;
+
+static int mdns_adv = 1;
+static char *mdns_name = NULL;
+
+static int tls_no_verify_certificate = 0;
+static char **tls_allowed_dn_list = NULL;
+
+static char *key_file = (char *) LIBVIRT_SERVERKEY;
+static char *cert_file = (char *) LIBVIRT_SERVERCERT;
+static char *ca_file = (char *) LIBVIRT_CACERT;
+static char *crl_file = (char *) "";
+
+static gnutls_certificate_credentials_t x509_cred;
+static gnutls_dh_params_t dh_params;
+
+static int min_workers = 5;
+static int max_workers = 20;
+static int max_clients = 20;
+
+/* Total number of 'in-process' RPC calls allowed across all clients */
+static int max_requests = 20;
+/* Total number of 'in-process' RPC calls allowed by a single client*/
+static int max_client_requests = 5;
+
+#define DH_BITS 1024
+
+static sig_atomic_t sig_errors = 0;
+static int sig_lasterrno = 0;
+
+static void sig_handler(int sig, siginfo_t * siginfo,
+                        void* context ATTRIBUTE_UNUSED) {
+    int origerrno;
+    int r;
+
+    /* set the sig num in the struct */
+    siginfo->si_signo = sig;
+
+    origerrno = errno;
+    r = safewrite(sigwrite, siginfo, sizeof(*siginfo));
+    if (r == -1) {
+        sig_errors++;
+        sig_lasterrno = errno;
+    }
+    errno = origerrno;
+}
+
+static void qemudDispatchClientEvent(int watch, int fd, int events, void *opaque);
+static void qemudDispatchServerEvent(int watch, int fd, int events, void *opaque);
+static int qemudStartWorker(struct qemud_server *server, struct qemud_worker *worker);
+
+void
+qemudClientMessageQueuePush(struct qemud_client_message **queue,
+                            struct qemud_client_message *msg)
+{
+    struct qemud_client_message *tmp = *queue;
+
+    if (tmp) {
+        while (tmp->next)
+            tmp = tmp->next;
+        tmp->next = msg;
+    } else {
+        *queue = msg;
+    }
+}
+
+struct qemud_client_message *
+qemudClientMessageQueueServe(struct qemud_client_message **queue)
+{
+    struct qemud_client_message *tmp = *queue;
+
+    if (tmp) {
+        *queue = tmp->next;
+        tmp->next = NULL;
+    }
+
+    return tmp;
+}
+
+static int
+remoteCheckCertFile(const char *type, const char *file)
+{
+    struct stat sb;
+    if (stat(file, &sb) < 0) {
+        char ebuf[1024];
+        VIR_ERROR(_("Cannot access %s '%s': %s"),
+                  type, file, virStrerror(errno, ebuf, sizeof ebuf));
+        return -1;
+    }
+    return 0;
+}
+
+static int
+remoteInitializeGnuTLS (void)
+{
+    int err;
+
+    /* Initialise GnuTLS. */
+    gnutls_global_init ();
+
+    err = gnutls_certificate_allocate_credentials (&x509_cred);
+    if (err) {
+        VIR_ERROR(_("gnutls_certificate_allocate_credentials: %s"),
+                  gnutls_strerror (err));
+        return -1;
+    }
+
+    if (ca_file && ca_file[0] != '\0') {
+        if (remoteCheckCertFile("CA certificate", ca_file) < 0)
+            return -1;
+
+        qemudDebug ("loading CA cert from %s", ca_file);
+        err = gnutls_certificate_set_x509_trust_file (x509_cred, ca_file,
+                                                      GNUTLS_X509_FMT_PEM);
+        if (err < 0) {
+            VIR_ERROR(_("gnutls_certificate_set_x509_trust_file: %s"),
+                      gnutls_strerror (err));
+            return -1;
+        }
+    }
+
+    if (crl_file && crl_file[0] != '\0') {
+        if (remoteCheckCertFile("CA revocation list", crl_file) < 0)
+            return -1;
+
+        DEBUG("loading CRL from %s", crl_file);
+        err = gnutls_certificate_set_x509_crl_file (x509_cred, crl_file,
+                                                    GNUTLS_X509_FMT_PEM);
+        if (err < 0) {
+            VIR_ERROR(_("gnutls_certificate_set_x509_crl_file: %s"),
+                      gnutls_strerror (err));
+            return -1;
+        }
+    }
+
+    if (cert_file && cert_file[0] != '\0' && key_file && key_file[0] != '\0') {
+        if (remoteCheckCertFile("server certificate", cert_file) < 0)
+            return -1;
+        if (remoteCheckCertFile("server key", key_file) < 0)
+            return -1;
+        DEBUG("loading cert and key from %s and %s", cert_file, key_file);
+        err =
+            gnutls_certificate_set_x509_key_file (x509_cred,
+                                                  cert_file, key_file,
+                                                  GNUTLS_X509_FMT_PEM);
+        if (err < 0) {
+            VIR_ERROR(_("gnutls_certificate_set_x509_key_file: %s"),
+                      gnutls_strerror (err));
+            return -1;
+        }
+    }
+
+    /* Generate Diffie Hellman parameters - for use with DHE
+     * kx algorithms. These should be discarded and regenerated
+     * once a day, once a week or once a month. Depending on the
+     * security requirements.
+     */
+    err = gnutls_dh_params_init (&dh_params);
+    if (err < 0) {
+        VIR_ERROR(_("gnutls_dh_params_init: %s"), gnutls_strerror (err));
+        return -1;
+    }
+    err = gnutls_dh_params_generate2 (dh_params, DH_BITS);
+    if (err < 0) {
+        VIR_ERROR(_("gnutls_dh_params_generate2: %s"), gnutls_strerror (err));
+        return -1;
+    }
+
+    gnutls_certificate_set_dh_params (x509_cred, dh_params);
+
+    return 0;
+}
+
+static void
+qemudDispatchSignalEvent(int watch ATTRIBUTE_UNUSED,
+                         int fd ATTRIBUTE_UNUSED,
+                         int events ATTRIBUTE_UNUSED,
+                         void *opaque) {
+    struct qemud_server *server = (struct qemud_server *)opaque;
+    siginfo_t siginfo;
+    int ret;
+
+    virMutexLock(&server->lock);
+
+    if (saferead(server->sigread, &siginfo, sizeof(siginfo)) != sizeof(siginfo)) {
+        char ebuf[1024];
+        VIR_ERROR(_("Failed to read from signal pipe: %s"),
+                  virStrerror(errno, ebuf, sizeof ebuf));
+        virMutexUnlock(&server->lock);
+        return;
+    }
+
+    ret = 0;
+
+    switch (siginfo.si_signo) {
+    case SIGHUP:
+        VIR_INFO0(_("Reloading configuration on SIGHUP"));
+        if (virStateReload() < 0)
+            VIR_WARN0(_("Error while reloading drivers"));
+        break;
+
+    case SIGINT:
+    case SIGQUIT:
+    case SIGTERM:
+        VIR_WARN(_("Shutting down on signal %d"), siginfo.si_signo);
+        server->shutdown = 1;
+        break;
+
+    default:
+        VIR_INFO(_("Received unexpected signal %d"), siginfo.si_signo);
+        break;
+    }
+
+    if (ret != 0)
+        server->shutdown = 1;
+
+    virMutexUnlock(&server->lock);
+}
+
+
+static int qemudGoDaemon(void) {
+    int pid = fork();
+    switch (pid) {
+    case 0:
+        {
+            int stdinfd = -1;
+            int stdoutfd = -1;
+            int nextpid;
+
+            if ((stdinfd = open("/dev/null", O_RDONLY)) < 0)
+                goto cleanup;
+            if ((stdoutfd = open("/dev/null", O_WRONLY)) < 0)
+                goto cleanup;
+            if (dup2(stdinfd, STDIN_FILENO) != STDIN_FILENO)
+                goto cleanup;
+            if (dup2(stdoutfd, STDOUT_FILENO) != STDOUT_FILENO)
+                goto cleanup;
+            if (dup2(stdoutfd, STDERR_FILENO) != STDERR_FILENO)
+                goto cleanup;
+            if (close(stdinfd) < 0)
+                goto cleanup;
+            stdinfd = -1;
+            if (close(stdoutfd) < 0)
+                goto cleanup;
+            stdoutfd = -1;
+
+            if (setsid() < 0)
+                goto cleanup;
+
+            nextpid = fork();
+            switch (nextpid) {
+            case 0:
+                return 0;
+            case -1:
+                return -1;
+            default:
+                _exit(0);
+            }
+
+        cleanup:
+            if (stdoutfd != -1)
+                close(stdoutfd);
+            if (stdinfd != -1)
+                close(stdinfd);
+            return -1;
+
+        }
+
+    case -1:
+        return -1;
+
+    default:
+        {
+            int got, status = 0;
+            /* We wait to make sure the next child forked
+               successfully */
+            if ((got = waitpid(pid, &status, 0)) < 0 ||
+                got != pid ||
+                status != 0) {
+                return -1;
+            }
+            _exit(0);
+        }
+    }
+}
+
+static int qemudWritePidFile(const char *pidFile) {
+    int fd;
+    FILE *fh;
+    char ebuf[1024];
+
+    if (pidFile[0] == '\0')
+        return 0;
+
+    if ((fd = open(pidFile, O_WRONLY|O_CREAT|O_EXCL, 0644)) < 0) {
+        VIR_ERROR(_("Failed to open pid file '%s' : %s"),
+                  pidFile, virStrerror(errno, ebuf, sizeof ebuf));
+        return -1;
+    }
+
+    if (!(fh = fdopen(fd, "w"))) {
+        VIR_ERROR(_("Failed to fdopen pid file '%s' : %s"),
+                  pidFile, virStrerror(errno, ebuf, sizeof ebuf));
+        close(fd);
+        return -1;
+    }
+
+    if (fprintf(fh, "%lu\n", (unsigned long)getpid()) < 0) {
+        VIR_ERROR(_("Failed to write to pid file '%s' : %s"),
+                  pidFile, virStrerror(errno, ebuf, sizeof ebuf));
+        fclose(fh);
+        return -1;
+    }
+
+    if (fclose(fh) == EOF) {
+        VIR_ERROR(_("Failed to close pid file '%s' : %s"),
+                  pidFile, virStrerror(errno, ebuf, sizeof ebuf));
+        return -1;
+    }
+
+    return 0;
+}
+
+static int qemudListenUnix(struct qemud_server *server,
+                           const char *path, int readonly, int auth) {
+    struct qemud_socket *sock;
+    struct sockaddr_un addr;
+    mode_t oldmask;
+    gid_t oldgrp;
+    char ebuf[1024];
+
+    if (VIR_ALLOC(sock) < 0) {
+        VIR_ERROR("%s", _("Failed to allocate memory for struct qemud_socket"));
+        return -1;
+    }
+
+    sock->readonly = readonly;
+    sock->port = -1;
+    sock->type = QEMUD_SOCK_TYPE_UNIX;
+    sock->auth = auth;
+
+    if ((sock->fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
+        VIR_ERROR(_("Failed to create socket: %s"),
+                  virStrerror(errno, ebuf, sizeof ebuf));
+        goto cleanup;
+    }
+
+    if (virSetCloseExec(sock->fd) < 0 ||
+        virSetNonBlock(sock->fd) < 0)
+        goto cleanup;
+
+    memset(&addr, 0, sizeof(addr));
+    addr.sun_family = AF_UNIX;
+    strncpy(addr.sun_path, path, sizeof(addr.sun_path)-1);
+    if (addr.sun_path[0] == '@')
+        addr.sun_path[0] = '\0';
+
+
+    oldgrp = getgid();
+    oldmask = umask(readonly ? ~unix_sock_ro_mask : ~unix_sock_rw_mask);
+    if (server->privileged)
+        setgid(unix_sock_gid);
+
+    if (bind(sock->fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+        VIR_ERROR(_("Failed to bind socket to '%s': %s"),
+                  path, virStrerror(errno, ebuf, sizeof ebuf));
+        goto cleanup;
+    }
+    umask(oldmask);
+    if (server->privileged)
+        setgid(oldgrp);
+
+    if (listen(sock->fd, 30) < 0) {
+        VIR_ERROR(_("Failed to listen for connections on '%s': %s"),
+                  path, virStrerror(errno, ebuf, sizeof ebuf));
+        goto cleanup;
+    }
+
+    if ((sock->watch = virEventAddHandleImpl(sock->fd,
+                                             VIR_EVENT_HANDLE_READABLE |
+                                             VIR_EVENT_HANDLE_ERROR |
+                                             VIR_EVENT_HANDLE_HANGUP,
+                                             qemudDispatchServerEvent,
+                                             server, NULL)) < 0) {
+        VIR_ERROR0(_("Failed to add server event callback"));
+        goto cleanup;
+    }
+
+    sock->next = server->sockets;
+    server->sockets = sock;
+    server->nsockets++;
+
+    return 0;
+
+ cleanup:
+    if (sock->fd)
+        close(sock->fd);
+    free(sock);
+    return -1;
+}
+
+// See: http://people.redhat.com/drepper/userapi-ipv6.html
+static int
+remoteMakeSockets (int *fds, int max_fds, int *nfds_r, const char *node, const char *service)
+{
+    struct addrinfo *ai;
+    struct addrinfo hints;
+    memset (&hints, 0, sizeof hints);
+    hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
+    hints.ai_socktype = SOCK_STREAM;
+
+    int e = getaddrinfo (node, service, &hints, &ai);
+    if (e != 0) {
+        VIR_ERROR(_("getaddrinfo: %s\n"), gai_strerror (e));
+        return -1;
+    }
+
+    struct addrinfo *runp = ai;
+    while (runp && *nfds_r < max_fds) {
+        char ebuf[1024];
+        fds[*nfds_r] = socket (runp->ai_family, runp->ai_socktype,
+                               runp->ai_protocol);
+        if (fds[*nfds_r] == -1) {
+            VIR_ERROR(_("socket: %s"), virStrerror (errno, ebuf, sizeof ebuf));
+            return -1;
+        }
+
+        int opt = 1;
+        setsockopt (fds[*nfds_r], SOL_SOCKET, SO_REUSEADDR, &opt, sizeof opt);
+
+        if (bind (fds[*nfds_r], runp->ai_addr, runp->ai_addrlen) == -1) {
+            if (errno != EADDRINUSE) {
+                VIR_ERROR(_("bind: %s"), virStrerror (errno, ebuf, sizeof ebuf));
+                return -1;
+            }
+            close (fds[*nfds_r]);
+        }
+        else {
+            if (listen (fds[*nfds_r], SOMAXCONN) == -1) {
+                VIR_ERROR(_("listen: %s"),
+                          virStrerror (errno, ebuf, sizeof ebuf));
+                return -1;
+            }
+            ++*nfds_r;
+        }
+        runp = runp->ai_next;
+    }
+
+    freeaddrinfo (ai);
+    return 0;
+}
+
+/* Listen on the named/numbered TCP port.  On a machine with IPv4 and
+ * IPv6 interfaces this may generate several sockets.
+ */
+static int
+remoteListenTCP (struct qemud_server *server,
+                 const char *addr,
+                 const char *port,
+                 int type,
+                 int auth)
+{
+    int fds[2];
+    int nfds = 0;
+    int i;
+    struct qemud_socket *sock;
+
+    if (remoteMakeSockets (fds, 2, &nfds, addr, port) == -1)
+        return -1;
+
+    for (i = 0; i < nfds; ++i) {
+        union {
+            struct sockaddr_storage sa_stor;
+            struct sockaddr sa;
+            struct sockaddr_in sa_in;
+#ifdef AF_INET6
+            struct sockaddr_in6 sa_in6;
+#endif
+        } s;
+        char ebuf[1024];
+        socklen_t salen = sizeof(s);
+
+        if (VIR_ALLOC(sock) < 0) {
+            VIR_ERROR(_("remoteListenTCP: calloc: %s"),
+                      virStrerror (errno, ebuf, sizeof ebuf));
+            goto cleanup;
+        }
+
+        sock->readonly = 0;
+        sock->next = server->sockets;
+        server->sockets = sock;
+        server->nsockets++;
+
+        sock->fd = fds[i];
+        sock->type = type;
+        sock->auth = auth;
+
+        if (getsockname(sock->fd, &s.sa, &salen) < 0)
+            goto cleanup;
+
+        if (s.sa.sa_family == AF_INET) {
+            sock->port = htons(s.sa_in.sin_port);
+#ifdef AF_INET6
+        } else if (s.sa.sa_family == AF_INET6)
+            sock->port = htons(s.sa_in6.sin6_port);
+#endif
+        else
+            sock->port = -1;
+
+        if (virSetCloseExec(sock->fd) < 0 ||
+            virSetNonBlock(sock->fd) < 0)
+            goto cleanup;
+
+        if (listen (sock->fd, 30) < 0) {
+            VIR_ERROR(_("remoteListenTCP: listen: %s"),
+                      virStrerror (errno, ebuf, sizeof ebuf));
+            goto cleanup;
+        }
+
+        if ((sock->watch = virEventAddHandleImpl(sock->fd,
+                                                 VIR_EVENT_HANDLE_READABLE |
+                                                 VIR_EVENT_HANDLE_ERROR |
+                                                 VIR_EVENT_HANDLE_HANGUP,
+                                                 qemudDispatchServerEvent,
+                                                 server, NULL)) < 0) {
+            VIR_ERROR0(_("Failed to add server event callback"));
+            goto cleanup;
+        }
+
+    }
+
+    return 0;
+
+cleanup:
+    for (i = 0; i < nfds; ++i)
+        close(fds[i]);
+    return -1;
+}
+
+static int qemudInitPaths(struct qemud_server *server,
+                          char *sockname,
+                          char *roSockname,
+                          int maxlen)
+{
+    char *sock_dir;
+    char *dir_prefix = NULL;
+    int ret = -1;
+    char *sock_dir_prefix = NULL;
+
+    if (unix_sock_dir)
+        sock_dir = unix_sock_dir;
+    else {
+        sock_dir = sockname;
+        if (server->privileged) {
+            dir_prefix = strdup (LOCAL_STATE_DIR);
+            if (dir_prefix == NULL) {
+                virReportOOMError(NULL);
+                goto cleanup;
+            }
+            if (snprintf (sock_dir, maxlen, "%s/run/libvirt",
+                          dir_prefix) >= maxlen)
+                goto snprintf_error;
+        } else {
+            uid_t uid = geteuid();
+            dir_prefix = virGetUserDirectory(NULL, uid);
+            if (dir_prefix == NULL) {
+                /* Do not diagnose here; virGetUserDirectory does that.  */
+                goto snprintf_error;
+            }
+
+            if (snprintf(sock_dir, maxlen, "%s/.libvirt", dir_prefix) >= maxlen)
+                goto snprintf_error;
+        }
+    }
+
+    sock_dir_prefix = strdup (sock_dir);
+    if (!sock_dir_prefix) {
+        virReportOOMError(NULL);
+        goto cleanup;
+    }
+
+    if (server->privileged) {
+        if (snprintf (sockname, maxlen, "%s/libvirt-sock",
+                      sock_dir_prefix) >= maxlen
+            || (snprintf (roSockname, maxlen, "%s/libvirt-sock-ro",
+                          sock_dir_prefix) >= maxlen))
+            goto snprintf_error;
+        unlink(sockname);
+        unlink(roSockname);
+    } else {
+        if (snprintf(sockname, maxlen, "@%s/libvirt-sock",
+                     sock_dir_prefix) >= maxlen)
+            goto snprintf_error;
+    }
+
+    if (server->privileged)
+        server->logDir = strdup (LOCAL_STATE_DIR "/log/libvirt");
+    else
+        virAsprintf(&server->logDir, "%s/.libvirt/log", dir_prefix);
+
+    if (server->logDir == NULL)
+        virReportOOMError(NULL);
+
+    ret = 0;
+
+ snprintf_error:
+    if (ret)
+        VIR_ERROR("%s",
+                  _("Resulting path too long for buffer in qemudInitPaths()"));
+
+ cleanup:
+    free (dir_prefix);
+    free (sock_dir_prefix);
+    return ret;
+}
+
+static struct qemud_server *qemudInitialize(int sigread) {
+    struct qemud_server *server;
+
+    if (VIR_ALLOC(server) < 0) {
+        VIR_ERROR0(_("Failed to allocate struct qemud_server"));
+        return NULL;
+    }
+
+    if (virMutexInit(&server->lock) < 0) {
+        VIR_ERROR("%s", _("cannot initialize mutex"));
+        VIR_FREE(server);
+    }
+    if (virCondInit(&server->job) < 0) {
+        VIR_ERROR("%s", _("cannot initialize condition variable"));
+        virMutexDestroy(&server->lock);
+        VIR_FREE(server);
+    }
+
+    server->privileged = geteuid() == 0 ? 1 : 0;
+    server->sigread = sigread;
+
+    if (virEventInit() < 0) {
+        VIR_ERROR0(_("Failed to initialize event system"));
+        VIR_FREE(server);
+        return NULL;
+    }
+
+    virInitialize();
+
+    /*
+     * Note that the order is important: the first ones have a higher
+     * priority when calling virStateInitialize. We must register
+     * the network, storage and nodedev drivers before any domain
+     * drivers, since their resources must be auto-started before
+     * any domains can be auto-started.
+     */
+#ifdef WITH_DRIVER_MODULES
+    /* We don't care if any of these fail, because the whole point
+     * is to allow users to only install modules they want to use.
+     * If they try to use a open a connection for a module that
+     * is not loaded they'll get a suitable error at that point
+     */
+    virDriverLoadModule("network");
+    virDriverLoadModule("storage");
+    virDriverLoadModule("nodedev");
+    virDriverLoadModule("secret");
+    virDriverLoadModule("qemu");
+    virDriverLoadModule("lxc");
+    virDriverLoadModule("uml");
+    virDriverLoadModule("one");
+#else
+#ifdef WITH_NETWORK
+    networkRegister();
+#endif
+#ifdef WITH_NETCF
+    interfaceRegister();
+#endif
+#ifdef WITH_STORAGE_DIR
+    storageRegister();
+#endif
+#if defined(WITH_NODE_DEVICES) && \
+    (defined(HAVE_HAL) || defined(HAVE_DEVKIT))
+    nodedevRegister();
+#endif
+    secretRegister();
+#ifdef WITH_QEMU
+    qemuRegister();
+#endif
+#ifdef WITH_LXC
+    lxcRegister();
+#endif
+#ifdef WITH_UML
+    umlRegister();
+#endif
+#ifdef WITH_ONE
+    oneRegister();
+#endif
+#endif
+
+    virEventRegisterImpl(virEventAddHandleImpl,
+                         virEventUpdateHandleImpl,
+                         virEventRemoveHandleImpl,
+                         virEventAddTimeoutImpl,
+                         virEventUpdateTimeoutImpl,
+                         virEventRemoveTimeoutImpl);
+
+    virStateInitialize(server->privileged);
+
+    return server;
+}
+
+static struct qemud_server *qemudNetworkInit(struct qemud_server *server) {
+    struct qemud_socket *sock;
+    char sockname[PATH_MAX];
+    char roSockname[PATH_MAX];
+#if HAVE_SASL
+    int err;
+#endif /* HAVE_SASL */
+
+    roSockname[0] = '\0';
+
+    if (qemudInitPaths(server, sockname, roSockname, PATH_MAX) < 0)
+        goto cleanup;
+
+    if (qemudListenUnix(server, sockname, 0, auth_unix_rw) < 0)
+        goto cleanup;
+
+    if (roSockname[0] != '\0' && qemudListenUnix(server, roSockname, 1, auth_unix_ro) < 0)
+        goto cleanup;
+
+#if HAVE_SASL
+    if (auth_unix_rw == REMOTE_AUTH_SASL ||
+        auth_unix_ro == REMOTE_AUTH_SASL ||
+        auth_tcp == REMOTE_AUTH_SASL ||
+        auth_tls == REMOTE_AUTH_SASL) {
+        if ((err = sasl_server_init(NULL, "libvirt")) != SASL_OK) {
+            VIR_ERROR(_("Failed to initialize SASL authentication %s"),
+                      sasl_errstring(err, NULL, NULL));
+            goto cleanup;
+        }
+    }
+#endif
+
+#if HAVE_POLKIT0
+    if (auth_unix_rw == REMOTE_AUTH_POLKIT ||
+        auth_unix_ro == REMOTE_AUTH_POLKIT) {
+        DBusError derr;
+
+        dbus_connection_set_change_sigpipe(FALSE);
+        dbus_threads_init_default();
+
+        dbus_error_init(&derr);
+        server->sysbus = dbus_bus_get(DBUS_BUS_SYSTEM, &derr);
+        if (!(server->sysbus)) {
+            VIR_ERROR(_("Failed to connect to system bus for PolicyKit auth: %s"),
+                      derr.message);
+            dbus_error_free(&derr);
+            goto cleanup;
+        }
+        dbus_connection_set_exit_on_disconnect(server->sysbus, FALSE);
+    }
+#endif
+
+    if (ipsock) {
+        if (listen_tcp && remoteListenTCP (server, listen_addr, tcp_port, QEMUD_SOCK_TYPE_TCP, auth_tcp) < 0)
+            goto cleanup;
+
+        if (listen_tls) {
+            if (remoteInitializeGnuTLS () < 0)
+                goto cleanup;
+
+            if (remoteListenTCP (server, listen_addr, tls_port, QEMUD_SOCK_TYPE_TLS, auth_tls) < 0)
+                goto cleanup;
+        }
+    }
+
+#ifdef HAVE_AVAHI
+    if (server->privileged && mdns_adv) {
+        struct libvirtd_mdns_group *group;
+        int port = 0;
+
+        server->mdns = libvirtd_mdns_new();
+
+        if (!mdns_name) {
+            char groupname[64], localhost[HOST_NAME_MAX+1], *tmp;
+            /* Extract the host part of the potentially FQDN */
+            gethostname(localhost, HOST_NAME_MAX);
+            localhost[HOST_NAME_MAX] = '\0';
+            if ((tmp = strchr(localhost, '.')))
+                *tmp = '\0';
+            snprintf(groupname, sizeof(groupname)-1, "Virtualization Host %s", localhost);
+            groupname[sizeof(groupname)-1] = '\0';
+            group = libvirtd_mdns_add_group(server->mdns, groupname);
+        } else {
+            group = libvirtd_mdns_add_group(server->mdns, mdns_name);
+        }
+
+        /*
+         * See if there's a TLS enabled port we can advertise. Cowardly
+         * don't bother to advertise TCP since we don't want people using
+         * them for real world apps
+         */
+        sock = server->sockets;
+        while (sock) {
+            if (sock->port != -1 && sock->type == QEMUD_SOCK_TYPE_TLS) {
+                port = sock->port;
+                break;
+            }
+            sock = sock->next;
+        }
+
+        /*
+         * Add the primary entry - we choose SSH because its most likely to always
+         * be available
+         */
+        libvirtd_mdns_add_entry(group, "_libvirt._tcp", port);
+        libvirtd_mdns_start(server->mdns);
+    }
+#endif
+
+    return server;
+
+ cleanup:
+    if (server) {
+        sock = server->sockets;
+        while (sock) {
+            close(sock->fd);
+            sock = sock->next;
+        }
+
+#if HAVE_POLKIT0
+        if (server->sysbus)
+            dbus_connection_unref(server->sysbus);
+#endif
+        free(server);
+    }
+    return NULL;
+}
+
+static gnutls_session_t
+remoteInitializeTLSSession (void)
+{
+  gnutls_session_t session;
+  int err;
+
+  err = gnutls_init (&session, GNUTLS_SERVER);
+  if (err != 0) goto failed;
+
+  /* avoid calling all the priority functions, since the defaults
+   * are adequate.
+   */
+  err = gnutls_set_default_priority (session);
+  if (err != 0) goto failed;
+
+  err = gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, x509_cred);
+  if (err != 0) goto failed;
+
+  /* request client certificate if any.
+   */
+  gnutls_certificate_server_set_request (session, GNUTLS_CERT_REQUEST);
+
+  gnutls_dh_set_prime_bits (session, DH_BITS);
+
+  return session;
+
+ failed:
+  VIR_ERROR(_("remoteInitializeTLSSession: %s"),
+            gnutls_strerror (err));
+  return NULL;
+}
+
+/* Check DN is on tls_allowed_dn_list. */
+static int
+remoteCheckDN (gnutls_x509_crt_t cert)
+{
+    char name[256];
+    size_t namesize = sizeof name;
+    char **wildcards;
+    int err;
+
+    err = gnutls_x509_crt_get_dn (cert, name, &namesize);
+    if (err != 0) {
+        VIR_ERROR(_("remoteCheckDN: gnutls_x509_cert_get_dn: %s"),
+                  gnutls_strerror (err));
+        return 0;
+    }
+
+    /* If the list is not set, allow any DN. */
+    wildcards = tls_allowed_dn_list;
+    if (!wildcards)
+        return 1;
+
+    while (*wildcards) {
+        if (fnmatch (*wildcards, name, 0) == 0)
+            return 1;
+        wildcards++;
+    }
+
+    /* Print the client's DN. */
+    DEBUG(_("remoteCheckDN: failed: client DN is %s"), name);
+
+    return 0; // Not found.
+}
+
+static int
+remoteCheckCertificate (gnutls_session_t session)
+{
+    int ret;
+    unsigned int status;
+    const gnutls_datum_t *certs;
+    unsigned int nCerts, i;
+    time_t now;
+
+    if ((ret = gnutls_certificate_verify_peers2 (session, &status)) < 0){
+        VIR_ERROR(_("remoteCheckCertificate: verify failed: %s"),
+                  gnutls_strerror (ret));
+        return -1;
+    }
+
+    if (status != 0) {
+        if (status & GNUTLS_CERT_INVALID)
+            VIR_ERROR0(_("remoteCheckCertificate: "
+                         "the client certificate is not trusted."));
+
+        if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
+            VIR_ERROR0(_("remoteCheckCertificate: the client "
+                         "certificate has unknown issuer."));
+
+        if (status & GNUTLS_CERT_REVOKED)
+            VIR_ERROR0(_("remoteCheckCertificate: "
+                         "the client certificate has been revoked."));
+
+#ifndef GNUTLS_1_0_COMPAT
+        if (status & GNUTLS_CERT_INSECURE_ALGORITHM)
+            VIR_ERROR0(_("remoteCheckCertificate: the client certificate"
+                         " uses an insecure algorithm."));
+#endif
+
+        return -1;
+    }
+
+    if (gnutls_certificate_type_get (session) != GNUTLS_CRT_X509) {
+        VIR_ERROR0(_("remoteCheckCertificate: certificate is not X.509"));
+        return -1;
+    }
+
+    if (!(certs = gnutls_certificate_get_peers(session, &nCerts))) {
+        VIR_ERROR0(_("remoteCheckCertificate: no peers"));
+        return -1;
+    }
+
+    now = time (NULL);
+
+    for (i = 0; i < nCerts; i++) {
+        gnutls_x509_crt_t cert;
+
+        if (gnutls_x509_crt_init (&cert) < 0) {
+            VIR_ERROR0(_("remoteCheckCertificate: gnutls_x509_crt_init failed"));
+            return -1;
+        }
+
+        if (gnutls_x509_crt_import(cert, &certs[i], GNUTLS_X509_FMT_DER) < 0) {
+            gnutls_x509_crt_deinit (cert);
+            return -1;
+        }
+
+        if (gnutls_x509_crt_get_expiration_time (cert) < now) {
+            VIR_ERROR0(_("remoteCheckCertificate: "
+                         "the client certificate has expired"));
+            gnutls_x509_crt_deinit (cert);
+            return -1;
+        }
+
+        if (gnutls_x509_crt_get_activation_time (cert) > now) {
+            VIR_ERROR0(_("remoteCheckCertificate: the client "
+                         "certificate is not yet activated"));
+            gnutls_x509_crt_deinit (cert);
+            return -1;
+        }
+
+        if (i == 0) {
+            if (!remoteCheckDN (cert)) {
+                /* This is the most common error: make it informative. */
+                VIR_ERROR0(_("remoteCheckCertificate: client's Distinguished Name is not on the list of allowed clients (tls_allowed_dn_list).  Use 'openssl x509 -in clientcert.pem -text' to view the Distinguished Name field in the client certificate, or run this daemon with --verbose option."));
+                gnutls_x509_crt_deinit (cert);
+                return -1;
+            }
+        }
+    }
+
+    return 0;
+}
+
+/* Check the client's access. */
+static int
+remoteCheckAccess (struct qemud_client *client)
+{
+    struct qemud_client_message *confirm;
+
+    /* Verify client certificate. */
+    if (remoteCheckCertificate (client->tlssession) == -1) {
+        VIR_ERROR0(_("remoteCheckCertificate: "
+                     "failed to verify client's certificate"));
+        if (!tls_no_verify_certificate) return -1;
+        else VIR_INFO0(_("remoteCheckCertificate: tls_no_verify_certificate "
+                          "is set so the bad certificate is ignored"));
+    }
+
+    if (client->tx) {
+        VIR_INFO("%s",
+                 _("client had unexpected data pending tx after access check"));
+        return -1;
+    }
+
+    if (VIR_ALLOC(confirm) < 0)
+        return -1;
+
+    /* Checks have succeeded.  Write a '\1' byte back to the client to
+     * indicate this (otherwise the socket is abruptly closed).
+     * (NB. The '\1' byte is sent in an encrypted record).
+     */
+    confirm->async = 1;
+    confirm->bufferLength = 1;
+    confirm->bufferOffset = 0;
+    confirm->buffer[0] = '\1';
+
+    client->tx = confirm;
+    return 0;
+}
+
+#if HAVE_POLKIT
+int qemudGetSocketIdentity(int fd, uid_t *uid, pid_t *pid) {
+#ifdef SO_PEERCRED
+    struct ucred cr;
+    unsigned int cr_len = sizeof (cr);
+
+    if (getsockopt (fd, SOL_SOCKET, SO_PEERCRED, &cr, &cr_len) < 0) {
+        char ebuf[1024];
+        VIR_ERROR(_("Failed to verify client credentials: %s"),
+                  virStrerror(errno, ebuf, sizeof ebuf));
+        return -1;
+    }
+
+    *pid = cr.pid;
+    *uid = cr.uid;
+#else
+    /* XXX Many more OS support UNIX socket credentials we could port to. See dbus ....*/
+#error "UNIX socket credentials not supported/implemented on this platform yet..."
+#endif
+    return 0;
+}
+#endif
+
+
+static int qemudDispatchServer(struct qemud_server *server, struct qemud_socket *sock) {
+    int fd;
+    struct sockaddr_storage addr;
+    socklen_t addrlen = (socklen_t) (sizeof addr);
+    struct qemud_client *client;
+    int no_slow_start = 1;
+
+    if ((fd = accept(sock->fd, (struct sockaddr *)&addr, &addrlen)) < 0) {
+        char ebuf[1024];
+        if (errno == EAGAIN)
+            return 0;
+        VIR_ERROR(_("Failed to accept connection: %s"),
+                  virStrerror(errno, ebuf, sizeof ebuf));
+        return -1;
+    }
+
+    if (server->nclients >= max_clients) {
+        VIR_ERROR(_("Too many active clients (%d), dropping connection"), max_clients);
+        close(fd);
+        return -1;
+    }
+
+    if (VIR_REALLOC_N(server->clients, server->nclients+1) < 0) {
+        VIR_ERROR0(_("Out of memory allocating clients"));
+        close(fd);
+        return -1;
+    }
+
+#ifdef __sun
+    {
+        ucred_t *ucred = NULL;
+        const priv_set_t *privs;
+
+        if (getpeerucred (fd, &ucred) == -1 ||
+            (privs = ucred_getprivset (ucred, PRIV_EFFECTIVE)) == NULL) {
+            if (ucred != NULL)
+                ucred_free (ucred);
+            close (fd);
+            return -1;
+        }
+
+        if (!priv_ismember (privs, PRIV_VIRT_MANAGE)) {
+            ucred_free (ucred);
+            close (fd);
+            return -1;
+        }
+
+        ucred_free (ucred);
+    }
+#endif /* __sun */
+
+    /* Disable Nagle.  Unix sockets will ignore this. */
+    setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, (void *)&no_slow_start,
+                sizeof no_slow_start);
+
+    if (virSetCloseExec(fd) < 0 ||
+        virSetNonBlock(fd) < 0) {
+        close(fd);
+        return -1;
+    }
+
+    if (VIR_ALLOC(client) < 0)
+        goto cleanup;
+    if (virMutexInit(&client->lock) < 0) {
+        VIR_ERROR("%s", _("cannot initialize mutex"));
+        VIR_FREE(client);
+        goto cleanup;
+    }
+
+    client->magic = QEMUD_CLIENT_MAGIC;
+    client->fd = fd;
+    client->readonly = sock->readonly;
+    client->type = sock->type;
+    client->auth = sock->auth;
+    memcpy (&client->addr, &addr, sizeof addr);
+    client->addrlen = addrlen;
+
+    /* Prepare one for packet receive */
+    if (VIR_ALLOC(client->rx) < 0)
+        goto cleanup;
+    client->rx->bufferLength = REMOTE_MESSAGE_HEADER_XDR_LEN;
+
+
+#if HAVE_POLKIT
+    /* Only do policy checks for non-root - allow root user
+       through with no checks, as a fail-safe - root can easily
+       change policykit policy anyway, so its pointless trying
+       to restrict root */
+    if (client->auth == REMOTE_AUTH_POLKIT) {
+        uid_t uid;
+        pid_t pid;
+
+        if (qemudGetSocketIdentity(client->fd, &uid, &pid) < 0)
+            goto cleanup;
+
+        /* Client is running as root, so disable auth */
+        if (uid == 0) {
+            VIR_INFO(_("Turn off polkit auth for privileged client %d"), pid);
+            client->auth = REMOTE_AUTH_NONE;
+        }
+    }
+#endif
+
+    if (client->type != QEMUD_SOCK_TYPE_TLS) {
+        /* Plain socket, so prepare to read first message */
+        if (qemudRegisterClientEvent (server, client) < 0)
+            goto cleanup;
+    } else {
+        int ret;
+
+        client->tlssession = remoteInitializeTLSSession ();
+        if (client->tlssession == NULL)
+            goto cleanup;
+
+        gnutls_transport_set_ptr (client->tlssession,
+                                  (gnutls_transport_ptr_t) (long) fd);
+
+        /* Begin the TLS handshake. */
+        ret = gnutls_handshake (client->tlssession);
+        if (ret == 0) {
+            client->handshake = 0;
+
+            /* Unlikely, but ...  Next step is to check the certificate. */
+            if (remoteCheckAccess (client) == -1)
+                goto cleanup;
+
+            /* Handshake & cert check OK,  so prepare to read first message */
+            if (qemudRegisterClientEvent(server, client) < 0)
+                goto cleanup;
+        } else if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) {
+            /* Most likely, need to do more handshake data */
+            client->handshake = 1;
+
+            if (qemudRegisterClientEvent (server, client) < 0)
+                goto cleanup;
+        } else {
+            VIR_ERROR(_("TLS handshake failed: %s"),
+                      gnutls_strerror (ret));
+            goto cleanup;
+        }
+    }
+
+    server->clients[server->nclients++] = client;
+
+    if (server->nclients > server->nactiveworkers &&
+        server->nactiveworkers < server->nworkers) {
+        int i;
+        for (i = 0 ; i < server->nworkers ; i++) {
+            if (!server->workers[i].hasThread) {
+                if (qemudStartWorker(server, &server->workers[i]) < 0)
+                    return -1;
+                server->nactiveworkers++;
+                break;
+            }
+        }
+    }
+
+
+    return 0;
+
+ cleanup:
+    if (client &&
+        client->tlssession) gnutls_deinit (client->tlssession);
+    close (fd);
+    VIR_FREE(client->rx);
+    VIR_FREE(client);
+    return -1;
+}
+
+
+/*
+ * You must hold lock for at least the client
+ * We don't free stuff here, merely disconnect the client's
+ * network socket & resources.
+ * We keep the libvirt connection open until any async
+ * jobs have finished, then clean it up elsehwere
+ */
+void qemudDispatchClientFailure(struct qemud_client *client) {
+    if (client->watch != -1) {
+        virEventRemoveHandleImpl(client->watch);
+        client->watch = -1;
+    }
+
+    /* Deregister event delivery callback */
+    if(client->conn) {
+        DEBUG0("Deregistering to relay remote events");
+        virConnectDomainEventDeregister(client->conn, remoteRelayDomainEvent);
+    }
+
+#if HAVE_SASL
+    if (client->saslconn) {
+        sasl_dispose(&client->saslconn);
+        client->saslconn = NULL;
+    }
+    free(client->saslUsername);
+    client->saslUsername = NULL;
+#endif
+    if (client->tlssession) {
+        gnutls_deinit (client->tlssession);
+        client->tlssession = NULL;
+    }
+    if (client->fd != -1) {
+        close(client->fd);
+        client->fd = -1;
+    }
+}
+
+
+/* Caller must hold server lock */
+static struct qemud_client *qemudPendingJob(struct qemud_server *server)
+{
+    int i;
+    for (i = 0 ; i < server->nclients ; i++) {
+        virMutexLock(&server->clients[i]->lock);
+        if (server->clients[i]->dx) {
+            /* Delibrately don't unlock client - caller wants the lock */
+            return server->clients[i];
+        }
+        virMutexUnlock(&server->clients[i]->lock);
+    }
+    return NULL;
+}
+
+static void *qemudWorker(void *data)
+{
+    struct qemud_worker *worker = data;
+    struct qemud_server *server = worker->server;
+
+    while (1) {
+        struct qemud_client *client = NULL;
+        struct qemud_client_message *msg;
+
+        virMutexLock(&server->lock);
+        while (((client = qemudPendingJob(server)) == NULL) &&
+               !worker->quitRequest) {
+            if (virCondWait(&server->job, &server->lock) < 0) {
+                virMutexUnlock(&server->lock);
+                return NULL;
+            }
+        }
+        if (worker->quitRequest) {
+            if (client)
+                virMutexUnlock(&client->lock);
+            virMutexUnlock(&server->lock);
+            return NULL;
+        }
+        worker->processingCall = 1;
+        virMutexUnlock(&server->lock);
+
+        /* We own a locked client now... */
+        client->refs++;
+
+        /* Remove our message from dispatch queue while we use it */
+        msg = qemudClientMessageQueueServe(&client->dx);
+
+        /* This function drops the lock during dispatch,
+         * and re-acquires it before returning */
+        if (remoteDispatchClientRequest (server, client, msg) < 0) {
+            VIR_FREE(msg);
+            qemudDispatchClientFailure(client);
+            client->refs--;
+            virMutexUnlock(&client->lock);
+            continue;
+        }
+
+        client->refs--;
+        virMutexUnlock(&client->lock);
+
+        virMutexLock(&server->lock);
+        worker->processingCall = 0;
+        virMutexUnlock(&server->lock);
+    }
+}
+
+static int qemudStartWorker(struct qemud_server *server,
+                            struct qemud_worker *worker) {
+    pthread_attr_t attr;
+    pthread_attr_init(&attr);
+    /* We want to join workers, so don't detach them */
+    /*pthread_attr_setdetachstate(&attr, 1);*/
+
+    if (worker->hasThread)
+        return -1;
+
+    worker->server = server;
+    worker->hasThread = 1;
+    worker->quitRequest = 0;
+    worker->processingCall = 0;
+
+    if (pthread_create(&worker->thread,
+                       &attr,
+                       qemudWorker,
+                       worker) != 0) {
+        worker->hasThread = 0;
+        worker->server = NULL;
+        return -1;
+    }
+
+    return 0;
+}
+
+
+/*
+ * Read data into buffer using wire decoding (plain or TLS)
+ *
+ * Returns:
+ *   -1 on error or EOF
+ *    0 on EAGAIN
+ *    n number of bytes
+ */
+static ssize_t qemudClientReadBuf(struct qemud_client *client,
+                                  char *data, ssize_t len) {
+    ssize_t ret;
+
+    if (len < 0) {
+        VIR_ERROR(_("unexpected negative length request %lld"),
+                  (long long int) len);
+        qemudDispatchClientFailure(client);
+        return -1;
+    }
+
+    /*qemudDebug ("qemudClientRead: len = %d", len);*/
+
+    if (!client->tlssession) {
+        char ebuf[1024];
+        ret = read (client->fd, data, len);
+        if (ret == -1 && (errno == EAGAIN ||
+                          errno == EINTR))
+            return 0;
+        if (ret <= 0) {
+            if (ret != 0)
+                VIR_ERROR(_("read: %s"),
+                          virStrerror (errno, ebuf, sizeof ebuf));
+            qemudDispatchClientFailure(client);
+            return -1;
+        }
+    } else {
+        ret = gnutls_record_recv (client->tlssession, data, len);
+
+        if (ret < 0 && (ret == GNUTLS_E_AGAIN ||
+                        ret == GNUTLS_E_INTERRUPTED))
+            return 0;
+        if (ret <= 0) {
+            if (ret != 0)
+                VIR_ERROR(_("gnutls_record_recv: %s"),
+                          gnutls_strerror (ret));
+            qemudDispatchClientFailure(client);
+            return -1;
+        }
+    }
+
+    return ret;
+}
+
+/*
+ * Read data into buffer without decoding
+ *
+ * Returns:
+ *   -1 on error or EOF
+ *    0 on EAGAIN
+ *    n number of bytes
+ */
+static ssize_t qemudClientReadPlain(struct qemud_client *client) {
+    ssize_t ret;
+    ret = qemudClientReadBuf(client,
+                             client->rx->buffer + client->rx->bufferOffset,
+                             client->rx->bufferLength - client->rx->bufferOffset);
+    if (ret <= 0)
+        return ret; /* -1 error, 0 eagain */
+
+    client->rx->bufferOffset += ret;
+    return ret;
+}
+
+#if HAVE_SASL
+/*
+ * Read data into buffer decoding with SASL
+ *
+ * Returns:
+ *   -1 on error or EOF
+ *    0 on EAGAIN
+ *    n number of bytes
+ */
+static ssize_t qemudClientReadSASL(struct qemud_client *client) {
+    ssize_t got, want;
+
+    /* We're doing a SSF data read, so now its times to ensure
+     * future writes are under SSF too.
+     *
+     * cf remoteSASLCheckSSF in remote.c
+     */
+    client->saslSSF |= QEMUD_SASL_SSF_WRITE;
+
+    /* Need to read some more data off the wire */
+    if (client->saslDecoded == NULL) {
+        int ret;
+        char encoded[8192];
+        ssize_t encodedLen = sizeof(encoded);
+        encodedLen = qemudClientReadBuf(client, encoded, encodedLen);
+
+        if (encodedLen <= 0)
+            return encodedLen;
+
+        ret = sasl_decode(client->saslconn, encoded, encodedLen,
+                          &client->saslDecoded, &client->saslDecodedLength);
+        if (ret != SASL_OK) {
+            VIR_ERROR(_("failed to decode SASL data %s"),
+                      sasl_errstring(ret, NULL, NULL));
+            qemudDispatchClientFailure(client);
+            return -1;
+        }
+
+        client->saslDecodedOffset = 0;
+    }
+
+    /* Some buffered decoded data to return now */
+    got = client->saslDecodedLength - client->saslDecodedOffset;
+    want = client->rx->bufferLength - client->rx->bufferOffset;
+
+    if (want > got)
+        want = got;
+
+    memcpy(client->rx->buffer + client->rx->bufferOffset,
+           client->saslDecoded + client->saslDecodedOffset, want);
+    client->saslDecodedOffset += want;
+    client->rx->bufferOffset += want;
+
+    if (client->saslDecodedOffset == client->saslDecodedLength) {
+        client->saslDecoded = NULL;
+        client->saslDecodedOffset = client->saslDecodedLength = 0;
+    }
+
+    return want;
+}
+#endif
+
+/*
+ * Read as much data off wire as possible till we fill our
+ * buffer, or would block on I/O
+ */
+static ssize_t qemudClientRead(struct qemud_client *client) {
+#if HAVE_SASL
+    if (client->saslSSF & QEMUD_SASL_SSF_READ)
+        return qemudClientReadSASL(client);
+    else
+#endif
+        return qemudClientReadPlain(client);
+}
+
+
+/*
+ * Read data until we get a complete message to process
+ */
+static void qemudDispatchClientRead(struct qemud_server *server,
+                                    struct qemud_client *client) {
+    /*qemudDebug ("qemudDispatchClientRead: mode = %d", client->mode);*/
+
+readmore:
+    if (qemudClientRead(client) < 0)
+        return; /* Error */
+
+    if (client->rx->bufferOffset < client->rx->bufferLength)
+        return; /* Still not read enough */
+
+    /* Either done with length word header */
+    if (client->rx->bufferLength == REMOTE_MESSAGE_HEADER_XDR_LEN) {
+        unsigned int len;
+        XDR x;
+
+        xdrmem_create(&x, client->rx->buffer, client->rx->bufferLength, XDR_DECODE);
+
+        if (!xdr_u_int(&x, &len)) {
+            xdr_destroy (&x);
+            DEBUG0("Failed to decode packet length");
+            qemudDispatchClientFailure(client);
+            return;
+        }
+        xdr_destroy (&x);
+
+        if (len < REMOTE_MESSAGE_HEADER_XDR_LEN) {
+            DEBUG("Packet length %u too small", len);
+            qemudDispatchClientFailure(client);
+            return;
+        }
+
+        /* Length includes the size of the length word itself */
+        len -= REMOTE_MESSAGE_HEADER_XDR_LEN;
+
+        if (len > REMOTE_MESSAGE_MAX) {
+            DEBUG("Packet length %u too large", len);
+            qemudDispatchClientFailure(client);
+            return;
+        }
+
+        /* Prepare to read rest of message */
+        client->rx->bufferLength += len;
+
+        qemudUpdateClientEvent(client);
+
+        /* Try and read payload immediately instead of going back
+           into poll() because chances are the data is already
+           waiting for us */
+        goto readmore;
+    } else {
+        /* Grab the completed message */
+        struct qemud_client_message *msg = qemudClientMessageQueueServe(&client->rx);
+        struct qemud_client_filter *filter;
+
+        /* Decode the header so we can use it for routing decisions */
+        if (remoteDecodeClientMessageHeader(msg) < 0) {
+            VIR_FREE(msg);
+            qemudDispatchClientFailure(client);
+        }
+
+        /* Check if any filters match this message */
+        filter = client->filters;
+        while (filter) {
+            if ((filter->query)(msg, filter->opaque)) {
+                qemudClientMessageQueuePush(&filter->dx, msg);
+                msg = NULL;
+                break;
+            }
+            filter = filter->next;
+        }
+
+        /* Move completed message to the end of the dispatch queue */
+        if (msg)
+            qemudClientMessageQueuePush(&client->dx, msg);
+        client->nrequests++;
+
+        /* Possibly need to create another receive buffer */
+        if ((client->nrequests < max_client_requests &&
+             VIR_ALLOC(client->rx) < 0)) {
+            qemudDispatchClientFailure(client);
+        } else {
+            if (client->rx)
+                client->rx->bufferLength = REMOTE_MESSAGE_HEADER_XDR_LEN;
+
+            qemudUpdateClientEvent(client);
+
+            /* Tell one of the workers to get on with it... */
+            virCondSignal(&server->job);
+        }
+    }
+}
+
+
+/*
+ * Send a chunk of data using wire encoding (plain or TLS)
+ *
+ * Returns:
+ *   -1 on error
+ *    0 on EAGAIN
+ *    n number of bytes
+ */
+static ssize_t qemudClientWriteBuf(struct qemud_client *client,
+                                   const char *data, ssize_t len) {
+    ssize_t ret;
+
+    if (len < 0) {
+        VIR_ERROR(_("unexpected negative length request %lld"),
+                  (long long int) len);
+        qemudDispatchClientFailure(client);
+        return -1;
+    }
+
+    if (!client->tlssession) {
+        char ebuf[1024];
+        if ((ret = write(client->fd, data, len)) == -1) {
+            if (errno == EAGAIN || errno == EINTR)
+                return 0;
+            VIR_ERROR(_("write: %s"), virStrerror (errno, ebuf, sizeof ebuf));
+            qemudDispatchClientFailure(client);
+            return -1;
+        }
+    } else {
+        ret = gnutls_record_send (client->tlssession, data, len);
+        if (ret < 0) {
+            if (ret == GNUTLS_E_INTERRUPTED ||
+                ret == GNUTLS_E_AGAIN)
+                return 0;
+
+            VIR_ERROR(_("gnutls_record_send: %s"), gnutls_strerror (ret));
+            qemudDispatchClientFailure(client);
+            return -1;
+        }
+    }
+    return ret;
+}
+
+
+/*
+ * Send client->tx using no encoding
+ *
+ * Returns:
+ *   -1 on error or EOF
+ *    0 on EAGAIN
+ *    n number of bytes
+ */
+static int qemudClientWritePlain(struct qemud_client *client) {
+    int ret = qemudClientWriteBuf(client,
+                                  client->tx->buffer + client->tx->bufferOffset,
+                                  client->tx->bufferLength - client->tx->bufferOffset);
+    if (ret <= 0)
+        return ret; /* -1 error, 0 = egain */
+    client->tx->bufferOffset += ret;
+    return ret;
+}
+
+
+#if HAVE_SASL
+/*
+ * Send client->tx using SASL encoding
+ *
+ * Returns:
+ *   -1 on error
+ *    0 on EAGAIN
+ *    n number of bytes
+ */
+static int qemudClientWriteSASL(struct qemud_client *client) {
+    int ret;
+
+    /* Not got any pending encoded data, so we need to encode raw stuff */
+    if (client->saslEncoded == NULL) {
+        ret = sasl_encode(client->saslconn,
+                          client->tx->buffer + client->tx->bufferOffset,
+                          client->tx->bufferLength - client->tx->bufferOffset,
+                          &client->saslEncoded,
+                          &client->saslEncodedLength);
+
+        if (ret != SASL_OK) {
+            VIR_ERROR(_("failed to encode SASL data %s"),
+                      sasl_errstring(ret, NULL, NULL));
+            qemudDispatchClientFailure(client);
+            return -1;
+        }
+
+        client->saslEncodedOffset = 0;
+    }
+
+    /* Send some of the encoded stuff out on the wire */
+    ret = qemudClientWriteBuf(client,
+                              client->saslEncoded + client->saslEncodedOffset,
+                              client->saslEncodedLength - client->saslEncodedOffset);
+
+    if (ret <= 0)
+        return ret; /* -1 error, 0 == egain */
+
+    /* Note how much we sent */
+    client->saslEncodedOffset += ret;
+
+    /* Sent all encoded, so update raw buffer to indicate completion */
+    if (client->saslEncodedOffset == client->saslEncodedLength) {
+        client->saslEncoded = NULL;
+        client->saslEncodedOffset = client->saslEncodedLength = 0;
+
+        /* Mark as complete, so caller detects completion */
+        client->tx->bufferOffset = client->tx->bufferLength;
+    }
+
+    return ret;
+}
+#endif
+
+/*
+ * Send as much data in the client->tx as possible
+ *
+ * Returns:
+ *   -1 on error or EOF
+ *    0 on EAGAIN
+ *    n number of bytes
+ */
+static ssize_t qemudClientWrite(struct qemud_client *client) {
+#if HAVE_SASL
+    if (client->saslSSF & QEMUD_SASL_SSF_WRITE)
+        return qemudClientWriteSASL(client);
+    else
+#endif
+        return qemudClientWritePlain(client);
+}
+
+
+/*
+ * Process all queued client->tx messages until
+ * we would block on I/O
+ */
+static void
+qemudDispatchClientWrite(struct qemud_client *client) {
+    while (client->tx) {
+        ssize_t ret;
+
+        ret = qemudClientWrite(client);
+        if (ret < 0) {
+            qemudDispatchClientFailure(client);
+            return;
+        }
+        if (ret == 0)
+            return; /* Would block on write EAGAIN */
+
+        if (client->tx->bufferOffset == client->tx->bufferLength) {
+            struct qemud_client_message *reply;
+
+            /* Get finished reply from head of tx queue */
+            reply = qemudClientMessageQueueServe(&client->tx);
+
+            /* If its not an async message, then we have
+             * just completed an RPC request */
+            if (!reply->async)
+                client->nrequests--;
+
+            /* Move record to end of 'rx' ist */
+            if (!client->rx &&
+                client->nrequests < max_client_requests) {
+                /* Reset message record for next RX attempt */
+                client->rx = reply;
+                client->rx->bufferOffset = 0;
+                client->rx->bufferLength = REMOTE_MESSAGE_HEADER_XDR_LEN;
+            } else {
+                VIR_FREE(reply);
+            }
+
+            if (client->closing)
+                qemudDispatchClientFailure(client);
+            else
+                qemudUpdateClientEvent(client);
+         }
+    }
+}
+
+static void
+qemudDispatchClientHandshake(struct qemud_client *client) {
+    int ret;
+    /* Continue the handshake. */
+    ret = gnutls_handshake (client->tlssession);
+    if (ret == 0) {
+        client->handshake = 0;
+
+        /* Finished.  Next step is to check the certificate. */
+        if (remoteCheckAccess (client) == -1)
+            qemudDispatchClientFailure(client);
+        else
+            qemudUpdateClientEvent(client);
+    } else if (ret == GNUTLS_E_AGAIN ||
+               ret == GNUTLS_E_INTERRUPTED) {
+        /* Carry on waiting for more handshake. Update
+           the events just in case handshake data flow
+           direction has changed */
+        qemudUpdateClientEvent (client);
+    } else {
+        /* Fatal error in handshake */
+        VIR_ERROR(_("TLS handshake failed: %s"),
+                  gnutls_strerror (ret));
+        qemudDispatchClientFailure(client);
+    }
+}
+
+static void
+qemudDispatchClientEvent(int watch, int fd, int events, void *opaque) {
+    struct qemud_server *server = (struct qemud_server *)opaque;
+    struct qemud_client *client = NULL;
+    int i;
+
+    virMutexLock(&server->lock);
+
+    for (i = 0 ; i < server->nclients ; i++) {
+        virMutexLock(&server->clients[i]->lock);
+        if (server->clients[i]->watch == watch) {
+            client = server->clients[i];
+            break;
+        }
+        virMutexUnlock(&server->clients[i]->lock);
+    }
+
+    virMutexUnlock(&server->lock);
+
+    if (!client) {
+        return;
+    }
+
+    if (client->fd != fd) {
+        virMutexUnlock(&client->lock);
+        return;
+    }
+
+    if (events & (VIR_EVENT_HANDLE_WRITABLE |
+                  VIR_EVENT_HANDLE_READABLE)) {
+        if (client->handshake) {
+            qemudDispatchClientHandshake(client);
+        } else {
+            if (events & VIR_EVENT_HANDLE_WRITABLE)
+                qemudDispatchClientWrite(client);
+            if (events & VIR_EVENT_HANDLE_READABLE)
+                qemudDispatchClientRead(server, client);
+        }
+    }
+
+    /* NB, will get HANGUP + READABLE at same time upon
+     * disconnect */
+    if (events & (VIR_EVENT_HANDLE_ERROR |
+                  VIR_EVENT_HANDLE_HANGUP))
+        qemudDispatchClientFailure(client);
+
+    virMutexUnlock(&client->lock);
+}
+
+
+/*
+ * @client: a locked client object
+ */
+static int
+qemudCalculateHandleMode(struct qemud_client *client) {
+    int mode = 0;
+
+    if (client->handshake) {
+        if (gnutls_record_get_direction (client->tlssession) == 0)
+            mode |= VIR_EVENT_HANDLE_READABLE;
+        else
+            mode |= VIR_EVENT_HANDLE_WRITABLE;
+    } else {
+        /* If there is a message on the rx queue then
+         * we're wanting more input */
+        if (client->rx)
+            mode |= VIR_EVENT_HANDLE_READABLE;
+
+        /* If there are one or more messages to send back to client,
+           then monitor for writability on socket */
+        if (client->tx)
+            mode |= VIR_EVENT_HANDLE_WRITABLE;
+    }
+
+    return mode;
+}
+
+/*
+ * @server: a locked or unlocked server object
+ * @client: a locked client object
+ */
+int qemudRegisterClientEvent(struct qemud_server *server,
+                             struct qemud_client *client) {
+    int mode;
+
+    mode = qemudCalculateHandleMode(client);
+
+    if ((client->watch = virEventAddHandleImpl(client->fd,
+                                               mode,
+                                               qemudDispatchClientEvent,
+                                               server, NULL)) < 0)
+        return -1;
+
+    return 0;
+}
+
+/*
+ * @client: a locked client object
+ */
+void qemudUpdateClientEvent(struct qemud_client *client) {
+    int mode;
+
+    mode = qemudCalculateHandleMode(client);
+
+    virEventUpdateHandleImpl(client->watch, mode);
+}
+
+
+static void
+qemudDispatchServerEvent(int watch, int fd, int events, void *opaque) {
+    struct qemud_server *server = (struct qemud_server *)opaque;
+    struct qemud_socket *sock;
+
+    virMutexLock(&server->lock);
+
+    sock = server->sockets;
+
+    while (sock) {
+        if (sock->watch == watch)
+            break;
+
+        sock = sock->next;
+    }
+
+    if (sock && sock->fd == fd && events)
+        qemudDispatchServer(server, sock);
+
+    virMutexUnlock(&server->lock);
+}
+
+
+static int qemudOneLoop(void) {
+    sig_atomic_t errors;
+
+    if (virEventRunOnce() < 0)
+        return -1;
+
+    /* Check for any signal handling errors and log them. */
+    errors = sig_errors;
+    if (errors) {
+        char ebuf[1024];
+        sig_errors -= errors;
+        VIR_ERROR(_("Signal handler reported %d errors: last error: %s"),
+                  errors, virStrerror (sig_lasterrno, ebuf, sizeof ebuf));
+        return -1;
+    }
+
+    return 0;
+}
+
+static void qemudInactiveTimer(int timerid, void *data) {
+    struct qemud_server *server = (struct qemud_server *)data;
+
+    if (virStateActive() ||
+        server->clients) {
+        DEBUG0("Timer expired but still active, not shutting down");
+        virEventUpdateTimeoutImpl(timerid, -1);
+    } else {
+        DEBUG0("Timer expired and inactive, shutting down");
+        server->shutdown = 1;
+    }
+}
+
+static void qemudFreeClient(struct qemud_client *client) {
+    while (client->rx) {
+        struct qemud_client_message *msg
+            = qemudClientMessageQueueServe(&client->rx);
+        VIR_FREE(msg);
+    }
+    while (client->dx) {
+        struct qemud_client_message *msg
+            = qemudClientMessageQueueServe(&client->dx);
+        VIR_FREE(msg);
+    }
+    while (client->tx) {
+        struct qemud_client_message *msg
+            = qemudClientMessageQueueServe(&client->tx);
+        VIR_FREE(msg);
+    }
+
+    if (client->conn)
+        virConnectClose(client->conn);
+    virMutexDestroy(&client->lock);
+    VIR_FREE(client);
+}
+
+static int qemudRunLoop(struct qemud_server *server) {
+    int timerid = -1;
+    int ret = -1, i;
+    int timerActive = 0;
+
+    virMutexLock(&server->lock);
+
+    if (timeout > 0 &&
+        (timerid = virEventAddTimeoutImpl(-1,
+                                          qemudInactiveTimer,
+                                          server, NULL)) < 0) {
+        VIR_ERROR0(_("Failed to register shutdown timeout"));
+        return -1;
+    }
+
+    if (min_workers > max_workers)
+        max_workers = min_workers;
+
+    server->nworkers = max_workers;
+    if (VIR_ALLOC_N(server->workers, server->nworkers) < 0) {
+        VIR_ERROR0(_("Failed to allocate workers"));
+        return -1;
+    }
+
+    for (i = 0 ; i < min_workers ; i++) {
+        if (qemudStartWorker(server, &server->workers[i]) < 0)
+            goto cleanup;
+        server->nactiveworkers++;
+    }
+
+    for (;;) {
+        /* A shutdown timeout is specified, so check
+         * if any drivers have active state, if not
+         * shutdown after timeout seconds
+         */
+        if (timeout > 0) {
+            if (timerActive) {
+                if (server->clients) {
+                    DEBUG("Deactivating shutdown timer %d", timerid);
+                    virEventUpdateTimeoutImpl(timerid, -1);
+                    timerActive = 0;
+                }
+            } else {
+                if (!virStateActive() &&
+                    !server->clients) {
+                    DEBUG("Activating shutdown timer %d", timerid);
+                    virEventUpdateTimeoutImpl(timerid, timeout * 1000);
+                    timerActive = 1;
+                }
+            }
+        }
+
+        virMutexUnlock(&server->lock);
+        if (qemudOneLoop() < 0) {
+            virMutexLock(&server->lock);
+            DEBUG0("Loop iteration error, exiting\n");
+            break;
+        }
+        virMutexLock(&server->lock);
+
+    reprocess:
+        for (i = 0 ; i < server->nclients ; i++) {
+            int inactive;
+            virMutexLock(&server->clients[i]->lock);
+            inactive = server->clients[i]->fd == -1
+                && server->clients[i]->refs == 0;
+            virMutexUnlock(&server->clients[i]->lock);
+            if (inactive) {
+                qemudFreeClient(server->clients[i]);
+                server->nclients--;
+                if (i < server->nclients)
+                    memmove(server->clients + i,
+                            server->clients + i + 1,
+                            sizeof (*server->clients) * (server->nclients - i));
+
+                if (VIR_REALLOC_N(server->clients,
+                                  server->nclients) < 0) {
+                    ; /* ignore */
+                }
+                goto reprocess;
+            }
+        }
+
+        /* If number of active workers exceeds both the min_workers
+         * threshold and the number of clients, then kill some
+         * off */
+        for (i = 0 ; (i < server->nworkers &&
+                      server->nactiveworkers > server->nclients &&
+                      server->nactiveworkers > min_workers) ; i++) {
+
+            if (server->workers[i].hasThread &&
+                !server->workers[i].processingCall) {
+                server->workers[i].quitRequest = 1;
+
+                virCondBroadcast(&server->job);
+                virMutexUnlock(&server->lock);
+                pthread_join(server->workers[i].thread, NULL);
+                virMutexLock(&server->lock);
+                server->workers[i].hasThread = 0;
+                server->nactiveworkers--;
+            }
+        }
+
+        if (server->shutdown) {
+            ret = 0;
+            break;
+        }
+    }
+
+cleanup:
+    for (i = 0 ; i < server->nworkers ; i++) {
+        if (!server->workers[i].hasThread)
+            continue;
+
+        server->workers[i].quitRequest = 1;
+        virCondBroadcast(&server->job);
+
+        virMutexUnlock(&server->lock);
+        pthread_join(server->workers[i].thread, NULL);
+        virMutexLock(&server->lock);
+        server->workers[i].hasThread = 0;
+    }
+    VIR_FREE(server->workers);
+
+    free(server->workers);
+    virMutexUnlock(&server->lock);
+    return ret;
+}
+
+static void qemudCleanup(struct qemud_server *server) {
+    struct qemud_socket *sock;
+
+    close(server->sigread);
+
+    sock = server->sockets;
+    while (sock) {
+        struct qemud_socket *next = sock->next;
+        close(sock->fd);
+        free(sock);
+        sock = next;
+    }
+    free(server->logDir);
+
+#ifdef HAVE_SASL
+    if (server->saslUsernameWhitelist) {
+        char **list = server->saslUsernameWhitelist;
+        while (*list) {
+            free(*list);
+            list++;
+        }
+        free(server->saslUsernameWhitelist);
+    }
+#endif
+
+    virStateCleanup();
+
+    if (virCondDestroy(&server->job) < 0) {
+        ;
+    }
+    virMutexDestroy(&server->lock);
+
+    VIR_FREE(server);
+}
+
+/* Allocate an array of malloc'd strings from the config file, filename
+ * (used only in diagnostics), using handle "conf".  Upon error, return -1
+ * and free any allocated memory.  Otherwise, save the array in *list_arg
+ * and return 0.
+ */
+static int
+remoteConfigGetStringList(virConfPtr conf, const char *key, char ***list_arg,
+                          const char *filename)
+{
+    char **list;
+    virConfValuePtr p = virConfGetValue (conf, key);
+    if (!p)
+        return 0;
+
+    switch (p->type) {
+    case VIR_CONF_STRING:
+        if (VIR_ALLOC_N(list, 2) < 0) {
+            VIR_ERROR(_("failed to allocate memory for %s config list"), key);
+            return -1;
+        }
+        list[0] = strdup (p->str);
+        list[1] = NULL;
+        if (list[0] == NULL) {
+            VIR_ERROR(_("failed to allocate memory for %s config list value"),
+                      key);
+            VIR_FREE(list);
+            return -1;
+        }
+        break;
+
+    case VIR_CONF_LIST: {
+        int i, len = 0;
+        virConfValuePtr pp;
+        for (pp = p->list; pp; pp = pp->next)
+            len++;
+        if (VIR_ALLOC_N(list, 1+len) < 0) {
+            VIR_ERROR(_("failed to allocate memory for %s config list"), key);
+            return -1;
+        }
+        for (i = 0, pp = p->list; pp; ++i, pp = pp->next) {
+            if (pp->type != VIR_CONF_STRING) {
+                VIR_ERROR(_("remoteReadConfigFile: %s: %s:"
+                            " must be a string or list of strings\n"),
+                          filename, key);
+                VIR_FREE(list);
+                return -1;
+            }
+            list[i] = strdup (pp->str);
+            if (list[i] == NULL) {
+                int j;
+                for (j = 0 ; j < i ; j++)
+                    VIR_FREE(list[j]);
+                VIR_FREE(list);
+                VIR_ERROR(_("failed to allocate memory for %s config list value"),
+                          key);
+                return -1;
+            }
+
+        }
+        list[i] = NULL;
+        break;
+    }
+
+    default:
+        VIR_ERROR(_("remoteReadConfigFile: %s: %s:"
+                    " must be a string or list of strings\n"),
+                  filename, key);
+        return -1;
+    }
+
+    *list_arg = list;
+    return 0;
+}
+
+/* A helper function used by each of the following macros.  */
+static int
+checkType (virConfValuePtr p, const char *filename,
+           const char *key, virConfType required_type)
+{
+    if (p->type != required_type) {
+        VIR_ERROR(_("remoteReadConfigFile: %s: %s: invalid type:"
+                    " got %s; expected %s\n"), filename, key,
+                  virConfTypeName (p->type),
+                  virConfTypeName (required_type));
+        return -1;
+    }
+    return 0;
+}
+
+/* If there is no config data for the key, #var_name, then do nothing.
+   If there is valid data of type VIR_CONF_STRING, and strdup succeeds,
+   store the result in var_name.  Otherwise, (i.e. invalid type, or strdup
+   failure), give a diagnostic and "goto" the cleanup-and-fail label.  */
+#define GET_CONF_STR(conf, filename, var_name)                          \
+    do {                                                                \
+        virConfValuePtr p = virConfGetValue (conf, #var_name);          \
+        if (p) {                                                        \
+            if (checkType (p, filename, #var_name, VIR_CONF_STRING) < 0) \
+                goto free_and_fail;                                     \
+            (var_name) = strdup (p->str);                               \
+            if ((var_name) == NULL) {                                   \
+                char ebuf[1024];                                        \
+                VIR_ERROR(_("remoteReadConfigFile: %s\n"),             \
+                          virStrerror(errno, ebuf, sizeof ebuf));       \
+                goto free_and_fail;                                     \
+            }                                                           \
+        }                                                               \
+    } while (0)
+
+/* Like GET_CONF_STR, but for integral values.  */
+#define GET_CONF_INT(conf, filename, var_name)                          \
+    do {                                                                \
+        virConfValuePtr p = virConfGetValue (conf, #var_name);          \
+        if (p) {                                                        \
+            if (checkType (p, filename, #var_name, VIR_CONF_LONG) < 0)  \
+                goto free_and_fail;                                     \
+            (var_name) = p->l;                                          \
+        }                                                               \
+    } while (0)
+
+
+static int remoteConfigGetAuth(virConfPtr conf, const char *key, int *auth, const char *filename) {
+    virConfValuePtr p;
+
+    p = virConfGetValue (conf, key);
+    if (!p)
+        return 0;
+
+    if (checkType (p, filename, key, VIR_CONF_STRING) < 0)
+        return -1;
+
+    if (!p->str)
+        return 0;
+
+    if (STREQ(p->str, "none")) {
+        *auth = REMOTE_AUTH_NONE;
+#if HAVE_SASL
+    } else if (STREQ(p->str, "sasl")) {
+        *auth = REMOTE_AUTH_SASL;
+#endif
+#if HAVE_POLKIT
+    } else if (STREQ(p->str, "polkit")) {
+        *auth = REMOTE_AUTH_POLKIT;
+#endif
+    } else {
+        VIR_ERROR(_("remoteReadConfigFile: %s: %s: unsupported auth %s\n"),
+                  filename, key, p->str);
+        return -1;
+    }
+
+    return 0;
+}
+
+#ifdef HAVE_SASL
+static inline int
+remoteReadSaslAllowedUsernameList (virConfPtr conf,
+                                   struct qemud_server *server,
+                                   const char *filename)
+{
+    return
+        remoteConfigGetStringList (conf, "sasl_allowed_username_list",
+                                   &server->saslUsernameWhitelist, filename);
+}
+#else
+static inline int
+remoteReadSaslAllowedUsernameList (virConfPtr conf ATTRIBUTE_UNUSED,
+                                   struct qemud_server *server ATTRIBUTE_UNUSED,
+                                   const char *filename ATTRIBUTE_UNUSED)
+{
+    return 0;
+}
+#endif
+
+/*
+ * Set up the logging environment
+ * By default if daemonized all errors go to syslog and the logging
+ * is also saved onto the logfile libvird.log, but if verbose or error
+ * debugging is asked for then output informations or debug.
+ */
+static int
+qemudSetLogging(virConfPtr conf, const char *filename) {
+    int log_level;
+    char *log_filters = NULL;
+    char *log_outputs = NULL;
+    int ret = -1;
+
+    virLogReset();
+
+    /*
+     * Libvirtd's order of precedence is:
+     * cmdline > environment > config
+     *
+     * In order to achieve this, we must process configuration in
+     * different order for the log level versus the filters and
+     * outputs. Because filters and outputs append, we have to look at
+     * the environment first and then only check the config file if
+     * there was no result from the environment. The default output is
+     * then applied only if there was no setting from either of the
+     * first two. Because we don't have a way to determine if the log
+     * level has been set, we must process variables in the opposite
+     * order, each one overriding the previous.
+     */
+    /*
+     * GET_CONF_INT returns 0 when there is no log_level setting in
+     * the config file. The conditional below eliminates a false
+     * warning in that case, but also has the side effect of missing
+     * a warning if the user actually does say log_level=0.
+     */
+    GET_CONF_INT (conf, filename, log_level);
+    if (log_level != 0)
+        virLogSetDefaultPriority(log_level);
+
+    virLogSetFromEnv();
+
+    if (virLogGetNbFilters() == 0) {
+        GET_CONF_STR (conf, filename, log_filters);
+        virLogParseFilters(log_filters);
+    }
+
+    if (virLogGetNbOutputs() == 0) {
+        GET_CONF_STR (conf, filename, log_outputs);
+        virLogParseOutputs(log_outputs);
+    }
+
+    /*
+     * If no defined outputs, then direct to syslog when running
+     * as daemon. Otherwise the default output is stderr.
+     */
+    if (virLogGetNbOutputs() == 0) {
+        char *tmp = NULL;
+        if (godaemon) {
+            if (virAsprintf (&tmp, "%d:syslog:libvirtd",
+                             virLogGetDefaultPriority()) < 0)
+                goto free_and_fail;
+        } else {
+            if (virAsprintf (&tmp, "%d:stderr",
+                             virLogGetDefaultPriority()) < 0)
+                goto free_and_fail;
+        }
+        virLogParseOutputs(tmp);
+        VIR_FREE(tmp);
+    }
+
+    /*
+     * Command line override for --verbose
+     */
+    if ((verbose) && (virLogGetDefaultPriority() > VIR_LOG_INFO))
+        virLogSetDefaultPriority(VIR_LOG_INFO);
+
+    ret = 0;
+
+free_and_fail:
+    VIR_FREE(log_filters);
+    VIR_FREE(log_outputs);
+    return(ret);
+}
+
+/* Read the config file if it exists.
+ * Only used in the remote case, hence the name.
+ */
+static int
+remoteReadConfigFile (struct qemud_server *server, const char *filename)
+{
+    virConfPtr conf;
+
+    /* The following variable names must match the corresponding
+       configuration strings.  */
+    char *unix_sock_ro_perms = NULL;
+    char *unix_sock_rw_perms = NULL;
+    char *unix_sock_group = NULL;
+    char *buf = NULL;
+
+#if HAVE_POLKIT
+    /* Change the default back to no auth for non-root */
+    if (!server->privileged && auth_unix_rw == REMOTE_AUTH_POLKIT)
+        auth_unix_rw = REMOTE_AUTH_NONE;
+    if (!server->privileged && auth_unix_ro == REMOTE_AUTH_POLKIT)
+        auth_unix_ro = REMOTE_AUTH_NONE;
+#endif
+
+    conf = virConfReadFile (filename, 0);
+    if (!conf) return -1;
+
+    /*
+     * First get all the logging settings and activate them
+     */
+    if (qemudSetLogging(conf, filename) < 0)
+        goto free_and_fail;
+
+    GET_CONF_INT (conf, filename, listen_tcp);
+    GET_CONF_INT (conf, filename, listen_tls);
+    GET_CONF_STR (conf, filename, tls_port);
+    GET_CONF_STR (conf, filename, tcp_port);
+    GET_CONF_STR (conf, filename, listen_addr);
+
+    if (remoteConfigGetAuth(conf, "auth_unix_rw", &auth_unix_rw, filename) < 0)
+        goto free_and_fail;
+#if HAVE_POLKIT
+    /* Change default perms to be wide-open if PolicyKit is enabled.
+     * Admin can always override in config file
+     */
+    if (auth_unix_rw == REMOTE_AUTH_POLKIT)
+        unix_sock_rw_mask = 0777;
+#endif
+    if (remoteConfigGetAuth(conf, "auth_unix_ro", &auth_unix_ro, filename) < 0)
+        goto free_and_fail;
+    if (remoteConfigGetAuth(conf, "auth_tcp", &auth_tcp, filename) < 0)
+        goto free_and_fail;
+    if (remoteConfigGetAuth(conf, "auth_tls", &auth_tls, filename) < 0)
+        goto free_and_fail;
+
+    GET_CONF_STR (conf, filename, unix_sock_group);
+    if (unix_sock_group) {
+        if (!server->privileged) {
+            VIR_WARN0(_("Cannot set group when not running as root"));
+        } else {
+            int ret;
+            struct group grpdata, *grp;
+            size_t maxbuf = sysconf(_SC_GETGR_R_SIZE_MAX);
+
+            if (maxbuf == -1)
+                maxbuf = 1024;
+
+            if (VIR_ALLOC_N(buf, maxbuf) < 0) {
+                VIR_ERROR("%s", _("Failed to allocate memory for buffer"));
+                goto free_and_fail;
+            }
+
+            while ((ret = getgrnam_r(unix_sock_group, &grpdata,
+                                     buf, maxbuf,
+                                     &grp)) == ERANGE) {
+                    maxbuf *= 2;
+                    if (maxbuf > 65536 || VIR_REALLOC_N(buf, maxbuf) < 0) {
+                        VIR_ERROR("%s", _("Failed to reallocate enough memory for buffer"));
+                        goto free_and_fail;
+                    }
+            }
+
+            if (ret != 0 || !grp) {
+                VIR_ERROR(_("Failed to lookup group '%s'"), unix_sock_group);
+                goto free_and_fail;
+            }
+            unix_sock_gid = grp->gr_gid;
+            VIR_FREE (buf);
+        }
+        free (unix_sock_group);
+        unix_sock_group = NULL;
+    }
+
+    GET_CONF_STR (conf, filename, unix_sock_ro_perms);
+    if (unix_sock_ro_perms) {
+        if (virStrToLong_i (unix_sock_ro_perms, NULL, 8, &unix_sock_ro_mask) != 0) {
+            VIR_ERROR(_("Failed to parse mode '%s'"), unix_sock_ro_perms);
+            goto free_and_fail;
+        }
+        free (unix_sock_ro_perms);
+        unix_sock_ro_perms = NULL;
+    }
+
+    GET_CONF_STR (conf, filename, unix_sock_rw_perms);
+    if (unix_sock_rw_perms) {
+        if (virStrToLong_i (unix_sock_rw_perms, NULL, 8, &unix_sock_rw_mask) != 0) {
+            VIR_ERROR(_("Failed to parse mode '%s'"), unix_sock_rw_perms);
+            goto free_and_fail;
+        }
+        free (unix_sock_rw_perms);
+        unix_sock_rw_perms = NULL;
+    }
+
+    GET_CONF_STR (conf, filename, unix_sock_dir);
+
+    GET_CONF_INT (conf, filename, mdns_adv);
+    GET_CONF_STR (conf, filename, mdns_name);
+
+    GET_CONF_INT (conf, filename, tls_no_verify_certificate);
+
+    GET_CONF_STR (conf, filename, key_file);
+    GET_CONF_STR (conf, filename, cert_file);
+    GET_CONF_STR (conf, filename, ca_file);
+    GET_CONF_STR (conf, filename, crl_file);
+
+    if (remoteConfigGetStringList (conf, "tls_allowed_dn_list",
+                                   &tls_allowed_dn_list, filename) < 0)
+        goto free_and_fail;
+
+    if (remoteReadSaslAllowedUsernameList (conf, server, filename) < 0)
+        goto free_and_fail;
+
+
+    GET_CONF_INT (conf, filename, min_workers);
+    GET_CONF_INT (conf, filename, max_workers);
+    GET_CONF_INT (conf, filename, max_clients);
+
+    GET_CONF_INT (conf, filename, max_requests);
+    GET_CONF_INT (conf, filename, max_client_requests);
+
+    virConfFree (conf);
+    return 0;
+
+ free_and_fail:
+    virConfFree (conf);
+    free (mdns_name);
+    mdns_name = NULL;
+    free (unix_sock_ro_perms);
+    free (unix_sock_rw_perms);
+    free (unix_sock_group);
+    VIR_FREE (buf);
+
+    /* Don't bother trying to free listen_addr, tcp_port, tls_port, key_file,
+       cert_file, ca_file, or crl_file, since they are initialized to
+       non-malloc'd strings.  Besides, these are static variables, and callers
+       are unlikely to call this function more than once, so there wouldn't
+       even be a real leak.  */
+
+    if (tls_allowed_dn_list) {
+        int i;
+        for (i = 0; tls_allowed_dn_list[i]; i++)
+            free (tls_allowed_dn_list[i]);
+        free (tls_allowed_dn_list);
+        tls_allowed_dn_list = NULL;
+    }
+
+    return -1;
+}
+
+/* Display version information. */
+static void
+version (const char *argv0)
+{
+    printf ("%s (%s) %s\n", argv0, PACKAGE_NAME, PACKAGE_VERSION);
+}
+
+#ifdef __sun
+static int
+qemudSetupPrivs (void)
+{
+    chown ("/var/run/libvirt", SYSTEM_UID, SYSTEM_UID);
+
+    if (__init_daemon_priv (PU_RESETGROUPS | PU_CLEARLIMITSET,
+        SYSTEM_UID, SYSTEM_UID, PRIV_XVM_CONTROL, NULL)) {
+        VIR_ERROR0(_("additional privileges are required\n"));
+        return -1;
+    }
+
+    if (priv_set (PRIV_OFF, PRIV_ALLSETS, PRIV_FILE_LINK_ANY, PRIV_PROC_INFO,
+        PRIV_PROC_SESSION, PRIV_PROC_EXEC, PRIV_PROC_FORK, NULL)) {
+        VIR_ERROR0(_("failed to set reduced privileges\n"));
+        return -1;
+    }
+
+    return 0;
+}
+#else
+#define qemudSetupPrivs() 0
+#endif
+
+/* Print command-line usage. */
+static void
+usage (const char *argv0)
+{
+    fprintf (stderr,
+             "\n\
+Usage:\n\
+  %s [options]\n\
+\n\
+Options:\n\
+  -v | --verbose         Verbose messages.\n\
+  -d | --daemon          Run as a daemon & write PID file.\n\
+  -l | --listen          Listen for TCP/IP connections.\n\
+  -t | --timeout <secs>  Exit after timeout period.\n\
+  -f | --config <file>   Configuration file.\n\
+     | --version         Display version information.\n\
+  -p | --pid-file <file> Change name of PID file.\n\
+\n\
+libvirt management daemon:\n\
+\n\
+  Default paths:\n\
+\n\
+    Configuration file (unless overridden by -c):\n\
+      " SYSCONF_DIR "/libvirt/libvirtd.conf\n\
+\n\
+    Sockets (as root):\n\
+      " LOCAL_STATE_DIR "/run/libvirt/libvirt-sock\n\
+      " LOCAL_STATE_DIR "/run/libvirt/libvirt-sock-ro\n\
+\n\
+    Sockets (as non-root):\n\
+      $HOME/.libvirt/libvirt-sock (in UNIX abstract namespace)\n\
+\n\
+    TLS:\n\
+      CA certificate:     " LIBVIRT_CACERT "\n\
+      Server certificate: " LIBVIRT_SERVERCERT "\n\
+      Server private key: " LIBVIRT_SERVERKEY "\n\
+\n\
+    PID file (unless overridden by --pid-file):\n\
+      %s\n\
+\n",
+             argv0,
+             REMOTE_PID_FILE[0] != '\0'
+               ? REMOTE_PID_FILE
+               : "(disabled in ./configure)");
+}
+
+enum {
+    OPT_VERSION = 129
+};
+
+#define MAX_LISTEN 5
+int main(int argc, char **argv) {
+    struct qemud_server *server = NULL;
+    struct sigaction sig_action;
+    int sigpipe[2];
+    const char *pid_file = NULL;
+    const char *remote_config_file = NULL;
+    int ret = 1;
+
+    struct option opts[] = {
+        { "verbose", no_argument, &verbose, 1},
+        { "daemon", no_argument, &godaemon, 1},
+        { "listen", no_argument, &ipsock, 1},
+        { "config", required_argument, NULL, 'f'},
+        { "timeout", required_argument, NULL, 't'},
+        { "pid-file", required_argument, NULL, 'p'},
+        { "version", no_argument, NULL, OPT_VERSION },
+        { "help", no_argument, NULL, '?' },
+        {0, 0, 0, 0}
+    };
+
+    while (1) {
+        int optidx = 0;
+        int c;
+        char *tmp;
+
+        c = getopt_long(argc, argv, "ldf:p:t:v", opts, &optidx);
+
+        if (c == -1) {
+            break;
+        }
+
+        switch (c) {
+        case 0:
+            /* Got one of the flags */
+            break;
+        case 'v':
+            verbose = 1;
+            break;
+        case 'd':
+            godaemon = 1;
+            break;
+        case 'l':
+            ipsock = 1;
+            break;
+
+        case 't':
+            if (virStrToLong_i(optarg, &tmp, 10, &timeout) != 0
+                || timeout <= 0
+                /* Ensure that we can multiply by 1000 without overflowing.  */
+                || timeout > INT_MAX / 1000)
+                timeout = -1;
+            break;
+
+        case 'p':
+            pid_file = optarg;
+            break;
+
+        case 'f':
+            remote_config_file = optarg;
+            break;
+
+        case OPT_VERSION:
+            version (argv[0]);
+            return 0;
+
+        case '?':
+            usage (argv[0]);
+            return 2;
+
+        default:
+            fprintf (stderr, "libvirtd: internal error: unknown flag: %c\n",
+                     c);
+            exit (1);
+        }
+    }
+
+    if (remote_config_file == NULL) {
+        static const char *default_config_file
+            = SYSCONF_DIR "/libvirt/libvirtd.conf";
+        remote_config_file =
+            (access(default_config_file, R_OK) == 0
+             ? default_config_file
+             : "/dev/null");
+    }
+
+    if (godaemon) {
+        char ebuf[1024];
+        if (qemudGoDaemon() < 0) {
+            VIR_ERROR(_("Failed to fork as daemon: %s"),
+                      virStrerror(errno, ebuf, sizeof ebuf));
+            goto error1;
+        }
+    }
+
+    /* If running as root and no PID file is set, use the default */
+    if (pid_file == NULL &&
+        geteuid() == 0 &&
+        REMOTE_PID_FILE[0] != '\0')
+        pid_file = REMOTE_PID_FILE;
+
+    /* If we have a pidfile set, claim it now, exiting if already taken */
+    if (pid_file != NULL &&
+        qemudWritePidFile (pid_file) < 0)
+        goto error1;
+
+    if (pipe(sigpipe) < 0 ||
+        virSetNonBlock(sigpipe[0]) < 0 ||
+        virSetNonBlock(sigpipe[1]) < 0 ||
+        virSetCloseExec(sigpipe[0]) < 0 ||
+        virSetCloseExec(sigpipe[1]) < 0) {
+        char ebuf[1024];
+        VIR_ERROR(_("Failed to create pipe: %s"),
+                  virStrerror(errno, ebuf, sizeof ebuf));
+        goto error2;
+    }
+    sigwrite = sigpipe[1];
+
+    sig_action.sa_sigaction = sig_handler;
+    sig_action.sa_flags = SA_SIGINFO;
+    sigemptyset(&sig_action.sa_mask);
+
+    sigaction(SIGHUP, &sig_action, NULL);
+    sigaction(SIGINT, &sig_action, NULL);
+    sigaction(SIGQUIT, &sig_action, NULL);
+    sigaction(SIGTERM, &sig_action, NULL);
+    sigaction(SIGCHLD, &sig_action, NULL);
+
+    sig_action.sa_handler = SIG_IGN;
+    sigaction(SIGPIPE, &sig_action, NULL);
+
+    /* Ensure the rundir exists (on tmpfs on some systems) */
+    if (geteuid() == 0) {
+        const char *rundir = LOCAL_STATE_DIR "/run/libvirt";
+
+        if (mkdir (rundir, 0755)) {
+            if (errno != EEXIST) {
+                VIR_ERROR0 (_("unable to create rundir"));
+                return -1;
+            }
+        }
+    }
+
+    /* Beyond this point, nothing should rely on using
+     * getuid/geteuid() == 0, for privilege level checks.
+     * It must all use the flag 'server->privileged'
+     * which is also passed into all libvirt stateful
+     * drivers
+     */
+    if (qemudSetupPrivs() < 0)
+        goto error2;
+
+    if (!(server = qemudInitialize(sigpipe[0]))) {
+        ret = 2;
+        goto error2;
+    }
+
+    /* Read the config file (if it exists). */
+    if (remoteReadConfigFile (server, remote_config_file) < 0)
+        goto error2;
+
+    /* Change the group ownership of /var/run/libvirt to unix_sock_gid */
+    if (unix_sock_dir && server->privileged) {
+        if (chown(unix_sock_dir, -1, unix_sock_gid) < 0)
+            VIR_ERROR(_("Failed to change group ownership of %s"),
+                      unix_sock_dir);
+    }
+
+    if (virEventAddHandleImpl(sigpipe[0],
+                              VIR_EVENT_HANDLE_READABLE,
+                              qemudDispatchSignalEvent,
+                              server, NULL) < 0) {
+        VIR_ERROR0(_("Failed to register callback for signal pipe"));
+        ret = 3;
+        goto error2;
+    }
+
+    if (!(server = qemudNetworkInit(server))) {
+        ret = 2;
+        goto error2;
+    }
+
+    qemudRunLoop(server);
+
+    ret = 0;
+
+error2:
+    if (server)
+        qemudCleanup(server);
+    if (pid_file)
+        unlink (pid_file);
+    close(sigwrite);
+
+error1:
+    virLogShutdown();
+    return ret;
+}
diff --git a/daemon/libvirtd.h b/daemon/libvirtd.h
new file mode 100644 (file)
index 0000000..241c637
--- /dev/null
@@ -0,0 +1,284 @@
+/*
+ * libvirtd.h: daemon data structure definitions
+ *
+ * Copyright (C) 2006-2009 Red Hat, Inc.
+ * Copyright (C) 2006 Daniel P. Berrange
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ *
+ * Author: Daniel P. Berrange <berrange@redhat.com>
+ */
+
+
+#ifndef QEMUD_INTERNAL_H__
+#define QEMUD_INTERNAL_H__
+
+#include <config.h>
+
+#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
+#include "gnutls_1_0_compat.h"
+#if HAVE_SASL
+#include <sasl/sasl.h>
+#endif
+
+#if HAVE_POLKIT0
+#include <dbus/dbus.h>
+#endif
+
+#ifdef HAVE_SYS_SYSLIMITS_H
+#include <sys/syslimits.h>
+#endif
+
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+#include "remote_protocol.h"
+#include "logging.h"
+#include "threads.h"
+
+#ifdef __GNUC__
+#ifdef HAVE_ANSIDECL_H
+#include <ansidecl.h>
+#endif
+
+#ifndef __GNUC_PREREQ
+#if defined __GNUC__ && defined __GNUC_MINOR__
+# define __GNUC_PREREQ(maj, min)                                        \
+    ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
+#else
+#define __GNUC_PREREQ(maj,min) 0
+#endif
+#endif
+
+/**
+ * ATTRIBUTE_UNUSED:
+ *
+ * Macro to flag conciously unused parameters to functions
+ */
+#ifndef ATTRIBUTE_UNUSED
+#define ATTRIBUTE_UNUSED __attribute__((__unused__))
+#endif
+
+/**
+ * ATTRIBUTE_FMT_PRINTF
+ *
+ * Macro used to check printf like functions, if compiling
+ * with gcc.
+ *
+ * We use gnulib which guarentees we always have GNU style
+ * printf format specifiers even on broken Win32 platforms
+ * hence we have to force 'gnu_printf' for new GCC
+ */
+#ifndef ATTRIBUTE_FMT_PRINTF
+#if __GNUC_PREREQ (4, 4)
+#define ATTRIBUTE_FMT_PRINTF(fmtpos,argpos) __attribute__((__format__ (gnu_printf, fmtpos,argpos)))
+#else
+#define ATTRIBUTE_FMT_PRINTF(fmtpos,argpos) __attribute__((__format__ (printf, fmtpos,argpos)))
+#endif
+#endif
+
+#ifndef ATTRIBUTE_RETURN_CHECK
+#if __GNUC_PREREQ (3, 4)
+#define ATTRIBUTE_RETURN_CHECK __attribute__((__warn_unused_result__))
+#else
+#define ATTRIBUTE_RETURN_CHECK
+#endif
+#endif
+
+#else
+#ifndef ATTRIBUTE_UNUSED
+#define ATTRIBUTE_UNUSED
+#endif
+#ifndef ATTRIBUTE_FMT_PRINTF
+#define ATTRIBUTE_FMT_PRINTF(...)
+#endif
+#ifndef ATTRIBUTE_RETURN_CHECK
+#define ATTRIBUTE_RETURN_CHECK
+#endif
+#endif
+
+#define qemudDebug DEBUG
+
+/* Whether we're passing reads & writes through a sasl SSF */
+enum qemud_sasl_ssf {
+    QEMUD_SASL_SSF_NONE = 0,
+    QEMUD_SASL_SSF_READ = 1,
+    QEMUD_SASL_SSF_WRITE = 2,
+};
+
+enum qemud_sock_type {
+    QEMUD_SOCK_TYPE_UNIX = 0,
+    QEMUD_SOCK_TYPE_TCP = 1,
+    QEMUD_SOCK_TYPE_TLS = 2,
+};
+
+struct qemud_client_message {
+    char buffer [REMOTE_MESSAGE_MAX + REMOTE_MESSAGE_HEADER_XDR_LEN];
+    unsigned int bufferLength;
+    unsigned int bufferOffset;
+
+    int async : 1;
+
+    remote_message_header hdr;
+
+    struct qemud_client_message *next;
+};
+
+/* Allow for filtering of incoming messages to a custom
+ * dispatch processing queue, instead of client->dx.
+ */
+typedef int (*qemud_client_filter_func)(struct qemud_client_message *msg, void *opaque);
+struct qemud_client_filter {
+    qemud_client_filter_func query;
+    void *opaque;
+
+    struct qemud_client_message *dx;
+
+    struct qemud_client_filter *next;
+};
+
+/* Stores the per-client connection state */
+struct qemud_client {
+    virMutex lock;
+
+    int magic;
+
+    int fd;
+    int watch;
+    int readonly:1;
+    int closing:1;
+
+    struct sockaddr_storage addr;
+    socklen_t addrlen;
+
+    int type; /* qemud_sock_type */
+    gnutls_session_t tlssession;
+    int auth;
+    int handshake : 1; /* If we're in progress for TLS handshake */
+#if HAVE_SASL
+    sasl_conn_t *saslconn;
+    int saslSSF;
+    const char *saslDecoded;
+    unsigned int saslDecodedLength;
+    unsigned int saslDecodedOffset;
+    const char *saslEncoded;
+    unsigned int saslEncodedLength;
+    unsigned int saslEncodedOffset;
+    char *saslUsername;
+#endif
+
+    /* Count of meages in 'dx' or 'tx' queue
+     * ie RPC calls in progress. Does not count
+     * async events which are not used for
+     * throttling calculations */
+    int nrequests;
+    /* Zero or one messages being received. Zero if
+     * nrequests >= max_clients and throttling */
+    struct qemud_client_message *rx;
+    /* Zero or many messages waiting for a worker
+     * to process them */
+    struct qemud_client_message *dx;
+    /* Zero or many messages waiting for transmit
+     * back to client, including async events */
+    struct qemud_client_message *tx;
+    /* Filters to capture messages that would otherwise
+     * end up on the 'dx' queue */
+    struct qemud_client_filter *filters;
+
+    /* This is only valid if a remote open call has been made on this
+     * connection, otherwise it will be NULL.  Also if remote close is
+     * called, it will be set back to NULL if that succeeds.
+     */
+    virConnectPtr conn;
+    int refs;
+
+};
+
+#define QEMUD_CLIENT_MAGIC 0x7788aaee
+
+
+struct qemud_socket {
+    int fd;
+    int watch;
+    int readonly;
+    int type; /* qemud_sock_type */
+    int auth;
+    int port;
+    struct qemud_socket *next;
+};
+
+struct qemud_worker {
+    pthread_t thread;
+    int hasThread :1;
+    int processingCall :1;
+    int quitRequest : 1;
+
+    /* back-pointer to our server */
+    struct qemud_server *server;
+};
+
+/* Main server state */
+struct qemud_server {
+    virMutex lock;
+    virCond job;
+
+    int privileged;
+
+    int nworkers;
+    int nactiveworkers;
+    struct qemud_worker *workers;
+    int nsockets;
+    struct qemud_socket *sockets;
+    int nclients;
+    struct qemud_client **clients;
+
+    int sigread;
+    char *logDir;
+    unsigned int shutdown : 1;
+#ifdef HAVE_AVAHI
+    struct libvirtd_mdns *mdns;
+#endif
+#if HAVE_SASL
+    char **saslUsernameWhitelist;
+#endif
+#if HAVE_POLKIT0
+    DBusConnection *sysbus;
+#endif
+};
+
+void qemudLog(int priority, const char *fmt, ...)
+    ATTRIBUTE_FMT_PRINTF(2,3);
+
+
+
+int qemudRegisterClientEvent(struct qemud_server *server,
+                             struct qemud_client *client);
+void qemudUpdateClientEvent(struct qemud_client *client);
+
+void qemudDispatchClientFailure(struct qemud_client *client);
+
+void
+qemudClientMessageQueuePush(struct qemud_client_message **queue,
+                            struct qemud_client_message *msg);
+struct qemud_client_message *
+qemudClientMessageQueueServe(struct qemud_client_message **queue);
+
+
+
+#if HAVE_POLKIT
+int qemudGetSocketIdentity(int fd, uid_t *uid, pid_t *pid);
+#endif
+
+#endif
index e1471af59cf8c69585fa16923c8d5b52ed473128..ae8dc40fdb563cf824c896d2032ad93581715c9a 100644 (file)
@@ -37,8 +37,7 @@
 #include <avahi-common/error.h>
 #include <avahi-common/timeval.h>
 
-#include "internal.h"
-#include "qemud.h"
+#include "libvirtd.h"
 #include "mdns.h"
 #include "event.h"
 #include "memory.h"
diff --git a/daemon/qemud.c b/daemon/qemud.c
deleted file mode 100644 (file)
index 7cd190f..0000000
+++ /dev/null
@@ -1,3015 +0,0 @@
-/*
- * qemud.c: daemon start of day, guest process & i/o management
- *
- * Copyright (C) 2006, 2007, 2008, 2009 Red Hat, Inc.
- * Copyright (C) 2006 Daniel P. Berrange
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
- *
- * Author: Daniel P. Berrange <berrange@redhat.com>
- */
-
-#include <config.h>
-
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <sys/poll.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <netdb.h>
-#include <stdlib.h>
-#include <pwd.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <syslog.h>
-#include <string.h>
-#include <errno.h>
-#include <getopt.h>
-#include <fnmatch.h>
-#include <grp.h>
-#include <signal.h>
-#include <netdb.h>
-
-#include "libvirt_internal.h"
-#include "virterror_internal.h"
-
-#define VIR_FROM_THIS VIR_FROM_QEMU
-
-#include "qemud.h"
-#include "dispatch.h"
-
-#include "util.h"
-#include "remote/remote_driver.h"
-#include "conf.h"
-#include "event.h"
-#include "memory.h"
-#ifdef HAVE_AVAHI
-#include "mdns.h"
-#endif
-
-#ifdef WITH_DRIVER_MODULES
-#include "driver.h"
-#else
-#ifdef WITH_QEMU
-#include "qemu/qemu_driver.h"
-#endif
-#ifdef WITH_LXC
-#include "lxc/lxc_driver.h"
-#endif
-#ifdef WITH_UML
-#include "uml/uml_driver.h"
-#endif
-#ifdef WITH_ONE
-#include "opennebula/one_driver.h"
-#endif
-#ifdef WITH_NETWORK
-#include "network/bridge_driver.h"
-#endif
-#ifdef WITH_NETCF
-#include "interface/netcf_driver.h"
-#endif
-#ifdef WITH_STORAGE_DIR
-#include "storage/storage_driver.h"
-#endif
-#ifdef WITH_NODE_DEVICES
-#include "node_device/node_device_driver.h"
-#endif
-#include "secret/secret_driver.h"
-#endif
-
-
-#ifdef __sun
-#include <ucred.h>
-#include <priv.h>
-
-#ifndef PRIV_VIRT_MANAGE
-#define PRIV_VIRT_MANAGE ((const char *)"virt_manage")
-#endif
-
-#ifndef PRIV_XVM_CONTROL
-#define PRIV_XVM_CONTROL ((const char *)"xvm_control")
-#endif
-
-#define PU_RESETGROUPS          0x0001  /* Remove supplemental groups */
-#define PU_CLEARLIMITSET        0x0008  /* L=0 */
-
-extern int __init_daemon_priv(int, uid_t, gid_t, ...);
-
-#define SYSTEM_UID 60
-
-static gid_t unix_sock_gid = 60; /* Not used */
-static int unix_sock_rw_mask = 0666;
-static int unix_sock_ro_mask = 0666;
-
-#else
-
-static gid_t unix_sock_gid = 0; /* Only root by default */
-static int unix_sock_rw_mask = 0700; /* Allow user only */
-static int unix_sock_ro_mask = 0777; /* Allow world */
-
-#endif /* __sun */
-
-static int godaemon = 0;        /* -d: Be a daemon */
-static int verbose = 0;         /* -v: Verbose mode */
-static int timeout = -1;        /* -t: Shutdown timeout */
-static int sigwrite = -1;       /* Signal handler pipe */
-static int ipsock = 0;          /* -l  Listen for TCP/IP */
-
-/* Defaults for configuration file elements */
-static int listen_tls = 1;
-static int listen_tcp = 0;
-static char *listen_addr  = (char *) LIBVIRTD_LISTEN_ADDR;
-static char *tls_port = (char *) LIBVIRTD_TLS_PORT;
-static char *tcp_port = (char *) LIBVIRTD_TCP_PORT;
-
-static char *unix_sock_dir = NULL;
-
-#if HAVE_POLKIT
-static int auth_unix_rw = REMOTE_AUTH_POLKIT;
-static int auth_unix_ro = REMOTE_AUTH_POLKIT;
-#else
-static int auth_unix_rw = REMOTE_AUTH_NONE;
-static int auth_unix_ro = REMOTE_AUTH_NONE;
-#endif /* HAVE_POLKIT */
-#if HAVE_SASL
-static int auth_tcp = REMOTE_AUTH_SASL;
-#else
-static int auth_tcp = REMOTE_AUTH_NONE;
-#endif
-static int auth_tls = REMOTE_AUTH_NONE;
-
-static int mdns_adv = 1;
-static char *mdns_name = NULL;
-
-static int tls_no_verify_certificate = 0;
-static char **tls_allowed_dn_list = NULL;
-
-static char *key_file = (char *) LIBVIRT_SERVERKEY;
-static char *cert_file = (char *) LIBVIRT_SERVERCERT;
-static char *ca_file = (char *) LIBVIRT_CACERT;
-static char *crl_file = (char *) "";
-
-static gnutls_certificate_credentials_t x509_cred;
-static gnutls_dh_params_t dh_params;
-
-static int min_workers = 5;
-static int max_workers = 20;
-static int max_clients = 20;
-
-/* Total number of 'in-process' RPC calls allowed across all clients */
-static int max_requests = 20;
-/* Total number of 'in-process' RPC calls allowed by a single client*/
-static int max_client_requests = 5;
-
-#define DH_BITS 1024
-
-static sig_atomic_t sig_errors = 0;
-static int sig_lasterrno = 0;
-
-static void sig_handler(int sig, siginfo_t * siginfo,
-                        void* context ATTRIBUTE_UNUSED) {
-    int origerrno;
-    int r;
-
-    /* set the sig num in the struct */
-    siginfo->si_signo = sig;
-
-    origerrno = errno;
-    r = safewrite(sigwrite, siginfo, sizeof(*siginfo));
-    if (r == -1) {
-        sig_errors++;
-        sig_lasterrno = errno;
-    }
-    errno = origerrno;
-}
-
-static void qemudDispatchClientEvent(int watch, int fd, int events, void *opaque);
-static void qemudDispatchServerEvent(int watch, int fd, int events, void *opaque);
-static int qemudStartWorker(struct qemud_server *server, struct qemud_worker *worker);
-
-void
-qemudClientMessageQueuePush(struct qemud_client_message **queue,
-                            struct qemud_client_message *msg)
-{
-    struct qemud_client_message *tmp = *queue;
-
-    if (tmp) {
-        while (tmp->next)
-            tmp = tmp->next;
-        tmp->next = msg;
-    } else {
-        *queue = msg;
-    }
-}
-
-struct qemud_client_message *
-qemudClientMessageQueueServe(struct qemud_client_message **queue)
-{
-    struct qemud_client_message *tmp = *queue;
-
-    if (tmp) {
-        *queue = tmp->next;
-        tmp->next = NULL;
-    }
-
-    return tmp;
-}
-
-static int
-remoteCheckCertFile(const char *type, const char *file)
-{
-    struct stat sb;
-    if (stat(file, &sb) < 0) {
-        char ebuf[1024];
-        VIR_ERROR(_("Cannot access %s '%s': %s"),
-                  type, file, virStrerror(errno, ebuf, sizeof ebuf));
-        return -1;
-    }
-    return 0;
-}
-
-static int
-remoteInitializeGnuTLS (void)
-{
-    int err;
-
-    /* Initialise GnuTLS. */
-    gnutls_global_init ();
-
-    err = gnutls_certificate_allocate_credentials (&x509_cred);
-    if (err) {
-        VIR_ERROR(_("gnutls_certificate_allocate_credentials: %s"),
-                  gnutls_strerror (err));
-        return -1;
-    }
-
-    if (ca_file && ca_file[0] != '\0') {
-        if (remoteCheckCertFile("CA certificate", ca_file) < 0)
-            return -1;
-
-        qemudDebug ("loading CA cert from %s", ca_file);
-        err = gnutls_certificate_set_x509_trust_file (x509_cred, ca_file,
-                                                      GNUTLS_X509_FMT_PEM);
-        if (err < 0) {
-            VIR_ERROR(_("gnutls_certificate_set_x509_trust_file: %s"),
-                      gnutls_strerror (err));
-            return -1;
-        }
-    }
-
-    if (crl_file && crl_file[0] != '\0') {
-        if (remoteCheckCertFile("CA revocation list", crl_file) < 0)
-            return -1;
-
-        DEBUG("loading CRL from %s", crl_file);
-        err = gnutls_certificate_set_x509_crl_file (x509_cred, crl_file,
-                                                    GNUTLS_X509_FMT_PEM);
-        if (err < 0) {
-            VIR_ERROR(_("gnutls_certificate_set_x509_crl_file: %s"),
-                      gnutls_strerror (err));
-            return -1;
-        }
-    }
-
-    if (cert_file && cert_file[0] != '\0' && key_file && key_file[0] != '\0') {
-        if (remoteCheckCertFile("server certificate", cert_file) < 0)
-            return -1;
-        if (remoteCheckCertFile("server key", key_file) < 0)
-            return -1;
-        DEBUG("loading cert and key from %s and %s", cert_file, key_file);
-        err =
-            gnutls_certificate_set_x509_key_file (x509_cred,
-                                                  cert_file, key_file,
-                                                  GNUTLS_X509_FMT_PEM);
-        if (err < 0) {
-            VIR_ERROR(_("gnutls_certificate_set_x509_key_file: %s"),
-                      gnutls_strerror (err));
-            return -1;
-        }
-    }
-
-    /* Generate Diffie Hellman parameters - for use with DHE
-     * kx algorithms. These should be discarded and regenerated
-     * once a day, once a week or once a month. Depending on the
-     * security requirements.
-     */
-    err = gnutls_dh_params_init (&dh_params);
-    if (err < 0) {
-        VIR_ERROR(_("gnutls_dh_params_init: %s"), gnutls_strerror (err));
-        return -1;
-    }
-    err = gnutls_dh_params_generate2 (dh_params, DH_BITS);
-    if (err < 0) {
-        VIR_ERROR(_("gnutls_dh_params_generate2: %s"), gnutls_strerror (err));
-        return -1;
-    }
-
-    gnutls_certificate_set_dh_params (x509_cred, dh_params);
-
-    return 0;
-}
-
-static void
-qemudDispatchSignalEvent(int watch ATTRIBUTE_UNUSED,
-                         int fd ATTRIBUTE_UNUSED,
-                         int events ATTRIBUTE_UNUSED,
-                         void *opaque) {
-    struct qemud_server *server = (struct qemud_server *)opaque;
-    siginfo_t siginfo;
-    int ret;
-
-    virMutexLock(&server->lock);
-
-    if (saferead(server->sigread, &siginfo, sizeof(siginfo)) != sizeof(siginfo)) {
-        char ebuf[1024];
-        VIR_ERROR(_("Failed to read from signal pipe: %s"),
-                  virStrerror(errno, ebuf, sizeof ebuf));
-        virMutexUnlock(&server->lock);
-        return;
-    }
-
-    ret = 0;
-
-    switch (siginfo.si_signo) {
-    case SIGHUP:
-        VIR_INFO0(_("Reloading configuration on SIGHUP"));
-        if (virStateReload() < 0)
-            VIR_WARN0(_("Error while reloading drivers"));
-        break;
-
-    case SIGINT:
-    case SIGQUIT:
-    case SIGTERM:
-        VIR_WARN(_("Shutting down on signal %d"), siginfo.si_signo);
-        server->shutdown = 1;
-        break;
-
-    default:
-        VIR_INFO(_("Received unexpected signal %d"), siginfo.si_signo);
-        break;
-    }
-
-    if (ret != 0)
-        server->shutdown = 1;
-
-    virMutexUnlock(&server->lock);
-}
-
-
-static int qemudGoDaemon(void) {
-    int pid = fork();
-    switch (pid) {
-    case 0:
-        {
-            int stdinfd = -1;
-            int stdoutfd = -1;
-            int nextpid;
-
-            if ((stdinfd = open("/dev/null", O_RDONLY)) < 0)
-                goto cleanup;
-            if ((stdoutfd = open("/dev/null", O_WRONLY)) < 0)
-                goto cleanup;
-            if (dup2(stdinfd, STDIN_FILENO) != STDIN_FILENO)
-                goto cleanup;
-            if (dup2(stdoutfd, STDOUT_FILENO) != STDOUT_FILENO)
-                goto cleanup;
-            if (dup2(stdoutfd, STDERR_FILENO) != STDERR_FILENO)
-                goto cleanup;
-            if (close(stdinfd) < 0)
-                goto cleanup;
-            stdinfd = -1;
-            if (close(stdoutfd) < 0)
-                goto cleanup;
-            stdoutfd = -1;
-
-            if (setsid() < 0)
-                goto cleanup;
-
-            nextpid = fork();
-            switch (nextpid) {
-            case 0:
-                return 0;
-            case -1:
-                return -1;
-            default:
-                _exit(0);
-            }
-
-        cleanup:
-            if (stdoutfd != -1)
-                close(stdoutfd);
-            if (stdinfd != -1)
-                close(stdinfd);
-            return -1;
-
-        }
-
-    case -1:
-        return -1;
-
-    default:
-        {
-            int got, status = 0;
-            /* We wait to make sure the next child forked
-               successfully */
-            if ((got = waitpid(pid, &status, 0)) < 0 ||
-                got != pid ||
-                status != 0) {
-                return -1;
-            }
-            _exit(0);
-        }
-    }
-}
-
-static int qemudWritePidFile(const char *pidFile) {
-    int fd;
-    FILE *fh;
-    char ebuf[1024];
-
-    if (pidFile[0] == '\0')
-        return 0;
-
-    if ((fd = open(pidFile, O_WRONLY|O_CREAT|O_EXCL, 0644)) < 0) {
-        VIR_ERROR(_("Failed to open pid file '%s' : %s"),
-                  pidFile, virStrerror(errno, ebuf, sizeof ebuf));
-        return -1;
-    }
-
-    if (!(fh = fdopen(fd, "w"))) {
-        VIR_ERROR(_("Failed to fdopen pid file '%s' : %s"),
-                  pidFile, virStrerror(errno, ebuf, sizeof ebuf));
-        close(fd);
-        return -1;
-    }
-
-    if (fprintf(fh, "%lu\n", (unsigned long)getpid()) < 0) {
-        VIR_ERROR(_("Failed to write to pid file '%s' : %s"),
-                  pidFile, virStrerror(errno, ebuf, sizeof ebuf));
-        fclose(fh);
-        return -1;
-    }
-
-    if (fclose(fh) == EOF) {
-        VIR_ERROR(_("Failed to close pid file '%s' : %s"),
-                  pidFile, virStrerror(errno, ebuf, sizeof ebuf));
-        return -1;
-    }
-
-    return 0;
-}
-
-static int qemudListenUnix(struct qemud_server *server,
-                           const char *path, int readonly, int auth) {
-    struct qemud_socket *sock;
-    struct sockaddr_un addr;
-    mode_t oldmask;
-    gid_t oldgrp;
-    char ebuf[1024];
-
-    if (VIR_ALLOC(sock) < 0) {
-        VIR_ERROR("%s", _("Failed to allocate memory for struct qemud_socket"));
-        return -1;
-    }
-
-    sock->readonly = readonly;
-    sock->port = -1;
-    sock->type = QEMUD_SOCK_TYPE_UNIX;
-    sock->auth = auth;
-
-    if ((sock->fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
-        VIR_ERROR(_("Failed to create socket: %s"),
-                  virStrerror(errno, ebuf, sizeof ebuf));
-        goto cleanup;
-    }
-
-    if (virSetCloseExec(sock->fd) < 0 ||
-        virSetNonBlock(sock->fd) < 0)
-        goto cleanup;
-
-    memset(&addr, 0, sizeof(addr));
-    addr.sun_family = AF_UNIX;
-    strncpy(addr.sun_path, path, sizeof(addr.sun_path)-1);
-    if (addr.sun_path[0] == '@')
-        addr.sun_path[0] = '\0';
-
-
-    oldgrp = getgid();
-    oldmask = umask(readonly ? ~unix_sock_ro_mask : ~unix_sock_rw_mask);
-    if (server->privileged)
-        setgid(unix_sock_gid);
-
-    if (bind(sock->fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
-        VIR_ERROR(_("Failed to bind socket to '%s': %s"),
-                  path, virStrerror(errno, ebuf, sizeof ebuf));
-        goto cleanup;
-    }
-    umask(oldmask);
-    if (server->privileged)
-        setgid(oldgrp);
-
-    if (listen(sock->fd, 30) < 0) {
-        VIR_ERROR(_("Failed to listen for connections on '%s': %s"),
-                  path, virStrerror(errno, ebuf, sizeof ebuf));
-        goto cleanup;
-    }
-
-    if ((sock->watch = virEventAddHandleImpl(sock->fd,
-                                             VIR_EVENT_HANDLE_READABLE |
-                                             VIR_EVENT_HANDLE_ERROR |
-                                             VIR_EVENT_HANDLE_HANGUP,
-                                             qemudDispatchServerEvent,
-                                             server, NULL)) < 0) {
-        VIR_ERROR0(_("Failed to add server event callback"));
-        goto cleanup;
-    }
-
-    sock->next = server->sockets;
-    server->sockets = sock;
-    server->nsockets++;
-
-    return 0;
-
- cleanup:
-    if (sock->fd)
-        close(sock->fd);
-    free(sock);
-    return -1;
-}
-
-// See: http://people.redhat.com/drepper/userapi-ipv6.html
-static int
-remoteMakeSockets (int *fds, int max_fds, int *nfds_r, const char *node, const char *service)
-{
-    struct addrinfo *ai;
-    struct addrinfo hints;
-    memset (&hints, 0, sizeof hints);
-    hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
-    hints.ai_socktype = SOCK_STREAM;
-
-    int e = getaddrinfo (node, service, &hints, &ai);
-    if (e != 0) {
-        VIR_ERROR(_("getaddrinfo: %s\n"), gai_strerror (e));
-        return -1;
-    }
-
-    struct addrinfo *runp = ai;
-    while (runp && *nfds_r < max_fds) {
-        char ebuf[1024];
-        fds[*nfds_r] = socket (runp->ai_family, runp->ai_socktype,
-                               runp->ai_protocol);
-        if (fds[*nfds_r] == -1) {
-            VIR_ERROR(_("socket: %s"), virStrerror (errno, ebuf, sizeof ebuf));
-            return -1;
-        }
-
-        int opt = 1;
-        setsockopt (fds[*nfds_r], SOL_SOCKET, SO_REUSEADDR, &opt, sizeof opt);
-
-        if (bind (fds[*nfds_r], runp->ai_addr, runp->ai_addrlen) == -1) {
-            if (errno != EADDRINUSE) {
-                VIR_ERROR(_("bind: %s"), virStrerror (errno, ebuf, sizeof ebuf));
-                return -1;
-            }
-            close (fds[*nfds_r]);
-        }
-        else {
-            if (listen (fds[*nfds_r], SOMAXCONN) == -1) {
-                VIR_ERROR(_("listen: %s"),
-                          virStrerror (errno, ebuf, sizeof ebuf));
-                return -1;
-            }
-            ++*nfds_r;
-        }
-        runp = runp->ai_next;
-    }
-
-    freeaddrinfo (ai);
-    return 0;
-}
-
-/* Listen on the named/numbered TCP port.  On a machine with IPv4 and
- * IPv6 interfaces this may generate several sockets.
- */
-static int
-remoteListenTCP (struct qemud_server *server,
-                 const char *addr,
-                 const char *port,
-                 int type,
-                 int auth)
-{
-    int fds[2];
-    int nfds = 0;
-    int i;
-    struct qemud_socket *sock;
-
-    if (remoteMakeSockets (fds, 2, &nfds, addr, port) == -1)
-        return -1;
-
-    for (i = 0; i < nfds; ++i) {
-        union {
-            struct sockaddr_storage sa_stor;
-            struct sockaddr sa;
-            struct sockaddr_in sa_in;
-#ifdef AF_INET6
-            struct sockaddr_in6 sa_in6;
-#endif
-        } s;
-        char ebuf[1024];
-        socklen_t salen = sizeof(s);
-
-        if (VIR_ALLOC(sock) < 0) {
-            VIR_ERROR(_("remoteListenTCP: calloc: %s"),
-                      virStrerror (errno, ebuf, sizeof ebuf));
-            goto cleanup;
-        }
-
-        sock->readonly = 0;
-        sock->next = server->sockets;
-        server->sockets = sock;
-        server->nsockets++;
-
-        sock->fd = fds[i];
-        sock->type = type;
-        sock->auth = auth;
-
-        if (getsockname(sock->fd, &s.sa, &salen) < 0)
-            goto cleanup;
-
-        if (s.sa.sa_family == AF_INET) {
-            sock->port = htons(s.sa_in.sin_port);
-#ifdef AF_INET6
-        } else if (s.sa.sa_family == AF_INET6)
-            sock->port = htons(s.sa_in6.sin6_port);
-#endif
-        else
-            sock->port = -1;
-
-        if (virSetCloseExec(sock->fd) < 0 ||
-            virSetNonBlock(sock->fd) < 0)
-            goto cleanup;
-
-        if (listen (sock->fd, 30) < 0) {
-            VIR_ERROR(_("remoteListenTCP: listen: %s"),
-                      virStrerror (errno, ebuf, sizeof ebuf));
-            goto cleanup;
-        }
-
-        if ((sock->watch = virEventAddHandleImpl(sock->fd,
-                                                 VIR_EVENT_HANDLE_READABLE |
-                                                 VIR_EVENT_HANDLE_ERROR |
-                                                 VIR_EVENT_HANDLE_HANGUP,
-                                                 qemudDispatchServerEvent,
-                                                 server, NULL)) < 0) {
-            VIR_ERROR0(_("Failed to add server event callback"));
-            goto cleanup;
-        }
-
-    }
-
-    return 0;
-
-cleanup:
-    for (i = 0; i < nfds; ++i)
-        close(fds[i]);
-    return -1;
-}
-
-static int qemudInitPaths(struct qemud_server *server,
-                          char *sockname,
-                          char *roSockname,
-                          int maxlen)
-{
-    char *sock_dir;
-    char *dir_prefix = NULL;
-    int ret = -1;
-    char *sock_dir_prefix = NULL;
-
-    if (unix_sock_dir)
-        sock_dir = unix_sock_dir;
-    else {
-        sock_dir = sockname;
-        if (server->privileged) {
-            dir_prefix = strdup (LOCAL_STATE_DIR);
-            if (dir_prefix == NULL) {
-                virReportOOMError(NULL);
-                goto cleanup;
-            }
-            if (snprintf (sock_dir, maxlen, "%s/run/libvirt",
-                          dir_prefix) >= maxlen)
-                goto snprintf_error;
-        } else {
-            uid_t uid = geteuid();
-            dir_prefix = virGetUserDirectory(NULL, uid);
-            if (dir_prefix == NULL) {
-                /* Do not diagnose here; virGetUserDirectory does that.  */
-                goto snprintf_error;
-            }
-
-            if (snprintf(sock_dir, maxlen, "%s/.libvirt", dir_prefix) >= maxlen)
-                goto snprintf_error;
-        }
-    }
-
-    sock_dir_prefix = strdup (sock_dir);
-    if (!sock_dir_prefix) {
-        virReportOOMError(NULL);
-        goto cleanup;
-    }
-
-    if (server->privileged) {
-        if (snprintf (sockname, maxlen, "%s/libvirt-sock",
-                      sock_dir_prefix) >= maxlen
-            || (snprintf (roSockname, maxlen, "%s/libvirt-sock-ro",
-                          sock_dir_prefix) >= maxlen))
-            goto snprintf_error;
-        unlink(sockname);
-        unlink(roSockname);
-    } else {
-        if (snprintf(sockname, maxlen, "@%s/libvirt-sock",
-                     sock_dir_prefix) >= maxlen)
-            goto snprintf_error;
-    }
-
-    if (server->privileged)
-        server->logDir = strdup (LOCAL_STATE_DIR "/log/libvirt");
-    else
-        virAsprintf(&server->logDir, "%s/.libvirt/log", dir_prefix);
-
-    if (server->logDir == NULL)
-        virReportOOMError(NULL);
-
-    ret = 0;
-
- snprintf_error:
-    if (ret)
-        VIR_ERROR("%s",
-                  _("Resulting path too long for buffer in qemudInitPaths()"));
-
- cleanup:
-    free (dir_prefix);
-    free (sock_dir_prefix);
-    return ret;
-}
-
-static struct qemud_server *qemudInitialize(int sigread) {
-    struct qemud_server *server;
-
-    if (VIR_ALLOC(server) < 0) {
-        VIR_ERROR0(_("Failed to allocate struct qemud_server"));
-        return NULL;
-    }
-
-    if (virMutexInit(&server->lock) < 0) {
-        VIR_ERROR("%s", _("cannot initialize mutex"));
-        VIR_FREE(server);
-    }
-    if (virCondInit(&server->job) < 0) {
-        VIR_ERROR("%s", _("cannot initialize condition variable"));
-        virMutexDestroy(&server->lock);
-        VIR_FREE(server);
-    }
-
-    server->privileged = geteuid() == 0 ? 1 : 0;
-    server->sigread = sigread;
-
-    if (virEventInit() < 0) {
-        VIR_ERROR0(_("Failed to initialize event system"));
-        VIR_FREE(server);
-        return NULL;
-    }
-
-    virInitialize();
-
-    /*
-     * Note that the order is important: the first ones have a higher
-     * priority when calling virStateInitialize. We must register
-     * the network, storage and nodedev drivers before any domain
-     * drivers, since their resources must be auto-started before
-     * any domains can be auto-started.
-     */
-#ifdef WITH_DRIVER_MODULES
-    /* We don't care if any of these fail, because the whole point
-     * is to allow users to only install modules they want to use.
-     * If they try to use a open a connection for a module that
-     * is not loaded they'll get a suitable error at that point
-     */
-    virDriverLoadModule("network");
-    virDriverLoadModule("storage");
-    virDriverLoadModule("nodedev");
-    virDriverLoadModule("secret");
-    virDriverLoadModule("qemu");
-    virDriverLoadModule("lxc");
-    virDriverLoadModule("uml");
-    virDriverLoadModule("one");
-#else
-#ifdef WITH_NETWORK
-    networkRegister();
-#endif
-#ifdef WITH_NETCF
-    interfaceRegister();
-#endif
-#ifdef WITH_STORAGE_DIR
-    storageRegister();
-#endif
-#if defined(WITH_NODE_DEVICES) && \
-    (defined(HAVE_HAL) || defined(HAVE_DEVKIT))
-    nodedevRegister();
-#endif
-    secretRegister();
-#ifdef WITH_QEMU
-    qemuRegister();
-#endif
-#ifdef WITH_LXC
-    lxcRegister();
-#endif
-#ifdef WITH_UML
-    umlRegister();
-#endif
-#ifdef WITH_ONE
-    oneRegister();
-#endif
-#endif
-
-    virEventRegisterImpl(virEventAddHandleImpl,
-                         virEventUpdateHandleImpl,
-                         virEventRemoveHandleImpl,
-                         virEventAddTimeoutImpl,
-                         virEventUpdateTimeoutImpl,
-                         virEventRemoveTimeoutImpl);
-
-    virStateInitialize(server->privileged);
-
-    return server;
-}
-
-static struct qemud_server *qemudNetworkInit(struct qemud_server *server) {
-    struct qemud_socket *sock;
-    char sockname[PATH_MAX];
-    char roSockname[PATH_MAX];
-#if HAVE_SASL
-    int err;
-#endif /* HAVE_SASL */
-
-    roSockname[0] = '\0';
-
-    if (qemudInitPaths(server, sockname, roSockname, PATH_MAX) < 0)
-        goto cleanup;
-
-    if (qemudListenUnix(server, sockname, 0, auth_unix_rw) < 0)
-        goto cleanup;
-
-    if (roSockname[0] != '\0' && qemudListenUnix(server, roSockname, 1, auth_unix_ro) < 0)
-        goto cleanup;
-
-#if HAVE_SASL
-    if (auth_unix_rw == REMOTE_AUTH_SASL ||
-        auth_unix_ro == REMOTE_AUTH_SASL ||
-        auth_tcp == REMOTE_AUTH_SASL ||
-        auth_tls == REMOTE_AUTH_SASL) {
-        if ((err = sasl_server_init(NULL, "libvirt")) != SASL_OK) {
-            VIR_ERROR(_("Failed to initialize SASL authentication %s"),
-                      sasl_errstring(err, NULL, NULL));
-            goto cleanup;
-        }
-    }
-#endif
-
-#if HAVE_POLKIT0
-    if (auth_unix_rw == REMOTE_AUTH_POLKIT ||
-        auth_unix_ro == REMOTE_AUTH_POLKIT) {
-        DBusError derr;
-
-        dbus_connection_set_change_sigpipe(FALSE);
-        dbus_threads_init_default();
-
-        dbus_error_init(&derr);
-        server->sysbus = dbus_bus_get(DBUS_BUS_SYSTEM, &derr);
-        if (!(server->sysbus)) {
-            VIR_ERROR(_("Failed to connect to system bus for PolicyKit auth: %s"),
-                      derr.message);
-            dbus_error_free(&derr);
-            goto cleanup;
-        }
-        dbus_connection_set_exit_on_disconnect(server->sysbus, FALSE);
-    }
-#endif
-
-    if (ipsock) {
-        if (listen_tcp && remoteListenTCP (server, listen_addr, tcp_port, QEMUD_SOCK_TYPE_TCP, auth_tcp) < 0)
-            goto cleanup;
-
-        if (listen_tls) {
-            if (remoteInitializeGnuTLS () < 0)
-                goto cleanup;
-
-            if (remoteListenTCP (server, listen_addr, tls_port, QEMUD_SOCK_TYPE_TLS, auth_tls) < 0)
-                goto cleanup;
-        }
-    }
-
-#ifdef HAVE_AVAHI
-    if (server->privileged && mdns_adv) {
-        struct libvirtd_mdns_group *group;
-        int port = 0;
-
-        server->mdns = libvirtd_mdns_new();
-
-        if (!mdns_name) {
-            char groupname[64], localhost[HOST_NAME_MAX+1], *tmp;
-            /* Extract the host part of the potentially FQDN */
-            gethostname(localhost, HOST_NAME_MAX);
-            localhost[HOST_NAME_MAX] = '\0';
-            if ((tmp = strchr(localhost, '.')))
-                *tmp = '\0';
-            snprintf(groupname, sizeof(groupname)-1, "Virtualization Host %s", localhost);
-            groupname[sizeof(groupname)-1] = '\0';
-            group = libvirtd_mdns_add_group(server->mdns, groupname);
-        } else {
-            group = libvirtd_mdns_add_group(server->mdns, mdns_name);
-        }
-
-        /*
-         * See if there's a TLS enabled port we can advertise. Cowardly
-         * don't bother to advertise TCP since we don't want people using
-         * them for real world apps
-         */
-        sock = server->sockets;
-        while (sock) {
-            if (sock->port != -1 && sock->type == QEMUD_SOCK_TYPE_TLS) {
-                port = sock->port;
-                break;
-            }
-            sock = sock->next;
-        }
-
-        /*
-         * Add the primary entry - we choose SSH because its most likely to always
-         * be available
-         */
-        libvirtd_mdns_add_entry(group, "_libvirt._tcp", port);
-        libvirtd_mdns_start(server->mdns);
-    }
-#endif
-
-    return server;
-
- cleanup:
-    if (server) {
-        sock = server->sockets;
-        while (sock) {
-            close(sock->fd);
-            sock = sock->next;
-        }
-
-#if HAVE_POLKIT0
-        if (server->sysbus)
-            dbus_connection_unref(server->sysbus);
-#endif
-        free(server);
-    }
-    return NULL;
-}
-
-static gnutls_session_t
-remoteInitializeTLSSession (void)
-{
-  gnutls_session_t session;
-  int err;
-
-  err = gnutls_init (&session, GNUTLS_SERVER);
-  if (err != 0) goto failed;
-
-  /* avoid calling all the priority functions, since the defaults
-   * are adequate.
-   */
-  err = gnutls_set_default_priority (session);
-  if (err != 0) goto failed;
-
-  err = gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, x509_cred);
-  if (err != 0) goto failed;
-
-  /* request client certificate if any.
-   */
-  gnutls_certificate_server_set_request (session, GNUTLS_CERT_REQUEST);
-
-  gnutls_dh_set_prime_bits (session, DH_BITS);
-
-  return session;
-
- failed:
-  VIR_ERROR(_("remoteInitializeTLSSession: %s"),
-            gnutls_strerror (err));
-  return NULL;
-}
-
-/* Check DN is on tls_allowed_dn_list. */
-static int
-remoteCheckDN (gnutls_x509_crt_t cert)
-{
-    char name[256];
-    size_t namesize = sizeof name;
-    char **wildcards;
-    int err;
-
-    err = gnutls_x509_crt_get_dn (cert, name, &namesize);
-    if (err != 0) {
-        VIR_ERROR(_("remoteCheckDN: gnutls_x509_cert_get_dn: %s"),
-                  gnutls_strerror (err));
-        return 0;
-    }
-
-    /* If the list is not set, allow any DN. */
-    wildcards = tls_allowed_dn_list;
-    if (!wildcards)
-        return 1;
-
-    while (*wildcards) {
-        if (fnmatch (*wildcards, name, 0) == 0)
-            return 1;
-        wildcards++;
-    }
-
-    /* Print the client's DN. */
-    DEBUG(_("remoteCheckDN: failed: client DN is %s"), name);
-
-    return 0; // Not found.
-}
-
-static int
-remoteCheckCertificate (gnutls_session_t session)
-{
-    int ret;
-    unsigned int status;
-    const gnutls_datum_t *certs;
-    unsigned int nCerts, i;
-    time_t now;
-
-    if ((ret = gnutls_certificate_verify_peers2 (session, &status)) < 0){
-        VIR_ERROR(_("remoteCheckCertificate: verify failed: %s"),
-                  gnutls_strerror (ret));
-        return -1;
-    }
-
-    if (status != 0) {
-        if (status & GNUTLS_CERT_INVALID)
-            VIR_ERROR0(_("remoteCheckCertificate: "
-                         "the client certificate is not trusted."));
-
-        if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
-            VIR_ERROR0(_("remoteCheckCertificate: the client "
-                         "certificate has unknown issuer."));
-
-        if (status & GNUTLS_CERT_REVOKED)
-            VIR_ERROR0(_("remoteCheckCertificate: "
-                         "the client certificate has been revoked."));
-
-#ifndef GNUTLS_1_0_COMPAT
-        if (status & GNUTLS_CERT_INSECURE_ALGORITHM)
-            VIR_ERROR0(_("remoteCheckCertificate: the client certificate"
-                         " uses an insecure algorithm."));
-#endif
-
-        return -1;
-    }
-
-    if (gnutls_certificate_type_get (session) != GNUTLS_CRT_X509) {
-        VIR_ERROR0(_("remoteCheckCertificate: certificate is not X.509"));
-        return -1;
-    }
-
-    if (!(certs = gnutls_certificate_get_peers(session, &nCerts))) {
-        VIR_ERROR0(_("remoteCheckCertificate: no peers"));
-        return -1;
-    }
-
-    now = time (NULL);
-
-    for (i = 0; i < nCerts; i++) {
-        gnutls_x509_crt_t cert;
-
-        if (gnutls_x509_crt_init (&cert) < 0) {
-            VIR_ERROR0(_("remoteCheckCertificate: gnutls_x509_crt_init failed"));
-            return -1;
-        }
-
-        if (gnutls_x509_crt_import(cert, &certs[i], GNUTLS_X509_FMT_DER) < 0) {
-            gnutls_x509_crt_deinit (cert);
-            return -1;
-        }
-
-        if (gnutls_x509_crt_get_expiration_time (cert) < now) {
-            VIR_ERROR0(_("remoteCheckCertificate: "
-                         "the client certificate has expired"));
-            gnutls_x509_crt_deinit (cert);
-            return -1;
-        }
-
-        if (gnutls_x509_crt_get_activation_time (cert) > now) {
-            VIR_ERROR0(_("remoteCheckCertificate: the client "
-                         "certificate is not yet activated"));
-            gnutls_x509_crt_deinit (cert);
-            return -1;
-        }
-
-        if (i == 0) {
-            if (!remoteCheckDN (cert)) {
-                /* This is the most common error: make it informative. */
-                VIR_ERROR0(_("remoteCheckCertificate: client's Distinguished Name is not on the list of allowed clients (tls_allowed_dn_list).  Use 'openssl x509 -in clientcert.pem -text' to view the Distinguished Name field in the client certificate, or run this daemon with --verbose option."));
-                gnutls_x509_crt_deinit (cert);
-                return -1;
-            }
-        }
-    }
-
-    return 0;
-}
-
-/* Check the client's access. */
-static int
-remoteCheckAccess (struct qemud_client *client)
-{
-    struct qemud_client_message *confirm;
-
-    /* Verify client certificate. */
-    if (remoteCheckCertificate (client->tlssession) == -1) {
-        VIR_ERROR0(_("remoteCheckCertificate: "
-                     "failed to verify client's certificate"));
-        if (!tls_no_verify_certificate) return -1;
-        else VIR_INFO0(_("remoteCheckCertificate: tls_no_verify_certificate "
-                          "is set so the bad certificate is ignored"));
-    }
-
-    if (client->tx) {
-        VIR_INFO("%s",
-                 _("client had unexpected data pending tx after access check"));
-        return -1;
-    }
-
-    if (VIR_ALLOC(confirm) < 0)
-        return -1;
-
-    /* Checks have succeeded.  Write a '\1' byte back to the client to
-     * indicate this (otherwise the socket is abruptly closed).
-     * (NB. The '\1' byte is sent in an encrypted record).
-     */
-    confirm->async = 1;
-    confirm->bufferLength = 1;
-    confirm->bufferOffset = 0;
-    confirm->buffer[0] = '\1';
-
-    client->tx = confirm;
-    return 0;
-}
-
-#if HAVE_POLKIT
-int qemudGetSocketIdentity(int fd, uid_t *uid, pid_t *pid) {
-#ifdef SO_PEERCRED
-    struct ucred cr;
-    unsigned int cr_len = sizeof (cr);
-
-    if (getsockopt (fd, SOL_SOCKET, SO_PEERCRED, &cr, &cr_len) < 0) {
-        char ebuf[1024];
-        VIR_ERROR(_("Failed to verify client credentials: %s"),
-                  virStrerror(errno, ebuf, sizeof ebuf));
-        return -1;
-    }
-
-    *pid = cr.pid;
-    *uid = cr.uid;
-#else
-    /* XXX Many more OS support UNIX socket credentials we could port to. See dbus ....*/
-#error "UNIX socket credentials not supported/implemented on this platform yet..."
-#endif
-    return 0;
-}
-#endif
-
-
-static int qemudDispatchServer(struct qemud_server *server, struct qemud_socket *sock) {
-    int fd;
-    struct sockaddr_storage addr;
-    socklen_t addrlen = (socklen_t) (sizeof addr);
-    struct qemud_client *client;
-    int no_slow_start = 1;
-
-    if ((fd = accept(sock->fd, (struct sockaddr *)&addr, &addrlen)) < 0) {
-        char ebuf[1024];
-        if (errno == EAGAIN)
-            return 0;
-        VIR_ERROR(_("Failed to accept connection: %s"),
-                  virStrerror(errno, ebuf, sizeof ebuf));
-        return -1;
-    }
-
-    if (server->nclients >= max_clients) {
-        VIR_ERROR(_("Too many active clients (%d), dropping connection"), max_clients);
-        close(fd);
-        return -1;
-    }
-
-    if (VIR_REALLOC_N(server->clients, server->nclients+1) < 0) {
-        VIR_ERROR0(_("Out of memory allocating clients"));
-        close(fd);
-        return -1;
-    }
-
-#ifdef __sun
-    {
-        ucred_t *ucred = NULL;
-        const priv_set_t *privs;
-
-        if (getpeerucred (fd, &ucred) == -1 ||
-            (privs = ucred_getprivset (ucred, PRIV_EFFECTIVE)) == NULL) {
-            if (ucred != NULL)
-                ucred_free (ucred);
-            close (fd);
-            return -1;
-        }
-
-        if (!priv_ismember (privs, PRIV_VIRT_MANAGE)) {
-            ucred_free (ucred);
-            close (fd);
-            return -1;
-        }
-
-        ucred_free (ucred);
-    }
-#endif /* __sun */
-
-    /* Disable Nagle.  Unix sockets will ignore this. */
-    setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, (void *)&no_slow_start,
-                sizeof no_slow_start);
-
-    if (virSetCloseExec(fd) < 0 ||
-        virSetNonBlock(fd) < 0) {
-        close(fd);
-        return -1;
-    }
-
-    if (VIR_ALLOC(client) < 0)
-        goto cleanup;
-    if (virMutexInit(&client->lock) < 0) {
-        VIR_ERROR("%s", _("cannot initialize mutex"));
-        VIR_FREE(client);
-        goto cleanup;
-    }
-
-    client->magic = QEMUD_CLIENT_MAGIC;
-    client->fd = fd;
-    client->readonly = sock->readonly;
-    client->type = sock->type;
-    client->auth = sock->auth;
-    memcpy (&client->addr, &addr, sizeof addr);
-    client->addrlen = addrlen;
-
-    /* Prepare one for packet receive */
-    if (VIR_ALLOC(client->rx) < 0)
-        goto cleanup;
-    client->rx->bufferLength = REMOTE_MESSAGE_HEADER_XDR_LEN;
-
-
-#if HAVE_POLKIT
-    /* Only do policy checks for non-root - allow root user
-       through with no checks, as a fail-safe - root can easily
-       change policykit policy anyway, so its pointless trying
-       to restrict root */
-    if (client->auth == REMOTE_AUTH_POLKIT) {
-        uid_t uid;
-        pid_t pid;
-
-        if (qemudGetSocketIdentity(client->fd, &uid, &pid) < 0)
-            goto cleanup;
-
-        /* Client is running as root, so disable auth */
-        if (uid == 0) {
-            VIR_INFO(_("Turn off polkit auth for privileged client %d"), pid);
-            client->auth = REMOTE_AUTH_NONE;
-        }
-    }
-#endif
-
-    if (client->type != QEMUD_SOCK_TYPE_TLS) {
-        /* Plain socket, so prepare to read first message */
-        if (qemudRegisterClientEvent (server, client) < 0)
-            goto cleanup;
-    } else {
-        int ret;
-
-        client->tlssession = remoteInitializeTLSSession ();
-        if (client->tlssession == NULL)
-            goto cleanup;
-
-        gnutls_transport_set_ptr (client->tlssession,
-                                  (gnutls_transport_ptr_t) (long) fd);
-
-        /* Begin the TLS handshake. */
-        ret = gnutls_handshake (client->tlssession);
-        if (ret == 0) {
-            client->handshake = 0;
-
-            /* Unlikely, but ...  Next step is to check the certificate. */
-            if (remoteCheckAccess (client) == -1)
-                goto cleanup;
-
-            /* Handshake & cert check OK,  so prepare to read first message */
-            if (qemudRegisterClientEvent(server, client) < 0)
-                goto cleanup;
-        } else if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) {
-            /* Most likely, need to do more handshake data */
-            client->handshake = 1;
-
-            if (qemudRegisterClientEvent (server, client) < 0)
-                goto cleanup;
-        } else {
-            VIR_ERROR(_("TLS handshake failed: %s"),
-                      gnutls_strerror (ret));
-            goto cleanup;
-        }
-    }
-
-    server->clients[server->nclients++] = client;
-
-    if (server->nclients > server->nactiveworkers &&
-        server->nactiveworkers < server->nworkers) {
-        int i;
-        for (i = 0 ; i < server->nworkers ; i++) {
-            if (!server->workers[i].hasThread) {
-                if (qemudStartWorker(server, &server->workers[i]) < 0)
-                    return -1;
-                server->nactiveworkers++;
-                break;
-            }
-        }
-    }
-
-
-    return 0;
-
- cleanup:
-    if (client &&
-        client->tlssession) gnutls_deinit (client->tlssession);
-    close (fd);
-    VIR_FREE(client->rx);
-    VIR_FREE(client);
-    return -1;
-}
-
-
-/*
- * You must hold lock for at least the client
- * We don't free stuff here, merely disconnect the client's
- * network socket & resources.
- * We keep the libvirt connection open until any async
- * jobs have finished, then clean it up elsehwere
- */
-void qemudDispatchClientFailure(struct qemud_client *client) {
-    if (client->watch != -1) {
-        virEventRemoveHandleImpl(client->watch);
-        client->watch = -1;
-    }
-
-    /* Deregister event delivery callback */
-    if(client->conn) {
-        DEBUG0("Deregistering to relay remote events");
-        virConnectDomainEventDeregister(client->conn, remoteRelayDomainEvent);
-    }
-
-#if HAVE_SASL
-    if (client->saslconn) {
-        sasl_dispose(&client->saslconn);
-        client->saslconn = NULL;
-    }
-    free(client->saslUsername);
-    client->saslUsername = NULL;
-#endif
-    if (client->tlssession) {
-        gnutls_deinit (client->tlssession);
-        client->tlssession = NULL;
-    }
-    if (client->fd != -1) {
-        close(client->fd);
-        client->fd = -1;
-    }
-}
-
-
-/* Caller must hold server lock */
-static struct qemud_client *qemudPendingJob(struct qemud_server *server)
-{
-    int i;
-    for (i = 0 ; i < server->nclients ; i++) {
-        virMutexLock(&server->clients[i]->lock);
-        if (server->clients[i]->dx) {
-            /* Delibrately don't unlock client - caller wants the lock */
-            return server->clients[i];
-        }
-        virMutexUnlock(&server->clients[i]->lock);
-    }
-    return NULL;
-}
-
-static void *qemudWorker(void *data)
-{
-    struct qemud_worker *worker = data;
-    struct qemud_server *server = worker->server;
-
-    while (1) {
-        struct qemud_client *client = NULL;
-        struct qemud_client_message *msg;
-
-        virMutexLock(&server->lock);
-        while (((client = qemudPendingJob(server)) == NULL) &&
-               !worker->quitRequest) {
-            if (virCondWait(&server->job, &server->lock) < 0) {
-                virMutexUnlock(&server->lock);
-                return NULL;
-            }
-        }
-        if (worker->quitRequest) {
-            if (client)
-                virMutexUnlock(&client->lock);
-            virMutexUnlock(&server->lock);
-            return NULL;
-        }
-        worker->processingCall = 1;
-        virMutexUnlock(&server->lock);
-
-        /* We own a locked client now... */
-        client->refs++;
-
-        /* Remove our message from dispatch queue while we use it */
-        msg = qemudClientMessageQueueServe(&client->dx);
-
-        /* This function drops the lock during dispatch,
-         * and re-acquires it before returning */
-        if (remoteDispatchClientRequest (server, client, msg) < 0) {
-            VIR_FREE(msg);
-            qemudDispatchClientFailure(client);
-            client->refs--;
-            virMutexUnlock(&client->lock);
-            continue;
-        }
-
-        client->refs--;
-        virMutexUnlock(&client->lock);
-
-        virMutexLock(&server->lock);
-        worker->processingCall = 0;
-        virMutexUnlock(&server->lock);
-    }
-}
-
-static int qemudStartWorker(struct qemud_server *server,
-                            struct qemud_worker *worker) {
-    pthread_attr_t attr;
-    pthread_attr_init(&attr);
-    /* We want to join workers, so don't detach them */
-    /*pthread_attr_setdetachstate(&attr, 1);*/
-
-    if (worker->hasThread)
-        return -1;
-
-    worker->server = server;
-    worker->hasThread = 1;
-    worker->quitRequest = 0;
-    worker->processingCall = 0;
-
-    if (pthread_create(&worker->thread,
-                       &attr,
-                       qemudWorker,
-                       worker) != 0) {
-        worker->hasThread = 0;
-        worker->server = NULL;
-        return -1;
-    }
-
-    return 0;
-}
-
-
-/*
- * Read data into buffer using wire decoding (plain or TLS)
- *
- * Returns:
- *   -1 on error or EOF
- *    0 on EAGAIN
- *    n number of bytes
- */
-static ssize_t qemudClientReadBuf(struct qemud_client *client,
-                                  char *data, ssize_t len) {
-    ssize_t ret;
-
-    if (len < 0) {
-        VIR_ERROR(_("unexpected negative length request %lld"),
-                  (long long int) len);
-        qemudDispatchClientFailure(client);
-        return -1;
-    }
-
-    /*qemudDebug ("qemudClientRead: len = %d", len);*/
-
-    if (!client->tlssession) {
-        char ebuf[1024];
-        ret = read (client->fd, data, len);
-        if (ret == -1 && (errno == EAGAIN ||
-                          errno == EINTR))
-            return 0;
-        if (ret <= 0) {
-            if (ret != 0)
-                VIR_ERROR(_("read: %s"),
-                          virStrerror (errno, ebuf, sizeof ebuf));
-            qemudDispatchClientFailure(client);
-            return -1;
-        }
-    } else {
-        ret = gnutls_record_recv (client->tlssession, data, len);
-
-        if (ret < 0 && (ret == GNUTLS_E_AGAIN ||
-                        ret == GNUTLS_E_INTERRUPTED))
-            return 0;
-        if (ret <= 0) {
-            if (ret != 0)
-                VIR_ERROR(_("gnutls_record_recv: %s"),
-                          gnutls_strerror (ret));
-            qemudDispatchClientFailure(client);
-            return -1;
-        }
-    }
-
-    return ret;
-}
-
-/*
- * Read data into buffer without decoding
- *
- * Returns:
- *   -1 on error or EOF
- *    0 on EAGAIN
- *    n number of bytes
- */
-static ssize_t qemudClientReadPlain(struct qemud_client *client) {
-    ssize_t ret;
-    ret = qemudClientReadBuf(client,
-                             client->rx->buffer + client->rx->bufferOffset,
-                             client->rx->bufferLength - client->rx->bufferOffset);
-    if (ret <= 0)
-        return ret; /* -1 error, 0 eagain */
-
-    client->rx->bufferOffset += ret;
-    return ret;
-}
-
-#if HAVE_SASL
-/*
- * Read data into buffer decoding with SASL
- *
- * Returns:
- *   -1 on error or EOF
- *    0 on EAGAIN
- *    n number of bytes
- */
-static ssize_t qemudClientReadSASL(struct qemud_client *client) {
-    ssize_t got, want;
-
-    /* We're doing a SSF data read, so now its times to ensure
-     * future writes are under SSF too.
-     *
-     * cf remoteSASLCheckSSF in remote.c
-     */
-    client->saslSSF |= QEMUD_SASL_SSF_WRITE;
-
-    /* Need to read some more data off the wire */
-    if (client->saslDecoded == NULL) {
-        int ret;
-        char encoded[8192];
-        ssize_t encodedLen = sizeof(encoded);
-        encodedLen = qemudClientReadBuf(client, encoded, encodedLen);
-
-        if (encodedLen <= 0)
-            return encodedLen;
-
-        ret = sasl_decode(client->saslconn, encoded, encodedLen,
-                          &client->saslDecoded, &client->saslDecodedLength);
-        if (ret != SASL_OK) {
-            VIR_ERROR(_("failed to decode SASL data %s"),
-                      sasl_errstring(ret, NULL, NULL));
-            qemudDispatchClientFailure(client);
-            return -1;
-        }
-
-        client->saslDecodedOffset = 0;
-    }
-
-    /* Some buffered decoded data to return now */
-    got = client->saslDecodedLength - client->saslDecodedOffset;
-    want = client->rx->bufferLength - client->rx->bufferOffset;
-
-    if (want > got)
-        want = got;
-
-    memcpy(client->rx->buffer + client->rx->bufferOffset,
-           client->saslDecoded + client->saslDecodedOffset, want);
-    client->saslDecodedOffset += want;
-    client->rx->bufferOffset += want;
-
-    if (client->saslDecodedOffset == client->saslDecodedLength) {
-        client->saslDecoded = NULL;
-        client->saslDecodedOffset = client->saslDecodedLength = 0;
-    }
-
-    return want;
-}
-#endif
-
-/*
- * Read as much data off wire as possible till we fill our
- * buffer, or would block on I/O
- */
-static ssize_t qemudClientRead(struct qemud_client *client) {
-#if HAVE_SASL
-    if (client->saslSSF & QEMUD_SASL_SSF_READ)
-        return qemudClientReadSASL(client);
-    else
-#endif
-        return qemudClientReadPlain(client);
-}
-
-
-/*
- * Read data until we get a complete message to process
- */
-static void qemudDispatchClientRead(struct qemud_server *server,
-                                    struct qemud_client *client) {
-    /*qemudDebug ("qemudDispatchClientRead: mode = %d", client->mode);*/
-
-readmore:
-    if (qemudClientRead(client) < 0)
-        return; /* Error */
-
-    if (client->rx->bufferOffset < client->rx->bufferLength)
-        return; /* Still not read enough */
-
-    /* Either done with length word header */
-    if (client->rx->bufferLength == REMOTE_MESSAGE_HEADER_XDR_LEN) {
-        unsigned int len;
-        XDR x;
-
-        xdrmem_create(&x, client->rx->buffer, client->rx->bufferLength, XDR_DECODE);
-
-        if (!xdr_u_int(&x, &len)) {
-            xdr_destroy (&x);
-            DEBUG0("Failed to decode packet length");
-            qemudDispatchClientFailure(client);
-            return;
-        }
-        xdr_destroy (&x);
-
-        if (len < REMOTE_MESSAGE_HEADER_XDR_LEN) {
-            DEBUG("Packet length %u too small", len);
-            qemudDispatchClientFailure(client);
-            return;
-        }
-
-        /* Length includes the size of the length word itself */
-        len -= REMOTE_MESSAGE_HEADER_XDR_LEN;
-
-        if (len > REMOTE_MESSAGE_MAX) {
-            DEBUG("Packet length %u too large", len);
-            qemudDispatchClientFailure(client);
-            return;
-        }
-
-        /* Prepare to read rest of message */
-        client->rx->bufferLength += len;
-
-        qemudUpdateClientEvent(client);
-
-        /* Try and read payload immediately instead of going back
-           into poll() because chances are the data is already
-           waiting for us */
-        goto readmore;
-    } else {
-        /* Grab the completed message */
-        struct qemud_client_message *msg = qemudClientMessageQueueServe(&client->rx);
-        struct qemud_client_filter *filter;
-
-        /* Decode the header so we can use it for routing decisions */
-        if (remoteDecodeClientMessageHeader(msg) < 0) {
-            VIR_FREE(msg);
-            qemudDispatchClientFailure(client);
-        }
-
-        /* Check if any filters match this message */
-        filter = client->filters;
-        while (filter) {
-            if ((filter->query)(msg, filter->opaque)) {
-                qemudClientMessageQueuePush(&filter->dx, msg);
-                msg = NULL;
-                break;
-            }
-            filter = filter->next;
-        }
-
-        /* Move completed message to the end of the dispatch queue */
-        if (msg)
-            qemudClientMessageQueuePush(&client->dx, msg);
-        client->nrequests++;
-
-        /* Possibly need to create another receive buffer */
-        if ((client->nrequests < max_client_requests &&
-             VIR_ALLOC(client->rx) < 0)) {
-            qemudDispatchClientFailure(client);
-        } else {
-            if (client->rx)
-                client->rx->bufferLength = REMOTE_MESSAGE_HEADER_XDR_LEN;
-
-            qemudUpdateClientEvent(client);
-
-            /* Tell one of the workers to get on with it... */
-            virCondSignal(&server->job);
-        }
-    }
-}
-
-
-/*
- * Send a chunk of data using wire encoding (plain or TLS)
- *
- * Returns:
- *   -1 on error
- *    0 on EAGAIN
- *    n number of bytes
- */
-static ssize_t qemudClientWriteBuf(struct qemud_client *client,
-                                   const char *data, ssize_t len) {
-    ssize_t ret;
-
-    if (len < 0) {
-        VIR_ERROR(_("unexpected negative length request %lld"),
-                  (long long int) len);
-        qemudDispatchClientFailure(client);
-        return -1;
-    }
-
-    if (!client->tlssession) {
-        char ebuf[1024];
-        if ((ret = write(client->fd, data, len)) == -1) {
-            if (errno == EAGAIN || errno == EINTR)
-                return 0;
-            VIR_ERROR(_("write: %s"), virStrerror (errno, ebuf, sizeof ebuf));
-            qemudDispatchClientFailure(client);
-            return -1;
-        }
-    } else {
-        ret = gnutls_record_send (client->tlssession, data, len);
-        if (ret < 0) {
-            if (ret == GNUTLS_E_INTERRUPTED ||
-                ret == GNUTLS_E_AGAIN)
-                return 0;
-
-            VIR_ERROR(_("gnutls_record_send: %s"), gnutls_strerror (ret));
-            qemudDispatchClientFailure(client);
-            return -1;
-        }
-    }
-    return ret;
-}
-
-
-/*
- * Send client->tx using no encoding
- *
- * Returns:
- *   -1 on error or EOF
- *    0 on EAGAIN
- *    n number of bytes
- */
-static int qemudClientWritePlain(struct qemud_client *client) {
-    int ret = qemudClientWriteBuf(client,
-                                  client->tx->buffer + client->tx->bufferOffset,
-                                  client->tx->bufferLength - client->tx->bufferOffset);
-    if (ret <= 0)
-        return ret; /* -1 error, 0 = egain */
-    client->tx->bufferOffset += ret;
-    return ret;
-}
-
-
-#if HAVE_SASL
-/*
- * Send client->tx using SASL encoding
- *
- * Returns:
- *   -1 on error
- *    0 on EAGAIN
- *    n number of bytes
- */
-static int qemudClientWriteSASL(struct qemud_client *client) {
-    int ret;
-
-    /* Not got any pending encoded data, so we need to encode raw stuff */
-    if (client->saslEncoded == NULL) {
-        ret = sasl_encode(client->saslconn,
-                          client->tx->buffer + client->tx->bufferOffset,
-                          client->tx->bufferLength - client->tx->bufferOffset,
-                          &client->saslEncoded,
-                          &client->saslEncodedLength);
-
-        if (ret != SASL_OK) {
-            VIR_ERROR(_("failed to encode SASL data %s"),
-                      sasl_errstring(ret, NULL, NULL));
-            qemudDispatchClientFailure(client);
-            return -1;
-        }
-
-        client->saslEncodedOffset = 0;
-    }
-
-    /* Send some of the encoded stuff out on the wire */
-    ret = qemudClientWriteBuf(client,
-                              client->saslEncoded + client->saslEncodedOffset,
-                              client->saslEncodedLength - client->saslEncodedOffset);
-
-    if (ret <= 0)
-        return ret; /* -1 error, 0 == egain */
-
-    /* Note how much we sent */
-    client->saslEncodedOffset += ret;
-
-    /* Sent all encoded, so update raw buffer to indicate completion */
-    if (client->saslEncodedOffset == client->saslEncodedLength) {
-        client->saslEncoded = NULL;
-        client->saslEncodedOffset = client->saslEncodedLength = 0;
-
-        /* Mark as complete, so caller detects completion */
-        client->tx->bufferOffset = client->tx->bufferLength;
-    }
-
-    return ret;
-}
-#endif
-
-/*
- * Send as much data in the client->tx as possible
- *
- * Returns:
- *   -1 on error or EOF
- *    0 on EAGAIN
- *    n number of bytes
- */
-static ssize_t qemudClientWrite(struct qemud_client *client) {
-#if HAVE_SASL
-    if (client->saslSSF & QEMUD_SASL_SSF_WRITE)
-        return qemudClientWriteSASL(client);
-    else
-#endif
-        return qemudClientWritePlain(client);
-}
-
-
-/*
- * Process all queued client->tx messages until
- * we would block on I/O
- */
-static void
-qemudDispatchClientWrite(struct qemud_client *client) {
-    while (client->tx) {
-        ssize_t ret;
-
-        ret = qemudClientWrite(client);
-        if (ret < 0) {
-            qemudDispatchClientFailure(client);
-            return;
-        }
-        if (ret == 0)
-            return; /* Would block on write EAGAIN */
-
-        if (client->tx->bufferOffset == client->tx->bufferLength) {
-            struct qemud_client_message *reply;
-
-            /* Get finished reply from head of tx queue */
-            reply = qemudClientMessageQueueServe(&client->tx);
-
-            /* If its not an async message, then we have
-             * just completed an RPC request */
-            if (!reply->async)
-                client->nrequests--;
-
-            /* Move record to end of 'rx' ist */
-            if (!client->rx &&
-                client->nrequests < max_client_requests) {
-                /* Reset message record for next RX attempt */
-                client->rx = reply;
-                client->rx->bufferOffset = 0;
-                client->rx->bufferLength = REMOTE_MESSAGE_HEADER_XDR_LEN;
-            } else {
-                VIR_FREE(reply);
-            }
-
-            if (client->closing)
-                qemudDispatchClientFailure(client);
-            else
-                qemudUpdateClientEvent(client);
-         }
-    }
-}
-
-static void
-qemudDispatchClientHandshake(struct qemud_client *client) {
-    int ret;
-    /* Continue the handshake. */
-    ret = gnutls_handshake (client->tlssession);
-    if (ret == 0) {
-        client->handshake = 0;
-
-        /* Finished.  Next step is to check the certificate. */
-        if (remoteCheckAccess (client) == -1)
-            qemudDispatchClientFailure(client);
-        else
-            qemudUpdateClientEvent(client);
-    } else if (ret == GNUTLS_E_AGAIN ||
-               ret == GNUTLS_E_INTERRUPTED) {
-        /* Carry on waiting for more handshake. Update
-           the events just in case handshake data flow
-           direction has changed */
-        qemudUpdateClientEvent (client);
-    } else {
-        /* Fatal error in handshake */
-        VIR_ERROR(_("TLS handshake failed: %s"),
-                  gnutls_strerror (ret));
-        qemudDispatchClientFailure(client);
-    }
-}
-
-static void
-qemudDispatchClientEvent(int watch, int fd, int events, void *opaque) {
-    struct qemud_server *server = (struct qemud_server *)opaque;
-    struct qemud_client *client = NULL;
-    int i;
-
-    virMutexLock(&server->lock);
-
-    for (i = 0 ; i < server->nclients ; i++) {
-        virMutexLock(&server->clients[i]->lock);
-        if (server->clients[i]->watch == watch) {
-            client = server->clients[i];
-            break;
-        }
-        virMutexUnlock(&server->clients[i]->lock);
-    }
-
-    virMutexUnlock(&server->lock);
-
-    if (!client) {
-        return;
-    }
-
-    if (client->fd != fd) {
-        virMutexUnlock(&client->lock);
-        return;
-    }
-
-    if (events & (VIR_EVENT_HANDLE_WRITABLE |
-                  VIR_EVENT_HANDLE_READABLE)) {
-        if (client->handshake) {
-            qemudDispatchClientHandshake(client);
-        } else {
-            if (events & VIR_EVENT_HANDLE_WRITABLE)
-                qemudDispatchClientWrite(client);
-            if (events & VIR_EVENT_HANDLE_READABLE)
-                qemudDispatchClientRead(server, client);
-        }
-    }
-
-    /* NB, will get HANGUP + READABLE at same time upon
-     * disconnect */
-    if (events & (VIR_EVENT_HANDLE_ERROR |
-                  VIR_EVENT_HANDLE_HANGUP))
-        qemudDispatchClientFailure(client);
-
-    virMutexUnlock(&client->lock);
-}
-
-
-/*
- * @client: a locked client object
- */
-static int
-qemudCalculateHandleMode(struct qemud_client *client) {
-    int mode = 0;
-
-    if (client->handshake) {
-        if (gnutls_record_get_direction (client->tlssession) == 0)
-            mode |= VIR_EVENT_HANDLE_READABLE;
-        else
-            mode |= VIR_EVENT_HANDLE_WRITABLE;
-    } else {
-        /* If there is a message on the rx queue then
-         * we're wanting more input */
-        if (client->rx)
-            mode |= VIR_EVENT_HANDLE_READABLE;
-
-        /* If there are one or more messages to send back to client,
-           then monitor for writability on socket */
-        if (client->tx)
-            mode |= VIR_EVENT_HANDLE_WRITABLE;
-    }
-
-    return mode;
-}
-
-/*
- * @server: a locked or unlocked server object
- * @client: a locked client object
- */
-int qemudRegisterClientEvent(struct qemud_server *server,
-                             struct qemud_client *client) {
-    int mode;
-
-    mode = qemudCalculateHandleMode(client);
-
-    if ((client->watch = virEventAddHandleImpl(client->fd,
-                                               mode,
-                                               qemudDispatchClientEvent,
-                                               server, NULL)) < 0)
-        return -1;
-
-    return 0;
-}
-
-/*
- * @client: a locked client object
- */
-void qemudUpdateClientEvent(struct qemud_client *client) {
-    int mode;
-
-    mode = qemudCalculateHandleMode(client);
-
-    virEventUpdateHandleImpl(client->watch, mode);
-}
-
-
-static void
-qemudDispatchServerEvent(int watch, int fd, int events, void *opaque) {
-    struct qemud_server *server = (struct qemud_server *)opaque;
-    struct qemud_socket *sock;
-
-    virMutexLock(&server->lock);
-
-    sock = server->sockets;
-
-    while (sock) {
-        if (sock->watch == watch)
-            break;
-
-        sock = sock->next;
-    }
-
-    if (sock && sock->fd == fd && events)
-        qemudDispatchServer(server, sock);
-
-    virMutexUnlock(&server->lock);
-}
-
-
-static int qemudOneLoop(void) {
-    sig_atomic_t errors;
-
-    if (virEventRunOnce() < 0)
-        return -1;
-
-    /* Check for any signal handling errors and log them. */
-    errors = sig_errors;
-    if (errors) {
-        char ebuf[1024];
-        sig_errors -= errors;
-        VIR_ERROR(_("Signal handler reported %d errors: last error: %s"),
-                  errors, virStrerror (sig_lasterrno, ebuf, sizeof ebuf));
-        return -1;
-    }
-
-    return 0;
-}
-
-static void qemudInactiveTimer(int timerid, void *data) {
-    struct qemud_server *server = (struct qemud_server *)data;
-
-    if (virStateActive() ||
-        server->clients) {
-        DEBUG0("Timer expired but still active, not shutting down");
-        virEventUpdateTimeoutImpl(timerid, -1);
-    } else {
-        DEBUG0("Timer expired and inactive, shutting down");
-        server->shutdown = 1;
-    }
-}
-
-static void qemudFreeClient(struct qemud_client *client) {
-    while (client->rx) {
-        struct qemud_client_message *msg
-            = qemudClientMessageQueueServe(&client->rx);
-        VIR_FREE(msg);
-    }
-    while (client->dx) {
-        struct qemud_client_message *msg
-            = qemudClientMessageQueueServe(&client->dx);
-        VIR_FREE(msg);
-    }
-    while (client->tx) {
-        struct qemud_client_message *msg
-            = qemudClientMessageQueueServe(&client->tx);
-        VIR_FREE(msg);
-    }
-
-    if (client->conn)
-        virConnectClose(client->conn);
-    virMutexDestroy(&client->lock);
-    VIR_FREE(client);
-}
-
-static int qemudRunLoop(struct qemud_server *server) {
-    int timerid = -1;
-    int ret = -1, i;
-    int timerActive = 0;
-
-    virMutexLock(&server->lock);
-
-    if (timeout > 0 &&
-        (timerid = virEventAddTimeoutImpl(-1,
-                                          qemudInactiveTimer,
-                                          server, NULL)) < 0) {
-        VIR_ERROR0(_("Failed to register shutdown timeout"));
-        return -1;
-    }
-
-    if (min_workers > max_workers)
-        max_workers = min_workers;
-
-    server->nworkers = max_workers;
-    if (VIR_ALLOC_N(server->workers, server->nworkers) < 0) {
-        VIR_ERROR0(_("Failed to allocate workers"));
-        return -1;
-    }
-
-    for (i = 0 ; i < min_workers ; i++) {
-        if (qemudStartWorker(server, &server->workers[i]) < 0)
-            goto cleanup;
-        server->nactiveworkers++;
-    }
-
-    for (;;) {
-        /* A shutdown timeout is specified, so check
-         * if any drivers have active state, if not
-         * shutdown after timeout seconds
-         */
-        if (timeout > 0) {
-            if (timerActive) {
-                if (server->clients) {
-                    DEBUG("Deactivating shutdown timer %d", timerid);
-                    virEventUpdateTimeoutImpl(timerid, -1);
-                    timerActive = 0;
-                }
-            } else {
-                if (!virStateActive() &&
-                    !server->clients) {
-                    DEBUG("Activating shutdown timer %d", timerid);
-                    virEventUpdateTimeoutImpl(timerid, timeout * 1000);
-                    timerActive = 1;
-                }
-            }
-        }
-
-        virMutexUnlock(&server->lock);
-        if (qemudOneLoop() < 0) {
-            virMutexLock(&server->lock);
-            DEBUG0("Loop iteration error, exiting\n");
-            break;
-        }
-        virMutexLock(&server->lock);
-
-    reprocess:
-        for (i = 0 ; i < server->nclients ; i++) {
-            int inactive;
-            virMutexLock(&server->clients[i]->lock);
-            inactive = server->clients[i]->fd == -1
-                && server->clients[i]->refs == 0;
-            virMutexUnlock(&server->clients[i]->lock);
-            if (inactive) {
-                qemudFreeClient(server->clients[i]);
-                server->nclients--;
-                if (i < server->nclients)
-                    memmove(server->clients + i,
-                            server->clients + i + 1,
-                            sizeof (*server->clients) * (server->nclients - i));
-
-                if (VIR_REALLOC_N(server->clients,
-                                  server->nclients) < 0) {
-                    ; /* ignore */
-                }
-                goto reprocess;
-            }
-        }
-
-        /* If number of active workers exceeds both the min_workers
-         * threshold and the number of clients, then kill some
-         * off */
-        for (i = 0 ; (i < server->nworkers &&
-                      server->nactiveworkers > server->nclients &&
-                      server->nactiveworkers > min_workers) ; i++) {
-
-            if (server->workers[i].hasThread &&
-                !server->workers[i].processingCall) {
-                server->workers[i].quitRequest = 1;
-
-                virCondBroadcast(&server->job);
-                virMutexUnlock(&server->lock);
-                pthread_join(server->workers[i].thread, NULL);
-                virMutexLock(&server->lock);
-                server->workers[i].hasThread = 0;
-                server->nactiveworkers--;
-            }
-        }
-
-        if (server->shutdown) {
-            ret = 0;
-            break;
-        }
-    }
-
-cleanup:
-    for (i = 0 ; i < server->nworkers ; i++) {
-        if (!server->workers[i].hasThread)
-            continue;
-
-        server->workers[i].quitRequest = 1;
-        virCondBroadcast(&server->job);
-
-        virMutexUnlock(&server->lock);
-        pthread_join(server->workers[i].thread, NULL);
-        virMutexLock(&server->lock);
-        server->workers[i].hasThread = 0;
-    }
-    VIR_FREE(server->workers);
-
-    free(server->workers);
-    virMutexUnlock(&server->lock);
-    return ret;
-}
-
-static void qemudCleanup(struct qemud_server *server) {
-    struct qemud_socket *sock;
-
-    close(server->sigread);
-
-    sock = server->sockets;
-    while (sock) {
-        struct qemud_socket *next = sock->next;
-        close(sock->fd);
-        free(sock);
-        sock = next;
-    }
-    free(server->logDir);
-
-#ifdef HAVE_SASL
-    if (server->saslUsernameWhitelist) {
-        char **list = server->saslUsernameWhitelist;
-        while (*list) {
-            free(*list);
-            list++;
-        }
-        free(server->saslUsernameWhitelist);
-    }
-#endif
-
-    virStateCleanup();
-
-    if (virCondDestroy(&server->job) < 0) {
-        ;
-    }
-    virMutexDestroy(&server->lock);
-
-    VIR_FREE(server);
-}
-
-/* Allocate an array of malloc'd strings from the config file, filename
- * (used only in diagnostics), using handle "conf".  Upon error, return -1
- * and free any allocated memory.  Otherwise, save the array in *list_arg
- * and return 0.
- */
-static int
-remoteConfigGetStringList(virConfPtr conf, const char *key, char ***list_arg,
-                          const char *filename)
-{
-    char **list;
-    virConfValuePtr p = virConfGetValue (conf, key);
-    if (!p)
-        return 0;
-
-    switch (p->type) {
-    case VIR_CONF_STRING:
-        if (VIR_ALLOC_N(list, 2) < 0) {
-            VIR_ERROR(_("failed to allocate memory for %s config list"), key);
-            return -1;
-        }
-        list[0] = strdup (p->str);
-        list[1] = NULL;
-        if (list[0] == NULL) {
-            VIR_ERROR(_("failed to allocate memory for %s config list value"),
-                      key);
-            VIR_FREE(list);
-            return -1;
-        }
-        break;
-
-    case VIR_CONF_LIST: {
-        int i, len = 0;
-        virConfValuePtr pp;
-        for (pp = p->list; pp; pp = pp->next)
-            len++;
-        if (VIR_ALLOC_N(list, 1+len) < 0) {
-            VIR_ERROR(_("failed to allocate memory for %s config list"), key);
-            return -1;
-        }
-        for (i = 0, pp = p->list; pp; ++i, pp = pp->next) {
-            if (pp->type != VIR_CONF_STRING) {
-                VIR_ERROR(_("remoteReadConfigFile: %s: %s:"
-                            " must be a string or list of strings\n"),
-                          filename, key);
-                VIR_FREE(list);
-                return -1;
-            }
-            list[i] = strdup (pp->str);
-            if (list[i] == NULL) {
-                int j;
-                for (j = 0 ; j < i ; j++)
-                    VIR_FREE(list[j]);
-                VIR_FREE(list);
-                VIR_ERROR(_("failed to allocate memory for %s config list value"),
-                          key);
-                return -1;
-            }
-
-        }
-        list[i] = NULL;
-        break;
-    }
-
-    default:
-        VIR_ERROR(_("remoteReadConfigFile: %s: %s:"
-                    " must be a string or list of strings\n"),
-                  filename, key);
-        return -1;
-    }
-
-    *list_arg = list;
-    return 0;
-}
-
-/* A helper function used by each of the following macros.  */
-static int
-checkType (virConfValuePtr p, const char *filename,
-           const char *key, virConfType required_type)
-{
-    if (p->type != required_type) {
-        VIR_ERROR(_("remoteReadConfigFile: %s: %s: invalid type:"
-                    " got %s; expected %s\n"), filename, key,
-                  virConfTypeName (p->type),
-                  virConfTypeName (required_type));
-        return -1;
-    }
-    return 0;
-}
-
-/* If there is no config data for the key, #var_name, then do nothing.
-   If there is valid data of type VIR_CONF_STRING, and strdup succeeds,
-   store the result in var_name.  Otherwise, (i.e. invalid type, or strdup
-   failure), give a diagnostic and "goto" the cleanup-and-fail label.  */
-#define GET_CONF_STR(conf, filename, var_name)                          \
-    do {                                                                \
-        virConfValuePtr p = virConfGetValue (conf, #var_name);          \
-        if (p) {                                                        \
-            if (checkType (p, filename, #var_name, VIR_CONF_STRING) < 0) \
-                goto free_and_fail;                                     \
-            (var_name) = strdup (p->str);                               \
-            if ((var_name) == NULL) {                                   \
-                char ebuf[1024];                                        \
-                VIR_ERROR(_("remoteReadConfigFile: %s\n"),             \
-                          virStrerror(errno, ebuf, sizeof ebuf));       \
-                goto free_and_fail;                                     \
-            }                                                           \
-        }                                                               \
-    } while (0)
-
-/* Like GET_CONF_STR, but for integral values.  */
-#define GET_CONF_INT(conf, filename, var_name)                          \
-    do {                                                                \
-        virConfValuePtr p = virConfGetValue (conf, #var_name);          \
-        if (p) {                                                        \
-            if (checkType (p, filename, #var_name, VIR_CONF_LONG) < 0)  \
-                goto free_and_fail;                                     \
-            (var_name) = p->l;                                          \
-        }                                                               \
-    } while (0)
-
-
-static int remoteConfigGetAuth(virConfPtr conf, const char *key, int *auth, const char *filename) {
-    virConfValuePtr p;
-
-    p = virConfGetValue (conf, key);
-    if (!p)
-        return 0;
-
-    if (checkType (p, filename, key, VIR_CONF_STRING) < 0)
-        return -1;
-
-    if (!p->str)
-        return 0;
-
-    if (STREQ(p->str, "none")) {
-        *auth = REMOTE_AUTH_NONE;
-#if HAVE_SASL
-    } else if (STREQ(p->str, "sasl")) {
-        *auth = REMOTE_AUTH_SASL;
-#endif
-#if HAVE_POLKIT
-    } else if (STREQ(p->str, "polkit")) {
-        *auth = REMOTE_AUTH_POLKIT;
-#endif
-    } else {
-        VIR_ERROR(_("remoteReadConfigFile: %s: %s: unsupported auth %s\n"),
-                  filename, key, p->str);
-        return -1;
-    }
-
-    return 0;
-}
-
-#ifdef HAVE_SASL
-static inline int
-remoteReadSaslAllowedUsernameList (virConfPtr conf,
-                                   struct qemud_server *server,
-                                   const char *filename)
-{
-    return
-        remoteConfigGetStringList (conf, "sasl_allowed_username_list",
-                                   &server->saslUsernameWhitelist, filename);
-}
-#else
-static inline int
-remoteReadSaslAllowedUsernameList (virConfPtr conf ATTRIBUTE_UNUSED,
-                                   struct qemud_server *server ATTRIBUTE_UNUSED,
-                                   const char *filename ATTRIBUTE_UNUSED)
-{
-    return 0;
-}
-#endif
-
-/*
- * Set up the logging environment
- * By default if daemonized all errors go to syslog and the logging
- * is also saved onto the logfile libvird.log, but if verbose or error
- * debugging is asked for then output informations or debug.
- */
-static int
-qemudSetLogging(virConfPtr conf, const char *filename) {
-    int log_level;
-    char *log_filters = NULL;
-    char *log_outputs = NULL;
-    int ret = -1;
-
-    virLogReset();
-
-    /*
-     * Libvirtd's order of precedence is:
-     * cmdline > environment > config
-     *
-     * In order to achieve this, we must process configuration in
-     * different order for the log level versus the filters and
-     * outputs. Because filters and outputs append, we have to look at
-     * the environment first and then only check the config file if
-     * there was no result from the environment. The default output is
-     * then applied only if there was no setting from either of the
-     * first two. Because we don't have a way to determine if the log
-     * level has been set, we must process variables in the opposite
-     * order, each one overriding the previous.
-     */
-    /*
-     * GET_CONF_INT returns 0 when there is no log_level setting in
-     * the config file. The conditional below eliminates a false
-     * warning in that case, but also has the side effect of missing
-     * a warning if the user actually does say log_level=0.
-     */
-    GET_CONF_INT (conf, filename, log_level);
-    if (log_level != 0)
-        virLogSetDefaultPriority(log_level);
-
-    virLogSetFromEnv();
-
-    if (virLogGetNbFilters() == 0) {
-        GET_CONF_STR (conf, filename, log_filters);
-        virLogParseFilters(log_filters);
-    }
-
-    if (virLogGetNbOutputs() == 0) {
-        GET_CONF_STR (conf, filename, log_outputs);
-        virLogParseOutputs(log_outputs);
-    }
-
-    /*
-     * If no defined outputs, then direct to syslog when running
-     * as daemon. Otherwise the default output is stderr.
-     */
-    if (virLogGetNbOutputs() == 0) {
-        char *tmp = NULL;
-        if (godaemon) {
-            if (virAsprintf (&tmp, "%d:syslog:libvirtd",
-                             virLogGetDefaultPriority()) < 0)
-                goto free_and_fail;
-        } else {
-            if (virAsprintf (&tmp, "%d:stderr",
-                             virLogGetDefaultPriority()) < 0)
-                goto free_and_fail;
-        }
-        virLogParseOutputs(tmp);
-        VIR_FREE(tmp);
-    }
-
-    /*
-     * Command line override for --verbose
-     */
-    if ((verbose) && (virLogGetDefaultPriority() > VIR_LOG_INFO))
-        virLogSetDefaultPriority(VIR_LOG_INFO);
-
-    ret = 0;
-
-free_and_fail:
-    VIR_FREE(log_filters);
-    VIR_FREE(log_outputs);
-    return(ret);
-}
-
-/* Read the config file if it exists.
- * Only used in the remote case, hence the name.
- */
-static int
-remoteReadConfigFile (struct qemud_server *server, const char *filename)
-{
-    virConfPtr conf;
-
-    /* The following variable names must match the corresponding
-       configuration strings.  */
-    char *unix_sock_ro_perms = NULL;
-    char *unix_sock_rw_perms = NULL;
-    char *unix_sock_group = NULL;
-    char *buf = NULL;
-
-#if HAVE_POLKIT
-    /* Change the default back to no auth for non-root */
-    if (!server->privileged && auth_unix_rw == REMOTE_AUTH_POLKIT)
-        auth_unix_rw = REMOTE_AUTH_NONE;
-    if (!server->privileged && auth_unix_ro == REMOTE_AUTH_POLKIT)
-        auth_unix_ro = REMOTE_AUTH_NONE;
-#endif
-
-    conf = virConfReadFile (filename, 0);
-    if (!conf) return -1;
-
-    /*
-     * First get all the logging settings and activate them
-     */
-    if (qemudSetLogging(conf, filename) < 0)
-        goto free_and_fail;
-
-    GET_CONF_INT (conf, filename, listen_tcp);
-    GET_CONF_INT (conf, filename, listen_tls);
-    GET_CONF_STR (conf, filename, tls_port);
-    GET_CONF_STR (conf, filename, tcp_port);
-    GET_CONF_STR (conf, filename, listen_addr);
-
-    if (remoteConfigGetAuth(conf, "auth_unix_rw", &auth_unix_rw, filename) < 0)
-        goto free_and_fail;
-#if HAVE_POLKIT
-    /* Change default perms to be wide-open if PolicyKit is enabled.
-     * Admin can always override in config file
-     */
-    if (auth_unix_rw == REMOTE_AUTH_POLKIT)
-        unix_sock_rw_mask = 0777;
-#endif
-    if (remoteConfigGetAuth(conf, "auth_unix_ro", &auth_unix_ro, filename) < 0)
-        goto free_and_fail;
-    if (remoteConfigGetAuth(conf, "auth_tcp", &auth_tcp, filename) < 0)
-        goto free_and_fail;
-    if (remoteConfigGetAuth(conf, "auth_tls", &auth_tls, filename) < 0)
-        goto free_and_fail;
-
-    GET_CONF_STR (conf, filename, unix_sock_group);
-    if (unix_sock_group) {
-        if (!server->privileged) {
-            VIR_WARN0(_("Cannot set group when not running as root"));
-        } else {
-            int ret;
-            struct group grpdata, *grp;
-            size_t maxbuf = sysconf(_SC_GETGR_R_SIZE_MAX);
-
-            if (maxbuf == -1)
-                maxbuf = 1024;
-
-            if (VIR_ALLOC_N(buf, maxbuf) < 0) {
-                VIR_ERROR("%s", _("Failed to allocate memory for buffer"));
-                goto free_and_fail;
-            }
-
-            while ((ret = getgrnam_r(unix_sock_group, &grpdata,
-                                     buf, maxbuf,
-                                     &grp)) == ERANGE) {
-                    maxbuf *= 2;
-                    if (maxbuf > 65536 || VIR_REALLOC_N(buf, maxbuf) < 0) {
-                        VIR_ERROR("%s", _("Failed to reallocate enough memory for buffer"));
-                        goto free_and_fail;
-                    }
-            }
-
-            if (ret != 0 || !grp) {
-                VIR_ERROR(_("Failed to lookup group '%s'"), unix_sock_group);
-                goto free_and_fail;
-            }
-            unix_sock_gid = grp->gr_gid;
-            VIR_FREE (buf);
-        }
-        free (unix_sock_group);
-        unix_sock_group = NULL;
-    }
-
-    GET_CONF_STR (conf, filename, unix_sock_ro_perms);
-    if (unix_sock_ro_perms) {
-        if (virStrToLong_i (unix_sock_ro_perms, NULL, 8, &unix_sock_ro_mask) != 0) {
-            VIR_ERROR(_("Failed to parse mode '%s'"), unix_sock_ro_perms);
-            goto free_and_fail;
-        }
-        free (unix_sock_ro_perms);
-        unix_sock_ro_perms = NULL;
-    }
-
-    GET_CONF_STR (conf, filename, unix_sock_rw_perms);
-    if (unix_sock_rw_perms) {
-        if (virStrToLong_i (unix_sock_rw_perms, NULL, 8, &unix_sock_rw_mask) != 0) {
-            VIR_ERROR(_("Failed to parse mode '%s'"), unix_sock_rw_perms);
-            goto free_and_fail;
-        }
-        free (unix_sock_rw_perms);
-        unix_sock_rw_perms = NULL;
-    }
-
-    GET_CONF_STR (conf, filename, unix_sock_dir);
-
-    GET_CONF_INT (conf, filename, mdns_adv);
-    GET_CONF_STR (conf, filename, mdns_name);
-
-    GET_CONF_INT (conf, filename, tls_no_verify_certificate);
-
-    GET_CONF_STR (conf, filename, key_file);
-    GET_CONF_STR (conf, filename, cert_file);
-    GET_CONF_STR (conf, filename, ca_file);
-    GET_CONF_STR (conf, filename, crl_file);
-
-    if (remoteConfigGetStringList (conf, "tls_allowed_dn_list",
-                                   &tls_allowed_dn_list, filename) < 0)
-        goto free_and_fail;
-
-    if (remoteReadSaslAllowedUsernameList (conf, server, filename) < 0)
-        goto free_and_fail;
-
-
-    GET_CONF_INT (conf, filename, min_workers);
-    GET_CONF_INT (conf, filename, max_workers);
-    GET_CONF_INT (conf, filename, max_clients);
-
-    GET_CONF_INT (conf, filename, max_requests);
-    GET_CONF_INT (conf, filename, max_client_requests);
-
-    virConfFree (conf);
-    return 0;
-
- free_and_fail:
-    virConfFree (conf);
-    free (mdns_name);
-    mdns_name = NULL;
-    free (unix_sock_ro_perms);
-    free (unix_sock_rw_perms);
-    free (unix_sock_group);
-    VIR_FREE (buf);
-
-    /* Don't bother trying to free listen_addr, tcp_port, tls_port, key_file,
-       cert_file, ca_file, or crl_file, since they are initialized to
-       non-malloc'd strings.  Besides, these are static variables, and callers
-       are unlikely to call this function more than once, so there wouldn't
-       even be a real leak.  */
-
-    if (tls_allowed_dn_list) {
-        int i;
-        for (i = 0; tls_allowed_dn_list[i]; i++)
-            free (tls_allowed_dn_list[i]);
-        free (tls_allowed_dn_list);
-        tls_allowed_dn_list = NULL;
-    }
-
-    return -1;
-}
-
-/* Display version information. */
-static void
-version (const char *argv0)
-{
-    printf ("%s (%s) %s\n", argv0, PACKAGE_NAME, PACKAGE_VERSION);
-}
-
-#ifdef __sun
-static int
-qemudSetupPrivs (void)
-{
-    chown ("/var/run/libvirt", SYSTEM_UID, SYSTEM_UID);
-
-    if (__init_daemon_priv (PU_RESETGROUPS | PU_CLEARLIMITSET,
-        SYSTEM_UID, SYSTEM_UID, PRIV_XVM_CONTROL, NULL)) {
-        VIR_ERROR0(_("additional privileges are required\n"));
-        return -1;
-    }
-
-    if (priv_set (PRIV_OFF, PRIV_ALLSETS, PRIV_FILE_LINK_ANY, PRIV_PROC_INFO,
-        PRIV_PROC_SESSION, PRIV_PROC_EXEC, PRIV_PROC_FORK, NULL)) {
-        VIR_ERROR0(_("failed to set reduced privileges\n"));
-        return -1;
-    }
-
-    return 0;
-}
-#else
-#define qemudSetupPrivs() 0
-#endif
-
-/* Print command-line usage. */
-static void
-usage (const char *argv0)
-{
-    fprintf (stderr,
-             "\n\
-Usage:\n\
-  %s [options]\n\
-\n\
-Options:\n\
-  -v | --verbose         Verbose messages.\n\
-  -d | --daemon          Run as a daemon & write PID file.\n\
-  -l | --listen          Listen for TCP/IP connections.\n\
-  -t | --timeout <secs>  Exit after timeout period.\n\
-  -f | --config <file>   Configuration file.\n\
-     | --version         Display version information.\n\
-  -p | --pid-file <file> Change name of PID file.\n\
-\n\
-libvirt management daemon:\n\
-\n\
-  Default paths:\n\
-\n\
-    Configuration file (unless overridden by -c):\n\
-      " SYSCONF_DIR "/libvirt/libvirtd.conf\n\
-\n\
-    Sockets (as root):\n\
-      " LOCAL_STATE_DIR "/run/libvirt/libvirt-sock\n\
-      " LOCAL_STATE_DIR "/run/libvirt/libvirt-sock-ro\n\
-\n\
-    Sockets (as non-root):\n\
-      $HOME/.libvirt/libvirt-sock (in UNIX abstract namespace)\n\
-\n\
-    TLS:\n\
-      CA certificate:     " LIBVIRT_CACERT "\n\
-      Server certificate: " LIBVIRT_SERVERCERT "\n\
-      Server private key: " LIBVIRT_SERVERKEY "\n\
-\n\
-    PID file (unless overridden by --pid-file):\n\
-      %s\n\
-\n",
-             argv0,
-             REMOTE_PID_FILE[0] != '\0'
-               ? REMOTE_PID_FILE
-               : "(disabled in ./configure)");
-}
-
-enum {
-    OPT_VERSION = 129
-};
-
-#define MAX_LISTEN 5
-int main(int argc, char **argv) {
-    struct qemud_server *server = NULL;
-    struct sigaction sig_action;
-    int sigpipe[2];
-    const char *pid_file = NULL;
-    const char *remote_config_file = NULL;
-    int ret = 1;
-
-    struct option opts[] = {
-        { "verbose", no_argument, &verbose, 1},
-        { "daemon", no_argument, &godaemon, 1},
-        { "listen", no_argument, &ipsock, 1},
-        { "config", required_argument, NULL, 'f'},
-        { "timeout", required_argument, NULL, 't'},
-        { "pid-file", required_argument, NULL, 'p'},
-        { "version", no_argument, NULL, OPT_VERSION },
-        { "help", no_argument, NULL, '?' },
-        {0, 0, 0, 0}
-    };
-
-    while (1) {
-        int optidx = 0;
-        int c;
-        char *tmp;
-
-        c = getopt_long(argc, argv, "ldf:p:t:v", opts, &optidx);
-
-        if (c == -1) {
-            break;
-        }
-
-        switch (c) {
-        case 0:
-            /* Got one of the flags */
-            break;
-        case 'v':
-            verbose = 1;
-            break;
-        case 'd':
-            godaemon = 1;
-            break;
-        case 'l':
-            ipsock = 1;
-            break;
-
-        case 't':
-            if (virStrToLong_i(optarg, &tmp, 10, &timeout) != 0
-                || timeout <= 0
-                /* Ensure that we can multiply by 1000 without overflowing.  */
-                || timeout > INT_MAX / 1000)
-                timeout = -1;
-            break;
-
-        case 'p':
-            pid_file = optarg;
-            break;
-
-        case 'f':
-            remote_config_file = optarg;
-            break;
-
-        case OPT_VERSION:
-            version (argv[0]);
-            return 0;
-
-        case '?':
-            usage (argv[0]);
-            return 2;
-
-        default:
-            fprintf (stderr, "libvirtd: internal error: unknown flag: %c\n",
-                     c);
-            exit (1);
-        }
-    }
-
-    if (remote_config_file == NULL) {
-        static const char *default_config_file
-            = SYSCONF_DIR "/libvirt/libvirtd.conf";
-        remote_config_file =
-            (access(default_config_file, R_OK) == 0
-             ? default_config_file
-             : "/dev/null");
-    }
-
-    if (godaemon) {
-        char ebuf[1024];
-        if (qemudGoDaemon() < 0) {
-            VIR_ERROR(_("Failed to fork as daemon: %s"),
-                      virStrerror(errno, ebuf, sizeof ebuf));
-            goto error1;
-        }
-    }
-
-    /* If running as root and no PID file is set, use the default */
-    if (pid_file == NULL &&
-        geteuid() == 0 &&
-        REMOTE_PID_FILE[0] != '\0')
-        pid_file = REMOTE_PID_FILE;
-
-    /* If we have a pidfile set, claim it now, exiting if already taken */
-    if (pid_file != NULL &&
-        qemudWritePidFile (pid_file) < 0)
-        goto error1;
-
-    if (pipe(sigpipe) < 0 ||
-        virSetNonBlock(sigpipe[0]) < 0 ||
-        virSetNonBlock(sigpipe[1]) < 0 ||
-        virSetCloseExec(sigpipe[0]) < 0 ||
-        virSetCloseExec(sigpipe[1]) < 0) {
-        char ebuf[1024];
-        VIR_ERROR(_("Failed to create pipe: %s"),
-                  virStrerror(errno, ebuf, sizeof ebuf));
-        goto error2;
-    }
-    sigwrite = sigpipe[1];
-
-    sig_action.sa_sigaction = sig_handler;
-    sig_action.sa_flags = SA_SIGINFO;
-    sigemptyset(&sig_action.sa_mask);
-
-    sigaction(SIGHUP, &sig_action, NULL);
-    sigaction(SIGINT, &sig_action, NULL);
-    sigaction(SIGQUIT, &sig_action, NULL);
-    sigaction(SIGTERM, &sig_action, NULL);
-    sigaction(SIGCHLD, &sig_action, NULL);
-
-    sig_action.sa_handler = SIG_IGN;
-    sigaction(SIGPIPE, &sig_action, NULL);
-
-    /* Ensure the rundir exists (on tmpfs on some systems) */
-    if (geteuid() == 0) {
-        const char *rundir = LOCAL_STATE_DIR "/run/libvirt";
-
-        if (mkdir (rundir, 0755)) {
-            if (errno != EEXIST) {
-                VIR_ERROR0 (_("unable to create rundir"));
-                return -1;
-            }
-        }
-    }
-
-    /* Beyond this point, nothing should rely on using
-     * getuid/geteuid() == 0, for privilege level checks.
-     * It must all use the flag 'server->privileged'
-     * which is also passed into all libvirt stateful
-     * drivers
-     */
-    if (qemudSetupPrivs() < 0)
-        goto error2;
-
-    if (!(server = qemudInitialize(sigpipe[0]))) {
-        ret = 2;
-        goto error2;
-    }
-
-    /* Read the config file (if it exists). */
-    if (remoteReadConfigFile (server, remote_config_file) < 0)
-        goto error2;
-
-    /* Change the group ownership of /var/run/libvirt to unix_sock_gid */
-    if (unix_sock_dir && server->privileged) {
-        if (chown(unix_sock_dir, -1, unix_sock_gid) < 0)
-            VIR_ERROR(_("Failed to change group ownership of %s"),
-                      unix_sock_dir);
-    }
-
-    if (virEventAddHandleImpl(sigpipe[0],
-                              VIR_EVENT_HANDLE_READABLE,
-                              qemudDispatchSignalEvent,
-                              server, NULL) < 0) {
-        VIR_ERROR0(_("Failed to register callback for signal pipe"));
-        ret = 3;
-        goto error2;
-    }
-
-    if (!(server = qemudNetworkInit(server))) {
-        ret = 2;
-        goto error2;
-    }
-
-    qemudRunLoop(server);
-
-    ret = 0;
-
-error2:
-    if (server)
-        qemudCleanup(server);
-    if (pid_file)
-        unlink (pid_file);
-    close(sigwrite);
-
-error1:
-    virLogShutdown();
-    return ret;
-}
diff --git a/daemon/qemud.h b/daemon/qemud.h
deleted file mode 100644 (file)
index e8ce209..0000000
+++ /dev/null
@@ -1,284 +0,0 @@
-/*
- * qemud.h: daemon data structure definitions
- *
- * Copyright (C) 2006-2009 Red Hat, Inc.
- * Copyright (C) 2006 Daniel P. Berrange
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
- *
- * Author: Daniel P. Berrange <berrange@redhat.com>
- */
-
-
-#ifndef QEMUD_INTERNAL_H__
-#define QEMUD_INTERNAL_H__
-
-#include <config.h>
-
-#include <gnutls/gnutls.h>
-#include <gnutls/x509.h>
-#include "gnutls_1_0_compat.h"
-#if HAVE_SASL
-#include <sasl/sasl.h>
-#endif
-
-#if HAVE_POLKIT0
-#include <dbus/dbus.h>
-#endif
-
-#ifdef HAVE_SYS_SYSLIMITS_H
-#include <sys/syslimits.h>
-#endif
-
-#include <rpc/types.h>
-#include <rpc/xdr.h>
-#include "remote_protocol.h"
-#include "logging.h"
-#include "threads.h"
-
-#ifdef __GNUC__
-#ifdef HAVE_ANSIDECL_H
-#include <ansidecl.h>
-#endif
-
-#ifndef __GNUC_PREREQ
-#if defined __GNUC__ && defined __GNUC_MINOR__
-# define __GNUC_PREREQ(maj, min)                                        \
-    ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
-#else
-#define __GNUC_PREREQ(maj,min) 0
-#endif
-#endif
-
-/**
- * ATTRIBUTE_UNUSED:
- *
- * Macro to flag conciously unused parameters to functions
- */
-#ifndef ATTRIBUTE_UNUSED
-#define ATTRIBUTE_UNUSED __attribute__((__unused__))
-#endif
-
-/**
- * ATTRIBUTE_FMT_PRINTF
- *
- * Macro used to check printf like functions, if compiling
- * with gcc.
- *
- * We use gnulib which guarentees we always have GNU style
- * printf format specifiers even on broken Win32 platforms
- * hence we have to force 'gnu_printf' for new GCC
- */
-#ifndef ATTRIBUTE_FMT_PRINTF
-#if __GNUC_PREREQ (4, 4)
-#define ATTRIBUTE_FMT_PRINTF(fmtpos,argpos) __attribute__((__format__ (gnu_printf, fmtpos,argpos)))
-#else
-#define ATTRIBUTE_FMT_PRINTF(fmtpos,argpos) __attribute__((__format__ (printf, fmtpos,argpos)))
-#endif
-#endif
-
-#ifndef ATTRIBUTE_RETURN_CHECK
-#if __GNUC_PREREQ (3, 4)
-#define ATTRIBUTE_RETURN_CHECK __attribute__((__warn_unused_result__))
-#else
-#define ATTRIBUTE_RETURN_CHECK
-#endif
-#endif
-
-#else
-#ifndef ATTRIBUTE_UNUSED
-#define ATTRIBUTE_UNUSED
-#endif
-#ifndef ATTRIBUTE_FMT_PRINTF
-#define ATTRIBUTE_FMT_PRINTF(...)
-#endif
-#ifndef ATTRIBUTE_RETURN_CHECK
-#define ATTRIBUTE_RETURN_CHECK
-#endif
-#endif
-
-#define qemudDebug DEBUG
-
-/* Whether we're passing reads & writes through a sasl SSF */
-enum qemud_sasl_ssf {
-    QEMUD_SASL_SSF_NONE = 0,
-    QEMUD_SASL_SSF_READ = 1,
-    QEMUD_SASL_SSF_WRITE = 2,
-};
-
-enum qemud_sock_type {
-    QEMUD_SOCK_TYPE_UNIX = 0,
-    QEMUD_SOCK_TYPE_TCP = 1,
-    QEMUD_SOCK_TYPE_TLS = 2,
-};
-
-struct qemud_client_message {
-    char buffer [REMOTE_MESSAGE_MAX + REMOTE_MESSAGE_HEADER_XDR_LEN];
-    unsigned int bufferLength;
-    unsigned int bufferOffset;
-
-    int async : 1;
-
-    remote_message_header hdr;
-
-    struct qemud_client_message *next;
-};
-
-/* Allow for filtering of incoming messages to a custom
- * dispatch processing queue, instead of client->dx.
- */
-typedef int (*qemud_client_filter_func)(struct qemud_client_message *msg, void *opaque);
-struct qemud_client_filter {
-    qemud_client_filter_func query;
-    void *opaque;
-
-    struct qemud_client_message *dx;
-
-    struct qemud_client_filter *next;
-};
-
-/* Stores the per-client connection state */
-struct qemud_client {
-    virMutex lock;
-
-    int magic;
-
-    int fd;
-    int watch;
-    int readonly:1;
-    int closing:1;
-
-    struct sockaddr_storage addr;
-    socklen_t addrlen;
-
-    int type; /* qemud_sock_type */
-    gnutls_session_t tlssession;
-    int auth;
-    int handshake : 1; /* If we're in progress for TLS handshake */
-#if HAVE_SASL
-    sasl_conn_t *saslconn;
-    int saslSSF;
-    const char *saslDecoded;
-    unsigned int saslDecodedLength;
-    unsigned int saslDecodedOffset;
-    const char *saslEncoded;
-    unsigned int saslEncodedLength;
-    unsigned int saslEncodedOffset;
-    char *saslUsername;
-#endif
-
-    /* Count of meages in 'dx' or 'tx' queue
-     * ie RPC calls in progress. Does not count
-     * async events which are not used for
-     * throttling calculations */
-    int nrequests;
-    /* Zero or one messages being received. Zero if
-     * nrequests >= max_clients and throttling */
-    struct qemud_client_message *rx;
-    /* Zero or many messages waiting for a worker
-     * to process them */
-    struct qemud_client_message *dx;
-    /* Zero or many messages waiting for transmit
-     * back to client, including async events */
-    struct qemud_client_message *tx;
-    /* Filters to capture messages that would otherwise
-     * end up on the 'dx' queue */
-    struct qemud_client_filter *filters;
-
-    /* This is only valid if a remote open call has been made on this
-     * connection, otherwise it will be NULL.  Also if remote close is
-     * called, it will be set back to NULL if that succeeds.
-     */
-    virConnectPtr conn;
-    int refs;
-
-};
-
-#define QEMUD_CLIENT_MAGIC 0x7788aaee
-
-
-struct qemud_socket {
-    int fd;
-    int watch;
-    int readonly;
-    int type; /* qemud_sock_type */
-    int auth;
-    int port;
-    struct qemud_socket *next;
-};
-
-struct qemud_worker {
-    pthread_t thread;
-    int hasThread :1;
-    int processingCall :1;
-    int quitRequest : 1;
-
-    /* back-pointer to our server */
-    struct qemud_server *server;
-};
-
-/* Main server state */
-struct qemud_server {
-    virMutex lock;
-    virCond job;
-
-    int privileged;
-
-    int nworkers;
-    int nactiveworkers;
-    struct qemud_worker *workers;
-    int nsockets;
-    struct qemud_socket *sockets;
-    int nclients;
-    struct qemud_client **clients;
-
-    int sigread;
-    char *logDir;
-    unsigned int shutdown : 1;
-#ifdef HAVE_AVAHI
-    struct libvirtd_mdns *mdns;
-#endif
-#if HAVE_SASL
-    char **saslUsernameWhitelist;
-#endif
-#if HAVE_POLKIT0
-    DBusConnection *sysbus;
-#endif
-};
-
-void qemudLog(int priority, const char *fmt, ...)
-    ATTRIBUTE_FMT_PRINTF(2,3);
-
-
-
-int qemudRegisterClientEvent(struct qemud_server *server,
-                             struct qemud_client *client);
-void qemudUpdateClientEvent(struct qemud_client *client);
-
-void qemudDispatchClientFailure(struct qemud_client *client);
-
-void
-qemudClientMessageQueuePush(struct qemud_client_message **queue,
-                            struct qemud_client_message *msg);
-struct qemud_client_message *
-qemudClientMessageQueueServe(struct qemud_client_message **queue);
-
-
-
-#if HAVE_POLKIT
-int qemudGetSocketIdentity(int fd, uid_t *uid, pid_t *pid);
-#endif
-
-#endif
index e3ee6964cc40d614dab9813e7d710eba19c4dc7c..5df601bb9b973d94bfe36d59acc7658b04f351b5 100644 (file)
@@ -25,7 +25,7 @@
 #define __LIBVIRTD_REMOTE_H__
 
 
-#include "qemud.h"
+#include "libvirtd.h"
 
 typedef union {
 #include "remote_dispatch_args.h"