[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[libvirt] [PATCH 2/4] Convert libvirtd over to the new RPC handling APIs



This guts the libvirtd daemon, removing all its networking and
RPC handling code. Instead it calls out to the new virServerPtr
APIs for all its RPC & networking work

As a fallout all libvirtd daemon error reporting now takes place
via the normal internal error reporting APIs. There is no need
to call separate error reporting APIs in RPC code, nor should
code use VIR_WARN/VIR_ERROR for reporting fatal problems anymore.

* daemon/qemu_dispatch_*.h, daemon/remote_dispatch_*.h: Remove
  old generated dispatcher code
* daemon/qemu_dispatch.h, daemon/remote_dispatch.h: New dispatch
  code
* daemon/dispatch.c, daemon/dispatch.h: Remove obsoleted code
* daemon/remote.c, daemon/remote.h: Rewrite for new dispatch
  APIs
* daemon/libvirtd.c, daemon/libvirtd.h: Remove all networking
  code
* daemon/stream.c, daemon/stream.h: Update for new APIs
* daemon/Makefile.am: Link to libvirt-net-rpc-server.la
---
 configure.ac           |   11 -
 daemon/Makefile.am     |   77 +-
 daemon/dispatch.c      |  693 -----------
 daemon/dispatch.h      |   68 -
 daemon/libvirtd.c      | 3171 ++++++++++--------------------------------------
 daemon/libvirtd.h      |  245 +----
 daemon/remote.c        | 1560 +++++++++++-------------
 daemon/remote.h        |   64 +-
 daemon/stream.c        |  495 +++++----
 daemon/stream.h        |   28 +-
 po/POTFILES.in         |    1 -
 src/rpc/gendispatch.pl |  292 +++---
 12 files changed, 1819 insertions(+), 4886 deletions(-)
 delete mode 100644 daemon/dispatch.c
 delete mode 100644 daemon/dispatch.h

diff --git a/configure.ac b/configure.ac
index a59e8e1..cd22afb 100644
--- a/configure.ac
+++ b/configure.ac
@@ -299,17 +299,6 @@ if test x"$enable_debug" = x"yes"; then
 fi
 
 
-AC_MSG_CHECKING([where to write libvirtd PID file])
-AC_ARG_WITH([remote-pid-file], [AC_HELP_STRING([--with-remote-pid-file=@<:@pidfile|none@:>@], [PID file for libvirtd])])
-if test "x$with_remote_pid_file" = "x" ; then
-   REMOTE_PID_FILE="$localstatedir/run/libvirtd.pid"
-elif test "x$with_remote_pid_file" = "xnone" ; then
-   REMOTE_PID_FILE=""
-else
-   REMOTE_PID_FILE="$with_remote_pid_file"
-fi
-AC_SUBST([REMOTE_PID_FILE])
-AC_MSG_RESULT($REMOTE_PID_FILE)
 
 dnl
 dnl init script flavor
diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index ad14c90..57499ac 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -3,33 +3,21 @@
 CLEANFILES =
 
 DAEMON_GENERATED =					\
-		$(srcdir)/remote_dispatch_prototypes.h	\
-		$(srcdir)/remote_dispatch_table.h	\
-		$(srcdir)/remote_dispatch_args.h	\
-		$(srcdir)/remote_dispatch_ret.h		\
-		$(srcdir)/remote_dispatch_bodies.h	\
-		$(srcdir)/qemu_dispatch_prototypes.h	\
-		$(srcdir)/qemu_dispatch_table.h		\
-		$(srcdir)/qemu_dispatch_args.h		\
-		$(srcdir)/qemu_dispatch_ret.h		\
-		$(srcdir)/qemu_dispatch_bodies.h
+		$(srcdir)/remote_dispatch.h		\
+		$(srcdir)/qemu_dispatch.h
 
 DAEMON_SOURCES =					\
 		libvirtd.c libvirtd.h			\
 		remote.c remote.h			\
-		dispatch.c dispatch.h			\
 		stream.c stream.h			\
 		../src/remote/remote_protocol.c		\
 		../src/remote/qemu_protocol.c		\
 		$(DAEMON_GENERATED)
 
-AVAHI_SOURCES =						\
-		mdns.c mdns.h
-
 DISTCLEANFILES =
 EXTRA_DIST =						\
-	remote_dispatch_bodies.h			\
-	qemu_dispatch_bodies.h				\
+	remote_dispatch.h				\
+	qemu_dispatch.h					\
 	libvirtd.conf					\
 	libvirtd.init.in				\
 	libvirtd.upstart				\
@@ -47,7 +35,6 @@ EXTRA_DIST =						\
 	libvirtd.pod.in					\
 	libvirtd.8.in					\
 	libvirtd.stp					\
-	$(AVAHI_SOURCES)				\
 	$(DAEMON_SOURCES)
 
 BUILT_SOURCES =
@@ -55,52 +42,12 @@ BUILT_SOURCES =
 REMOTE_PROTOCOL = $(top_srcdir)/src/remote/remote_protocol.x
 QEMU_PROTOCOL = $(top_srcdir)/src/remote/qemu_protocol.x
 
-$(srcdir)/remote_dispatch_prototypes.h: $(srcdir)/../src/rpc/gendispatch.pl \
-		$(REMOTE_PROTOCOL)
-	$(AM_V_GEN)perl -w $(srcdir)/../src/rpc/gendispatch.pl -c -p remote \
-	  $(REMOTE_PROTOCOL) > $@
-
-$(srcdir)/remote_dispatch_table.h: $(srcdir)/../src/rpc/gendispatch.pl \
-		$(REMOTE_PROTOCOL)
-	$(AM_V_GEN)perl -w $(srcdir)/../src/rpc/gendispatch.pl -c -t remote \
-	  $(REMOTE_PROTOCOL) > $@
-
-$(srcdir)/remote_dispatch_args.h: $(srcdir)/../src/rpc/gendispatch.pl \
-		$(REMOTE_PROTOCOL)
-	$(AM_V_GEN)perl -w $(srcdir)/../src/rpc/gendispatch.pl -c -a remote \
-	  $(REMOTE_PROTOCOL) > $@
-
-$(srcdir)/remote_dispatch_ret.h: $(srcdir)/../src/rpc/gendispatch.pl \
-		$(REMOTE_PROTOCOL)
-	$(AM_V_GEN)perl -w $(srcdir)/../src/rpc/gendispatch.pl -c -r remote \
-	  $(REMOTE_PROTOCOL) > $@
-
-$(srcdir)/remote_dispatch_bodies.h: $(srcdir)/../src/rpc/gendispatch.pl \
+$(srcdir)/remote_dispatch.h: $(srcdir)/../src/rpc/gendispatch.pl \
 		$(REMOTE_PROTOCOL)
 	$(AM_V_GEN)perl -w $(srcdir)/../src/rpc/gendispatch.pl -c -b remote \
 	  $(REMOTE_PROTOCOL) > $@
 
-$(srcdir)/qemu_dispatch_prototypes.h: $(srcdir)/../src/rpc/gendispatch.pl \
-		$(QEMU_PROTOCOL)
-	$(AM_V_GEN)perl -w $(srcdir)/../src/rpc/gendispatch.pl -p qemu \
-	  $(QEMU_PROTOCOL) > $@
-
-$(srcdir)/qemu_dispatch_table.h: $(srcdir)/../src/rpc/gendispatch.pl \
-		$(QEMU_PROTOCOL)
-	$(AM_V_GEN)perl -w $(srcdir)/../src/rpc/gendispatch.pl -t qemu \
-	  $(QEMU_PROTOCOL) > $@
-
-$(srcdir)/qemu_dispatch_args.h: $(srcdir)/../src/rpc/gendispatch.pl \
-		$(QEMU_PROTOCOL)
-	$(AM_V_GEN)perl -w $(srcdir)/../src/rpc/gendispatch.pl -a qemu \
-	  $(QEMU_PROTOCOL) > $@
-
-$(srcdir)/qemu_dispatch_ret.h: $(srcdir)/../src/rpc/gendispatch.pl \
-		$(QEMU_PROTOCOL)
-	$(AM_V_GEN)perl -w $(srcdir)/../src/rpc/gendispatch.pl -r qemu \
-	  $(QEMU_PROTOCOL) > $@
-
-$(srcdir)/qemu_dispatch_bodies.h: $(srcdir)/../src/rpc/gendispatch.pl \
+$(srcdir)/qemu_dispatch.h: $(srcdir)/../src/rpc/gendispatch.pl \
 		$(QEMU_PROTOCOL)
 	$(AM_V_GEN)perl -w $(srcdir)/../src/rpc/gendispatch.pl -b qemu \
 	  $(QEMU_PROTOCOL) > $@
@@ -137,6 +84,7 @@ libvirtd_CFLAGS = \
 	-I$(top_srcdir)/src \
 	-I$(top_srcdir)/src/util \
 	-I$(top_srcdir)/src/conf \
+	-I$(top_srcdir)/src/rpc \
 	-I$(top_srcdir)/src/remote \
 	$(LIBXML_CFLAGS) $(GNUTLS_CFLAGS) $(SASL_CFLAGS) \
 	$(XDR_CFLAGS) $(POLKIT_CFLAGS) \
@@ -155,7 +103,10 @@ libvirtd_LDADD =					\
 	$(SASL_LIBS)					\
 	$(POLKIT_LIBS)
 
-libvirtd_LDADD += ../src/libvirt-qemu.la
+libvirtd_LDADD += \
+	../src/libvirt-net-rpc-server.la \
+	../src/libvirt-net-rpc.la \
+	../src/libvirt-qemu.la
 
 if ! WITH_DRIVER_MODULES
 if WITH_QEMU
@@ -211,11 +162,7 @@ policyfile = libvirtd.policy-1
 endif
 endif
 
-if HAVE_AVAHI
-libvirtd_SOURCES += $(AVAHI_SOURCES)
-libvirtd_CFLAGS += $(AVAHI_CFLAGS)
-libvirtd_LDADD += $(AVAHI_LIBS)
-endif
+EXTRA_DIST += probes.d libvirtd.stp
 
 if WITH_DTRACE
 libvirtd_LDADD += probes.o
diff --git a/daemon/dispatch.c b/daemon/dispatch.c
deleted file mode 100644
index 010be1e..0000000
--- a/daemon/dispatch.c
+++ /dev/null
@@ -1,693 +0,0 @@
-/*
- * dispatch.h: RPC message dispatching infrastructure
- *
- * Copyright (C) 2007, 2008, 2009 Red Hat, Inc.
- *
- * 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: Richard W.M. Jones <rjones redhat com>
- * Author: Daniel P. Berrange <berrange redhat com>
- */
-
-#include <config.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-
-#include "dispatch.h"
-#include "remote.h"
-
-#include "memory.h"
-
-/* Convert a libvirt  virError object into wire format */
-static void
-remoteDispatchCopyError (remote_error *rerr,
-                         virErrorPtr verr)
-{
-    rerr->code = verr->code;
-    rerr->domain = verr->domain;
-    rerr->message = verr->message ? malloc(sizeof(char*)) : NULL;
-    if (rerr->message) *rerr->message = strdup(verr->message);
-    rerr->level = verr->level;
-    rerr->str1 = verr->str1 ? malloc(sizeof(char*)) : NULL;
-    if (rerr->str1) *rerr->str1 = strdup(verr->str1);
-    rerr->str2 = verr->str2 ? malloc(sizeof(char*)) : NULL;
-    if (rerr->str2) *rerr->str2 = strdup(verr->str2);
-    rerr->str3 = verr->str3 ? malloc(sizeof(char*)) : NULL;
-    if (rerr->str3) *rerr->str3 = strdup(verr->str3);
-    rerr->int1 = verr->int1;
-    rerr->int2 = verr->int2;
-}
-
-
-/* A set of helpers for sending back errors to client
-   in various ways .... */
-
-static void
-remoteDispatchStringError (remote_error *rerr,
-                           int code, const char *msg)
-{
-    virError verr;
-
-    memset(&verr, 0, sizeof verr);
-
-    /* Construct the dummy libvirt virError. */
-    verr.code = code;
-    verr.domain = VIR_FROM_REMOTE;
-    verr.message = (char *)msg;
-    verr.level = VIR_ERR_ERROR;
-    verr.str1 = (char *)msg;
-
-    remoteDispatchCopyError(rerr, &verr);
-}
-
-
-void remoteDispatchAuthError (remote_error *rerr)
-{
-    remoteDispatchStringError (rerr, VIR_ERR_AUTH_FAILED, "authentication failed");
-}
-
-
-void remoteDispatchFormatError (remote_error *rerr,
-                                const char *fmt, ...)
-{
-    va_list args;
-    char msgbuf[1024];
-    char *msg = msgbuf;
-
-    va_start (args, fmt);
-    vsnprintf (msgbuf, sizeof msgbuf, fmt, args);
-    va_end (args);
-
-    remoteDispatchStringError (rerr, VIR_ERR_RPC, msg);
-}
-
-
-void remoteDispatchGenericError (remote_error *rerr)
-{
-    remoteDispatchStringError(rerr,
-                              VIR_ERR_INTERNAL_ERROR,
-                              "library function returned error but did not set virterror");
-}
-
-
-void remoteDispatchError(remote_error *rerr)
-{
-    virErrorPtr verr = virGetLastError();
-
-    if (verr)
-        remoteDispatchCopyError(rerr, verr);
-    else
-        remoteDispatchGenericError(rerr);
-}
-
-static int
-remoteSerializeError(struct qemud_client *client,
-                     remote_error *rerr,
-                     int program,
-                     int version,
-                     int procedure,
-                     int type,
-                     int serial)
-{
-    XDR xdr;
-    unsigned int len;
-    struct qemud_client_message *msg = NULL;
-
-    VIR_DEBUG("prog=%d ver=%d proc=%d type=%d serial=%d, msg=%s",
-          program, version, procedure, type, serial,
-          rerr->message ? *rerr->message : "(none)");
-
-    if (VIR_ALLOC(msg) < 0)
-        goto fatal_error;
-
-    /* Return header. */
-    msg->hdr.prog = program;
-    msg->hdr.vers = version;
-    msg->hdr.proc = procedure;
-    msg->hdr.type = type;
-    msg->hdr.serial = serial;
-    msg->hdr.status = REMOTE_ERROR;
-
-    msg->bufferLength = sizeof(msg->buffer);
-
-    /* Serialise the return header. */
-    xdrmem_create (&xdr,
-                   msg->buffer,
-                   msg->bufferLength,
-                   XDR_ENCODE);
-
-    len = 0; /* We'll come back and write this later. */
-    if (!xdr_u_int (&xdr, &len))
-        goto xdr_error;
-
-    if (!xdr_remote_message_header (&xdr, &msg->hdr))
-        goto xdr_error;
-
-    /* Error was not set, so synthesize a generic error message. */
-    if (rerr->code == 0)
-        remoteDispatchGenericError(rerr);
-
-    if (!xdr_remote_error (&xdr, rerr))
-        goto xdr_error;
-
-    /* Write the length word. */
-    len = xdr_getpos (&xdr);
-    if (xdr_setpos (&xdr, 0) == 0)
-        goto xdr_error;
-
-    if (!xdr_u_int (&xdr, &len))
-        goto xdr_error;
-
-    xdr_destroy (&xdr);
-
-    msg->bufferLength = len;
-    msg->bufferOffset = 0;
-
-    /* Put reply on end of tx queue to send out  */
-    qemudClientMessageQueuePush(&client->tx, msg);
-    qemudUpdateClientEvent(client);
-    xdr_free((xdrproc_t)xdr_remote_error,  (char *)rerr);
-
-    return 0;
-
-xdr_error:
-    VIR_WARN("Failed to serialize remote error '%s' as XDR",
-             rerr->message ? *rerr->message : "<unknown>");
-    xdr_destroy(&xdr);
-    VIR_FREE(msg);
-fatal_error:
-    xdr_free((xdrproc_t)xdr_remote_error,  (char *)rerr);
-    return -1;
-}
-
-
-/*
- * @client: the client to send the error to
- * @rerr: the error object to send
- * @req: the message this error is in reply to
- *
- * Send an error message to the client
- *
- * Returns 0 if the error was sent, -1 upon fatal error
- */
-int
-remoteSerializeReplyError(struct qemud_client *client,
-                          remote_error *rerr,
-                          remote_message_header *req) {
-    /*
-     * For data streams, errors are sent back as data streams
-     * For method calls, errors are sent back as method replies
-     */
-    return remoteSerializeError(client,
-                                rerr,
-                                req->prog,
-                                req->vers,
-                                req->proc,
-                                req->type == REMOTE_STREAM ? REMOTE_STREAM : REMOTE_REPLY,
-                                req->serial);
-}
-
-int
-remoteSerializeStreamError(struct qemud_client *client,
-                           remote_error *rerr,
-                           int proc,
-                           int serial)
-{
-    return remoteSerializeError(client,
-                                rerr,
-                                REMOTE_PROGRAM,
-                                REMOTE_PROTOCOL_VERSION,
-                                proc,
-                                REMOTE_STREAM,
-                                serial);
-}
-
-/*
- * @msg: the complete incoming message, whose header to decode
- *
- * Decodes the header part of the client message, but does not
- * validate the decoded fields in the header. It expects
- * bufferLength to refer to length of the data packet. Upon
- * return bufferOffset will refer to the amount of the packet
- * consumed by decoding of the header.
- *
- * returns 0 if successfully decoded, -1 upon fatal error
- */
-int
-remoteDecodeClientMessageHeader (struct qemud_client_message *msg)
-{
-    XDR xdr;
-    int ret = -1;
-
-    msg->bufferOffset = REMOTE_MESSAGE_HEADER_XDR_LEN;
-
-    /* Parse the header. */
-    xdrmem_create (&xdr,
-                   msg->buffer + msg->bufferOffset,
-                   msg->bufferLength - msg->bufferOffset,
-                   XDR_DECODE);
-
-    if (!xdr_remote_message_header (&xdr, &msg->hdr))
-        goto cleanup;
-
-    msg->bufferOffset += xdr_getpos(&xdr);
-
-    ret = 0;
-
-cleanup:
-    xdr_destroy(&xdr);
-    return ret;
-}
-
-
-/*
- * @msg: the outgoing message, whose header to encode
- *
- * Encodes the header part of the client message, setting the
- * message offset ready to encode the payload. Leaves space
- * for the length field later. Upon return bufferLength will
- * refer to the total available space for message, while
- * bufferOffset will refer to current space used by header
- *
- * returns 0 if successfully encoded, -1 upon fatal error
- */
-int
-remoteEncodeClientMessageHeader (struct qemud_client_message *msg)
-{
-    XDR xdr;
-    int ret = -1;
-    unsigned int len = 0;
-
-    msg->bufferLength = sizeof(msg->buffer);
-    msg->bufferOffset = 0;
-
-    /* Format the header. */
-    xdrmem_create (&xdr,
-                   msg->buffer,
-                   msg->bufferLength,
-                   XDR_ENCODE);
-
-    /* The real value is filled in shortly */
-    if (!xdr_u_int (&xdr, &len)) {
-        goto cleanup;
-    }
-
-    if (!xdr_remote_message_header (&xdr, &msg->hdr))
-        goto cleanup;
-
-    len = xdr_getpos(&xdr);
-    xdr_setpos(&xdr, 0);
-
-    /* Fill in current length - may be re-written later
-     * if a payload is added
-     */
-    if (!xdr_u_int (&xdr, &len)) {
-        goto cleanup;
-    }
-
-    msg->bufferOffset += len;
-
-    ret = 0;
-
-cleanup:
-    xdr_destroy(&xdr);
-    return ret;
-}
-
-
-static int
-remoteDispatchClientCall (struct qemud_server *server,
-                          struct qemud_client *client,
-                          struct qemud_client_message *msg,
-                          bool qemu_protocol);
-
-
-/*
- * @server: the unlocked server object
- * @client: the locked client object
- * @msg: the complete incoming message packet, with header already decoded
- *
- * This function gets called from qemud when it pulls a incoming
- * remote protocol message off the dispatch queue for processing.
- *
- * The @msg parameter must have had its header decoded already by
- * calling remoteDecodeClientMessageHeader
- *
- * Returns 0 if the message was dispatched, -1 upon fatal error
- */
-int
-remoteDispatchClientRequest(struct qemud_server *server,
-                            struct qemud_client *client,
-                            struct qemud_client_message *msg)
-{
-    int ret;
-    remote_error rerr;
-    bool qemu_call;
-
-    VIR_DEBUG("prog=%d ver=%d type=%d status=%d serial=%d proc=%d",
-          msg->hdr.prog, msg->hdr.vers, msg->hdr.type,
-          msg->hdr.status, msg->hdr.serial, msg->hdr.proc);
-
-    memset(&rerr, 0, sizeof rerr);
-
-    /* Check version, etc. */
-    if (msg->hdr.prog == REMOTE_PROGRAM)
-        qemu_call = false;
-    else if (msg->hdr.prog == QEMU_PROGRAM)
-        qemu_call = true;
-    else {
-        remoteDispatchFormatError (&rerr,
-                                   _("program mismatch (actual %x, expected %x or %x)"),
-                                   msg->hdr.prog, REMOTE_PROGRAM, QEMU_PROGRAM);
-        goto error;
-    }
-
-    if (!qemu_call && msg->hdr.vers != REMOTE_PROTOCOL_VERSION) {
-        remoteDispatchFormatError (&rerr,
-                                   _("version mismatch (actual %x, expected %x)"),
-                                   msg->hdr.vers, REMOTE_PROTOCOL_VERSION);
-        goto error;
-    }
-    else if (qemu_call && msg->hdr.vers != QEMU_PROTOCOL_VERSION) {
-        remoteDispatchFormatError (&rerr,
-                                   _("version mismatch (actual %x, expected %x)"),
-                                   msg->hdr.vers, QEMU_PROTOCOL_VERSION);
-        goto error;
-    }
-
-    switch (msg->hdr.type) {
-    case REMOTE_CALL:
-        return remoteDispatchClientCall(server, client, msg, qemu_call);
-
-    case REMOTE_STREAM:
-        /* Since stream data is non-acked, async, we may continue to received
-         * stream packets after we closed down a stream. Just drop & ignore
-         * these.
-         */
-        VIR_INFO("Ignoring unexpected stream data serial=%d proc=%d status=%d",
-                 msg->hdr.serial, msg->hdr.proc, msg->hdr.status);
-        qemudClientMessageRelease(client, msg);
-        break;
-
-    default:
-        remoteDispatchFormatError (&rerr, _("type (%d) != REMOTE_CALL"),
-                                   (int) msg->hdr.type);
-        goto error;
-    }
-
-    return 0;
-
-error:
-    ret = remoteSerializeReplyError(client, &rerr, &msg->hdr);
-
-    if (ret >= 0)
-        VIR_FREE(msg);
-
-    return ret;
-}
-
-
-/*
- * @server: the unlocked server object
- * @client: the locked client object
- * @msg: the complete incoming method call, with header already decoded
- *
- * This method is used to dispatch an message representing an
- * incoming method call from a client. It decodes the payload
- * to obtain method call arguments, invokves the method and
- * then sends a reply packet with the return values
- *
- * Returns 0 if the reply was sent, or -1 upon fatal error
- */
-static int
-remoteDispatchClientCall (struct qemud_server *server,
-                          struct qemud_client *client,
-                          struct qemud_client_message *msg,
-                          bool qemu_protocol)
-{
-    XDR xdr;
-    remote_error rerr;
-    dispatch_args args;
-    dispatch_ret ret;
-    const dispatch_data *data = NULL;
-    int rv = -1;
-    unsigned int len;
-    virConnectPtr conn = NULL;
-
-    memset(&args, 0, sizeof args);
-    memset(&ret, 0, sizeof ret);
-    memset(&rerr, 0, sizeof rerr);
-
-    if (msg->hdr.status != REMOTE_OK) {
-        remoteDispatchFormatError (&rerr, _("status (%d) != REMOTE_OK"),
-                                   (int) msg->hdr.status);
-        goto rpc_error;
-    }
-
-    /* If client is marked as needing auth, don't allow any RPC ops,
-     * except for authentication ones
-     */
-    if (client->auth) {
-        if (msg->hdr.proc != REMOTE_PROC_AUTH_LIST &&
-            msg->hdr.proc != REMOTE_PROC_AUTH_SASL_INIT &&
-            msg->hdr.proc != REMOTE_PROC_AUTH_SASL_START &&
-            msg->hdr.proc != REMOTE_PROC_AUTH_SASL_STEP &&
-            msg->hdr.proc != REMOTE_PROC_AUTH_POLKIT
-            ) {
-            /* Explicitly *NOT* calling  remoteDispatchAuthError() because
-               we want back-compatability with libvirt clients which don't
-               support the VIR_ERR_AUTH_FAILED error code */
-            remoteDispatchFormatError (&rerr, "%s", _("authentication required"));
-            goto rpc_error;
-        }
-    }
-
-    if (qemu_protocol)
-        data = qemuGetDispatchData(msg->hdr.proc);
-    else
-        data = remoteGetDispatchData(msg->hdr.proc);
-
-    if (!data) {
-        remoteDispatchFormatError (&rerr, _("unknown procedure: %d"),
-                                   msg->hdr.proc);
-        goto rpc_error;
-    }
-
-    /* De-serialize payload with args from the wire message */
-    xdrmem_create (&xdr,
-                   msg->buffer + msg->bufferOffset,
-                   msg->bufferLength - msg->bufferOffset,
-                   XDR_DECODE);
-    if (!((data->args_filter)(&xdr, &args))) {
-        xdr_destroy (&xdr);
-        remoteDispatchFormatError (&rerr, "%s", _("parse args failed"));
-        goto rpc_error;
-    }
-    xdr_destroy (&xdr);
-
-    /* Call function. */
-    conn = client->conn;
-    virMutexUnlock(&client->lock);
-
-    /*
-     * When the RPC handler is called:
-     *
-     *  - Server object is unlocked
-     *  - Client object is unlocked
-     *
-     * Without locking, it is safe to use:
-     *
-     *   'conn', 'rerr', 'args and 'ret'
-     */
-    rv = (data->fn)(server, client, conn, &msg->hdr, &rerr, &args, &ret);
-
-    virMutexLock(&server->lock);
-    virMutexLock(&client->lock);
-    virMutexUnlock(&server->lock);
-
-    xdr_free (data->args_filter, (char*)&args);
-
-    if (rv < 0)
-        goto rpc_error;
-
-    /* Return header. We're re-using same message object, so
-     * only need to tweak type/status fields */
-    /*msg->hdr.prog = msg->hdr.prog;*/
-    /*msg->hdr.vers = msg->hdr.vers;*/
-    /*msg->hdr.proc = msg->hdr.proc;*/
-    msg->hdr.type = REMOTE_REPLY;
-    /*msg->hdr.serial = msg->hdr.serial;*/
-    msg->hdr.status = REMOTE_OK;
-
-    if (remoteEncodeClientMessageHeader(msg) < 0) {
-        xdr_free (data->ret_filter, (char*)&ret);
-        remoteDispatchFormatError(&rerr, "%s", _("failed to serialize reply header"));
-        goto xdr_hdr_error;
-    }
-
-
-    /* Now for the payload */
-    xdrmem_create (&xdr,
-                   msg->buffer,
-                   msg->bufferLength,
-                   XDR_ENCODE);
-
-    if (xdr_setpos(&xdr, msg->bufferOffset) == 0) {
-        remoteDispatchFormatError(&rerr, "%s", _("failed to change XDR reply offset"));
-        goto xdr_error;
-    }
-
-    /* If OK, serialise return structure, if error serialise error. */
-    /* Serialise reply data */
-    if (!((data->ret_filter) (&xdr, &ret))) {
-        remoteDispatchFormatError(&rerr, "%s", _("failed to serialize reply payload (probable message size limit)"));
-        goto xdr_error;
-    }
-
-    /* Update the length word. */
-    msg->bufferOffset += xdr_getpos (&xdr);
-    len = msg->bufferOffset;
-    if (xdr_setpos (&xdr, 0) == 0) {
-        remoteDispatchFormatError(&rerr, "%s", _("failed to change XDR reply offset"));
-        goto xdr_error;
-    }
-
-    if (!xdr_u_int (&xdr, &len)) {
-        remoteDispatchFormatError(&rerr, "%s", _("failed to update reply length header"));
-        goto xdr_error;
-    }
-
-    xdr_destroy (&xdr);
-    xdr_free (data->ret_filter, (char*)&ret);
-
-    /* Reset ready for I/O */
-    msg->bufferLength = len;
-    msg->bufferOffset = 0;
-
-    /* Put reply on end of tx queue to send out  */
-    qemudClientMessageQueuePush(&client->tx, msg);
-    qemudUpdateClientEvent(client);
-
-    return 0;
-
-xdr_error:
-    /* Bad stuff serializing reply. Try to send a little info
-     * back to client to assist in bug reporting/diagnosis */
-    xdr_free (data->ret_filter, (char*)&ret);
-    xdr_destroy (&xdr);
-    /* fallthrough */
-
-xdr_hdr_error:
-    VIR_WARN("Failed to serialize reply for program '%d' proc '%d' as XDR",
-             msg->hdr.prog, msg->hdr.proc);
-    /* fallthrough */
-
-rpc_error:
-    /* Bad stuff (de-)serializing message, but we have an
-     * RPC error message we can send back to the client */
-    rv = remoteSerializeReplyError(client, &rerr, &msg->hdr);
-
-    if (rv >= 0)
-        VIR_FREE(msg);
-
-    return rv;
-}
-
-
-int
-remoteSendStreamData(struct qemud_client *client,
-                     struct qemud_client_stream *stream,
-                     const char *data,
-                     unsigned int len)
-{
-    struct qemud_client_message *msg;
-    XDR xdr;
-
-    VIR_DEBUG("client=%p stream=%p data=%p len=%d", client, stream, data, len);
-
-    if (VIR_ALLOC(msg) < 0) {
-        return -1;
-    }
-
-    /* Return header. We're re-using same message object, so
-     * only need to tweak type/status fields */
-    msg->hdr.prog = REMOTE_PROGRAM;
-    msg->hdr.vers = REMOTE_PROTOCOL_VERSION;
-    msg->hdr.proc = stream->procedure;
-    msg->hdr.type = REMOTE_STREAM;
-    msg->hdr.serial = stream->serial;
-    /*
-     * NB
-     *   data != NULL + len > 0    => REMOTE_CONTINUE   (Sending back data)
-     *   data != NULL + len == 0   => REMOTE_CONTINUE   (Sending read EOF)
-     *   data == NULL              => REMOTE_OK         (Sending finish handshake confirmation)
-     */
-    msg->hdr.status = data ? REMOTE_CONTINUE : REMOTE_OK;
-
-    if (remoteEncodeClientMessageHeader(msg) < 0)
-        goto fatal_error;
-
-    if (data && len) {
-        if ((msg->bufferLength - msg->bufferOffset) < len)
-            goto fatal_error;
-
-        /* Now for the payload */
-        xdrmem_create (&xdr,
-                       msg->buffer,
-                       msg->bufferLength,
-                       XDR_ENCODE);
-
-        /* Skip over existing header already written */
-        if (xdr_setpos(&xdr, msg->bufferOffset) == 0)
-            goto xdr_error;
-
-        memcpy(msg->buffer + msg->bufferOffset, data, len);
-        msg->bufferOffset += len;
-
-        /* Update the length word. */
-        len = msg->bufferOffset;
-        if (xdr_setpos (&xdr, 0) == 0)
-            goto xdr_error;
-
-        if (!xdr_u_int (&xdr, &len))
-            goto xdr_error;
-
-        xdr_destroy (&xdr);
-
-        VIR_DEBUG("Total %d", msg->bufferOffset);
-    }
-    if (data)
-        msg->streamTX = 1;
-
-    /* Reset ready for I/O */
-    msg->bufferLength = msg->bufferOffset;
-    msg->bufferOffset = 0;
-
-    /* Put reply on end of tx queue to send out  */
-    qemudClientMessageQueuePush(&client->tx, msg);
-    qemudUpdateClientEvent(client);
-
-    return 0;
-
-xdr_error:
-    xdr_destroy (&xdr);
-fatal_error:
-    VIR_FREE(msg);
-    VIR_WARN("Failed to serialize stream data for proc %d as XDR",
-             stream->procedure);
-    return -1;
-}
diff --git a/daemon/dispatch.h b/daemon/dispatch.h
deleted file mode 100644
index f24f494..0000000
--- a/daemon/dispatch.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * dispatch.h: RPC message dispatching infrastructure
- *
- * Copyright (C) 2007, 2008, 2009 Red Hat, Inc.
- *
- * 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: Richard W.M. Jones <rjones redhat com>
- * Author: Daniel P. Berrange <berrange redhat com>
- */
-
-#ifndef __LIBVIRTD_DISPATCH_H__
-# define __LIBVIRTD_DISPATCH_H__
-
-
-# include "libvirtd.h"
-
-
-int
-remoteDecodeClientMessageHeader (struct qemud_client_message *req);
-int
-remoteEncodeClientMessageHeader (struct qemud_client_message *req);
-
-int
-remoteDispatchClientRequest (struct qemud_server *server,
-                             struct qemud_client *client,
-                             struct qemud_client_message *req);
-
-
-void remoteDispatchFormatError (remote_error *rerr,
-                                const char *fmt, ...)
-    ATTRIBUTE_FMT_PRINTF(2, 3);
-
-void remoteDispatchAuthError (remote_error *rerr);
-void remoteDispatchGenericError (remote_error *rerr);
-void remoteDispatchError(remote_error *rerr);
-
-
-int
-remoteSerializeReplyError(struct qemud_client *client,
-                          remote_error *rerr,
-                          remote_message_header *req);
-int
-remoteSerializeStreamError(struct qemud_client *client,
-                           remote_error *rerr,
-                           int proc,
-                           int serial);
-
-
-int
-remoteSendStreamData(struct qemud_client *client,
-                     struct qemud_client_stream *stream,
-                     const char *data,
-                     unsigned int len);
-
-#endif /* __LIBVIRTD_DISPATCH_H__ */
diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c
index 5f291ec..214199b 100644
--- a/daemon/libvirtd.c
+++ b/daemon/libvirtd.c
@@ -23,31 +23,13 @@
 
 #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 <sys/wait.h>
+#include <sys/stat.h>
 #include <getopt.h>
-#include <fnmatch.h>
+#include <stdlib.h>
 #include <grp.h>
-#include <signal.h>
-#include <netdb.h>
-#include <locale.h>
 
 #include "libvirt_internal.h"
 #include "virterror_internal.h"
@@ -56,20 +38,21 @@
 #define VIR_FROM_THIS VIR_FROM_QEMU
 
 #include "libvirtd.h"
-#include "dispatch.h"
 
 #include "util.h"
 #include "uuid.h"
 #include "remote_driver.h"
 #include "conf.h"
-#include "event_poll.h"
 #include "memory.h"
-#include "stream.h"
+#include "conf.h"
+#include "virnetserver.h"
+#include "threads.h"
+#include "remote.h"
+#include "remote_driver.h"
+//#include "stream.h"
 #include "hooks.h"
+#include "uuid.h"
 #include "virtaudit.h"
-#ifdef HAVE_AVAHI
-# include "mdns.h"
-#endif
 
 #ifdef WITH_DRIVER_MODULES
 # include "driver.h"
@@ -106,100 +89,58 @@
 # endif
 #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 */
-
 #include "configmake.h"
 
-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;
+virNetSASLContextPtr saslCtxt = NULL;
+virNetServerProgramPtr remoteProgram = NULL;
+virNetServerProgramPtr qemuProgram = NULL;
 
-static char *unix_sock_dir = NULL;
+struct daemonConfig {
+    char *host_uuid;
 
-#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;
+    int listen_tls;
+    int listen_tcp;
+    char *listen_addr;
+    char *tls_port;
+    char *tcp_port;
 
-static int mdns_adv = 1;
-static char *mdns_name = NULL;
+    char *unix_sock_ro_perms;
+    char *unix_sock_rw_perms;
+    char *unix_sock_group;
+    char *unix_sock_dir;
 
-static int tls_no_verify_certificate = 0;
-static char **tls_allowed_dn_list = NULL;
+    int auth_unix_rw;
+    int auth_unix_ro;
+    int auth_tcp;
+    int auth_tls;
 
-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 *) "";
+    int mdns_adv;
+    char *mdns_name;
 
-static gnutls_certificate_credentials_t x509_cred;
-static gnutls_dh_params_t dh_params;
+    int tls_no_verify_certificate;
+    char **tls_allowed_dn_list;
+    char **sasl_allowed_username_list;
 
-static int min_workers = 5;
-static int max_workers = 20;
-static int max_clients = 20;
+    char *key_file;
+    char *cert_file;
+    char *ca_file;
+    char *crl_file;
 
-/* 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;
+    int min_workers;
+    int max_workers;
+    int max_clients;
 
-static int audit_level = 1;
-static int audit_logging = 0;
+    int max_requests;
+    int max_client_requests;
 
-#define DH_BITS 1024
+    int log_level;
+    char *log_filters;
+    char *log_outputs;
+    int log_buffer_size;
 
-static sig_atomic_t sig_errors = 0;
-static int sig_lasterrno = 0;
-static const char *argv0;
+    int audit_level;
+    int audit_logging;
+};
 
 enum {
     VIR_DAEMON_ERR_NONE = 0,
@@ -229,211 +170,8 @@ VIR_ENUM_IMPL(virDaemonErr, VIR_DAEMON_ERR_LAST,
               "Unable to look for hook scripts",
               "Unable to initialize audit system")
 
-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 sig_fatal(int sig, siginfo_t * siginfo ATTRIBUTE_UNUSED,
-                      void* context ATTRIBUTE_UNUSED) {
-    struct sigaction sig_action;
-    int origerrno;
-
-    origerrno = errno;
-    virLogEmergencyDumpAll(sig);
-
-    /*
-     * If the signal is fatal, avoid looping over this handler
-     * by desactivating it
-     */
-    if (sig != SIGUSR2) {
-        sig_action.sa_flags = SA_SIGINFO;
-        sig_action.sa_handler = SIG_IGN;
-        sigaction(sig, &sig_action, NULL);
-    }
-    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)
+static int daemonForkIntoBackground(const char *argv0)
 {
-    int err;
-
-    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;
-
-        VIR_DEBUG("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;
-
-        VIR_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;
-        VIR_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;
-
-    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;
-    }
-
-    switch (siginfo.si_signo) {
-    case SIGHUP:
-        VIR_INFO("Reloading configuration on SIGHUP");
-        virHookCall(VIR_HOOK_DRIVER_DAEMON, "-",
-                    VIR_HOOK_DAEMON_OP_RELOAD, SIGHUP, "SIGHUP", NULL);
-        if (virStateReload() < 0)
-            VIR_WARN("Error while reloading drivers");
-
-        break;
-
-    case SIGINT:
-    case SIGQUIT:
-    case SIGTERM:
-        VIR_WARN("Shutting down on signal %d", siginfo.si_signo);
-        server->quitEventThread = 1;
-        break;
-
-    default:
-        VIR_INFO("Received unexpected signal %d", siginfo.si_signo);
-        break;
-    }
-
-    virMutexUnlock(&server->lock);
-}
-
-
-static int daemonForkIntoBackground(void) {
     int statuspipe[2];
     if (pipe(statuspipe) < 0)
         return -1;
@@ -518,7 +256,8 @@ static int daemonForkIntoBackground(void) {
     }
 }
 
-static int qemudWritePidFile(const char *pidFile) {
+static int daemonWritePidFile(const char *pidFile, const char *argv0)
+{
     int fd;
     FILE *fh;
     char ebuf[1024];
@@ -555,289 +294,77 @@ static int qemudWritePidFile(const char *pidFile) {
     return 0;
 }
 
-static int qemudListenUnix(struct qemud_server *server,
-                           char *path, int readonly, int auth) {
-    struct qemud_socket *sock;
-    mode_t oldmask;
-    char ebuf[1024];
-
-    if (VIR_ALLOC(sock) < 0) {
-        VIR_ERROR(_("Failed to allocate memory for struct qemud_socket"));
-        return -1;
-    }
-
-    sock->readonly = readonly;
-    sock->type = QEMUD_SOCK_TYPE_UNIX;
-    sock->auth = auth;
-    sock->path = path;
-    sock->addr.len = sizeof(sock->addr.data.un);
-    if (!(sock->addrstr = strdup(path))) {
-        VIR_ERROR(_("Failed to copy socket address: %s"),
-                  virStrerror(errno, ebuf, sizeof ebuf));
-        goto cleanup;
-    }
-
-    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;
-
-    sock->addr.data.un.sun_family = AF_UNIX;
-    if (virStrcpyStatic(sock->addr.data.un.sun_path, path) == NULL) {
-        VIR_ERROR(_("Path %s too long for unix socket"), path);
-        goto cleanup;
-    }
-    if (sock->addr.data.un.sun_path[0] == '@')
-        sock->addr.data.un.sun_path[0] = '\0';
-
-    oldmask = umask(readonly ? ~unix_sock_ro_mask : ~unix_sock_rw_mask);
-    if (bind(sock->fd, &sock->addr.data.sa, sock->addr.len) < 0) {
-        VIR_ERROR(_("Failed to bind socket to '%s': %s"),
-                  path, virStrerror(errno, ebuf, sizeof ebuf));
-        umask(oldmask);
-        goto cleanup;
-    }
-    umask(oldmask);
-
-    /* chown() doesn't work for abstract sockets but we use them only
-     * if libvirtd runs unprivileged
-     */
-    if (server->privileged && chown(path, -1, unix_sock_gid)) {
-        VIR_ERROR(_("Failed to change group ID of '%s' to %d: %s"),
-                  path, unix_sock_gid,
-                  virStrerror(errno, ebuf, sizeof ebuf));
-        goto cleanup;
-    }
-
-    if (listen(sock->fd, 30) < 0) {
-        VIR_ERROR(_("Failed to listen for connections on '%s': %s"),
-                  path, virStrerror(errno, ebuf, sizeof ebuf));
-        goto cleanup;
-    }
-
-    sock->next = server->sockets;
-    server->sockets = sock;
-    server->nsockets++;
-
-    return 0;
-
- cleanup:
-    VIR_FORCE_CLOSE(sock->fd);
-    VIR_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"), 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);
-
-#ifdef IPV6_V6ONLY
-        if (runp->ai_family == PF_INET6) {
-            int on = 1;
-            /*
-             * Normally on Linux an INET6 socket will bind to the INET4
-             * address too. If getaddrinfo returns results with INET4
-             * first though, this will result in INET6 binding failing.
-             * We can trivially cope with multiple server sockets, so
-             * we force it to only listen on IPv6
-             */
-            setsockopt(fds[*nfds_r], IPPROTO_IPV6,IPV6_V6ONLY,
-                       (void*)&on, sizeof on);
-        }
-#endif
-
-        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;
-            }
-            VIR_FORCE_CLOSE(fds[*nfds_r]);
-        } else {
-            ++*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)
+daemonPidFilePath(bool privileged,
+                  char **pidfile)
 {
-    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) {
-        char ebuf[1024];
-
-        if (VIR_ALLOC(sock) < 0) {
-            VIR_ERROR(_("remoteListenTCP: calloc: %s"),
-                      virStrerror (errno, ebuf, sizeof ebuf));
-            goto cleanup;
-        }
-
-        sock->addr.len = sizeof(sock->addr.data.stor);
-        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, &sock->addr.data.sa, &sock->addr.len) < 0)
-            goto cleanup;
+    if (privileged) {
+        if (!(*pidfile = strdup(LOCALSTATEDIR "/run/libvirtd.pid")))
+            goto no_memory;
+    } else {
+        char *userdir = NULL;
 
-        if (!(sock->addrstr = virSocketFormatAddrFull(&sock->addr, true, ";")))
-            goto cleanup;
+        if (!(userdir = virGetUserDirectory(geteuid())))
+            goto error;
 
-        if (virSetCloseExec(sock->fd) < 0 ||
-            virSetNonBlock(sock->fd) < 0)
-            goto cleanup;
+        if (virAsprintf(pidfile, "%s/.libvirt/libvirtd.pid", userdir) < 0)
+            goto no_memory;
 
-        if (listen (sock->fd, 30) < 0) {
-            VIR_ERROR(_("remoteListenTCP: listen: %s"),
-                      virStrerror (errno, ebuf, sizeof ebuf));
-            goto cleanup;
-        }
+        VIR_FREE(userdir);
     }
 
     return 0;
 
-cleanup:
-    for (i = 0; i < nfds; ++i)
-        VIR_FORCE_CLOSE(fds[i]);
+no_memory:
+    virReportOOMError();
+error:
     return -1;
 }
 
-static int qemudInitPaths(struct qemud_server *server,
-                          char **sockname,
-                          char **roSockname)
+static int
+daemonUnixSocketPaths(struct daemonConfig *config,
+                      bool privileged,
+                      char **sockfile,
+                      char **rosockfile)
 {
-    char *base_dir_prefix = NULL;
-    char *sock_dir_prefix = NULL;
-    int ret = -1;
-
-    /* The base_dir_prefix is the base under which all libvirtd
-     * files live */
-    if (server->privileged) {
-        if (!(base_dir_prefix = strdup (LOCALSTATEDIR)))
+    if (config->unix_sock_dir) {
+        if (virAsprintf(sockfile, "%s/libvirt-sock", config->unix_sock_dir) < 0)
             goto no_memory;
-    } else {
-        uid_t uid = geteuid();
-        if (!(base_dir_prefix = virGetUserDirectory(uid)))
-            goto cleanup;
-    }
-
-    /* The unix_sock_dir is the location under which all
-     * unix domain sockets live */
-    if (unix_sock_dir) {
-        if (!(sock_dir_prefix = strdup(unix_sock_dir)))
+        if (privileged &&
+            virAsprintf(rosockfile, "%s/libvirt-sock-ro", config->unix_sock_dir) < 0)
             goto no_memory;
-
-        /* Change the group ownership of /var/run/libvirt to unix_sock_gid */
-        if (server->privileged) {
-            if (chown(unix_sock_dir, -1, unix_sock_gid) < 0)
-                VIR_ERROR(_("Failed to change group ownership of %s"),
-                          unix_sock_dir);
-        }
     } else {
-        if (server->privileged) {
-            if (virAsprintf(&sock_dir_prefix, "%s/run/libvirt",
-                            base_dir_prefix) < 0)
+        if (privileged) {
+            if (!(*sockfile = strdup(LOCALSTATEDIR "/run/libvirt/libvirt-sock")))
                 goto no_memory;
-        } else {
-            if (virAsprintf(&sock_dir_prefix, "%s/.libvirt",
-                            base_dir_prefix) < 0)
+            if (!(*rosockfile = strdup(LOCALSTATEDIR "/run/libvirt/libvirt-sock-ro")))
                 goto no_memory;
-        }
-    }
+        } else {
+            char *userdir = NULL;
 
-    if (server->privileged) {
-        if (virAsprintf(sockname, "%s/libvirt-sock",
-                        sock_dir_prefix) < 0)
-            goto no_memory;
-        if (virAsprintf(roSockname, "%s/libvirt-sock-ro",
-                        sock_dir_prefix) < 0)
-            goto no_memory;
-        unlink(*sockname);
-        unlink(*roSockname);
-    } else {
-        if (virAsprintf(sockname, "@%s/libvirt-sock",
-                        sock_dir_prefix) < 0)
-            goto no_memory;
-        /* There is no RO socket in unprivileged mode,
-         * since the user always has full RW access
-         * to their private instance */
-    }
+            if (!(userdir = virGetUserDirectory(geteuid())))
+                goto error;
 
-    if (server->privileged) {
-        if (virAsprintf(&server->logDir, "%s/log/libvirt",
-                        base_dir_prefix) < 0)
-            goto no_memory;
-    } else {
-        if (virAsprintf(&server->logDir, "%s/.libvirt/log",
-                        base_dir_prefix) < 0)
-            goto no_memory;
-    }
+            if (virAsprintf(sockfile, "@%s/.libvirt/libvirt-sock", userdir) < 0) {
+                VIR_FREE(userdir);
+                goto no_memory;
+            }
 
-    ret = 0;
+            VIR_FREE(userdir);
+        }
+    }
+    return 0;
 
 no_memory:
-    if (ret != 0)
-        virReportOOMError();
-
- cleanup:
-    VIR_FREE(base_dir_prefix);
-    VIR_FREE(sock_dir_prefix);
-    return ret;
+    virReportOOMError();
+error:
+    return -1;
 }
 
-static void virshErrorHandler(void *opaque ATTRIBUTE_UNUSED, virErrorPtr err ATTRIBUTE_UNUSED)
+
+static void daemonErrorHandler(void *opaque ATTRIBUTE_UNUSED,
+                               virErrorPtr err ATTRIBUTE_UNUSED)
 {
     /* Don't do anything, since logging infrastructure already
      * took care of reporting the error */
@@ -866,38 +393,8 @@ static int daemonErrorLogFilter(virErrorPtr err, int priority)
     return priority;
 }
 
-
-static struct qemud_server *qemudInitialize(void) {
-    struct qemud_server *server;
-
-    if (VIR_ALLOC(server) < 0) {
-        VIR_ERROR(_("Failed to allocate struct qemud_server"));
-        return NULL;
-    }
-
-    server->privileged = geteuid() == 0 ? 1 : 0;
-    server->sigread = server->sigwrite = -1;
-
-    if (virMutexInit(&server->lock) < 0) {
-        VIR_ERROR(_("cannot initialize mutex"));
-        VIR_FREE(server);
-        return NULL;
-    }
-    if (virCondInit(&server->job) < 0) {
-        VIR_ERROR(_("cannot initialize condition variable"));
-        virMutexDestroy(&server->lock);
-        VIR_FREE(server);
-        return NULL;
-    }
-
-    if (virEventRegisterDefaultImpl() < 0) {
-        virMutexDestroy(&server->lock);
-        if (virCondDestroy(&server->job) < 0)
-        {}
-        VIR_FREE(server);
-        return NULL;
-    }
-
+static void daemonInitialize(void)
+{
     /*
      * Note that the order is important: the first ones have a higher
      * priority when calling virStateInitialize. We must register
@@ -951,1589 +448,169 @@ static struct qemud_server *qemudInitialize(void) {
     umlRegister();
 # endif
 #endif
-
-    return server;
 }
 
-static int qemudNetworkInit(struct qemud_server *server) {
-    char *sockname = NULL;
-    char *roSockname = NULL;
-#if HAVE_SASL
-    int err;
-#endif /* HAVE_SASL */
 
-    if (qemudInitPaths(server, &sockname, &roSockname) < 0)
-        goto cleanup;
+static int daemonSetupNetworking(virNetServerPtr srv,
+                                 struct daemonConfig *config,
+                                 const char *sock_path,
+                                 const char *sock_path_ro,
+                                 bool ipsock,
+                                 bool privileged)
+{
+    virNetServerServicePtr svc = NULL;
+    virNetServerServicePtr svcRO = NULL;
+    virNetServerServicePtr svcTCP = NULL;
+    virNetServerServicePtr svcTLS = NULL;
+    gid_t unix_sock_gid = 0;
+    int unix_sock_ro_mask = 0;
+    int unix_sock_rw_mask = 0;
+
+    if (config->unix_sock_group) {
+        if (!virNetServerIsPrivileged(srv)) {
+            VIR_WARN("Cannot set group when not running as root");
+            return -1;
+        }
+        if (virGetGroupID(config->unix_sock_group, &unix_sock_gid) < 0)
+            return -1;
+    }
 
-    if (qemudListenUnix(server, sockname, 0, auth_unix_rw) < 0)
-        goto cleanup;
-    sockname = NULL;
+    if (virStrToLong_i(config->unix_sock_ro_perms, NULL, 8, &unix_sock_ro_mask) != 0) {
+        VIR_ERROR(_("Failed to parse mode '%s'"), config->unix_sock_ro_perms);
+        goto error;
+    }
 
-    if (roSockname != NULL && qemudListenUnix(server, roSockname, 1, auth_unix_ro) < 0)
-        goto cleanup;
-    roSockname = NULL;
-
-#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;
-        }
+    if (virStrToLong_i(config->unix_sock_rw_perms, NULL, 8, &unix_sock_rw_mask) != 0) {
+        VIR_ERROR(_("Failed to parse mode '%s'"), config->unix_sock_rw_perms);
+        goto error;
     }
-#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();
+    if (!(svc = virNetServerServiceNewUNIX(sock_path,
+                                           unix_sock_rw_mask,
+                                           unix_sock_gid,
+                                           config->auth_unix_rw,
+                                           false,
+                                           NULL)))
+        goto error;
+    if (sock_path_ro &&
+        !(svcRO = virNetServerServiceNewUNIX(sock_path_ro,
+                                             unix_sock_ro_mask,
+                                             unix_sock_gid,
+                                             config->auth_unix_ro,
+                                             true,
+                                             NULL)))
+        goto error;
 
-        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 (virNetServerAddService(srv, svc, NULL) < 0)
+        goto error;
+    if (svcRO &&
+        virNetServerAddService(srv, svcRO, NULL) < 0)
+        goto error;
 
     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;
-        struct qemud_socket *sock;
-        int port = 0;
-        int ret;
-
-        server->mdns = libvirtd_mdns_new();
-
-        if (!mdns_name) {
-            char *groupname, *localhost, *tmp;
-
-            localhost = virGetHostname(NULL);
-            if (localhost == NULL)
-                /* we couldn't resolve the hostname; assume that we are
-                 * running in disconnected operation, and report a less
-                 * useful Avahi string
-                 */
-                ret = virAsprintf(&groupname, "Virtualization Host");
-            else {
-                /* Extract the host part of the potentially FQDN */
-                if ((tmp = strchr(localhost, '.')))
-                    *tmp = '\0';
-                ret = virAsprintf(&groupname, "Virtualization Host %s",
-                                  localhost);
-            }
-            VIR_FREE(localhost);
-            if (ret < 0) {
-                virReportOOMError();
-                goto cleanup;
-            }
-            group = libvirtd_mdns_add_group(server->mdns, groupname);
-            VIR_FREE(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 (virSocketGetPort(&sock->addr) != -1 &&
-                sock->type == QEMUD_SOCK_TYPE_TLS) {
-                port = virSocketGetPort(&sock->addr);
-                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 0;
-
- cleanup:
-    VIR_FREE(sockname);
-    VIR_FREE(roSockname);
-    return -1;
-}
-
-static int qemudNetworkEnable(struct qemud_server *server) {
-    struct qemud_socket *sock;
-
-    sock = server->sockets;
-    while (sock) {
-        if ((sock->watch = virEventAddHandle(sock->fd,
-                                             VIR_EVENT_HANDLE_READABLE |
-                                             VIR_EVENT_HANDLE_ERROR |
-                                             VIR_EVENT_HANDLE_HANGUP,
-                                             qemudDispatchServerEvent,
-                                             server, NULL)) < 0) {
-            VIR_ERROR(_("Failed to add server event callback"));
-            return -1;
-        }
-
-        sock = sock->next;
-    }
-    return 0;
-}
-
-
-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 (const char *dname)
-{
-    char **wildcards;
-
-    /* If the list is not set, allow any DN. */
-    wildcards = tls_allowed_dn_list;
-    if (!wildcards)
-        return 1;
-
-    while (*wildcards) {
-        if (fnmatch (*wildcards, dname, 0) == 0)
-            return 1;
-        wildcards++;
-    }
-
-    /* Print the client's DN. */
-    VIR_DEBUG("remoteCheckDN: failed: client DN is %s", dname);
-
-    return 0; /* Not found. */
-}
-
-static int
-remoteCheckCertificate(struct qemud_client *client)
-{
-    int ret;
-    unsigned int status;
-    const gnutls_datum_t *certs;
-    unsigned int nCerts, i;
-    time_t now;
-    char name[256];
-    size_t namesize = sizeof name;
-
-    memset(name, 0, namesize);
-
-    if ((ret = gnutls_certificate_verify_peers2 (client->tlssession, &status)) < 0){
-        VIR_ERROR(_("Failed to verify certificate peers: %s"),
-                  gnutls_strerror (ret));
-        goto authdeny;
-    }
-
-    if (status != 0) {
-        if (status & GNUTLS_CERT_INVALID)
-            VIR_ERROR(_("The client certificate is not trusted."));
-
-        if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
-            VIR_ERROR(_("The client certificate has unknown issuer."));
-
-        if (status & GNUTLS_CERT_REVOKED)
-            VIR_ERROR(_("The client certificate has been revoked."));
-
-#ifndef GNUTLS_1_0_COMPAT
-        if (status & GNUTLS_CERT_INSECURE_ALGORITHM)
-            VIR_ERROR(_("The client certificate uses an insecure algorithm."));
-#endif
-
-        goto authdeny;
-    }
-
-    if (gnutls_certificate_type_get(client->tlssession) != GNUTLS_CRT_X509) {
-        VIR_ERROR(_("Only x509 certificates are supported"));
-        goto authdeny;
-    }
-
-    if (!(certs = gnutls_certificate_get_peers(client->tlssession, &nCerts))) {
-        VIR_ERROR(_("The certificate has no peers"));
-        goto authdeny;
-    }
-
-    now = time (NULL);
-
-    for (i = 0; i < nCerts; i++) {
-        gnutls_x509_crt_t cert;
+        if (config->listen_tcp) {
+            if (!(svcTCP = virNetServerServiceNewTCP(config->listen_addr,
+                                                     config->tcp_port,
+                                                     config->auth_tcp,
+                                                     false,
+                                                     NULL)))
+                goto error;
 
-        if (gnutls_x509_crt_init (&cert) < 0) {
-            VIR_ERROR(_("Unable to initialize certificate"));
-            goto authfail;
+            if (virNetServerAddService(srv, svcTCP,
+                                       config->mdns_adv ? "_libvirt._tcp" : NULL) < 0)
+                goto error;
         }
 
-        if (gnutls_x509_crt_import(cert, &certs[i], GNUTLS_X509_FMT_DER) < 0) {
-            VIR_ERROR(_("Unable to load certificate"));
-            gnutls_x509_crt_deinit (cert);
-            goto authfail;
-        }
+        if (config->listen_tls) {
+            virNetTLSContextPtr ctxt = NULL;
 
-        if (i == 0) {
-            ret = gnutls_x509_crt_get_dn (cert, name, &namesize);
-            if (ret != 0) {
-                VIR_ERROR(_("Failed to get certificate distinguished name: %s"),
-                          gnutls_strerror(ret));
-                gnutls_x509_crt_deinit (cert);
-                goto authfail;
+            if (config->ca_file ||
+                config->cert_file ||
+                config->key_file) {
+                if (!(ctxt = virNetTLSContextNewServer(config->ca_file,
+                                                       config->crl_file,
+                                                       config->cert_file,
+                                                       config->key_file,
+                                                       (const char *const*)config->tls_allowed_dn_list,
+                                                       config->tls_no_verify_certificate ? false : true)))
+                    goto error;
+            } else {
+                if (!(ctxt = virNetTLSContextNewServerPath(NULL,
+                                                           !privileged,
+                                                           (const char *const*)config->tls_allowed_dn_list,
+                                                           config->tls_no_verify_certificate ? false : true)))
+                    goto error;
             }
 
-            if (!remoteCheckDN (name)) {
-                /* This is the most common error: make it informative. */
-                VIR_ERROR(_("Client's Distinguished Name is not on the list "
-                             "of allowed clients (tls_allowed_dn_list).  Use "
-                             "'certtool -i --infile clientcert.pem' to view the"
-                             "Distinguished Name field in the client certificate,"
-                             "or run this daemon with --verbose option."));
-                gnutls_x509_crt_deinit (cert);
-                goto authdeny;
+            if (!(svcTLS =
+                  virNetServerServiceNewTCP(config->listen_addr,
+                                            config->tls_port,
+                                            config->auth_tls,
+                                            false,
+                                            ctxt))) {
+                virNetTLSContextFree(ctxt);
+                goto error;
             }
-        }
-
-        if (gnutls_x509_crt_get_expiration_time (cert) < now) {
-            VIR_ERROR(_("The client certificate has expired"));
-            gnutls_x509_crt_deinit (cert);
-            goto authdeny;
-        }
+            if (virNetServerAddService(srv, svcTLS,
+                                       config->mdns_adv &&
+                                       !config->listen_tcp ? "_libvirt._tcp" : NULL) < 0)
+                goto error;
 
-        if (gnutls_x509_crt_get_activation_time (cert) > now) {
-            VIR_ERROR(_("The client certificate is not yet active"));
-            gnutls_x509_crt_deinit (cert);
-            goto authdeny;
+            virNetTLSContextFree(ctxt);
         }
     }
 
-    PROBE(CLIENT_TLS_ALLOW, "fd=%d, name=%s", client->fd, (char *)name);
-    return 0;
-
-authdeny:
-    PROBE(CLIENT_TLS_DENY, "fd=%d, name=%s", client->fd, (char *)name);
-    return -1;
-
-authfail:
-    PROBE(CLIENT_TLS_FAIL, "fd=%d", client->fd);
-    return -1;
-}
-
-/* Check the client's access. */
-static int
-remoteCheckAccess (struct qemud_client *client)
-{
-    struct qemud_client_message *confirm;
-
-    /* Verify client certificate. */
-    if (remoteCheckCertificate (client) == -1) {
-        VIR_ERROR(_("remoteCheckCertificate: "
-                     "failed to verify client's certificate"));
-        if (!tls_no_verify_certificate) return -1;
-        else VIR_INFO("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;
-    virSocketAddr addr;
-    char *addrstr = NULL;
-    struct qemud_client *client = NULL;
-    int no_slow_start = 1;
-    int i;
-
-    addr.len = sizeof(addr.data.stor);
-    if ((fd = accept(sock->fd, &addr.data.sa, &addr.len)) < 0) {
-        char ebuf[1024];
-        if (errno == EAGAIN)
-            return 0;
-        VIR_ERROR(_("Failed to accept connection: %s"),
-                  virStrerror(errno, ebuf, sizeof ebuf));
-        return -1;
-    }
-    if (!(addrstr = virSocketFormatAddrFull(&addr, true, ";"))) {
-        VIR_ERROR(_("Failed to format addresss: out of memory"));
-        goto error;
-    }
-
-    PROBE(CLIENT_CONNECT, "fd=%d, readonly=%d localAddr=%s remoteAddr=%s",
-          fd, sock->readonly, sock->addrstr, addrstr);
-
-    if (server->nclients >= max_clients) {
-        VIR_ERROR(_("Too many active clients (%d), dropping connection from %s"),
-                  max_clients, addrstr);
-        goto error;
-    }
-
-    if (VIR_RESIZE_N(server->clients, server->nclients_max,
-                     server->nclients, 1) < 0) {
-        VIR_ERROR(_("Out of memory allocating clients"));
-        goto error;
-    }
-
-#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);
-            goto error;
-        }
-
-        if (!priv_ismember (privs, PRIV_VIRT_MANAGE)) {
-            ucred_free (ucred);
+    if (config->auth_unix_rw == REMOTE_AUTH_SASL ||
+        config->auth_unix_ro == REMOTE_AUTH_SASL ||
+        config->auth_tcp == REMOTE_AUTH_SASL ||
+        config->auth_tls == REMOTE_AUTH_SASL) {
+        saslCtxt = virNetSASLContextNewServer(
+            (const char *const*)config->sasl_allowed_username_list);
+        if (!saslCtxt)
             goto error;
-        }
-
-        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) {
-        goto error;
-    }
-
-    if (VIR_ALLOC(client) < 0)
-        goto error;
-    if (virMutexInit(&client->lock) < 0) {
-        VIR_ERROR(_("cannot initialize mutex"));
-        goto error;
-    }
-
-    client->magic = QEMUD_CLIENT_MAGIC;
-    client->fd = fd;
-    client->readonly = sock->readonly;
-    client->type = sock->type;
-    client->auth = sock->auth;
-    client->addr = addr;
-    client->addrstr = addrstr;
-    addrstr = NULL;
-
-    for (i = 0 ; i < VIR_DOMAIN_EVENT_ID_LAST ; i++) {
-        client->domainEventCallbackID[i] = -1;
     }
 
-    /* Prepare one for packet receive */
-    if (VIR_ALLOC(client->rx) < 0)
-        goto error;
-    client->rx->bufferLength = REMOTE_MESSAGE_HEADER_XDR_LEN;
+#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();
 
-#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)
+        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 error;
-
-        /* Client is running as root, so disable auth */
-        if (uid == 0) {
-            VIR_INFO("Turn off polkit auth for privileged client pid %d from %s",
-                     pid, client->addrstr);
-            client->auth = REMOTE_AUTH_NONE;
         }
+        dbus_connection_set_exit_on_disconnect(server->sysbus, FALSE);
     }
 #endif
 
-    if (client->type != QEMUD_SOCK_TYPE_TLS) {
-        /* Plain socket, so prepare to read first message */
-        if (qemudRegisterClientEvent (server, client) < 0)
-            goto error;
-    } else {
-        int ret;
-
-        client->tlssession = remoteInitializeTLSSession ();
-        if (client->tlssession == NULL)
-            goto error;
-
-        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 error;
-
-            /* Handshake & cert check OK,  so prepare to read first message */
-            if (qemudRegisterClientEvent(server, client) < 0)
-                goto error;
-        } 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 error;
-        } else {
-            PROBE(CLIENT_TLS_FAIL, "fd=%d", client->fd);
-            VIR_ERROR(_("TLS handshake failed for client %s: %s"),
-                      client->addrstr, gnutls_strerror (ret));
-            goto error;
-        }
-    }
-
-    server->clients[server->nclients++] = client;
-
-    if (server->nclients > server->nactiveworkers &&
-        server->nactiveworkers < server->nworkers) {
-        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;
 
 error:
-    if (client) {
-        if (client->tlssession) gnutls_deinit (client->tlssession);
-        if (client) {
-            VIR_FREE(client->addrstr);
-            VIR_FREE(client->rx);
-        }
-        VIR_FREE(client);
-    }
-    VIR_FREE(addrstr);
-    VIR_FORCE_CLOSE(fd);
-    PROBE(CLIENT_DISCONNECT, "fd=%d", fd);
+    virNetServerServiceFree(svcTLS);
+    virNetServerServiceFree(svcTCP);
+    virNetServerServiceFree(svc);
+    virNetServerServiceFree(svcRO);
     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) {
-        virEventRemoveHandle(client->watch);
-        client->watch = -1;
-    }
-
-    /* Deregister event delivery callback */
-    if (client->conn) {
-        int i;
-
-        for (i = 0 ; i < VIR_DOMAIN_EVENT_ID_LAST ; i++) {
-            if (client->domainEventCallbackID[i] != -1) {
-                VIR_DEBUG("Deregistering to relay remote events %d", i);
-                virConnectDomainEventDeregisterAny(client->conn,
-                                                   client->domainEventCallbackID[i]);
-            }
-            client->domainEventCallbackID[i] = -1;
-        }
-    }
-
-#if HAVE_SASL
-    if (client->saslconn) {
-        sasl_dispose(&client->saslconn);
-        client->saslconn = NULL;
-    }
-    VIR_FREE(client->saslUsername);
-#endif
-    if (client->tlssession) {
-        gnutls_deinit (client->tlssession);
-        client->tlssession = NULL;
-    }
-    if (client->fd != -1) {
-        PROBE(CLIENT_DISCONNECT, "fd=%d", client->fd);
-        VIR_FORCE_CLOSE(client->fd);
-    }
-    VIR_FREE(client->addrstr);
-}
-
-
-/* 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) {
-            if (worker->quitRequest ||
-                virCondWait(&server->job, &server->lock) < 0) {
-                virMutexUnlock(&server->lock);
-                return NULL;
-            }
-        }
-        if (worker->quitRequest) {
-            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)
+static int daemonShutdownCheck(virNetServerPtr srv ATTRIBUTE_UNUSED,
+                               void *opaque ATTRIBUTE_UNUSED)
 {
-    pthread_attr_t attr;
-    int ret = -1;
-
-    if (pthread_attr_init(&attr) != 0)
-        return -1;
-    /* We want to join workers, so don't detach them */
-    /*pthread_attr_setdetachstate(&attr, 1);*/
-
-    if (worker->hasThread)
-        goto cleanup;
-
-    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;
-        goto cleanup;
-    }
-
-    ret = 0;
-cleanup:
-    pthread_attr_destroy(&attr);
-    return ret;
-}
-
-
-/*
- * 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;
-    }
-
-    /* VIR_DEBUG("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;
-        ssize_t encodedLen;
-
-        encodedLen = qemudClientReadBuf(client, client->saslTemporary,
-                                        sizeof(client->saslTemporary));
-
-        if (encodedLen <= 0)
-            return encodedLen;
-
-        ret = sasl_decode(client->saslconn, client->saslTemporary, 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) {
-    /* VIR_DEBUG("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);
-            VIR_DEBUG("Failed to decode packet length");
-            qemudDispatchClientFailure(client);
-            return;
-        }
-        xdr_destroy (&x);
-
-        if (len < REMOTE_MESSAGE_HEADER_XDR_LEN) {
-            VIR_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) {
-            VIR_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) {
-            int ret;
-            ret = (filter->query)(client, msg, filter->opaque);
-            if (ret == 1) {
-                msg = NULL;
-                break;
-            } else if (ret == -1) {
-                VIR_FREE(msg);
-                qemudDispatchClientFailure(client);
-                return;
-            }
-            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);
-}
-
-
-void
-qemudClientMessageRelease(struct qemud_client *client,
-                          struct qemud_client_message *msg)
-{
-    if (msg->streamTX) {
-        remoteStreamMessageFinished(client, msg);
-    } else if (!msg->async)
-        client->nrequests--;
-
-    /* See if the recv queue is currently throttled */
-    if (!client->rx &&
-        client->nrequests < max_client_requests) {
-        /* Reset message record for next RX attempt */
-        memset(msg, 0, sizeof(*msg));
-        client->rx = msg;
-        /* Get ready to receive next message */
-        client->rx->bufferLength = REMOTE_MESSAGE_HEADER_XDR_LEN;
-    } else {
-        VIR_FREE(msg);
-    }
-
-    qemudUpdateClientEvent(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);
-
-            qemudClientMessageRelease(client, reply);
-
-            if (client->closing)
-                qemudDispatchClientFailure(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 {
-        PROBE(CLIENT_TLS_FAIL, "fd=%d", client->fd);
-        /* 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 = virEventAddHandle(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);
-
-    virEventUpdateHandle(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 (virEventRunDefaultImpl() < 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) {
-        VIR_DEBUG("Timer expired but still active, not shutting down");
-        virEventUpdateTimeout(timerid, -1);
-    } else {
-        VIR_DEBUG("Timer expired and inactive, shutting down");
-        server->quitEventThread = 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);
-    }
-
-    while (client->streams)
-        remoteRemoveClientStream(client, client->streams);
-
-    if (client->conn)
-        virConnectClose(client->conn);
-    virMutexDestroy(&client->lock);
-    VIR_FREE(client->addrstr);
-    VIR_FREE(client);
-}
-
-static void *qemudRunLoop(void *opaque) {
-    struct qemud_server *server = opaque;
-    int timerid = -1;
-    int i;
-    int timerActive = 0;
-
-    virMutexLock(&server->lock);
-
-    if (timeout > 0 &&
-        (timerid = virEventAddTimeout(-1,
-                                      qemudInactiveTimer,
-                                      server, NULL)) < 0) {
-        VIR_ERROR(_("Failed to register shutdown timeout"));
-        return NULL;
-    }
-
-    if (min_workers > max_workers)
-        max_workers = min_workers;
-
-    server->nworkers = max_workers;
-    if (VIR_ALLOC_N(server->workers, server->nworkers) < 0) {
-        VIR_ERROR(_("Failed to allocate workers"));
-        return NULL;
-    }
-
-    for (i = 0 ; i < min_workers ; i++) {
-        if (qemudStartWorker(server, &server->workers[i]) < 0)
-            goto cleanup;
-        server->nactiveworkers++;
-    }
-
-    for (;!server->quitEventThread;) {
-        /* 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) {
-                    VIR_DEBUG("Deactivating shutdown timer %d", timerid);
-                    virEventUpdateTimeout(timerid, -1);
-                    timerActive = 0;
-                }
-            } else {
-                if (!virStateActive() &&
-                    !server->clients) {
-                    VIR_DEBUG("Activating shutdown timer %d", timerid);
-                    virEventUpdateTimeout(timerid, timeout * 1000);
-                    timerActive = 1;
-                }
-            }
-        }
-
-        virMutexUnlock(&server->lock);
-        if (qemudOneLoop() < 0) {
-            virMutexLock(&server->lock);
-            VIR_DEBUG("Loop iteration error, exiting");
-            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));
-
-                VIR_SHRINK_N(server->clients, server->nclients_max,
-                             server->nclients_max - server->nclients);
-                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--;
-            }
-        }
-    }
-
-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);
-    for (i = 0; i < server->nclients; i++)
-        qemudFreeClient(server->clients[i]);
-    server->nclients = 0;
-    VIR_SHRINK_N(server->clients, server->nclients_max, server->nclients_max);
-
-    virMutexUnlock(&server->lock);
-    return NULL;
-}
-
-
-static int
-qemudStartEventLoop(struct qemud_server *server)
-{
-    pthread_attr_t attr;
-    int ret = -1;
-
-    if (pthread_attr_init(&attr) != 0)
-        return -1;
-    /* We want to join the eventloop, so don't detach it */
-    /*pthread_attr_setdetachstate(&attr, 1);*/
-
-    if (pthread_create(&server->eventThread,
-                       &attr,
-                       qemudRunLoop,
-                       server) != 0)
-        goto cleanup;
-
-    server->hasEventThread = 1;
-
-    ret = 0;
-cleanup:
-    pthread_attr_destroy(&attr);
-    return ret;
-}
-
-
-static void qemudCleanup(struct qemud_server *server) {
-    struct qemud_socket *sock;
-
-    VIR_FORCE_CLOSE(server->sigread);
-    VIR_FORCE_CLOSE(server->sigwrite);
-
-    sock = server->sockets;
-    while (sock) {
-        struct qemud_socket *next = sock->next;
-        if (sock->watch)
-            virEventRemoveHandle(sock->watch);
-        VIR_FORCE_CLOSE(sock->fd);
-
-        /* Unlink unix domain sockets which are not in
-         * the abstract namespace */
-        if (sock->path &&
-            sock->path[0] != '@')
-            unlink(sock->path);
-        VIR_FREE(sock->path);
-        VIR_FREE(sock->addrstr);
-
-        VIR_FREE(sock);
-        sock = next;
-    }
-    VIR_FREE(server->logDir);
-
-#ifdef HAVE_SASL
-    if (server->saslUsernameWhitelist) {
-        char **list = server->saslUsernameWhitelist;
-        while (*list) {
-            VIR_FREE(*list);
-            list++;
-        }
-        VIR_FREE(server->saslUsernameWhitelist);
-    }
-#endif
-
-#if HAVE_POLKIT0
-        if (server->sysbus)
-            dbus_connection_unref(server->sysbus);
-#endif
-
-    virStateCleanup();
-
-    if (virCondDestroy(&server->job) < 0) {
-        ;
-    }
-    virMutexDestroy(&server->lock);
+    if (virStateActive())
+        return 0;
 
-    VIR_FREE(server);
+    return 1;
 }
 
+
 /* 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
@@ -2632,13 +709,11 @@ checkType (virConfValuePtr p, const char *filename,
         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"),		\
-                          virStrerror(errno, ebuf, sizeof ebuf));       \
-                goto free_and_fail;                                     \
+                goto error;                                             \
+            VIR_FREE(data->var_name);                                   \
+            if (!(data->var_name = strdup (p->str))) {                  \
+                virReportOOMError();                                    \
+                goto error;                                             \
             }                                                           \
         }                                                               \
     } while (0)
@@ -2649,8 +724,8 @@ checkType (virConfValuePtr p, const char *filename,
         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;                                          \
+                goto error;                                             \
+            data->var_name = p->l;                                      \
         }                                                               \
     } while (0)
 
@@ -2669,15 +744,11 @@ static int remoteConfigGetAuth(virConfPtr conf, const char *key, int *auth, cons
         return 0;
 
     if (STREQ(p->str, "none")) {
-        *auth = REMOTE_AUTH_NONE;
-#if HAVE_SASL
+        *auth = VIR_NET_SERVER_SERVICE_AUTH_NONE;
     } else if (STREQ(p->str, "sasl")) {
-        *auth = REMOTE_AUTH_SASL;
-#endif
-#if HAVE_POLKIT
+        *auth = VIR_NET_SERVER_SERVICE_AUTH_SASL;
     } else if (STREQ(p->str, "polkit")) {
-        *auth = REMOTE_AUTH_POLKIT;
-#endif
+        *auth = VIR_NET_SERVER_SERVICE_AUTH_POLKIT;
     } else {
         VIR_ERROR(_("remoteReadConfigFile: %s: %s: unsupported auth %s"),
                   filename, key, p->str);
@@ -2687,26 +758,6 @@ static int remoteConfigGetAuth(virConfPtr conf, const char *key, int *auth, cons
     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 the logfile libvirtd.log,
@@ -2714,19 +765,11 @@ remoteReadSaslAllowedUsernameList (virConfPtr conf ATTRIBUTE_UNUSED,
  * informational and debug messages. Default size if 64 kB.
  */
 static int
-qemudSetLogging(struct qemud_server *server, virConfPtr conf,
-                const char *filename)
+daemonSetupLogging(struct daemonConfig *config,
+                   bool privileged,
+                   bool verbose,
+                   bool godaemon)
 {
-    int log_level = 0;
-    int log_buffer_size = 64;
-    char *log_filters = NULL;
-    char *log_outputs = NULL;
-    char *log_file = NULL;
-    int ret = -1;
-
-    GET_CONF_INT (conf, filename, log_buffer_size);
-    virLogSetBufferSize(log_buffer_size);
-
     virLogReset();
 
     /*
@@ -2743,21 +786,18 @@ qemudSetLogging(struct qemud_server *server, virConfPtr conf,
      * level has been set, we must process variables in the opposite
      * order, each one overriding the previous.
      */
-    GET_CONF_INT (conf, filename, log_level);
-    if (log_level != 0)
-        virLogSetDefaultPriority(log_level);
+    if (config->log_level != 0)
+        virLogSetDefaultPriority(config->log_level);
 
     virLogSetFromEnv();
 
-    if (virLogGetNbFilters() == 0) {
-        GET_CONF_STR (conf, filename, log_filters);
-        virLogParseFilters(log_filters);
-    }
+    virLogSetBufferSize(config->log_buffer_size);
 
-    if (virLogGetNbOutputs() == 0) {
-        GET_CONF_STR (conf, filename, log_outputs);
-        virLogParseOutputs(log_outputs);
-    }
+    if (virLogGetNbFilters() == 0)
+        virLogParseFilters(config->log_filters);
+
+    if (virLogGetNbOutputs() == 0)
+        virLogParseOutputs(config->log_outputs);
 
     /*
      * If no defined outputs, then direct to libvirtd.log when running
@@ -2767,26 +807,26 @@ qemudSetLogging(struct qemud_server *server, virConfPtr conf,
         char *tmp = NULL;
 
         if (godaemon) {
-            if (server->privileged) {
+            if (privileged) {
                 if (virAsprintf(&tmp, "%d:file:%s/log/libvirt/libvirtd.log",
                                 virLogGetDefaultPriority(),
                                 LOCALSTATEDIR) == -1)
-                    goto out_of_memory;
+                    goto no_memory;
             } else {
                 char *userdir = virGetUserDirectory(geteuid());
                 if (!userdir)
-                    goto free_and_fail;
+                    goto error;
 
                 if (virAsprintf(&tmp, "%d:file:%s/.libvirt/libvirtd.log",
                                 virLogGetDefaultPriority(), userdir) == -1) {
                     VIR_FREE(userdir);
-                    goto out_of_memory;
+                    goto no_memory;
                 }
                 VIR_FREE(userdir);
             }
         } else {
             if (virAsprintf(&tmp, "%d:stderr", virLogGetDefaultPriority()) < 0)
-                goto out_of_memory;
+                goto no_memory;
         }
         virLogParseOutputs(tmp);
         VIR_FREE(tmp);
@@ -2798,60 +838,191 @@ qemudSetLogging(struct qemud_server *server, virConfPtr conf,
     if ((verbose) && (virLogGetDefaultPriority() > VIR_LOG_INFO))
         virLogSetDefaultPriority(VIR_LOG_INFO);
 
-    ret = 0;
+    return 0;
+
+no_memory:
+    virReportOOMError();
+error:
+    return -1;
+}
+
+
+static int
+daemonConfigFilePath(bool privileged, char **configfile)
+{
+    if (privileged) {
+        if (!(*configfile = strdup(SYSCONFDIR "/libvirt/libvirtd.conf")))
+            goto no_memory;
+    } else {
+        char *userdir = NULL;
+
+        if (!(userdir = virGetUserDirectory(geteuid())))
+            goto error;
+
+        if (virAsprintf(configfile, "%s/.libvirt/libvirtd.conf", userdir) < 0) {
+            VIR_FREE(userdir);
+            goto no_memory;
+        }
+        VIR_FREE(userdir);
+    }
 
-free_and_fail:
-    VIR_FREE(log_filters);
-    VIR_FREE(log_outputs);
-    VIR_FREE(log_file);
-    return(ret);
+    return 0;
 
-out_of_memory:
+no_memory:
     virReportOOMError();
-    goto free_and_fail;
+error:
+    return -1;
 }
 
-/*
- * Stop logging
- */
 static void
-qemudStopLogging(void)
+daemonConfigFree(struct daemonConfig *data);
+
+static struct daemonConfig*
+daemonConfigNew(bool privileged)
 {
-    virLogShutdown();
+    struct daemonConfig *data;
+    char *localhost;
+    int ret;
+
+    if (VIR_ALLOC(data) < 0) {
+        virReportOOMError();
+        return NULL;
+    }
+
+    data->listen_tls = 1;
+    data->listen_tcp = 0;
+
+    if (!(data->tls_port = strdup(LIBVIRTD_TLS_PORT)))
+        goto no_memory;
+    if (!(data->tcp_port = strdup(LIBVIRTD_TCP_PORT)))
+        goto no_memory;
+
+    /* Only default to PolicyKit if running as root */
+#if HAVE_POLKIT
+    if (privileged) {
+        data->auth_unix_rw = REMOTE_AUTH_POLKIT;
+        data->auth_unix_ro = REMOTE_AUTH_POLKIT;
+    } else {
+#endif
+        data->auth_unix_rw = REMOTE_AUTH_NONE;
+        data->auth_unix_ro = REMOTE_AUTH_NONE;
+#if HAVE_POLKIT
+    }
+#endif
+
+    if (data->auth_unix_rw == REMOTE_AUTH_POLKIT)
+        data->unix_sock_rw_perms = strdup("0777"); /* Allow world */
+    else
+        data->unix_sock_rw_perms = strdup("0700"); /* Allow user only */
+    data->unix_sock_ro_perms = strdup("0777"); /* Always allow world */
+    if (!data->unix_sock_ro_perms ||
+        !data->unix_sock_rw_perms)
+        goto no_memory;
+
+#if HAVE_SASL
+    data->auth_tcp = REMOTE_AUTH_SASL;
+#else
+    data->auth_tcp = REMOTE_AUTH_NONE;
+#endif
+    data->auth_tls = REMOTE_AUTH_NONE;
+
+    data->mdns_adv = 1;
+
+    data->min_workers = 5;
+    data->max_workers = 20;
+    data->max_clients = 20;
+
+    data->max_requests = 20;
+    data->max_client_requests = 5;
+
+    data->log_buffer_size = 64;
+
+    data->audit_level = 1;
+    data->audit_logging = 0;
+
+    localhost = virGetHostname(NULL);
+    if (localhost == NULL) {
+        /* we couldn't resolve the hostname; assume that we are
+         * running in disconnected operation, and report a less
+         * useful Avahi string
+         */
+        ret = virAsprintf(&data->mdns_name, "Virtualization Host");
+    } else {
+        char *tmp;
+        /* Extract the host part of the potentially FQDN */
+        if ((tmp = strchr(localhost, '.')))
+            *tmp = '\0';
+        ret = virAsprintf(&data->mdns_name, "Virtualization Host %s",
+                          localhost);
+    }
+    VIR_FREE(localhost);
+    if (ret < 0)
+        goto no_memory;
+
+    return data;
+
+no_memory:
+    virReportOOMError();
+    daemonConfigFree(data);
+    return NULL;
+}
+
+static void
+daemonConfigFree(struct daemonConfig *data)
+{
+    char **tmp;
+
+    if (!data)
+        return;
+
+    VIR_FREE(data->listen_addr);
+    VIR_FREE(data->tls_port);
+    VIR_FREE(data->tcp_port);
+
+    VIR_FREE(data->unix_sock_ro_perms);
+    VIR_FREE(data->unix_sock_rw_perms);
+    VIR_FREE(data->unix_sock_group);
+    VIR_FREE(data->unix_sock_dir);
+    VIR_FREE(data->mdns_name);
+
+    tmp = data->tls_allowed_dn_list;
+    while (tmp && *tmp) {
+        VIR_FREE(*tmp);
+        tmp++;
+    }
+    VIR_FREE(data->tls_allowed_dn_list);
+
+    tmp = data->sasl_allowed_username_list;
+    while (tmp && *tmp) {
+        VIR_FREE(*tmp);
+        tmp++;
+    }
+    VIR_FREE(data->sasl_allowed_username_list);
+
+    VIR_FREE(data->key_file);
+    VIR_FREE(data->ca_file);
+    VIR_FREE(data->cert_file);
+    VIR_FREE(data->crl_file);
+
+    VIR_FREE(data->log_filters);
+    VIR_FREE(data->log_outputs);
+
+    VIR_FREE(data);
 }
 
+
 /* 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)
+daemonConfigLoad(struct daemonConfig *data,
+                 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;
-    char *host_uuid = 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(server, conf, filename) < 0)
-        goto free_and_fail;
+    if (!conf)
+        return -1;
 
     GET_CONF_INT (conf, filename, listen_tcp);
     GET_CONF_INT (conf, filename, listen_tls);
@@ -2859,76 +1030,28 @@ remoteReadConfigFile (struct qemud_server *server, const char *filename)
     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 (remoteConfigGetAuth(conf, "auth_unix_rw", &data->auth_unix_rw, filename) < 0)
+        goto error;
 #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;
+    if (data->auth_unix_rw == REMOTE_AUTH_POLKIT) {
+        VIR_FREE(data->unix_sock_rw_perms);
+        if (!(data->unix_sock_rw_perms = strdup("0777")))
+            goto no_memory;
+    }
 #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;
+    if (remoteConfigGetAuth(conf, "auth_unix_ro", &data->auth_unix_ro, filename) < 0)
+        goto error;
+    if (remoteConfigGetAuth(conf, "auth_tcp", &data->auth_tcp, filename) < 0)
+        goto error;
+    if (remoteConfigGetAuth(conf, "auth_tls", &data->auth_tls, filename) < 0)
+        goto error;
 
     GET_CONF_STR (conf, filename, unix_sock_group);
-    if (unix_sock_group) {
-        if (!server->privileged) {
-            VIR_WARN("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(_("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(_("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);
-        }
-        VIR_FREE(unix_sock_group);
-    }
-
     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;
-        }
-        VIR_FREE(unix_sock_ro_perms);
-    }
-
     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;
-        }
-        VIR_FREE(unix_sock_rw_perms);
-    }
 
     GET_CONF_STR (conf, filename, unix_sock_dir);
 
@@ -2942,12 +1065,14 @@ remoteReadConfigFile (struct qemud_server *server, const char *filename)
     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 (remoteConfigGetStringList(conf, "tls_allowed_dn_list",
+                                  &data->tls_allowed_dn_list, filename) < 0)
+        goto error;
+
 
-    if (remoteReadSaslAllowedUsernameList (conf, server, filename) < 0)
-        goto free_and_fail;
+    if (remoteConfigGetStringList(conf, "sasl_allowed_username_list",
+                                  &data->sasl_allowed_username_list, filename) < 0)
+        goto error;
 
 
     GET_CONF_INT (conf, filename, min_workers);
@@ -2961,51 +1086,32 @@ remoteReadConfigFile (struct qemud_server *server, const char *filename)
     GET_CONF_INT (conf, filename, audit_logging);
 
     GET_CONF_STR (conf, filename, host_uuid);
-    if (virSetHostUUIDStr(host_uuid)) {
-        VIR_ERROR(_("invalid host UUID: %s"), host_uuid);
-        goto free_and_fail;
-    }
 
-    VIR_FREE(host_uuid);
+    GET_CONF_INT (conf, filename, log_level);
+    GET_CONF_STR (conf, filename, log_filters);
+    GET_CONF_STR (conf, filename, log_outputs);
+    GET_CONF_INT (conf, filename, log_buffer_size);
 
     virConfFree (conf);
     return 0;
 
- free_and_fail:
+no_memory:
+    virReportOOMError();
+error:
     virConfFree (conf);
-    VIR_FREE(host_uuid);
-    VIR_FREE(mdns_name);
-    VIR_FREE(unix_sock_ro_perms);
-    VIR_FREE(unix_sock_rw_perms);
-    VIR_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++)
-            VIR_FREE(tls_allowed_dn_list[i]);
-        VIR_FREE(tls_allowed_dn_list);
-    }
-
     return -1;
 }
 
 /* Display version information. */
 static void
-version (void)
+daemonVersion(const char *argv0)
 {
     printf ("%s (%s) %s\n", argv0, PACKAGE_NAME, PACKAGE_VERSION);
 }
 
 #ifdef __sun
 static int
-qemudSetupPrivs (void)
+daemonSetupPrivs(void)
 {
     chown ("/var/run/libvirt", SYSTEM_UID, SYSTEM_UID);
 
@@ -3024,84 +1130,61 @@ qemudSetupPrivs (void)
     return 0;
 }
 #else
-# define qemudSetupPrivs() 0
+# define daemonSetupPrivs() 0
 #endif
 
 
-/*
- * Doing anything non-trivial in signal handlers is pretty dangerous,
- * since there are very few async-signal safe POSIX funtions. To
- * deal with this we setup a very simple signal handler. It simply
- * writes the signal number to a pipe. The main event loop then sees
- * the signal on the pipe and can safely do the processing from
- * event loop context
- */
-static int
-daemonSetupSignals(struct qemud_server *server)
+static void daemonShutdownHandler(virNetServerPtr srv,
+                                  siginfo_t *sig ATTRIBUTE_UNUSED,
+                                  void *opaque ATTRIBUTE_UNUSED)
 {
-    struct sigaction sig_action;
-    int sigpipe[2];
+    virNetServerQuit(srv);
+}
 
-    if (pipe(sigpipe) < 0)
+static int daemonSetupSignals(virNetServerPtr srv)
+{
+    if (virNetServerAddSignalHandler(srv, SIGINT, daemonShutdownHandler, NULL) < 0)
         return -1;
+    if (virNetServerAddSignalHandler(srv, SIGQUIT, daemonShutdownHandler, NULL) < 0)
+        return -1;
+    if (virNetServerAddSignalHandler(srv, SIGTERM, daemonShutdownHandler, NULL) < 0)
+        return -1;
+    return 0;
+}
 
-    if (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 error;
-    }
-
-    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);
+static void daemonRunStateInit(void *opaque)
+{
+    virNetServerPtr srv = opaque;
 
-    /*
-     * catch fatal errors to dump a log, also hook to USR2 for dynamic
-     * debugging purposes or testing
-     */
-    sig_action.sa_sigaction = sig_fatal;
-    sigaction(SIGFPE, &sig_action, NULL);
-    sigaction(SIGSEGV, &sig_action, NULL);
-    sigaction(SIGILL, &sig_action, NULL);
-    sigaction(SIGABRT, &sig_action, NULL);
-    sigaction(SIGBUS, &sig_action, NULL);
-    sigaction(SIGUSR2, &sig_action, NULL);
-
-    sig_action.sa_handler = SIG_IGN;
-    sigaction(SIGPIPE, &sig_action, NULL);
-
-    if (virEventAddHandle(sigpipe[0],
-                          VIR_EVENT_HANDLE_READABLE,
-                          qemudDispatchSignalEvent,
-                          server, NULL) < 0) {
-        VIR_ERROR(_("Failed to register callback for signal pipe"));
-        goto error;
+    /* Start the stateful HV drivers
+     * This is delibrately done after telling the parent process
+     * we're ready, since it can take a long time and this will
+     * seriously delay OS bootup process */
+    if (virStateInitialize(virNetServerIsPrivileged(srv)) < 0) {
+        VIR_ERROR(_("Driver state initialization failed"));
+        virNetServerFree(srv);
+        return;
     }
 
-    server->sigread = sigpipe[0];
-    server->sigwrite = sigpipe[1];
-    sigwrite = sigpipe[1];
+    /* Only now accept clients from network */
+    virNetServerUpdateServices(srv, true);
+    virNetServerFree(srv);
+}
 
+static int daemonStateInit(virNetServerPtr srv)
+{
+    virThread thr;
+    virNetServerRef(srv);
+    if (virThreadCreate(&thr, false, daemonRunStateInit, srv) < 0) {
+        virNetServerFree(srv);
+        return -1;
+    }
     return 0;
-
-error:
-    VIR_FORCE_CLOSE(sigpipe[0]);
-    VIR_FORCE_CLOSE(sigpipe[1]);
-    return -1;
 }
 
 /* Print command-line usage. */
 static void
-usage (void)
+daemonUsage(const char *argv0, bool privileged)
 {
     fprintf (stderr,
              _("\n\
@@ -3117,38 +1200,55 @@ Options:\n\
      | --version         Display version information.\n\
   -p | --pid-file <file> Change name of PID file.\n\
 \n\
-libvirt management daemon:\n\
-\n\
+libvirt management daemon:\n"), argv0);
+
+    if (privileged) {
+        fprintf(stderr,
+                _("\n\
   Default paths:\n\
 \n\
     Configuration file (unless overridden by -f):\n\
       %s/libvirt/libvirtd.conf\n\
 \n\
-    Sockets (as root):\n\
+    Sockets:\n\
       %s/run/libvirt/libvirt-sock\n\
       %s/run/libvirt/libvirt-sock-ro\n\
 \n\
-    Sockets (as non-root):\n\
+    TLS:\n\
+      CA certificate:     %s/pki/CA/caert.pem\n\
+      Server certificate: %s/pki/libvirt/servercert.pem\n\
+      Server private key: %s/pki/libvirt/private/serverkey.pem\n\
+\n\
+    PID file (unless overridden by -p):\n\
+      %s/run/libvirtd.pid\n\
+\n"),
+                SYSCONFDIR,
+                LOCALSTATEDIR,
+                LOCALSTATEDIR,
+                SYSCONFDIR,
+                SYSCONFDIR,
+                SYSCONFDIR,
+                LOCALSTATEDIR);
+    } else {
+        fprintf(stderr,
+                "%s", _("\n\
+  Default paths:\n\
+\n\
+    Configuration file (unless overridden by -f):\n\
+      $HOME/.libvirt/libvirtd.conf\n\
+\n\
+    Sockets:\n\
       $HOME/.libvirt/libvirt-sock (in UNIX abstract namespace)\n\
 \n\
     TLS:\n\
-      CA certificate:     %s\n\
-      Server certificate: %s\n\
-      Server private key: %s\n\
+      CA certificate:     $HOME/.pki/libvirt/cacert.pem\n\
+      Server certificate: $HOME/.pki/libvirt/servercert.pem\n\
+      Server private key: $HOME/.pki/libvirt/serverkey.pem\n\
 \n\
-    PID file (unless overridden by --pid-file):\n\
-      %s\n\
-\n"),
-               argv0,
-               SYSCONFDIR,
-               LOCALSTATEDIR,
-               LOCALSTATEDIR,
-               LIBVIRT_CACERT,
-               LIBVIRT_SERVERCERT,
-               LIBVIRT_SERVERKEY,
-               (REMOTE_PID_FILE[0] != '\0'
-                ? REMOTE_PID_FILE
-                : _("(disabled in ./configure)")));
+    PID file:\n\
+      $HOME/.libvirt/libvirtd.pid\n\
+\n"));
+    }
 }
 
 enum {
@@ -3157,12 +1257,19 @@ enum {
 
 #define MAX_LISTEN 5
 int main(int argc, char **argv) {
-    struct qemud_server *server = NULL;
-    const char *pid_file = NULL;
-    const char *remote_config_file = NULL;
+    virNetServerPtr srv = NULL;
+    char *remote_config_file = NULL;
     int statuswrite = -1;
     int ret = 1;
-    argv0 = argv[0];
+    char *pid_file = NULL;
+    char *sock_file = NULL;
+    char *sock_file_ro = NULL;
+    int timeout = -1;        /* -t: Shutdown timeout */
+    int verbose = 0;
+    int godaemon = 0;
+    int ipsock = 0;
+    struct daemonConfig *config;
+    bool privileged = geteuid() == 0 ? true : false;
 
     struct option opts[] = {
         { "verbose", no_argument, &verbose, 1},
@@ -3180,7 +1287,7 @@ int main(int argc, char **argv) {
         bindtextdomain (PACKAGE, LOCALEDIR) == NULL ||
         textdomain(PACKAGE) == NULL ||
         virInitialize() < 0) {
-        fprintf(stderr, _("%s: initialization failed\n"), argv0);
+        fprintf(stderr, _("%s: initialization failed\n"), argv[0]);
         exit(EXIT_FAILURE);
     }
 
@@ -3218,69 +1325,91 @@ int main(int argc, char **argv) {
             break;
 
         case 'p':
-            pid_file = optarg;
+            VIR_FREE(pid_file);
+            if (!(pid_file = strdup(optarg)))
+                exit(EXIT_FAILURE);
             break;
 
         case 'f':
-            remote_config_file = optarg;
+            if (!(remote_config_file = strdup(optarg)))
+                exit(EXIT_FAILURE);
             break;
 
         case OPT_VERSION:
-            version ();
+            daemonVersion(argv[0]);
             return 0;
 
         case '?':
-            usage ();
+            daemonUsage(argv[0], privileged);
             return 2;
 
         default:
             fprintf (stderr, _("%s: internal error: unknown flag: %c\n"),
-                     argv0, c);
+                     argv[0], c);
             exit (EXIT_FAILURE);
         }
     }
 
-    if (remote_config_file == NULL) {
-        static const char *default_config_file
-            = SYSCONFDIR "/libvirt/libvirtd.conf";
-        remote_config_file =
-            (access(default_config_file, R_OK) == 0
-             ? default_config_file
-             : "/dev/null");
+    if (!(config = daemonConfigNew(privileged)))
+        exit(EXIT_FAILURE);
+
+    /* No explicit config, so try and find a default one */
+    if (remote_config_file == NULL &&
+        daemonConfigFilePath(privileged,
+                             &remote_config_file) < 0)
+        exit(EXIT_FAILURE);
+
+    /* Read the config file if it exists*/
+    if (remote_config_file &&
+        daemonConfigLoad(config, remote_config_file) < 0)
+        exit(EXIT_FAILURE);
+
+    if (config->host_uuid &&
+        virSetHostUUIDStr(config->host_uuid) < 0) {
+        VIR_ERROR(_("invalid host UUID: %s"), config->host_uuid);
+        exit(EXIT_FAILURE);
     }
 
+    if (daemonSetupLogging(config, privileged, verbose, godaemon) < 0)
+        exit(EXIT_FAILURE);
+
+    if (!pid_file && privileged &&
+        daemonPidFilePath(privileged,
+                          &pid_file) < 0)
+        exit(EXIT_FAILURE);
+
+    if (daemonUnixSocketPaths(config,
+                              privileged,
+                              &sock_file,
+                              &sock_file_ro) < 0)
+        exit(EXIT_FAILURE);
+
     if (godaemon) {
         char ebuf[1024];
 
         if (chdir("/") < 0) {
             VIR_ERROR(_("cannot change to root directory: %s"),
                       virStrerror(errno, ebuf, sizeof(ebuf)));
-            goto error;
+            goto cleanup;
         }
 
-        if ((statuswrite = daemonForkIntoBackground()) < 0) {
+        if ((statuswrite = daemonForkIntoBackground(argv[0])) < 0) {
             VIR_ERROR(_("Failed to fork as daemon: %s"),
                       virStrerror(errno, ebuf, sizeof ebuf));
-            goto error;
+            goto cleanup;
         }
     }
 
-    /* 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) {
-        pid_file = NULL; /* Prevent unlinking of someone else's pid ! */
+        daemonWritePidFile(pid_file, argv[0]) < 0) {
+        VIR_FREE(pid_file); /* Prevent unlinking of someone else's pid ! */
         ret = VIR_DAEMON_ERR_PIDFILE;
-        goto error;
+        goto cleanup;
     }
 
     /* Ensure the rundir exists (on tmpfs on some systems) */
-    if (geteuid() == 0) {
+    if (privileged) {
         const char *rundir = LOCALSTATEDIR "/run/libvirt";
         mode_t old_umask;
 
@@ -3292,62 +1421,89 @@ int main(int argc, char **argv) {
                           virStrerror(errno, ebuf, sizeof(ebuf)));
                 ret = VIR_DAEMON_ERR_RUNDIR;
                 umask(old_umask);
-                goto error;
+                goto cleanup;
             }
         }
         umask(old_umask);
     }
 
+    if (!(srv = virNetServerNew(config->min_workers,
+                                config->max_workers,
+                                config->max_clients,
+                                config->mdns_adv ? config->mdns_name : NULL,
+                                remoteClientInitHook))) {
+        ret = VIR_DAEMON_ERR_INIT;
+        goto cleanup;
+    }
+
     /* 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) {
+    if (daemonSetupPrivs() < 0) {
         ret = VIR_DAEMON_ERR_PRIVS;
-        goto error;
+        goto cleanup;
     }
 
-    /* Initialise GnuTLS. Required even if we don't use TLS
-     * for libvirtd, because QEMU driver needs to be able to
-     * parse x590 certificates for seamless migration */
-    gnutls_global_init();
+    daemonInitialize();
 
-    if (!(server = qemudInitialize())) {
+    remoteProcs[REMOTE_PROC_AUTH_LIST].needAuth = false;
+    remoteProcs[REMOTE_PROC_AUTH_SASL_INIT].needAuth = false;
+    remoteProcs[REMOTE_PROC_AUTH_SASL_STEP].needAuth = false;
+    remoteProcs[REMOTE_PROC_AUTH_SASL_START].needAuth = false;
+    remoteProcs[REMOTE_PROC_AUTH_POLKIT].needAuth = false;
+    if (!(remoteProgram = virNetServerProgramNew(REMOTE_PROGRAM,
+                                                 REMOTE_PROTOCOL_VERSION,
+                                                 remoteProcs,
+                                                 remoteNProcs))) {
         ret = VIR_DAEMON_ERR_INIT;
-        goto error;
+        goto cleanup;
+    }
+    if (virNetServerAddProgram(srv, remoteProgram) < 0) {
+        ret = VIR_DAEMON_ERR_INIT;
+        goto cleanup;
     }
 
-    if ((daemonSetupSignals(server)) < 0) {
-        ret = VIR_DAEMON_ERR_SIGNAL;
-        goto error;
+    if (!(qemuProgram = virNetServerProgramNew(QEMU_PROGRAM,
+                                               QEMU_PROTOCOL_VERSION,
+                                               qemuProcs,
+                                               qemuNProcs))) {
+        ret = VIR_DAEMON_ERR_INIT;
+        goto cleanup;
+    }
+    if (virNetServerAddProgram(srv, qemuProgram) < 0) {
+        ret = VIR_DAEMON_ERR_INIT;
+        goto cleanup;
     }
 
-    /* Read the config file (if it exists). */
-    if (remoteReadConfigFile (server, remote_config_file) < 0) {
-        ret = VIR_DAEMON_ERR_CONFIG;
-        goto error;
+    if (timeout != -1)
+        virNetServerAutoShutdown(srv,
+                                 timeout,
+                                 daemonShutdownCheck,
+                                 NULL);
+
+    if ((daemonSetupSignals(srv)) < 0) {
+        ret = VIR_DAEMON_ERR_SIGNAL;
+        goto cleanup;
     }
 
-    if (audit_level) {
+    if (config->audit_level) {
         if (virAuditOpen() < 0) {
-            if (audit_level > 1) {
+            if (config->audit_level > 1) {
                 ret = VIR_DAEMON_ERR_AUDIT;
-                goto error;
+                goto cleanup;
             }
         }
     }
-    virAuditLog(audit_logging);
+    virAuditLog(config->audit_logging);
 
     /* setup the hooks if any */
     if (virHookInitialize() < 0) {
         ret = VIR_DAEMON_ERR_HOOKS;
-        goto error;
+        goto cleanup;
     }
 
     /* Disable error func, now logging is setup */
-    virSetErrorFunc(NULL, virshErrorHandler);
+    virSetErrorFunc(NULL, daemonErrorHandler);
     virSetErrorLogPriorityFunc(daemonErrorLogFilter);
 
     /*
@@ -3358,9 +1514,11 @@ int main(int argc, char **argv) {
     virHookCall(VIR_HOOK_DRIVER_DAEMON, "-", VIR_HOOK_DAEMON_OP_START,
                 0, "start", NULL);
 
-    if (qemudNetworkInit(server) < 0) {
+    if (daemonSetupNetworking(srv, config,
+                              sock_file, sock_file_ro,
+                              ipsock, privileged) < 0) {
         ret = VIR_DAEMON_ERR_NETWORK;
-        goto error;
+        goto cleanup;
     }
 
     /* Tell parent of daemon that basic initialization is complete
@@ -3375,52 +1533,24 @@ int main(int argc, char **argv) {
         VIR_FORCE_CLOSE(statuswrite);
     }
 
-    /* Start the event loop in a background thread, since
-     * state initialization needs events to be being processed */
-    if (qemudStartEventLoop(server) < 0) {
-        VIR_ERROR(_("Event thread startup failed"));
-        goto error;
-    }
-
-    /* Start the stateful HV drivers
-     * This is delibrately done after telling the parent process
-     * we're ready, since it can take a long time and this will
-     * seriously delay OS bootup process */
-    if (virStateInitialize(server->privileged) < 0) {
-        VIR_ERROR(_("Driver state initialization failed"));
-        goto shutdown;
+    /* Initialize drivers & then start accepting new clients from network */
+    if (daemonStateInit(srv) < 0) {
+        ret = VIR_DAEMON_ERR_INIT;
+        goto cleanup;
     }
 
-    /* Start accepting new clients from network */
-    virMutexLock(&server->lock);
-    if (qemudNetworkEnable(server) < 0) {
-        VIR_ERROR(_("Network event loop enablement failed"));
-        goto shutdown;
-    }
-    virMutexUnlock(&server->lock);
+    /* Run event loop. */
+    virNetServerRun(srv);
 
     ret = 0;
 
-shutdown:
-    /* In a non-0 shutdown scenario we need to tell event loop
-     * to quit immediately. Otherwise in normal case we just
-     * sit in the thread join forever. Sure this means the
-     * main thread doesn't do anything useful ever, but that's
-     * not too much of drain on resources
-     */
-    if (ret != 0) {
-        virMutexLock(&server->lock);
-        if (server->hasEventThread)
-            /* This SIGQUIT triggers the shutdown process */
-            kill(getpid(), SIGQUIT);
-        virMutexUnlock(&server->lock);
-    }
-    pthread_join(server->eventThread, NULL);
-
     virHookCall(VIR_HOOK_DRIVER_DAEMON, "-", VIR_HOOK_DAEMON_OP_SHUTDOWN,
                 0, "shutdown", NULL);
 
-error:
+cleanup:
+    virNetServerProgramFree(remoteProgram);
+    virNetServerProgramFree(qemuProgram);
+    virNetServerFree(srv);
     if (statuswrite != -1) {
         if (ret != 0) {
             /* Tell parent of daemon what failed */
@@ -3431,10 +1561,15 @@ error:
         }
         VIR_FORCE_CLOSE(statuswrite);
     }
-    if (server)
-        qemudCleanup(server);
     if (pid_file)
         unlink (pid_file);
-    qemudStopLogging();
+
+    VIR_FREE(sock_file);
+    VIR_FREE(sock_file_ro);
+    VIR_FREE(pid_file);
+    VIR_FREE(remote_config_file);
+    daemonConfigFree(config);
+    virLogShutdown();
+
     return ret;
 }
diff --git a/daemon/libvirtd.h b/daemon/libvirtd.h
index ea00d5c..6c604fc 100644
--- a/daemon/libvirtd.h
+++ b/daemon/libvirtd.h
@@ -27,13 +27,6 @@
 
 # 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
@@ -45,6 +38,8 @@
 # include "logging.h"
 # include "threads.h"
 # include "network.h"
+# include "virnetsaslcontext.h"
+# include "virnetserverprogram.h"
 
 # if WITH_DTRACE
 #  ifndef LIBVIRTD_PROBES_H
@@ -63,230 +58,37 @@
                   #NAME ": " FMT, __VA_ARGS__);
 # endif
 
-# 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
-
-/* 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;
-
-    unsigned int async : 1;
-    unsigned int streamTX : 1;
-
-    remote_message_header hdr;
-
-    struct qemud_client_message *next;
-};
-
-struct qemud_client;
-
-/* 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 *client,
-                                        struct qemud_client_message *msg, void *opaque);
-struct qemud_client_filter {
-    qemud_client_filter_func query;
-    void *opaque;
-
-    struct qemud_client_filter *next;
-};
-
-struct qemud_client_stream {
-    virStreamPtr st;
-    int procedure;
-    int serial;
-
-    unsigned int recvEOF : 1;
-    unsigned int closed : 1;
-
-    struct qemud_client_filter filter;
-
-    struct qemud_client_message *rx;
-    int tx;
-
-    struct qemud_client_stream *next;
-};
+typedef struct daemonClientStream daemonClientStream;
+typedef daemonClientStream *daemonClientStreamPtr;
+typedef struct daemonClientPrivate daemonClientPrivate;
+typedef daemonClientPrivate *daemonClientPrivatePtr;
 
 /* Stores the per-client connection state */
-struct qemud_client {
+struct daemonClientPrivate {
+    /* Hold while accessing any data except conn */
     virMutex lock;
 
-    int magic;
-
-    int fd;
-    int watch;
-    unsigned int readonly :1;
-    unsigned int closing :1;
     int domainEventCallbackID[VIR_DOMAIN_EVENT_ID_LAST];
 
-    virSocketAddr addr;
-    const char *addrstr;
-
-    int type; /* qemud_sock_type */
-    gnutls_session_t tlssession;
-    int auth;
-    unsigned 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;
-    char saslTemporary[8192]; /* temorary holds data to be decoded */
-# 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;
-
-    /* Data streams */
-    struct qemud_client_stream *streams;
-
+    virNetSASLSessionPtr sasl;
 
     /* 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 {
-    char *path;
-
-    virSocketAddr addr;
-    const char *addrstr;
-
-    int fd;
-    int watch;
-    int readonly;
-    int type; /* qemud_sock_type */
-    int auth;
-
-    struct qemud_socket *next;
+    daemonClientStreamPtr streams;
 };
 
-struct qemud_worker {
-    pthread_t thread;
-    unsigned int hasThread :1;
-    unsigned int processingCall :1;
-    unsigned int quitRequest :1;
-
-    /* back-pointer to our server */
-    struct qemud_server *server;
-};
+extern virNetSASLContextPtr saslCtxt;
+extern virNetServerProgramPtr remoteProgram;
+extern virNetServerProgramPtr qemuProgram;
 
 /* Main server state */
 struct qemud_server {
-    virMutex lock;
-    virCond job;
-
     int privileged;
 
-    size_t nworkers;
-    size_t nactiveworkers;
-    struct qemud_worker *workers;
-    size_t nsockets;
-    struct qemud_socket *sockets;
-    size_t nclients;
-    size_t nclients_max;
-    struct qemud_client **clients;
-
     int sigread;
     int sigwrite;
     char *logDir;
@@ -304,27 +106,6 @@ struct qemud_server {
 # 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);
-
-void
-qemudClientMessageRelease(struct qemud_client *client,
-                          struct qemud_client_message *msg);
-
 
 # if HAVE_POLKIT
 int qemudGetSocketIdentity(int fd, uid_t *uid, pid_t *pid);
diff --git a/daemon/remote.c b/daemon/remote.c
index aa726cf..3df6f87 100644
--- a/daemon/remote.c
+++ b/daemon/remote.c
@@ -22,26 +22,6 @@
 
 #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 <netdb.h>
-#include <stdlib.h>
-#include <pwd.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <syslog.h>
-#include <string.h>
-#include <errno.h>
-#include <fnmatch.h>
-#include <arpa/inet.h>
 #include "virterror_internal.h"
 
 #if HAVE_POLKIT0
@@ -50,11 +30,11 @@
 #endif
 
 #include "remote.h"
-#include "dispatch.h"
-
+#include "libvirtd.h"
 #include "libvirt_internal.h"
 #include "datatypes.h"
 #include "memory.h"
+#include "logging.h"
 #include "util.h"
 #include "stream.h"
 #include "uuid.h"
@@ -62,8 +42,13 @@
 #include "libvirt/libvirt-qemu.h"
 #include "command.h"
 #include "intprops.h"
+#include "virnetserverservice.h"
+
+#include "remote_protocol.h"
+#include "qemu_protocol.h"
 
-#define VIR_FROM_THIS VIR_FROM_REMOTE
+
+#define VIR_FROM_THIS VIR_FROM_RPC
 
 #define virNetError(code, ...)                                    \
     virReportErrorHelper(VIR_FROM_THIS, code, __FILE__,           \
@@ -105,41 +90,25 @@ static void make_nonnull_secret(remote_nonnull_secret *secret_dst, virSecretPtr
 static void make_nonnull_nwfilter(remote_nonnull_nwfilter *net_dst, virNWFilterPtr nwfilter_src);
 static void make_nonnull_domain_snapshot(remote_nonnull_domain_snapshot *snapshot_dst, virDomainSnapshotPtr snapshot_src);
 
+static int
+remoteSerializeTypedParameters(virTypedParameterPtr params,
+                               int nparams,
+                               remote_typed_param **ret_params_val,
+                               u_int *ret_params_len);
+static virTypedParameterPtr
+remoteDeserializeTypedParameters(remote_typed_param *args_params_val,
+                                 u_int args_params_len,
+                                 int limit,
+                                 int *nparams);
 
-#include "remote_dispatch_prototypes.h"
-#include "qemu_dispatch_prototypes.h"
-
-static const dispatch_data const dispatch_table[] = {
-#include "remote_dispatch_table.h"
-};
-
-static const dispatch_data const qemu_dispatch_table[] = {
-#include "qemu_dispatch_table.h"
-};
-
-const dispatch_data const *remoteGetDispatchData(int proc)
-{
-    if (proc >= ARRAY_CARDINALITY(dispatch_table) ||
-        dispatch_table[proc].fn == NULL) {
-        return NULL;
-    }
-
-    return &(dispatch_table[proc]);
-}
-
-const dispatch_data const *qemuGetDispatchData(int proc)
-{
-    if (proc >= ARRAY_CARDINALITY(qemu_dispatch_table) ||
-        qemu_dispatch_table[proc].fn == NULL) {
-        return NULL;
-    }
+#include "remote_dispatch.h"
+#include "qemu_dispatch.h"
 
-    return &(qemu_dispatch_table[proc]);
-}
 
 /* Prototypes */
 static void
-remoteDispatchDomainEventSend(struct qemud_client *client,
+remoteDispatchDomainEventSend(virNetServerClientPtr client,
+                              virNetServerProgramPtr program,
                               int procnr,
                               xdrproc_t proc,
                               void *data);
@@ -150,7 +119,7 @@ static int remoteRelayDomainEventLifecycle(virConnectPtr conn ATTRIBUTE_UNUSED,
                                            int detail,
                                            void *opaque)
 {
-    struct qemud_client *client = opaque;
+    virNetServerClientPtr client = opaque;
     remote_domain_event_lifecycle_msg data;
 
     if (!client)
@@ -158,20 +127,16 @@ static int remoteRelayDomainEventLifecycle(virConnectPtr conn ATTRIBUTE_UNUSED,
 
     VIR_DEBUG("Relaying domain lifecycle event %d %d", event, detail);
 
-    virMutexLock(&client->lock);
-
     /* build return data */
     memset(&data, 0, sizeof data);
     make_nonnull_domain(&data.dom, dom);
     data.event = event;
     data.detail = detail;
 
-    remoteDispatchDomainEventSend(client,
+    remoteDispatchDomainEventSend(client, remoteProgram,
                                   REMOTE_PROC_DOMAIN_EVENT_LIFECYCLE,
                                   (xdrproc_t)xdr_remote_domain_event_lifecycle_msg, &data);
 
-    virMutexUnlock(&client->lock);
-
     return 0;
 }
 
@@ -179,7 +144,7 @@ static int remoteRelayDomainEventReboot(virConnectPtr conn ATTRIBUTE_UNUSED,
                                         virDomainPtr dom,
                                         void *opaque)
 {
-    struct qemud_client *client = opaque;
+    virNetServerClientPtr client = opaque;
     remote_domain_event_reboot_msg data;
 
     if (!client)
@@ -187,18 +152,14 @@ static int remoteRelayDomainEventReboot(virConnectPtr conn ATTRIBUTE_UNUSED,
 
     VIR_DEBUG("Relaying domain reboot event %s %d", dom->name, dom->id);
 
-    virMutexLock(&client->lock);
-
     /* build return data */
     memset(&data, 0, sizeof data);
     make_nonnull_domain(&data.dom, dom);
 
-    remoteDispatchDomainEventSend(client,
+    remoteDispatchDomainEventSend(client, remoteProgram,
                                   REMOTE_PROC_DOMAIN_EVENT_REBOOT,
                                   (xdrproc_t)xdr_remote_domain_event_reboot_msg, &data);
 
-    virMutexUnlock(&client->lock);
-
     return 0;
 }
 
@@ -208,7 +169,7 @@ static int remoteRelayDomainEventRTCChange(virConnectPtr conn ATTRIBUTE_UNUSED,
                                            long long offset,
                                            void *opaque)
 {
-    struct qemud_client *client = opaque;
+    virNetServerClientPtr client = opaque;
     remote_domain_event_rtc_change_msg data;
 
     if (!client)
@@ -216,19 +177,15 @@ static int remoteRelayDomainEventRTCChange(virConnectPtr conn ATTRIBUTE_UNUSED,
 
     VIR_DEBUG("Relaying domain rtc change event %s %d %lld", dom->name, dom->id, offset);
 
-    virMutexLock(&client->lock);
-
     /* build return data */
     memset(&data, 0, sizeof data);
     make_nonnull_domain(&data.dom, dom);
     data.offset = offset;
 
-    remoteDispatchDomainEventSend(client,
+    remoteDispatchDomainEventSend(client, remoteProgram,
                                   REMOTE_PROC_DOMAIN_EVENT_RTC_CHANGE,
                                   (xdrproc_t)xdr_remote_domain_event_rtc_change_msg, &data);
 
-    virMutexUnlock(&client->lock);
-
     return 0;
 }
 
@@ -238,7 +195,7 @@ static int remoteRelayDomainEventWatchdog(virConnectPtr conn ATTRIBUTE_UNUSED,
                                           int action,
                                           void *opaque)
 {
-    struct qemud_client *client = opaque;
+    virNetServerClientPtr client = opaque;
     remote_domain_event_watchdog_msg data;
 
     if (!client)
@@ -246,19 +203,15 @@ static int remoteRelayDomainEventWatchdog(virConnectPtr conn ATTRIBUTE_UNUSED,
 
     VIR_DEBUG("Relaying domain watchdog event %s %d %d", dom->name, dom->id, action);
 
-    virMutexLock(&client->lock);
-
     /* build return data */
     memset(&data, 0, sizeof data);
     make_nonnull_domain(&data.dom, dom);
     data.action = action;
 
-    remoteDispatchDomainEventSend(client,
+    remoteDispatchDomainEventSend(client, remoteProgram,
                                   REMOTE_PROC_DOMAIN_EVENT_WATCHDOG,
                                   (xdrproc_t)xdr_remote_domain_event_watchdog_msg, &data);
 
-    virMutexUnlock(&client->lock);
-
     return 0;
 }
 
@@ -270,7 +223,7 @@ static int remoteRelayDomainEventIOError(virConnectPtr conn ATTRIBUTE_UNUSED,
                                          int action,
                                          void *opaque)
 {
-    struct qemud_client *client = opaque;
+    virNetServerClientPtr client = opaque;
     remote_domain_event_io_error_msg data;
 
     if (!client)
@@ -278,8 +231,6 @@ static int remoteRelayDomainEventIOError(virConnectPtr conn ATTRIBUTE_UNUSED,
 
     VIR_DEBUG("Relaying domain io error %s %d %s %s %d", dom->name, dom->id, srcPath, devAlias, action);
 
-    virMutexLock(&client->lock);
-
     /* build return data */
     memset(&data, 0, sizeof data);
     make_nonnull_domain(&data.dom, dom);
@@ -287,12 +238,10 @@ static int remoteRelayDomainEventIOError(virConnectPtr conn ATTRIBUTE_UNUSED,
     data.devAlias = (char*)devAlias;
     data.action = action;
 
-    remoteDispatchDomainEventSend(client,
+    remoteDispatchDomainEventSend(client, remoteProgram,
                                   REMOTE_PROC_DOMAIN_EVENT_IO_ERROR,
                                   (xdrproc_t)xdr_remote_domain_event_io_error_msg, &data);
 
-    virMutexUnlock(&client->lock);
-
     return 0;
 }
 
@@ -305,7 +254,7 @@ static int remoteRelayDomainEventIOErrorReason(virConnectPtr conn ATTRIBUTE_UNUS
                                                const char *reason,
                                                void *opaque)
 {
-    struct qemud_client *client = opaque;
+    virNetServerClientPtr client = opaque;
     remote_domain_event_io_error_reason_msg data;
 
     if (!client)
@@ -314,8 +263,6 @@ static int remoteRelayDomainEventIOErrorReason(virConnectPtr conn ATTRIBUTE_UNUS
     VIR_DEBUG("Relaying domain io error %s %d %s %s %d %s",
               dom->name, dom->id, srcPath, devAlias, action, reason);
 
-    virMutexLock(&client->lock);
-
     /* build return data */
     memset(&data, 0, sizeof data);
     make_nonnull_domain(&data.dom, dom);
@@ -324,12 +271,10 @@ static int remoteRelayDomainEventIOErrorReason(virConnectPtr conn ATTRIBUTE_UNUS
     data.action = action;
     data.reason = (char*)reason;
 
-    remoteDispatchDomainEventSend(client,
+    remoteDispatchDomainEventSend(client, remoteProgram,
                                   REMOTE_PROC_DOMAIN_EVENT_IO_ERROR_REASON,
                                   (xdrproc_t)xdr_remote_domain_event_io_error_reason_msg, &data);
 
-    virMutexUnlock(&client->lock);
-
     return 0;
 }
 
@@ -343,7 +288,7 @@ static int remoteRelayDomainEventGraphics(virConnectPtr conn ATTRIBUTE_UNUSED,
                                           virDomainEventGraphicsSubjectPtr subject,
                                           void *opaque)
 {
-    struct qemud_client *client = opaque;
+    virNetServerClientPtr client = opaque;
     remote_domain_event_graphics_msg data;
     int i;
 
@@ -360,8 +305,6 @@ static int remoteRelayDomainEventGraphics(virConnectPtr conn ATTRIBUTE_UNUSED,
         VIR_DEBUG("  %s=%s", subject->identities[i].type, subject->identities[i].name);
     }
 
-    virMutexLock(&client->lock);
-
     /* build return data */
     memset(&data, 0, sizeof data);
     make_nonnull_domain(&data.dom, dom);
@@ -378,7 +321,7 @@ static int remoteRelayDomainEventGraphics(virConnectPtr conn ATTRIBUTE_UNUSED,
 
     data.subject.subject_len = subject->nidentity;
     if (VIR_ALLOC_N(data.subject.subject_val, data.subject.subject_len) < 0) {
-        VIR_WARN("cannot allocate memory for graphics event subject");
+        virReportOOMError();
         return -1;
     }
     for (i = 0 ; i < data.subject.subject_len ; i++) {
@@ -386,14 +329,12 @@ static int remoteRelayDomainEventGraphics(virConnectPtr conn ATTRIBUTE_UNUSED,
         data.subject.subject_val[i].name = (char*)subject->identities[i].name;
     }
 
-    remoteDispatchDomainEventSend(client,
+    remoteDispatchDomainEventSend(client, remoteProgram,
                                   REMOTE_PROC_DOMAIN_EVENT_GRAPHICS,
                                   (xdrproc_t)xdr_remote_domain_event_graphics_msg, &data);
 
     VIR_FREE(data.subject.subject_val);
 
-    virMutexUnlock(&client->lock);
-
     return 0;
 }
 
@@ -402,7 +343,7 @@ static int remoteRelayDomainEventControlError(virConnectPtr conn ATTRIBUTE_UNUSE
                                               virDomainPtr dom,
                                               void *opaque)
 {
-    struct qemud_client *client = opaque;
+    virNetServerClientPtr client = opaque;
     remote_domain_event_control_error_msg data;
 
     if (!client)
@@ -410,18 +351,14 @@ static int remoteRelayDomainEventControlError(virConnectPtr conn ATTRIBUTE_UNUSE
 
     VIR_DEBUG("Relaying domain control error %s %d", dom->name, dom->id);
 
-    virMutexLock(&client->lock);
-
     /* build return data */
     memset(&data, 0, sizeof data);
     make_nonnull_domain(&data.dom, dom);
 
-    remoteDispatchDomainEventSend(client,
+    remoteDispatchDomainEventSend(client, remoteProgram,
                                   REMOTE_PROC_DOMAIN_EVENT_CONTROL_ERROR,
                                   (xdrproc_t)xdr_remote_domain_event_control_error_msg, &data);
 
-    virMutexUnlock(&client->lock);
-
     return 0;
 }
 
@@ -439,25 +376,80 @@ static virConnectDomainEventGenericCallback domainEventCallbacks[] = {
 
 verify(ARRAY_CARDINALITY(domainEventCallbacks) == VIR_DOMAIN_EVENT_ID_LAST);
 
+/*
+ * 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
+ */
+static void remoteClientFreeFunc(void *data)
+{
+    struct daemonClientPrivate *priv = data;
+
+    /* Deregister event delivery callback */
+    if (priv->conn) {
+        int i;
+
+        for (i = 0 ; i < VIR_DOMAIN_EVENT_ID_LAST ; i++) {
+            if (priv->domainEventCallbackID[i] != -1) {
+                VIR_DEBUG("Deregistering to relay remote events %d", i);
+                virConnectDomainEventDeregisterAny(priv->conn,
+                                                   priv->domainEventCallbackID[i]);
+            }
+            priv->domainEventCallbackID[i] = -1;
+        }
+
+        virConnectClose(priv->conn);
+    }
+
+    VIR_FREE(priv);
+}
+
+
+
+int remoteClientInitHook(virNetServerPtr srv ATTRIBUTE_UNUSED,
+                         virNetServerClientPtr client)
+{
+    struct daemonClientPrivate *priv;
+    int i;
+
+    if (VIR_ALLOC(priv) < 0) {
+        virReportOOMError();
+        return -1;
+    }
+
+    if (virMutexInit(&priv->lock) < 0) {
+        VIR_FREE(priv);
+        virReportOOMError();
+        return -1;
+    }
+
+    for (i = 0 ; i < VIR_DOMAIN_EVENT_ID_LAST ; i++)
+        priv->domainEventCallbackID[i] = -1;
+
+    virNetServerClientSetPrivateData(client, priv, remoteClientFreeFunc);
+    return 0;
+}
+
 /*----- Functions. -----*/
 
 static int
-remoteDispatchOpen(struct qemud_server *server,
-                   struct qemud_client *client,
-                   virConnectPtr conn,
-                   remote_message_header *hdr ATTRIBUTE_UNUSED,
-                   remote_error *rerr,
-                   struct remote_open_args *args, void *ret ATTRIBUTE_UNUSED)
+remoteDispatchOpen(virNetServerPtr server ATTRIBUTE_UNUSED,
+                   virNetServerClientPtr client,
+                   virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+                   virNetMessageErrorPtr rerr,
+                   struct remote_open_args *args)
 {
     const char *name;
     int flags;
+    struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client);
     int rv = -1;
 
-    virMutexLock(&server->lock);
-    virMutexLock(&client->lock);
-    virMutexUnlock(&server->lock);
-
-    if (conn) {
+    VIR_DEBUG("priv=%p conn=%p", priv, priv->conn);
+    virMutexLock(&priv->lock);
+    /* Already opened? */
+    if (priv->conn) {
         virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection already open"));
         goto cleanup;
     }
@@ -468,50 +460,43 @@ remoteDispatchOpen(struct qemud_server *server,
      * the connection to be readonly.
      */
     flags = args->flags;
-    if (client->readonly) flags |= VIR_CONNECT_RO;
+    if (virNetServerClientGetReadonly(client))
+        flags |= VIR_CONNECT_RO;
 
-    client->conn =
+    priv->conn =
         flags & VIR_CONNECT_RO
         ? virConnectOpenReadOnly(name)
         : virConnectOpen(name);
 
-    if (client->conn == NULL)
+    if (priv->conn == NULL)
         goto cleanup;
 
     rv = 0;
 
 cleanup:
     if (rv < 0)
-        remoteDispatchError(rerr);
-    virMutexUnlock(&client->lock);
+        virNetMessageSaveError(rerr);
+    virMutexUnlock(&priv->lock);
     return rv;
 }
 
 
 static int
-remoteDispatchClose(struct qemud_server *server ATTRIBUTE_UNUSED,
-                    struct qemud_client *client ATTRIBUTE_UNUSED,
-                    virConnectPtr conn ATTRIBUTE_UNUSED,
-                    remote_message_header *hdr ATTRIBUTE_UNUSED,
-                    remote_error *rerr ATTRIBUTE_UNUSED,
-                    void *args ATTRIBUTE_UNUSED, void *ret ATTRIBUTE_UNUSED)
+remoteDispatchClose(virNetServerPtr server ATTRIBUTE_UNUSED,
+                    virNetServerClientPtr client,
+                    virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+                    virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED)
 {
-    virMutexLock(&server->lock);
-    virMutexLock(&client->lock);
-    virMutexUnlock(&server->lock);
-
-    client->closing = 1;
-
-    virMutexUnlock(&client->lock);
+    virNetServerClientClose(client);
     return 0;
 }
 
+
 static int
-remoteDispatchDomainGetSchedulerType(struct qemud_server *server ATTRIBUTE_UNUSED,
-                                     struct qemud_client *client ATTRIBUTE_UNUSED,
-                                     virConnectPtr conn,
-                                     remote_message_header *hdr ATTRIBUTE_UNUSED,
-                                     remote_error *rerr,
+remoteDispatchDomainGetSchedulerType(virNetServerPtr server ATTRIBUTE_UNUSED,
+                                     virNetServerClientPtr client ATTRIBUTE_UNUSED,
+                                     virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+                                     virNetMessageErrorPtr rerr,
                                      remote_domain_get_scheduler_type_args *args,
                                      remote_domain_get_scheduler_type_ret *ret)
 {
@@ -519,13 +504,15 @@ remoteDispatchDomainGetSchedulerType(struct qemud_server *server ATTRIBUTE_UNUSE
     char *type;
     int nparams;
     int rv = -1;
+    struct daemonClientPrivate *priv =
+        virNetServerClientGetPrivateData(client);
 
-    if (!conn) {
+    if (!priv->conn) {
         virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
         goto cleanup;
     }
 
-    if (!(dom = get_nonnull_domain(conn, args->dom)))
+    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
         goto cleanup;
 
     if (!(type = virDomainGetSchedulerType(dom, &nparams)))
@@ -537,7 +524,7 @@ remoteDispatchDomainGetSchedulerType(struct qemud_server *server ATTRIBUTE_UNUSE
 
 cleanup:
     if (rv < 0)
-        remoteDispatchError(rerr);
+        virNetMessageSaveError(rerr);
     if (dom)
         virDomainFree(dom);
     return rv;
@@ -681,11 +668,10 @@ cleanup:
 }
 
 static int
-remoteDispatchDomainGetSchedulerParameters(struct qemud_server *server ATTRIBUTE_UNUSED,
-                                           struct qemud_client *client ATTRIBUTE_UNUSED,
-                                           virConnectPtr conn,
-                                           remote_message_header *hdr ATTRIBUTE_UNUSED,
-                                           remote_error *rerr,
+remoteDispatchDomainGetSchedulerParameters(virNetServerPtr server ATTRIBUTE_UNUSED,
+                                           virNetServerClientPtr client ATTRIBUTE_UNUSED,
+                                           virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+                                           virNetMessageErrorPtr rerr,
                                            remote_domain_get_scheduler_parameters_args *args,
                                            remote_domain_get_scheduler_parameters_ret *ret)
 {
@@ -693,8 +679,10 @@ remoteDispatchDomainGetSchedulerParameters(struct qemud_server *server ATTRIBUTE
     virTypedParameterPtr params = NULL;
     int nparams = args->nparams;
     int rv = -1;
+    struct daemonClientPrivate *priv =
+        virNetServerClientGetPrivateData(client);
 
-    if (!conn) {
+    if (!priv->conn) {
         virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
         goto cleanup;
     }
@@ -706,7 +694,7 @@ remoteDispatchDomainGetSchedulerParameters(struct qemud_server *server ATTRIBUTE
     if (VIR_ALLOC_N(params, nparams) < 0)
         goto no_memory;
 
-    if (!(dom = get_nonnull_domain(conn, args->dom)))
+    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
         goto cleanup;
 
     if (virDomainGetSchedulerParameters(dom, params, &nparams) < 0)
@@ -721,7 +709,7 @@ remoteDispatchDomainGetSchedulerParameters(struct qemud_server *server ATTRIBUTE
 
 cleanup:
     if (rv < 0)
-        remoteDispatchError(rerr);
+        virNetMessageSaveError(rerr);
     if (dom)
         virDomainFree(dom);
     VIR_FREE(params);
@@ -733,11 +721,10 @@ no_memory:
 }
 
 static int
-remoteDispatchDomainGetSchedulerParametersFlags(struct qemud_server *server ATTRIBUTE_UNUSED,
-                                                struct qemud_client *client ATTRIBUTE_UNUSED,
-                                                virConnectPtr conn,
-                                                remote_message_header *hdr ATTRIBUTE_UNUSED,
-                                                remote_error *rerr,
+remoteDispatchDomainGetSchedulerParametersFlags(virNetServerPtr server ATTRIBUTE_UNUSED,
+                                                virNetServerClientPtr client ATTRIBUTE_UNUSED,
+                                                virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+                                                virNetMessageErrorPtr rerr,
                                                 remote_domain_get_scheduler_parameters_flags_args *args,
                                                 remote_domain_get_scheduler_parameters_flags_ret *ret)
 {
@@ -745,8 +732,10 @@ remoteDispatchDomainGetSchedulerParametersFlags(struct qemud_server *server ATTR
     virTypedParameterPtr params = NULL;
     int nparams = args->nparams;
     int rv = -1;
+    struct daemonClientPrivate *priv =
+        virNetServerClientGetPrivateData(client);
 
-    if (!conn) {
+    if (!priv->conn) {
         virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
         goto cleanup;
     }
@@ -758,7 +747,7 @@ remoteDispatchDomainGetSchedulerParametersFlags(struct qemud_server *server ATTR
     if (VIR_ALLOC_N(params, nparams) < 0)
         goto no_memory;
 
-    if (!(dom = get_nonnull_domain(conn, args->dom)))
+    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
         goto cleanup;
 
     if (virDomainGetSchedulerParametersFlags(dom, params, &nparams,
@@ -774,7 +763,7 @@ remoteDispatchDomainGetSchedulerParametersFlags(struct qemud_server *server ATTR
 
 cleanup:
     if (rv < 0)
-        remoteDispatchError(rerr);
+        virNetMessageSaveError(rerr);
     if (dom)
         virDomainFree(dom);
     VIR_FREE(params);
@@ -786,11 +775,10 @@ no_memory:
 }
 
 static int
-remoteDispatchDomainMemoryStats(struct qemud_server *server ATTRIBUTE_UNUSED,
-                                struct qemud_client *client ATTRIBUTE_UNUSED,
-                                virConnectPtr conn,
-                                remote_message_header *hdr ATTRIBUTE_UNUSED,
-                                remote_error *rerr,
+remoteDispatchDomainMemoryStats(virNetServerPtr server ATTRIBUTE_UNUSED,
+                                virNetServerClientPtr client ATTRIBUTE_UNUSED,
+                                virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+                                virNetMessageErrorPtr rerr,
                                 remote_domain_memory_stats_args *args,
                                 remote_domain_memory_stats_ret *ret)
 {
@@ -798,8 +786,10 @@ remoteDispatchDomainMemoryStats(struct qemud_server *server ATTRIBUTE_UNUSED,
     struct _virDomainMemoryStat *stats;
     int nr_stats, i;
     int rv = -1;
+    struct daemonClientPrivate *priv =
+        virNetServerClientGetPrivateData(client);
 
-    if (!conn) {
+    if (!priv->conn) {
         virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
         goto cleanup;
     }
@@ -810,7 +800,7 @@ remoteDispatchDomainMemoryStats(struct qemud_server *server ATTRIBUTE_UNUSED,
         goto cleanup;
     }
 
-    if (!(dom = get_nonnull_domain(conn, args->dom)))
+    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
         goto cleanup;
 
     /* Allocate stats array for making dispatch call */
@@ -839,7 +829,7 @@ remoteDispatchDomainMemoryStats(struct qemud_server *server ATTRIBUTE_UNUSED,
 
 cleanup:
     if (rv < 0)
-        remoteDispatchError(rerr);
+        virNetMessageSaveError(rerr);
     if (dom)
         virDomainFree(dom);
     VIR_FREE(stats);
@@ -847,11 +837,10 @@ cleanup:
 }
 
 static int
-remoteDispatchDomainBlockPeek(struct qemud_server *server ATTRIBUTE_UNUSED,
-                              struct qemud_client *client ATTRIBUTE_UNUSED,
-                              virConnectPtr conn,
-                              remote_message_header *hdr ATTRIBUTE_UNUSED,
-                              remote_error *rerr,
+remoteDispatchDomainBlockPeek(virNetServerPtr server ATTRIBUTE_UNUSED,
+                              virNetServerClientPtr client ATTRIBUTE_UNUSED,
+                              virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+                              virNetMessageErrorPtr rerr,
                               remote_domain_block_peek_args *args,
                               remote_domain_block_peek_ret *ret)
 {
@@ -861,13 +850,15 @@ remoteDispatchDomainBlockPeek(struct qemud_server *server ATTRIBUTE_UNUSED,
     size_t size;
     unsigned int flags;
     int rv = -1;
+    struct daemonClientPrivate *priv =
+        virNetServerClientGetPrivateData(client);
 
-    if (!conn) {
+    if (!priv->conn) {
         virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
         goto cleanup;
     }
 
-    if (!(dom = get_nonnull_domain(conn, args->dom)))
+    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
         goto cleanup;
     path = args->path;
     offset = args->offset;
@@ -894,7 +885,7 @@ remoteDispatchDomainBlockPeek(struct qemud_server *server ATTRIBUTE_UNUSED,
 
 cleanup:
     if (rv < 0) {
-        remoteDispatchError(rerr);
+        virNetMessageSaveError(rerr);
         VIR_FREE(ret->buffer.buffer_val);
     }
     if (dom)
@@ -903,11 +894,10 @@ cleanup:
 }
 
 static int
-remoteDispatchDomainMemoryPeek(struct qemud_server *server ATTRIBUTE_UNUSED,
-                               struct qemud_client *client ATTRIBUTE_UNUSED,
-                               virConnectPtr conn,
-                               remote_message_header *hdr ATTRIBUTE_UNUSED,
-                               remote_error *rerr,
+remoteDispatchDomainMemoryPeek(virNetServerPtr server ATTRIBUTE_UNUSED,
+                               virNetServerClientPtr client ATTRIBUTE_UNUSED,
+                               virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+                               virNetMessageErrorPtr rerr,
                                remote_domain_memory_peek_args *args,
                                remote_domain_memory_peek_ret *ret)
 {
@@ -916,13 +906,15 @@ remoteDispatchDomainMemoryPeek(struct qemud_server *server ATTRIBUTE_UNUSED,
     size_t size;
     unsigned int flags;
     int rv = -1;
+    struct daemonClientPrivate *priv =
+        virNetServerClientGetPrivateData(client);
 
-    if (!conn) {
+    if (!priv->conn) {
         virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
         goto cleanup;
     }
 
-    if (!(dom = get_nonnull_domain(conn, args->dom)))
+    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
         goto cleanup;
     offset = args->offset;
     size = args->size;
@@ -948,7 +940,7 @@ remoteDispatchDomainMemoryPeek(struct qemud_server *server ATTRIBUTE_UNUSED,
 
 cleanup:
     if (rv < 0) {
-        remoteDispatchError(rerr);
+        virNetMessageSaveError(rerr);
         VIR_FREE(ret->buffer.buffer_val);
     }
     if (dom)
@@ -957,24 +949,25 @@ cleanup:
 }
 
 static int
-remoteDispatchDomainGetSecurityLabel(struct qemud_server *server ATTRIBUTE_UNUSED,
-                                     struct qemud_client *client ATTRIBUTE_UNUSED,
-                                     virConnectPtr conn,
-                                     remote_message_header *hdr ATTRIBUTE_UNUSED,
-                                     remote_error *rerr,
+remoteDispatchDomainGetSecurityLabel(virNetServerPtr server ATTRIBUTE_UNUSED,
+                                     virNetServerClientPtr client ATTRIBUTE_UNUSED,
+                                     virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+                                     virNetMessageErrorPtr rerr,
                                      remote_domain_get_security_label_args *args,
                                      remote_domain_get_security_label_ret *ret)
 {
     virDomainPtr dom = NULL;
     virSecurityLabelPtr seclabel = NULL;
     int rv = -1;
+    struct daemonClientPrivate *priv =
+        virNetServerClientGetPrivateData(client);
 
-    if (!conn) {
+    if (!priv->conn) {
         virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
         goto cleanup;
     }
 
-    if (!(dom = get_nonnull_domain(conn, args->dom)))
+    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
         goto cleanup;
 
     if (VIR_ALLOC(seclabel) < 0) {
@@ -997,7 +990,7 @@ remoteDispatchDomainGetSecurityLabel(struct qemud_server *server ATTRIBUTE_UNUSE
 
 cleanup:
     if (rv < 0)
-        remoteDispatchError(rerr);
+        virNetMessageSaveError(rerr);
     if (dom)
         virDomainFree(dom);
     VIR_FREE(seclabel);
@@ -1005,24 +998,24 @@ cleanup:
 }
 
 static int
-remoteDispatchNodeGetSecurityModel(struct qemud_server *server ATTRIBUTE_UNUSED,
-                                   struct qemud_client *client ATTRIBUTE_UNUSED,
-                                   virConnectPtr conn,
-                                   remote_message_header *hdr ATTRIBUTE_UNUSED,
-                                   remote_error *rerr,
-                                   void *args ATTRIBUTE_UNUSED,
+remoteDispatchNodeGetSecurityModel(virNetServerPtr server ATTRIBUTE_UNUSED,
+                                   virNetServerClientPtr client ATTRIBUTE_UNUSED,
+                                   virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+                                   virNetMessageErrorPtr rerr,
                                    remote_node_get_security_model_ret *ret)
 {
     virSecurityModel secmodel;
     int rv = -1;
+    struct daemonClientPrivate *priv =
+        virNetServerClientGetPrivateData(client);
 
-    if (!conn) {
+    if (!priv->conn) {
         virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
         goto cleanup;
     }
 
     memset(&secmodel, 0, sizeof secmodel);
-    if (virNodeGetSecurityModel(conn, &secmodel) < 0)
+    if (virNodeGetSecurityModel(priv->conn, &secmodel) < 0)
         goto cleanup;
 
     ret->model.model_len = strlen(secmodel.model) + 1;
@@ -1043,16 +1036,15 @@ remoteDispatchNodeGetSecurityModel(struct qemud_server *server ATTRIBUTE_UNUSED,
 
 cleanup:
     if (rv < 0)
-        remoteDispatchError(rerr);
+        virNetMessageSaveError(rerr);
     return rv;
 }
 
 static int
-remoteDispatchDomainGetVcpupinInfo(struct qemud_server *server ATTRIBUTE_UNUSED,
-                                   struct qemud_client *client ATTRIBUTE_UNUSED,
-                                   virConnectPtr conn,
-                                   remote_message_header *hdr ATTRIBUTE_UNUSED,
-                                   remote_error *rerr,
+remoteDispatchDomainGetVcpupinInfo(virNetServerPtr server ATTRIBUTE_UNUSED,
+                                   virNetServerClientPtr client ATTRIBUTE_UNUSED,
+                                   virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+                                   virNetMessageErrorPtr rerr,
                                    remote_domain_get_vcpupin_info_args *args,
                                    remote_domain_get_vcpupin_info_ret *ret)
 {
@@ -1060,13 +1052,15 @@ remoteDispatchDomainGetVcpupinInfo(struct qemud_server *server ATTRIBUTE_UNUSED,
     unsigned char *cpumaps = NULL;
     int num;
     int rv = -1;
+    struct daemonClientPrivate *priv =
+        virNetServerClientGetPrivateData(client);
 
-    if (!conn) {
+    if (!priv->conn) {
         virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
         goto cleanup;
     }
 
-    if (!(dom = get_nonnull_domain(conn, args->dom)))
+    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
         goto cleanup;
 
     if (args->ncpumaps > REMOTE_VCPUINFO_MAX) {
@@ -1105,7 +1099,7 @@ remoteDispatchDomainGetVcpupinInfo(struct qemud_server *server ATTRIBUTE_UNUSED,
 
 cleanup:
     if (rv < 0)
-        remoteDispatchError(rerr);
+        virNetMessageSaveError(rerr);
     VIR_FREE(cpumaps);
     if (dom)
         virDomainFree(dom);
@@ -1117,11 +1111,10 @@ no_memory:
 }
 
 static int
-remoteDispatchDomainGetVcpus(struct qemud_server *server ATTRIBUTE_UNUSED,
-                             struct qemud_client *client ATTRIBUTE_UNUSED,
-                             virConnectPtr conn,
-                             remote_message_header *hdr ATTRIBUTE_UNUSED,
-                             remote_error *rerr,
+remoteDispatchDomainGetVcpus(virNetServerPtr server ATTRIBUTE_UNUSED,
+                             virNetServerClientPtr client ATTRIBUTE_UNUSED,
+                             virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+                             virNetMessageErrorPtr rerr,
                              remote_domain_get_vcpus_args *args,
                              remote_domain_get_vcpus_ret *ret)
 {
@@ -1130,13 +1123,15 @@ remoteDispatchDomainGetVcpus(struct qemud_server *server ATTRIBUTE_UNUSED,
     unsigned char *cpumaps = NULL;
     int info_len, i;
     int rv = -1;
+    struct daemonClientPrivate *priv =
+        virNetServerClientGetPrivateData(client);
 
-    if (!conn) {
+    if (!priv->conn) {
         virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
         goto cleanup;
     }
 
-    if (!(dom = get_nonnull_domain(conn, args->dom)))
+    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
         goto cleanup;
 
     if (args->maxinfo > REMOTE_VCPUINFO_MAX) {
@@ -1186,7 +1181,7 @@ remoteDispatchDomainGetVcpus(struct qemud_server *server ATTRIBUTE_UNUSED,
 
 cleanup:
     if (rv < 0) {
-        remoteDispatchError(rerr);
+        virNetMessageSaveError(rerr);
         VIR_FREE(ret->info.info_val);
     }
     VIR_FREE(cpumaps);
@@ -1201,11 +1196,10 @@ no_memory:
 }
 
 static int
-remoteDispatchDomainMigratePrepare(struct qemud_server *server ATTRIBUTE_UNUSED,
-                                   struct qemud_client *client ATTRIBUTE_UNUSED,
-                                   virConnectPtr conn,
-                                   remote_message_header *hdr ATTRIBUTE_UNUSED,
-                                   remote_error *rerr,
+remoteDispatchDomainMigratePrepare(virNetServerPtr server ATTRIBUTE_UNUSED,
+                                   virNetServerClientPtr client ATTRIBUTE_UNUSED,
+                                   virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+                                   virNetMessageErrorPtr rerr,
                                    remote_domain_migrate_prepare_args *args,
                                    remote_domain_migrate_prepare_ret *ret)
 {
@@ -1215,8 +1209,10 @@ remoteDispatchDomainMigratePrepare(struct qemud_server *server ATTRIBUTE_UNUSED,
     char **uri_out;
     char *dname;
     int rv = -1;
+    struct daemonClientPrivate *priv =
+        virNetServerClientGetPrivateData(client);
 
-    if (!conn) {
+    if (!priv->conn) {
         virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
         goto cleanup;
     }
@@ -1230,7 +1226,7 @@ remoteDispatchDomainMigratePrepare(struct qemud_server *server ATTRIBUTE_UNUSED,
         goto cleanup;
     }
 
-    if (virDomainMigratePrepare(conn, &cookie, &cookielen,
+    if (virDomainMigratePrepare(priv->conn, &cookie, &cookielen,
                                 uri_in, uri_out,
                                 args->flags, dname, args->resource) < 0)
         goto cleanup;
@@ -1251,17 +1247,16 @@ remoteDispatchDomainMigratePrepare(struct qemud_server *server ATTRIBUTE_UNUSED,
 
 cleanup:
     if (rv < 0)
-        remoteDispatchError(rerr);
+        virNetMessageSaveError(rerr);
     VIR_FREE(uri_out);
     return rv;
 }
 
 static int
-remoteDispatchDomainMigratePrepare2(struct qemud_server *server ATTRIBUTE_UNUSED,
-                                    struct qemud_client *client ATTRIBUTE_UNUSED,
-                                    virConnectPtr conn,
-                                    remote_message_header *hdr ATTRIBUTE_UNUSED,
-                                    remote_error *rerr,
+remoteDispatchDomainMigratePrepare2(virNetServerPtr server ATTRIBUTE_UNUSED,
+                                    virNetServerClientPtr client ATTRIBUTE_UNUSED,
+                                    virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+                                    virNetMessageErrorPtr rerr,
                                     remote_domain_migrate_prepare2_args *args,
                                     remote_domain_migrate_prepare2_ret *ret)
 {
@@ -1271,8 +1266,10 @@ remoteDispatchDomainMigratePrepare2(struct qemud_server *server ATTRIBUTE_UNUSED
     char **uri_out;
     char *dname;
     int rv = -1;
+    struct daemonClientPrivate *priv =
+        virNetServerClientGetPrivateData(client);
 
-    if (!conn) {
+    if (!priv->conn) {
         virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
         goto cleanup;
     }
@@ -1286,7 +1283,7 @@ remoteDispatchDomainMigratePrepare2(struct qemud_server *server ATTRIBUTE_UNUSED
         goto cleanup;
     }
 
-    if (virDomainMigratePrepare2(conn, &cookie, &cookielen,
+    if (virDomainMigratePrepare2(priv->conn, &cookie, &cookielen,
                                  uri_in, uri_out,
                                  args->flags, dname, args->resource,
                                  args->dom_xml) < 0)
@@ -1303,31 +1300,27 @@ remoteDispatchDomainMigratePrepare2(struct qemud_server *server ATTRIBUTE_UNUSED
 
 cleanup:
     if (rv < 0)
-        remoteDispatchError(rerr);
+        virNetMessageSaveError(rerr);
     return rv;
 }
 
 static int
-remoteDispatchDomainGetMemoryParameters(struct qemud_server *server
-                                        ATTRIBUTE_UNUSED,
-                                        struct qemud_client *client
-                                        ATTRIBUTE_UNUSED,
-                                        virConnectPtr conn,
-                                        remote_message_header *
-                                        hdr ATTRIBUTE_UNUSED,
-                                        remote_error * rerr,
-                                        remote_domain_get_memory_parameters_args
-                                        * args,
-                                        remote_domain_get_memory_parameters_ret
-                                        * ret)
+remoteDispatchDomainGetMemoryParameters(virNetServerPtr server ATTRIBUTE_UNUSED,
+                                        virNetServerClientPtr client ATTRIBUTE_UNUSED,
+                                        virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+                                        virNetMessageErrorPtr rerr,
+                                        remote_domain_get_memory_parameters_args *args,
+                                        remote_domain_get_memory_parameters_ret *ret)
 {
     virDomainPtr dom = NULL;
     virTypedParameterPtr params = NULL;
     int nparams = args->nparams;
     unsigned int flags;
     int rv = -1;
+    struct daemonClientPrivate *priv =
+        virNetServerClientGetPrivateData(client);
 
-    if (!conn) {
+    if (!priv->conn) {
         virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
         goto cleanup;
     }
@@ -1343,7 +1336,7 @@ remoteDispatchDomainGetMemoryParameters(struct qemud_server *server
         goto cleanup;
     }
 
-    if (!(dom = get_nonnull_domain(conn, args->dom)))
+    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
         goto cleanup;
 
     if (virDomainGetMemoryParameters(dom, params, &nparams, flags) < 0)
@@ -1367,7 +1360,7 @@ success:
 
 cleanup:
     if (rv < 0)
-        remoteDispatchError(rerr);
+        virNetMessageSaveError(rerr);
     if (dom)
         virDomainFree(dom);
     VIR_FREE(params);
@@ -1375,26 +1368,22 @@ cleanup:
 }
 
 static int
-remoteDispatchDomainGetBlkioParameters(struct qemud_server *server
-                                        ATTRIBUTE_UNUSED,
-                                        struct qemud_client *client
-                                        ATTRIBUTE_UNUSED,
-                                        virConnectPtr conn,
-                                        remote_message_header *
-                                        hdr ATTRIBUTE_UNUSED,
-                                        remote_error * rerr,
-                                        remote_domain_get_blkio_parameters_args
-                                        * args,
-                                        remote_domain_get_blkio_parameters_ret
-                                        * ret)
+remoteDispatchDomainGetBlkioParameters(virNetServerPtr server ATTRIBUTE_UNUSED,
+                                       virNetServerClientPtr client ATTRIBUTE_UNUSED,
+                                       virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+                                       virNetMessageErrorPtr rerr,
+                                       remote_domain_get_blkio_parameters_args *args,
+                                       remote_domain_get_blkio_parameters_ret *ret)
 {
     virDomainPtr dom = NULL;
     virTypedParameterPtr params = NULL;
     int nparams = args->nparams;
     unsigned int flags;
     int rv = -1;
+    struct daemonClientPrivate *priv =
+        virNetServerClientGetPrivateData(client);
 
-    if (!conn) {
+    if (!priv->conn) {
         virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
         goto cleanup;
     }
@@ -1410,7 +1399,7 @@ remoteDispatchDomainGetBlkioParameters(struct qemud_server *server
         goto cleanup;
     }
 
-    if (!(dom = get_nonnull_domain(conn, args->dom)))
+    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
         goto cleanup;
 
     if (virDomainGetBlkioParameters(dom, params, &nparams, flags) < 0)
@@ -1434,7 +1423,7 @@ success:
 
 cleanup:
     if (rv < 0)
-        remoteDispatchError(rerr);
+        virNetMessageSaveError(rerr);
     VIR_FREE(params);
     if (dom)
         virDomainFree(dom);
@@ -1442,13 +1431,12 @@ cleanup:
 }
 
 static int
-remoteDispatchNodeGetCPUStats (struct qemud_server *server ATTRIBUTE_UNUSED,
-                               struct qemud_client *client ATTRIBUTE_UNUSED,
-                               virConnectPtr conn,
-                               remote_message_header *hdr ATTRIBUTE_UNUSED,
-                               remote_error *rerr,
-                               remote_node_get_cpu_stats_args *args,
-                               remote_node_get_cpu_stats_ret *ret)
+remoteDispatchNodeGetCPUStats(virNetServerPtr server ATTRIBUTE_UNUSED,
+                              virNetServerClientPtr client ATTRIBUTE_UNUSED,
+                              virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+                              virNetMessageErrorPtr rerr,
+                              remote_node_get_cpu_stats_args *args,
+                              remote_node_get_cpu_stats_ret *ret)
 {
     virCPUStatsPtr params = NULL;
     int i;
@@ -1456,8 +1444,10 @@ remoteDispatchNodeGetCPUStats (struct qemud_server *server ATTRIBUTE_UNUSED,
     int nparams = args->nparams;
     unsigned int flags;
     int rv = -1;
+    struct daemonClientPrivate *priv =
+        virNetServerClientGetPrivateData(client);
 
-    if (!conn) {
+    if (!priv->conn) {
         virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
         goto cleanup;
     }
@@ -1473,7 +1463,7 @@ remoteDispatchNodeGetCPUStats (struct qemud_server *server ATTRIBUTE_UNUSED,
         goto cleanup;
     }
 
-    if (virNodeGetCPUStats(conn, cpuNum, params, &nparams, flags) < 0)
+    if (virNodeGetCPUStats(priv->conn, cpuNum, params, &nparams, flags) < 0)
         goto cleanup;
 
     /* In this case, we need to send back the number of stats
@@ -1503,7 +1493,7 @@ success:
 
 cleanup:
     if (rv < 0) {
-        remoteDispatchError(rerr);
+        virNetMessageSaveError(rerr);
         if (ret->params.params_val) {
             for (i = 0; i < nparams; i++)
                 VIR_FREE(ret->params.params_val[i].field);
@@ -1519,13 +1509,12 @@ no_memory:
 }
 
 static int
-remoteDispatchNodeGetMemoryStats (struct qemud_server *server ATTRIBUTE_UNUSED,
-                                  struct qemud_client *client ATTRIBUTE_UNUSED,
-                                  virConnectPtr conn,
-                                  remote_message_header *hdr ATTRIBUTE_UNUSED,
-                                  remote_error *rerr,
-                                  remote_node_get_memory_stats_args *args,
-                                  remote_node_get_memory_stats_ret *ret)
+remoteDispatchNodeGetMemoryStats(virNetServerPtr server ATTRIBUTE_UNUSED,
+                                 virNetServerClientPtr client ATTRIBUTE_UNUSED,
+                                 virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+                                 virNetMessageErrorPtr rerr,
+                                 remote_node_get_memory_stats_args *args,
+                                 remote_node_get_memory_stats_ret *ret)
 {
     virMemoryStatsPtr params = NULL;
     int i;
@@ -1533,8 +1522,10 @@ remoteDispatchNodeGetMemoryStats (struct qemud_server *server ATTRIBUTE_UNUSED,
     int nparams = args->nparams;
     unsigned int flags;
     int rv = -1;
+    struct daemonClientPrivate *priv =
+        virNetServerClientGetPrivateData(client);
 
-    if (!conn) {
+    if (!priv->conn) {
         virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
         goto cleanup;
     }
@@ -1550,7 +1541,7 @@ remoteDispatchNodeGetMemoryStats (struct qemud_server *server ATTRIBUTE_UNUSED,
         goto cleanup;
     }
 
-    if (virNodeGetMemoryStats(conn, cellNum, params, &nparams, flags) < 0)
+    if (virNodeGetMemoryStats(priv->conn, cellNum, params, &nparams, flags) < 0)
         goto cleanup;
 
     /* In this case, we need to send back the number of parameters
@@ -1580,7 +1571,7 @@ success:
 
 cleanup:
     if (rv < 0) {
-        remoteDispatchError(rerr);
+        virNetMessageSaveError(rerr);
         if (ret->params.params_val) {
             for (i = 0; i < nparams; i++)
                 VIR_FREE(ret->params.params_val[i].field);
@@ -1598,360 +1589,242 @@ no_memory:
 /*-------------------------------------------------------------*/
 
 static int
-remoteDispatchAuthList(struct qemud_server *server,
-                       struct qemud_client *client,
-                       virConnectPtr conn ATTRIBUTE_UNUSED,
-                       remote_message_header *hdr ATTRIBUTE_UNUSED,
-                       remote_error *rerr,
-                       void *args ATTRIBUTE_UNUSED,
+remoteDispatchAuthList(virNetServerPtr server ATTRIBUTE_UNUSED,
+                       virNetServerClientPtr client,
+                       virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+                       virNetMessageErrorPtr rerr,
                        remote_auth_list_ret *ret)
 {
     int rv = -1;
+    int auth = virNetServerClientGetAuth(client);
+    uid_t callerUid;
+    pid_t callerPid;
+
+    /* If the client is root then we want to bypass the
+     * policykit auth to avoid root being denied if
+     * some piece of polkit isn't present/running
+     */
+    if (auth == VIR_NET_SERVER_SERVICE_AUTH_POLKIT) {
+        if (virNetServerClientGetLocalIdentity(client, &callerUid, &callerPid) < 0) {
+            /* Don't do anything on error - it'll be validated at next
+             * phase of auth anyway */
+            virResetLastError();
+        } else if (callerUid == 0) {
+            char ident[100];
+            rv = snprintf(ident, sizeof ident, "pid:%d,uid:%d", callerPid, callerUid);
+            if (rv > 0 || rv < sizeof ident) {
+                VIR_INFO("Bypass polkit auth for privileged client %s",
+                         ident);
+                if (virNetServerClientSetIdentity(client, ident) < 0)
+                    virResetLastError();
+                else
+                    auth = VIR_NET_SERVER_SERVICE_AUTH_NONE;
+            }
+            rv = -1;
+        }
+    }
 
     ret->types.types_len = 1;
     if (VIR_ALLOC_N(ret->types.types_val, ret->types.types_len) < 0) {
         virReportOOMError();
         goto cleanup;
     }
-    virMutexLock(&server->lock);
-    virMutexLock(&client->lock);
-    virMutexUnlock(&server->lock);
-    ret->types.types_val[0] = client->auth;
-    virMutexUnlock(&client->lock);
+
+    switch (auth) {
+    case VIR_NET_SERVER_SERVICE_AUTH_NONE:
+        ret->types.types_val[0] = REMOTE_AUTH_NONE;
+        break;
+    case VIR_NET_SERVER_SERVICE_AUTH_POLKIT:
+        ret->types.types_val[0] = REMOTE_AUTH_POLKIT;
+        break;
+    case VIR_NET_SERVER_SERVICE_AUTH_SASL:
+        ret->types.types_val[0] = REMOTE_AUTH_SASL;
+        break;
+    default:
+        ret->types.types_val[0] = REMOTE_AUTH_NONE;
+    }
 
     rv = 0;
 
 cleanup:
     if (rv < 0)
-        remoteDispatchError(rerr);
+        virNetMessageSaveError(rerr);
     return rv;
 }
 
 
-#if HAVE_SASL
 /*
  * Initializes the SASL session in prepare for authentication
  * and gives the client a list of allowed mechanisms to choose
- *
- * XXX callbacks for stuff like password verification ?
  */
 static int
-remoteDispatchAuthSaslInit(struct qemud_server *server,
-                           struct qemud_client *client,
-                           virConnectPtr conn ATTRIBUTE_UNUSED,
-                           remote_message_header *hdr ATTRIBUTE_UNUSED,
-                           remote_error *rerr,
-                           void *args ATTRIBUTE_UNUSED,
+remoteDispatchAuthSaslInit(virNetServerPtr server ATTRIBUTE_UNUSED,
+                           virNetServerClientPtr client,
+                           virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+                           virNetMessageErrorPtr rerr,
                            remote_auth_sasl_init_ret *ret)
 {
-    const char *mechlist = NULL;
-    sasl_security_properties_t secprops;
-    int err;
-    virSocketAddr sa;
-    char *localAddr, *remoteAddr;
+    virNetSASLSessionPtr sasl = NULL;
+    struct daemonClientPrivate *priv =
+        virNetServerClientGetPrivateData(client);
 
-    virMutexLock(&server->lock);
-    virMutexLock(&client->lock);
-    virMutexUnlock(&server->lock);
+    virMutexLock(&priv->lock);
 
-    VIR_DEBUG("Initialize SASL auth %d", client->fd);
-    if (client->auth != REMOTE_AUTH_SASL ||
-        client->saslconn != NULL) {
+    VIR_DEBUG("Initialize SASL auth %d", virNetServerClientGetFD(client));
+    if (virNetServerClientGetAuth(client) != VIR_NET_SERVER_SERVICE_AUTH_SASL ||
+        priv->sasl != NULL) {
         VIR_ERROR(_("client tried invalid SASL init request"));
         goto authfail;
     }
 
-    /* Get local address in form  IPADDR:PORT */
-    sa.len = sizeof(sa.data.stor);
-    if (getsockname(client->fd, &sa.data.sa, &sa.len) < 0) {
-        char ebuf[1024];
-        virNetError(VIR_ERR_INTERNAL_ERROR,
-                    _("failed to get sock address: %s"),
-                    virStrerror(errno, ebuf, sizeof ebuf));
-        goto error;
-    }
-    if ((localAddr = virSocketFormatAddrFull(&sa, true, ";")) == NULL)
-        goto error;
-
-    /* Get remote address in form  IPADDR:PORT */
-    sa.len = sizeof(sa.data.stor);
-    if (getpeername(client->fd, &sa.data.sa, &sa.len) < 0) {
-        char ebuf[1024];
-        virNetError(VIR_ERR_INTERNAL_ERROR, _("failed to get peer address: %s"),
-                    virStrerror(errno, ebuf, sizeof ebuf));
-        VIR_FREE(localAddr);
-        goto error;
-    }
-    if ((remoteAddr = virSocketFormatAddrFull(&sa, true, ";")) == NULL) {
-        VIR_FREE(localAddr);
-        goto error;
-    }
-
-    err = sasl_server_new("libvirt",
-                          NULL, /* FQDN - just delegates to gethostname */
-                          NULL, /* User realm */
-                          localAddr,
-                          remoteAddr,
-                          NULL, /* XXX Callbacks */
-                          SASL_SUCCESS_DATA,
-                          &client->saslconn);
-    VIR_FREE(localAddr);
-    VIR_FREE(remoteAddr);
-    if (err != SASL_OK) {
-        VIR_ERROR(_("sasl context setup failed %d (%s)"),
-                  err, sasl_errstring(err, NULL, NULL));
-        client->saslconn = NULL;
+    sasl = virNetSASLSessionNewServer(saslCtxt,
+                                      "libvirt",
+                                      virNetServerClientLocalAddrString(client),
+                                      virNetServerClientRemoteAddrString(client));
+    if (!sasl)
         goto authfail;
-    }
 
     /* Inform SASL that we've got an external SSF layer from TLS */
-    if (client->type == QEMUD_SOCK_TYPE_TLS) {
-        gnutls_cipher_algorithm_t cipher;
-        sasl_ssf_t ssf;
-
-        cipher = gnutls_cipher_get(client->tlssession);
-        if (!(ssf = (sasl_ssf_t)gnutls_cipher_get_key_size(cipher))) {
-            VIR_ERROR(_("cannot get TLS cipher size"));
-            sasl_dispose(&client->saslconn);
-            client->saslconn = NULL;
+    if (virNetServerClientHasTLSSession(client)) {
+        int ssf;
+
+        if ((ssf = virNetServerClientGetTLSKeySize(client)) < 0)
             goto authfail;
-        }
-        ssf *= 8; /* tls key size is bytes, sasl wants bits */
-
-        err = sasl_setprop(client->saslconn, SASL_SSF_EXTERNAL, &ssf);
-        if (err != SASL_OK) {
-            VIR_ERROR(_("cannot set SASL external SSF %d (%s)"),
-                      err, sasl_errstring(err, NULL, NULL));
-            sasl_dispose(&client->saslconn);
-            client->saslconn = NULL;
+
+        ssf *= 8; /* key size is bytes, sasl wants bits */
+
+        VIR_DEBUG("Setting external SSF %d", ssf);
+        if (virNetSASLSessionExtKeySize(sasl, ssf) < 0)
             goto authfail;
-        }
     }
 
-    memset(&secprops, 0, sizeof secprops);
-    if (client->type == QEMUD_SOCK_TYPE_TLS ||
-        client->type == QEMUD_SOCK_TYPE_UNIX) {
+    if (virNetServerClientIsSecure(client))
         /* If we've got TLS or UNIX domain sock, we don't care about SSF */
-        secprops.min_ssf = 0;
-        secprops.max_ssf = 0;
-        secprops.maxbufsize = 8192;
-        secprops.security_flags = 0;
-    } else {
+        virNetSASLSessionSecProps(sasl, 0, 0, true);
+    else
         /* Plain TCP, better get an SSF layer */
-        secprops.min_ssf = 56; /* Good enough to require kerberos */
-        secprops.max_ssf = 100000; /* Arbitrary big number */
-        secprops.maxbufsize = 8192;
-        /* Forbid any anonymous or trivially crackable auth */
-        secprops.security_flags =
-            SASL_SEC_NOANONYMOUS | SASL_SEC_NOPLAINTEXT;
-    }
-
-    err = sasl_setprop(client->saslconn, SASL_SEC_PROPS, &secprops);
-    if (err != SASL_OK) {
-        VIR_ERROR(_("cannot set SASL security props %d (%s)"),
-                  err, sasl_errstring(err, NULL, NULL));
-        sasl_dispose(&client->saslconn);
-        client->saslconn = NULL;
-        goto authfail;
-    }
+        virNetSASLSessionSecProps(sasl,
+                                  56,  /* Good enough to require kerberos */
+                                  100000,  /* Arbitrary big number */
+                                  false); /* No anonymous */
 
-    err = sasl_listmech(client->saslconn,
-                        NULL, /* Don't need to set user */
-                        "", /* Prefix */
-                        ",", /* Separator */
-                        "", /* Suffix */
-                        &mechlist,
-                        NULL,
-                        NULL);
-    if (err != SASL_OK) {
-        VIR_ERROR(_("cannot list SASL mechanisms %d (%s)"),
-                  err, sasl_errdetail(client->saslconn));
-        sasl_dispose(&client->saslconn);
-        client->saslconn = NULL;
-        goto authfail;
-    }
-    VIR_DEBUG("Available mechanisms for client: '%s'", mechlist);
-    ret->mechlist = strdup(mechlist);
-    if (!ret->mechlist) {
-        VIR_ERROR(_("cannot allocate mechlist"));
-        sasl_dispose(&client->saslconn);
-        client->saslconn = NULL;
+    if (!(ret->mechlist = virNetSASLSessionListMechanisms(sasl)))
         goto authfail;
-    }
+    VIR_DEBUG("Available mechanisms for client: '%s'", ret->mechlist);
 
-    virMutexUnlock(&client->lock);
+    priv->sasl = sasl;
+    virMutexUnlock(&priv->lock);
     return 0;
 
 authfail:
-    remoteDispatchAuthError(rerr);
-error:
-    PROBE(CLIENT_AUTH_FAIL, "fd=%d, auth=%d", client->fd, REMOTE_AUTH_SASL);
-    virMutexUnlock(&client->lock);
+    virResetLastError();
+    virNetError(VIR_ERR_AUTH_FAILED, "%s",
+                _("authentication failed"));
+    virNetMessageSaveError(rerr);
+    PROBE(CLIENT_AUTH_FAIL, "fd=%d, auth=%d",
+          virNetServerClientGetFD(client), REMOTE_AUTH_SASL);
+    virNetSASLSessionFree(sasl);
+    virMutexUnlock(&priv->lock);
     return -1;
 }
 
-
-/* We asked for an SSF layer, so sanity check that we actually
- * got what we asked for
+/*
  * Returns 0 if ok, -1 on error, -2 if rejected
  */
 static int
-remoteSASLCheckSSF(struct qemud_client *client,
-                   remote_error *rerr) {
-    const void *val;
-    int err, ssf;
-
-    if (client->type == QEMUD_SOCK_TYPE_TLS ||
-        client->type == QEMUD_SOCK_TYPE_UNIX)
-        return 0; /* TLS or UNIX domain sockets trivially OK */
-
-    err = sasl_getprop(client->saslconn, SASL_SSF, &val);
-    if (err != SASL_OK) {
-        VIR_ERROR(_("cannot query SASL ssf on connection %d (%s)"),
-                  err, sasl_errstring(err, NULL, NULL));
-        remoteDispatchAuthError(rerr);
-        sasl_dispose(&client->saslconn);
-        client->saslconn = NULL;
-        return -1;
+remoteSASLFinish(virNetServerClientPtr client)
+{
+    const char *identity;
+    struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client);
+    int ssf;
+
+    /* TLS or UNIX domain sockets trivially OK */
+    if (!virNetServerClientIsSecure(client)) {
+        if ((ssf = virNetSASLSessionGetKeySize(priv->sasl)) < 0)
+            goto error;
+
+        VIR_DEBUG("negotiated an SSF of %d", ssf);
+        if (ssf < 56) { /* 56 is good for Kerberos */
+            VIR_ERROR(_("negotiated SSF %d was not strong enough"), ssf);
+            return -2;
+        }
     }
-    ssf = *(const int *)val;
-    VIR_DEBUG("negotiated an SSF of %d", ssf);
-    if (ssf < 56) { /* 56 is good for Kerberos */
-        VIR_ERROR(_("negotiated SSF %d was not strong enough"), ssf);
-        remoteDispatchAuthError(rerr);
-        sasl_dispose(&client->saslconn);
-        client->saslconn = NULL;
+
+    if (!(identity = virNetSASLSessionGetIdentity(priv->sasl)))
         return -2;
-    }
 
-    /* Only setup for read initially, because we're about to send an RPC
-     * reply which must be in plain text. When the next incoming RPC
-     * arrives, we'll switch on writes too
-     *
-     * cf qemudClientReadSASL  in qemud.c
-     */
-    client->saslSSF = QEMUD_SASL_SSF_READ;
+    if (!virNetSASLContextCheckIdentity(saslCtxt, identity))
+        return -2;
 
-    /* We have a SSF !*/
-    return 0;
-}
+    if (virNetServerClientSetIdentity(client, identity) < 0)
+        goto error;
 
-/*
- * Returns 0 if ok, -1 on error, -2 if rejected
- */
-static int
-remoteSASLCheckAccess(struct qemud_server *server,
-                      struct qemud_client *client,
-                      remote_error *rerr) {
-    const void *val;
-    int err;
-    char **wildcards;
-
-    err = sasl_getprop(client->saslconn, SASL_USERNAME, &val);
-    if (err != SASL_OK) {
-        VIR_ERROR(_("cannot query SASL username on connection %d (%s)"),
-                  err, sasl_errstring(err, NULL, NULL));
-        remoteDispatchAuthError(rerr);
-        sasl_dispose(&client->saslconn);
-        client->saslconn = NULL;
-        return -1;
-    }
-    if (val == NULL) {
-        VIR_ERROR(_("no client username was found"));
-        remoteDispatchAuthError(rerr);
-        sasl_dispose(&client->saslconn);
-        client->saslconn = NULL;
-        return -1;
-    }
-    VIR_DEBUG("SASL client username %s", (const char *)val);
 
-    client->saslUsername = strdup((const char*)val);
-    if (client->saslUsername == NULL) {
-        VIR_ERROR(_("out of memory copying username"));
-        remoteDispatchAuthError(rerr);
-        sasl_dispose(&client->saslconn);
-        client->saslconn = NULL;
-        return -1;
-    }
+    virNetServerClientSetSASLSession(client, priv->sasl);
+
+    VIR_DEBUG("Authentication successful %d", virNetServerClientGetFD(client));
+    PROBE(CLIENT_AUTH_ALLOW, "fd=%d, auth=%d, username=%s",
+          virNetServerClientGetFD(client), REMOTE_AUTH_SASL,
+          virNetSASLSessionGetIdentity(priv->sasl));
 
-    /* If the list is not set, allow any DN. */
-    wildcards = server->saslUsernameWhitelist;
-    if (!wildcards)
-        return 0; /* No ACL, allow all */
+    virNetSASLSessionFree(priv->sasl);
+    priv->sasl = NULL;
 
-    while (*wildcards) {
-        if (fnmatch(*wildcards, client->saslUsername, 0) == 0)
-            return 0; /* Allowed */
-        wildcards++;
-    }
+    return 0;
 
-    /* Denied */
-    VIR_ERROR(_("SASL client %s not allowed in whitelist"), client->saslUsername);
-    remoteDispatchAuthError(rerr);
-    sasl_dispose(&client->saslconn);
-    client->saslconn = NULL;
-    return -2;
+error:
+    return -1;
 }
 
-
 /*
  * This starts the SASL authentication negotiation.
  */
 static int
-remoteDispatchAuthSaslStart(struct qemud_server *server,
-                            struct qemud_client *client,
-                            virConnectPtr conn ATTRIBUTE_UNUSED,
-                            remote_message_header *hdr ATTRIBUTE_UNUSED,
-                            remote_error *rerr,
+remoteDispatchAuthSaslStart(virNetServerPtr server ATTRIBUTE_UNUSED,
+                            virNetServerClientPtr client,
+                            virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+                            virNetMessageErrorPtr rerr,
                             remote_auth_sasl_start_args *args,
                             remote_auth_sasl_start_ret *ret)
 {
     const char *serverout;
-    unsigned int serveroutlen;
+    size_t serveroutlen;
     int err;
+    int rv = -1;
+    struct daemonClientPrivate *priv =
+        virNetServerClientGetPrivateData(client);
 
-    virMutexLock(&server->lock);
-    virMutexLock(&client->lock);
-    virMutexUnlock(&server->lock);
+    virMutexLock(&priv->lock);
 
-    VIR_DEBUG("Start SASL auth %d", client->fd);
-    if (client->auth != REMOTE_AUTH_SASL ||
-        client->saslconn == NULL) {
+    VIR_DEBUG("Start SASL auth %d", virNetServerClientGetFD(client));
+    if (virNetServerClientGetAuth(client) != VIR_NET_SERVER_SERVICE_AUTH_SASL ||
+        priv->sasl == NULL) {
         VIR_ERROR(_("client tried invalid SASL start request"));
         goto authfail;
     }
 
     VIR_DEBUG("Using SASL mechanism %s. Data %d bytes, nil: %d",
               args->mech, args->data.data_len, args->nil);
-    err = sasl_server_start(client->saslconn,
-                            args->mech,
-                            /* NB, distinction of NULL vs "" is *critical* in SASL */
-                            args->nil ? NULL : args->data.data_val,
-                            args->data.data_len,
-                            &serverout,
-                            &serveroutlen);
-    if (err != SASL_OK &&
-        err != SASL_CONTINUE) {
-        VIR_ERROR(_("sasl start failed %d (%s)"),
-                  err, sasl_errdetail(client->saslconn));
-        sasl_dispose(&client->saslconn);
-        client->saslconn = NULL;
+    err = virNetSASLSessionServerStart(priv->sasl,
+                                       args->mech,
+                                       /* NB, distinction of NULL vs "" is *critical* in SASL */
+                                       args->nil ? NULL : args->data.data_val,
+                                       args->data.data_len,
+                                       &serverout,
+                                       &serveroutlen);
+    if (err != VIR_NET_SASL_COMPLETE &&
+        err != VIR_NET_SASL_CONTINUE)
         goto authfail;
-    }
+
     if (serveroutlen > REMOTE_AUTH_SASL_DATA_MAX) {
-        VIR_ERROR(_("sasl start reply data too long %d"), serveroutlen);
-        sasl_dispose(&client->saslconn);
-        client->saslconn = NULL;
+        VIR_ERROR(_("sasl start reply data too long %d"), (int)serveroutlen);
         goto authfail;
     }
 
     /* NB, distinction of NULL vs "" is *critical* in SASL */
     if (serverout) {
-        if (VIR_ALLOC_N(ret->data.data_val, serveroutlen) < 0) {
-            virReportOOMError();
-            remoteDispatchError(rerr);
-            goto error;
-        }
+        if (VIR_ALLOC_N(ret->data.data_val, serveroutlen) < 0)
+            goto authfail;
         memcpy(ret->data.data_val, serverout, serveroutlen);
     } else {
         ret->data.data_val = NULL;
@@ -1960,100 +1833,94 @@ remoteDispatchAuthSaslStart(struct qemud_server *server,
     ret->data.data_len = serveroutlen;
 
     VIR_DEBUG("SASL return data %d bytes, nil; %d", ret->data.data_len, ret->nil);
-    if (err == SASL_CONTINUE) {
+    if (err == VIR_NET_SASL_CONTINUE) {
         ret->complete = 0;
     } else {
         /* Check username whitelist ACL */
-        if ((err = remoteSASLCheckAccess(server, client, rerr)) < 0 ||
-            (err = remoteSASLCheckSSF(client, rerr)) < 0) {
+        if ((err = remoteSASLFinish(client)) < 0) {
             if (err == -2)
                 goto authdeny;
             else
                 goto authfail;
         }
 
-        VIR_DEBUG("Authentication successful %d", client->fd);
-        PROBE(CLIENT_AUTH_ALLOW, "fd=%d, auth=%d, username=%s",
-              client->fd, REMOTE_AUTH_SASL, client->saslUsername);
         ret->complete = 1;
-        client->auth = REMOTE_AUTH_NONE;
     }
 
-    virMutexUnlock(&client->lock);
+    virMutexUnlock(&priv->lock);
     return 0;
 
 authfail:
-    PROBE(CLIENT_AUTH_FAIL, "fd=%d, auth=%d", client->fd, REMOTE_AUTH_SASL);
-    remoteDispatchAuthError(rerr);
+    PROBE(CLIENT_AUTH_FAIL, "fd=%d, auth=%d",
+          virNetServerClientGetFD(client), REMOTE_AUTH_SASL);
     goto error;
 
 authdeny:
     PROBE(CLIENT_AUTH_DENY, "fd=%d, auth=%d, username=%s",
-          client->fd, REMOTE_AUTH_SASL, client->saslUsername);
+          virNetServerClientGetFD(client), REMOTE_AUTH_SASL,
+          virNetSASLSessionGetIdentity(priv->sasl));
     goto error;
 
 error:
-    virMutexUnlock(&client->lock);
+    virNetSASLSessionFree(priv->sasl);
+    priv->sasl = NULL;
+    virResetLastError();
+    virNetError(VIR_ERR_AUTH_FAILED, "%s",
+                _("authentication failed"));
+    if (rv < 0)
+        virNetMessageSaveError(rerr);
+    virMutexUnlock(&priv->lock);
     return -1;
 }
 
 
 static int
-remoteDispatchAuthSaslStep(struct qemud_server *server,
-                           struct qemud_client *client,
-                           virConnectPtr conn ATTRIBUTE_UNUSED,
-                           remote_message_header *hdr ATTRIBUTE_UNUSED,
-                           remote_error *rerr,
+remoteDispatchAuthSaslStep(virNetServerPtr server ATTRIBUTE_UNUSED,
+                           virNetServerClientPtr client,
+                           virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+                           virNetMessageErrorPtr rerr,
                            remote_auth_sasl_step_args *args,
                            remote_auth_sasl_step_ret *ret)
 {
     const char *serverout;
-    unsigned int serveroutlen;
+    size_t serveroutlen;
     int err;
+    int rv = -1;
+    struct daemonClientPrivate *priv =
+        virNetServerClientGetPrivateData(client);
 
-    virMutexLock(&server->lock);
-    virMutexLock(&client->lock);
-    virMutexUnlock(&server->lock);
 
-    VIR_DEBUG("Step SASL auth %d", client->fd);
-    if (client->auth != REMOTE_AUTH_SASL ||
-        client->saslconn == NULL) {
+    virMutexLock(&priv->lock);
+
+    VIR_DEBUG("Step SASL auth %d", virNetServerClientGetFD(client));
+    if (virNetServerClientGetAuth(client) != VIR_NET_SERVER_SERVICE_AUTH_SASL ||
+        priv->sasl == NULL) {
         VIR_ERROR(_("client tried invalid SASL start request"));
         goto authfail;
     }
 
-    VIR_DEBUG("Using SASL Data %d bytes, nil: %d",
+    VIR_DEBUG("Step using SASL Data %d bytes, nil: %d",
               args->data.data_len, args->nil);
-    err = sasl_server_step(client->saslconn,
-                           /* NB, distinction of NULL vs "" is *critical* in SASL */
-                           args->nil ? NULL : args->data.data_val,
-                           args->data.data_len,
-                           &serverout,
-                           &serveroutlen);
-    if (err != SASL_OK &&
-        err != SASL_CONTINUE) {
-        VIR_ERROR(_("sasl step failed %d (%s)"),
-                  err, sasl_errdetail(client->saslconn));
-        sasl_dispose(&client->saslconn);
-        client->saslconn = NULL;
+    err = virNetSASLSessionServerStep(priv->sasl,
+                                      /* NB, distinction of NULL vs "" is *critical* in SASL */
+                                      args->nil ? NULL : args->data.data_val,
+                                      args->data.data_len,
+                                      &serverout,
+                                      &serveroutlen);
+    if (err != VIR_NET_SASL_COMPLETE &&
+        err != VIR_NET_SASL_CONTINUE)
         goto authfail;
-    }
 
     if (serveroutlen > REMOTE_AUTH_SASL_DATA_MAX) {
         VIR_ERROR(_("sasl step reply data too long %d"),
-                  serveroutlen);
-        sasl_dispose(&client->saslconn);
-        client->saslconn = NULL;
+                  (int)serveroutlen);
         goto authfail;
     }
 
     /* NB, distinction of NULL vs "" is *critical* in SASL */
     if (serverout) {
-        if (VIR_ALLOC_N(ret->data.data_val, serveroutlen) < 0) {
-            virReportOOMError();
-            remoteDispatchError(rerr);
-            goto error;
-        }
+        if (VIR_ALLOC_N(ret->data.data_val, serveroutlen) < 0)
+            goto authfail;
         memcpy(ret->data.data_val, serverout, serveroutlen);
     } else {
         ret->data.data_val = NULL;
@@ -2062,100 +1929,54 @@ remoteDispatchAuthSaslStep(struct qemud_server *server,
     ret->data.data_len = serveroutlen;
 
     VIR_DEBUG("SASL return data %d bytes, nil; %d", ret->data.data_len, ret->nil);
-    if (err == SASL_CONTINUE) {
+    if (err == VIR_NET_SASL_CONTINUE) {
         ret->complete = 0;
     } else {
         /* Check username whitelist ACL */
-        if ((err = remoteSASLCheckAccess(server, client, rerr)) < 0 ||
-            (err = remoteSASLCheckSSF(client, rerr)) < 0) {
+        if ((err = remoteSASLFinish(client)) < 0) {
             if (err == -2)
                 goto authdeny;
             else
                 goto authfail;
         }
 
-        VIR_DEBUG("Authentication successful %d", client->fd);
-        PROBE(CLIENT_AUTH_ALLOW, "fd=%d, auth=%d, username=%s",
-              client->fd, REMOTE_AUTH_SASL, client->saslUsername);
         ret->complete = 1;
-        client->auth = REMOTE_AUTH_NONE;
     }
 
-    virMutexUnlock(&client->lock);
+    virMutexUnlock(&priv->lock);
     return 0;
 
 authfail:
-    PROBE(CLIENT_AUTH_FAIL, "fd=%d, auth=%d", client->fd, REMOTE_AUTH_SASL);
-    remoteDispatchAuthError(rerr);
+    PROBE(CLIENT_AUTH_FAIL, "fd=%d, auth=%d",
+          virNetServerClientGetFD(client), REMOTE_AUTH_SASL);
     goto error;
 
 authdeny:
     PROBE(CLIENT_AUTH_DENY, "fd=%d, auth=%d, username=%s",
-          client->fd, REMOTE_AUTH_SASL, client->saslUsername);
+          virNetServerClientGetFD(client), REMOTE_AUTH_SASL,
+          virNetSASLSessionGetIdentity(priv->sasl));
     goto error;
 
 error:
-    virMutexUnlock(&client->lock);
-    return -1;
-}
-
-
-#else /* HAVE_SASL */
-static int
-remoteDispatchAuthSaslInit(struct qemud_server *server ATTRIBUTE_UNUSED,
-                           struct qemud_client *client ATTRIBUTE_UNUSED,
-                           virConnectPtr conn ATTRIBUTE_UNUSED,
-                           remote_message_header *hdr ATTRIBUTE_UNUSED,
-                           remote_error *rerr,
-                           void *args ATTRIBUTE_UNUSED,
-                           remote_auth_sasl_init_ret *ret ATTRIBUTE_UNUSED)
-{
-    VIR_ERROR(_("client tried unsupported SASL init request"));
-    PROBE(CLIENT_AUTH_FAIL, "fd=%d, auth=%d", client->fd, REMOTE_AUTH_SASL);
-    remoteDispatchAuthError(rerr);
-    return -1;
-}
-
-static int
-remoteDispatchAuthSaslStart(struct qemud_server *server ATTRIBUTE_UNUSED,
-                            struct qemud_client *client ATTRIBUTE_UNUSED,
-                            virConnectPtr conn ATTRIBUTE_UNUSED,
-                            remote_message_header *hdr ATTRIBUTE_UNUSED,
-                            remote_error *rerr,
-                            remote_auth_sasl_start_args *args ATTRIBUTE_UNUSED,
-                            remote_auth_sasl_start_ret *ret ATTRIBUTE_UNUSED)
-{
-    VIR_ERROR(_("client tried unsupported SASL start request"));
-    PROBE(CLIENT_AUTH_FAIL, "fd=%d, auth=%d", client->fd, REMOTE_AUTH_SASL);
-    remoteDispatchAuthError(rerr);
+    virNetSASLSessionFree(priv->sasl);
+    priv->sasl = NULL;
+    virResetLastError();
+    virNetError(VIR_ERR_AUTH_FAILED, "%s",
+                _("authentication failed"));
+    if (rv < 0)
+        virNetMessageSaveError(rerr);
+    virMutexUnlock(&priv->lock);
     return -1;
 }
 
-static int
-remoteDispatchAuthSaslStep(struct qemud_server *server ATTRIBUTE_UNUSED,
-                           struct qemud_client *client ATTRIBUTE_UNUSED,
-                           virConnectPtr conn ATTRIBUTE_UNUSED,
-                           remote_message_header *hdr ATTRIBUTE_UNUSED,
-                           remote_error *rerr,
-                           remote_auth_sasl_step_args *args ATTRIBUTE_UNUSED,
-                           remote_auth_sasl_step_ret *ret ATTRIBUTE_UNUSED)
-{
-    VIR_ERROR(_("client tried unsupported SASL step request"));
-    PROBE(CLIENT_AUTH_FAIL, "fd=%d, auth=%d", client->fd, REMOTE_AUTH_SASL);
-    remoteDispatchAuthError(rerr);
-    return -1;
-}
-#endif /* HAVE_SASL */
 
 
 #if HAVE_POLKIT1
 static int
-remoteDispatchAuthPolkit(struct qemud_server *server,
-                         struct qemud_client *client,
-                         virConnectPtr conn ATTRIBUTE_UNUSED,
-                         remote_message_header *hdr ATTRIBUTE_UNUSED,
-                         remote_error *rerr,
-                         void *args ATTRIBUTE_UNUSED,
+remoteDispatchAuthPolkit(virNetServerPtr server ATTRIBUTE_UNUSED,
+                         virNetServerClientPtr client,
+                         virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+                         virNetMessageErrorPtr rerr,
                          remote_auth_polkit_ret *ret)
 {
     pid_t callerPid = -1;
@@ -2164,15 +1985,14 @@ remoteDispatchAuthPolkit(struct qemud_server *server,
     int status = -1;
     char pidbuf[50];
     char ident[100];
-    int rv;
+    int rv = -1;
+    struct daemonClientPrivate *priv =
+        virNetServerClientGetPrivateData(client);
 
     memset(ident, 0, sizeof ident);
 
-    virMutexLock(&server->lock);
-    virMutexLock(&client->lock);
-    virMutexUnlock(&server->lock);
-
-    action = client->readonly ?
+    virMutexLock(&priv->lock);
+    action = virNetServerClientGetReadonly(client) ?
         "org.libvirt.unix.monitor" :
         "org.libvirt.unix.manage";
 
@@ -2184,14 +2004,13 @@ remoteDispatchAuthPolkit(struct qemud_server *server,
       NULL
     };
 
-    VIR_DEBUG("Start PolicyKit auth %d", client->fd);
-    if (client->auth != REMOTE_AUTH_POLKIT) {
+    VIR_DEBUG("Start PolicyKit auth %d", virNetServerClientGetFD(client));
+    if (virNetServerClientGetAuth(client) != VIR_NET_SERVER_SERVICE_AUTH_POLKIT) {
         VIR_ERROR(_("client tried invalid PolicyKit init request"));
         goto authfail;
     }
 
-    if (qemudGetSocketIdentity(client->fd, &callerUid, &callerPid) < 0) {
-        VIR_ERROR(_("cannot get peer socket identity"));
+    if (virNetServerClientGetLocalIdentity(client, &callerUid, &callerPid) < 0) {
         goto authfail;
     }
 
@@ -2221,37 +2040,40 @@ remoteDispatchAuthPolkit(struct qemud_server *server,
         goto authdeny;
     }
     PROBE(CLIENT_AUTH_ALLOW, "fd=%d, auth=%d, username=%s",
-          client->fd, REMOTE_AUTH_POLKIT, (char *)ident);
+          virNetServerClientGetFD(client), REMOTE_AUTH_POLKIT, ident);
     VIR_INFO("Policy allowed action %s from pid %d, uid %d",
              action, callerPid, callerUid);
     ret->complete = 1;
-    client->auth = REMOTE_AUTH_NONE;
 
-    virMutexUnlock(&client->lock);
+    virNetServerClientSetIdentity(client, ident);
+    virMutexUnlock(&priv->lock);
+
     return 0;
 
+error:
+    virResetLastError();
+    virNetError(VIR_ERR_AUTH_FAILED, "%s",
+                _("authentication failed"));
+    virNetMessageSaveError(rerr);
+    virMutexUnlock(&priv->lock);
+    return -1;
+
 authfail:
-    PROBE(CLIENT_AUTH_FAIL, "fd=%d, auth=%d", client->fd, REMOTE_AUTH_POLKIT);
+    PROBE(CLIENT_AUTH_FAIL, "fd=%d, auth=%d",
+          virNetServerClientGetFD(client), REMOTE_AUTH_POLKIT);
     goto error;
 
 authdeny:
     PROBE(CLIENT_AUTH_DENY, "fd=%d, auth=%d, username=%s",
-          client->fd, REMOTE_AUTH_POLKIT, (char *)ident);
+          virNetServerClientGetFD(client), REMOTE_AUTH_POLKIT, (char *)ident);
     goto error;
-
-error:
-    remoteDispatchAuthError(rerr);
-    virMutexUnlock(&client->lock);
-    return -1;
 }
 #elif HAVE_POLKIT0
 static int
-remoteDispatchAuthPolkit(struct qemud_server *server,
-                         struct qemud_client *client,
-                         virConnectPtr conn ATTRIBUTE_UNUSED,
-                         remote_message_header *hdr ATTRIBUTE_UNUSED,
-                         remote_error *rerr,
-                         void *args ATTRIBUTE_UNUSED,
+remoteDispatchAuthPolkit(virNetServerPtr server ATTRIBUTE_UNUSED,
+                         virNetServerClientPtr client,
+                         virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+                         virNetMessageErrorPtr rerr,
                          remote_auth_polkit_ret *ret)
 {
     pid_t callerPid;
@@ -2264,7 +2086,9 @@ remoteDispatchAuthPolkit(struct qemud_server *server,
     DBusError err;
     const char *action;
     char ident[100];
-    int rv;
+    int rv = -1;
+    struct daemonClientPrivate *priv =
+        virNetServerClientGetPrivateData(client);
 
     memset(ident, 0, sizeof ident);
 
@@ -2276,13 +2100,13 @@ remoteDispatchAuthPolkit(struct qemud_server *server,
         "org.libvirt.unix.monitor" :
         "org.libvirt.unix.manage";
 
-    VIR_DEBUG("Start PolicyKit auth %d", client->fd);
+    VIR_DEBUG("Start PolicyKit auth %d", virNetServerClientGetFD(client));
     if (client->auth != REMOTE_AUTH_POLKIT) {
         VIR_ERROR(_("client tried invalid PolicyKit init request"));
         goto authfail;
     }
 
-    if (qemudGetSocketIdentity(client->fd, &callerUid, &callerPid) < 0) {
+    if (qemudGetSocketIdentity(virNetServerClientGetFD(client), &callerUid, &callerPid) < 0) {
         VIR_ERROR(_("cannot get peer socket identity"));
         goto authfail;
     }
@@ -2352,7 +2176,7 @@ remoteDispatchAuthPolkit(struct qemud_server *server,
         goto authdeny;
     }
     PROBE(CLIENT_AUTH_ALLOW, "fd=%d, auth=%d, username=%s",
-          client->fd, REMOTE_AUTH_POLKIT, ident);
+          virNetServerClientGetFD(client), REMOTE_AUTH_POLKIT, ident);
     VIR_INFO("Policy allowed action %s from pid %d, uid %d, result %s",
              action, callerPid, callerUid,
              polkit_result_to_string_representation(pkresult));
@@ -2362,34 +2186,38 @@ remoteDispatchAuthPolkit(struct qemud_server *server,
     virMutexUnlock(&client->lock);
     return 0;
 
+error:
+    virResetLastError();
+    virNetError(VIR_ERR_AUTH_FAILED, "%s",
+                _("authentication failed"));
+    virNetMessageSaveError(rerr);
+    virMutexUnlock(&client->lock);
+    return -1;
+
 authfail:
-    PROBE(CLIENT_AUTH_FAIL, "fd=%d, auth=%d", client->fd, REMOTE_AUTH_POLKIT);
+    PROBE(CLIENT_AUTH_FAIL, "fd=%d, auth=%d",
+          virNetServerClientGetFD(client), REMOTE_AUTH_POLKIT);
     goto error;
 
 authdeny:
     PROBE(CLIENT_AUTH_DENY, "fd=%d, auth=%d, username=%s",
-          client->fd, REMOTE_AUTH_POLKIT, ident);
+          virNetServerClientGetFD(client), REMOTE_AUTH_POLKIT, ident);
     goto error;
-
-error:
-    remoteDispatchAuthError(rerr);
-    virMutexUnlock(&client->lock);
-    return -1;
 }
 
 #else /* !HAVE_POLKIT0 & !HAVE_POLKIT1*/
 
 static int
-remoteDispatchAuthPolkit(struct qemud_server *server ATTRIBUTE_UNUSED,
-                         struct qemud_client *client ATTRIBUTE_UNUSED,
-                         virConnectPtr conn ATTRIBUTE_UNUSED,
-                         remote_message_header *hdr ATTRIBUTE_UNUSED,
-                         remote_error *rerr,
-                         void *args ATTRIBUTE_UNUSED,
+remoteDispatchAuthPolkit(virNetServerPtr server ATTRIBUTE_UNUSED,
+                         virNetServerClientPtr client,
+                         virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+                         virNetMessageErrorPtr rerr,
                          remote_auth_polkit_ret *ret ATTRIBUTE_UNUSED)
 {
     VIR_ERROR(_("client tried unsupported PolicyKit init request"));
-    remoteDispatchAuthError(rerr);
+    virNetError(VIR_ERR_AUTH_FAILED, "%s",
+                _("authentication failed"));
+    virNetMessageSaveError(rerr);
     return -1;
 }
 #endif /* HAVE_POLKIT1 */
@@ -2400,24 +2228,25 @@ remoteDispatchAuthPolkit(struct qemud_server *server ATTRIBUTE_UNUSED,
  **************************************************************/
 
 static int
-remoteDispatchNodeDeviceGetParent(struct qemud_server *server ATTRIBUTE_UNUSED,
-                                  struct qemud_client *client ATTRIBUTE_UNUSED,
-                                  virConnectPtr conn,
-                                  remote_message_header *hdr ATTRIBUTE_UNUSED,
-                                  remote_error *rerr,
+remoteDispatchNodeDeviceGetParent(virNetServerPtr server ATTRIBUTE_UNUSED,
+                                  virNetServerClientPtr client ATTRIBUTE_UNUSED,
+                                  virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+                                  virNetMessageErrorPtr rerr,
                                   remote_node_device_get_parent_args *args,
                                   remote_node_device_get_parent_ret *ret)
 {
     virNodeDevicePtr dev = NULL;
     const char *parent = NULL;
     int rv = -1;
+    struct daemonClientPrivate *priv =
+        virNetServerClientGetPrivateData(client);
 
-    if (!conn) {
+    if (!priv->conn) {
         virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
         goto cleanup;
     }
 
-    if (!(dev = virNodeDeviceLookupByName(conn, args->name)))
+    if (!(dev = virNodeDeviceLookupByName(priv->conn, args->name)))
         goto cleanup;
 
     parent = virNodeDeviceGetParent(dev);
@@ -2443,7 +2272,7 @@ remoteDispatchNodeDeviceGetParent(struct qemud_server *server ATTRIBUTE_UNUSED,
 
 cleanup:
     if (rv < 0)
-        remoteDispatchError(rerr);
+        virNetMessageSaveError(rerr);
     if (dev)
         virNodeDeviceFree(dev);
     return rv;
@@ -2454,148 +2283,124 @@ cleanup:
  * Register / deregister events
  ***************************/
 static int
-remoteDispatchDomainEventsRegister(struct qemud_server *server ATTRIBUTE_UNUSED,
-                                   struct qemud_client *client ATTRIBUTE_UNUSED,
-                                   virConnectPtr conn,
-                                   remote_message_header *hdr ATTRIBUTE_UNUSED,
-                                   remote_error *rerr ATTRIBUTE_UNUSED,
-                                   void *args ATTRIBUTE_UNUSED,
+remoteDispatchDomainEventsRegister(virNetServerPtr server ATTRIBUTE_UNUSED,
+                                   virNetServerClientPtr client ATTRIBUTE_UNUSED,
+                                   virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+                                   virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
                                    remote_domain_events_register_ret *ret ATTRIBUTE_UNUSED)
 {
     int callbackID;
     int rv = -1;
+    struct daemonClientPrivate *priv =
+        virNetServerClientGetPrivateData(client);
 
-    if (!conn) {
+    if (!priv->conn) {
         virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
         goto cleanup;
     }
 
-    if (client->domainEventCallbackID[VIR_DOMAIN_EVENT_ID_LIFECYCLE] != -1) {
+    virMutexLock(&priv->lock);
+
+    if (priv->domainEventCallbackID[VIR_DOMAIN_EVENT_ID_LIFECYCLE] != -1) {
         virNetError(VIR_ERR_INTERNAL_ERROR, _("domain event %d already registered"), VIR_DOMAIN_EVENT_ID_LIFECYCLE);
         goto cleanup;
     }
 
-    if ((callbackID = virConnectDomainEventRegisterAny(conn,
+    if ((callbackID = virConnectDomainEventRegisterAny(priv->conn,
                                                        NULL,
                                                        VIR_DOMAIN_EVENT_ID_LIFECYCLE,
                                                        VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventLifecycle),
                                                        client, NULL)) < 0)
         goto cleanup;
 
-    client->domainEventCallbackID[VIR_DOMAIN_EVENT_ID_LIFECYCLE] = callbackID;
+    priv->domainEventCallbackID[VIR_DOMAIN_EVENT_ID_LIFECYCLE] = callbackID;
 
     rv = 0;
 
 cleanup:
     if (rv < 0)
-        remoteDispatchError(rerr);
+        virNetMessageSaveError(rerr);
+    virMutexUnlock(&priv->lock);
     return rv;
 }
 
 static int
-remoteDispatchDomainEventsDeregister(struct qemud_server *server ATTRIBUTE_UNUSED,
-                                     struct qemud_client *client ATTRIBUTE_UNUSED,
-                                     virConnectPtr conn,
-                                     remote_message_header *hdr ATTRIBUTE_UNUSED,
-                                     remote_error *rerr ATTRIBUTE_UNUSED,
-                                     void *args ATTRIBUTE_UNUSED,
+remoteDispatchDomainEventsDeregister(virNetServerPtr server ATTRIBUTE_UNUSED,
+                                     virNetServerClientPtr client ATTRIBUTE_UNUSED,
+                                     virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+                                     virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
                                      remote_domain_events_deregister_ret *ret ATTRIBUTE_UNUSED)
 {
     int rv = -1;
+    struct daemonClientPrivate *priv =
+        virNetServerClientGetPrivateData(client);
 
-    if (!conn) {
+    if (!priv->conn) {
         virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
         goto cleanup;
     }
 
-    if (client->domainEventCallbackID[VIR_DOMAIN_EVENT_ID_LIFECYCLE] < 0) {
+    virMutexLock(&priv->lock);
+
+    if (priv->domainEventCallbackID[VIR_DOMAIN_EVENT_ID_LIFECYCLE] < 0) {
         virNetError(VIR_ERR_INTERNAL_ERROR, _("domain event %d not registered"), VIR_DOMAIN_EVENT_ID_LIFECYCLE);
         goto cleanup;
     }
 
-    if (virConnectDomainEventDeregisterAny(conn,
-                                           client->domainEventCallbackID[VIR_DOMAIN_EVENT_ID_LIFECYCLE]) < 0)
+    if (virConnectDomainEventDeregisterAny(priv->conn,
+                                           priv->domainEventCallbackID[VIR_DOMAIN_EVENT_ID_LIFECYCLE]) < 0)
         goto cleanup;
 
-    client->domainEventCallbackID[VIR_DOMAIN_EVENT_ID_LIFECYCLE] = -1;
+    priv->domainEventCallbackID[VIR_DOMAIN_EVENT_ID_LIFECYCLE] = -1;
+
     rv = 0;
 
 cleanup:
     if (rv < 0)
-        remoteDispatchError(rerr);
+        virNetMessageSaveError(rerr);
+    virMutexUnlock(&priv->lock);
     return rv;
 }
 
 static void
-remoteDispatchDomainEventSend(struct qemud_client *client,
+remoteDispatchDomainEventSend(virNetServerClientPtr client,
+                              virNetServerProgramPtr program,
                               int procnr,
                               xdrproc_t proc,
                               void *data)
 {
-    struct qemud_client_message *msg = NULL;
-    XDR xdr;
-    unsigned int len;
+    virNetMessagePtr msg;
 
-    if (VIR_ALLOC(msg) < 0)
+    if (!(msg = virNetMessageNew()))
         return;
 
-    msg->hdr.prog = REMOTE_PROGRAM;
-    msg->hdr.vers = REMOTE_PROTOCOL_VERSION;
-    msg->hdr.proc = procnr;
-    msg->hdr.type = REMOTE_MESSAGE;
-    msg->hdr.serial = 1;
-    msg->hdr.status = REMOTE_OK;
+    msg->header.prog = virNetServerProgramGetID(program);
+    msg->header.vers = virNetServerProgramGetVersion(program);
+    msg->header.proc = procnr;
+    msg->header.type = VIR_NET_MESSAGE;
+    msg->header.serial = 1;
+    msg->header.status = VIR_NET_OK;
 
-    if (remoteEncodeClientMessageHeader(msg) < 0)
+    if (virNetMessageEncodeHeader(msg) < 0)
         goto cleanup;
 
-    /* Serialise the return header and event. */
-    xdrmem_create(&xdr,
-                  msg->buffer,
-                  msg->bufferLength,
-                  XDR_ENCODE);
-
-    /* Skip over the header we just wrote */
-    if (xdr_setpos(&xdr, msg->bufferOffset) == 0)
-        goto xdr_cleanup;
-
-    if (!(proc)(&xdr, data)) {
-        VIR_WARN("Failed to serialize domain event %d", procnr);
-        goto xdr_cleanup;
-    }
-
-    /* Update length word to include payload*/
-    len = msg->bufferOffset = xdr_getpos(&xdr);
-    if (xdr_setpos(&xdr, 0) == 0)
-        goto xdr_cleanup;
-
-    if (!xdr_u_int(&xdr, &len))
-        goto xdr_cleanup;
-
-    /* Send it. */
-    msg->async = 1;
-    msg->bufferLength = len;
-    msg->bufferOffset = 0;
+    if (virNetMessageEncodePayload(msg, proc, data) < 0)
+        goto cleanup;
 
-    VIR_DEBUG("Queue event %d %d", procnr, msg->bufferLength);
-    qemudClientMessageQueuePush(&client->tx, msg);
-    qemudUpdateClientEvent(client);
+    VIR_DEBUG("Queue event %d %Zu", procnr, msg->bufferLength);
+    virNetServerClientSendMessage(client, msg);
 
-    xdr_destroy(&xdr);
     return;
 
-xdr_cleanup:
-    xdr_destroy(&xdr);
 cleanup:
-    VIR_FREE(msg);
+    virNetMessageFree(msg);
 }
 
 static int
-remoteDispatchSecretGetValue(struct qemud_server *server ATTRIBUTE_UNUSED,
-                             struct qemud_client *client ATTRIBUTE_UNUSED,
-                             virConnectPtr conn,
-                             remote_message_header *hdr ATTRIBUTE_UNUSED,
-                             remote_error *rerr,
+remoteDispatchSecretGetValue(virNetServerPtr server ATTRIBUTE_UNUSED,
+                             virNetServerClientPtr client ATTRIBUTE_UNUSED,
+                             virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+                             virNetMessageErrorPtr rerr,
                              remote_secret_get_value_args *args,
                              remote_secret_get_value_ret *ret)
 {
@@ -2603,13 +2408,15 @@ remoteDispatchSecretGetValue(struct qemud_server *server ATTRIBUTE_UNUSED,
     size_t value_size;
     unsigned char *value;
     int rv = -1;
+    struct daemonClientPrivate *priv =
+        virNetServerClientGetPrivateData(client);
 
-    if (!conn) {
+    if (!priv->conn) {
         virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
         goto cleanup;
     }
 
-    if (!(secret = get_nonnull_secret(conn, args->secret)))
+    if (!(secret = get_nonnull_secret(priv->conn, args->secret)))
         goto cleanup;
 
     if (!(value = virSecretGetValue(secret, &value_size, args->flags)))
@@ -2622,30 +2429,31 @@ remoteDispatchSecretGetValue(struct qemud_server *server ATTRIBUTE_UNUSED,
 
 cleanup:
     if (rv < 0)
-        remoteDispatchError(rerr);
+        virNetMessageSaveError(rerr);
     if (secret)
         virSecretFree(secret);
     return rv;
 }
 
 static int
-remoteDispatchDomainGetState(struct qemud_server *server ATTRIBUTE_UNUSED,
-                             struct qemud_client *client ATTRIBUTE_UNUSED,
-                             virConnectPtr conn,
-                             remote_message_header *hdr ATTRIBUTE_UNUSED,
-                             remote_error *rerr,
+remoteDispatchDomainGetState(virNetServerPtr server ATTRIBUTE_UNUSED,
+                             virNetServerClientPtr client ATTRIBUTE_UNUSED,
+                             virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+                             virNetMessageErrorPtr rerr,
                              remote_domain_get_state_args *args,
                              remote_domain_get_state_ret *ret)
 {
     virDomainPtr dom = NULL;
     int rv = -1;
+    struct daemonClientPrivate *priv =
+        virNetServerClientGetPrivateData(client);
 
-    if (!conn) {
+    if (!priv->conn) {
         virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
         goto cleanup;
     }
 
-    if (!(dom = get_nonnull_domain(conn, args->dom)))
+    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
         goto cleanup;
 
     if (virDomainGetState(dom, &ret->state, &ret->reason, args->flags) < 0)
@@ -2655,116 +2463,125 @@ remoteDispatchDomainGetState(struct qemud_server *server ATTRIBUTE_UNUSED,
 
 cleanup:
     if (rv < 0)
-        remoteDispatchError(rerr);
+        virNetMessageSaveError(rerr);
     if (dom)
         virDomainFree(dom);
     return rv;
 }
 
 static int
-remoteDispatchDomainEventsRegisterAny(struct qemud_server *server ATTRIBUTE_UNUSED,
-                                      struct qemud_client *client ATTRIBUTE_UNUSED,
-                                      virConnectPtr conn,
-                                      remote_message_header *hdr ATTRIBUTE_UNUSED,
-                                      remote_error *rerr ATTRIBUTE_UNUSED,
-                                      remote_domain_events_register_any_args *args,
-                                      void *ret ATTRIBUTE_UNUSED)
+remoteDispatchDomainEventsRegisterAny(virNetServerPtr server ATTRIBUTE_UNUSED,
+                                      virNetServerClientPtr client ATTRIBUTE_UNUSED,
+                                      virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+                                      virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
+                                      remote_domain_events_register_any_args *args)
 {
     int callbackID;
     int rv = -1;
+    struct daemonClientPrivate *priv =
+        virNetServerClientGetPrivateData(client);
 
-    if (!conn) {
+    if (!priv->conn) {
         virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
         goto cleanup;
     }
 
+    virMutexLock(&priv->lock);
+
     if (args->eventID >= VIR_DOMAIN_EVENT_ID_LAST ||
         args->eventID < 0) {
         virNetError(VIR_ERR_INTERNAL_ERROR, _("unsupported event ID %d"), args->eventID);
         goto cleanup;
     }
 
-    if (client->domainEventCallbackID[args->eventID] != -1)  {
+    if (priv->domainEventCallbackID[args->eventID] != -1)  {
         virNetError(VIR_ERR_INTERNAL_ERROR, _("domain event %d already registered"), args->eventID);
         goto cleanup;
     }
 
-    if ((callbackID = virConnectDomainEventRegisterAny(conn,
+    if ((callbackID = virConnectDomainEventRegisterAny(priv->conn,
                                                        NULL,
                                                        args->eventID,
                                                        domainEventCallbacks[args->eventID],
                                                        client, NULL)) < 0)
         goto cleanup;
 
-    client->domainEventCallbackID[args->eventID] = callbackID;
+    priv->domainEventCallbackID[args->eventID] = callbackID;
 
     rv = 0;
 
 cleanup:
     if (rv < 0)
-        remoteDispatchError(rerr);
+        virNetMessageSaveError(rerr);
+    virMutexUnlock(&priv->lock);
     return rv;
 }
 
 
 static int
-remoteDispatchDomainEventsDeregisterAny(struct qemud_server *server ATTRIBUTE_UNUSED,
-                                        struct qemud_client *client ATTRIBUTE_UNUSED,
-                                        virConnectPtr conn,
-                                        remote_message_header *hdr ATTRIBUTE_UNUSED,
-                                        remote_error *rerr ATTRIBUTE_UNUSED,
-                                        remote_domain_events_deregister_any_args *args,
-                                        void *ret ATTRIBUTE_UNUSED)
+remoteDispatchDomainEventsDeregisterAny(virNetServerPtr server ATTRIBUTE_UNUSED,
+                                        virNetServerClientPtr client ATTRIBUTE_UNUSED,
+                                        virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+                                        virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
+                                        remote_domain_events_deregister_any_args *args)
 {
     int callbackID = -1;
     int rv = -1;
+    struct daemonClientPrivate *priv =
+        virNetServerClientGetPrivateData(client);
 
-    if (!conn) {
+    if (!priv->conn) {
         virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
         goto cleanup;
     }
 
+    virMutexLock(&priv->lock);
+
     if (args->eventID >= VIR_DOMAIN_EVENT_ID_LAST ||
         args->eventID < 0) {
         virNetError(VIR_ERR_INTERNAL_ERROR, _("unsupported event ID %d"), args->eventID);
         goto cleanup;
     }
 
-    if ((callbackID = client->domainEventCallbackID[args->eventID]) < 0) {
+    callbackID = priv->domainEventCallbackID[args->eventID];
+    if (callbackID < 0) {
         virNetError(VIR_ERR_INTERNAL_ERROR, _("domain event %d not registered"), args->eventID);
         goto cleanup;
     }
 
-    if (virConnectDomainEventDeregisterAny(conn, callbackID) < 0)
+    if (virConnectDomainEventDeregisterAny(priv->conn, callbackID) < 0)
         goto cleanup;
 
-    client->domainEventCallbackID[args->eventID] = -1;
+    priv->domainEventCallbackID[args->eventID] = -1;
+
     rv = 0;
 
 cleanup:
     if (rv < 0)
-        remoteDispatchError(rerr);
+        virNetMessageSaveError(rerr);
+    virMutexUnlock(&priv->lock);
     return rv;
 }
 
 static int
-qemuDispatchMonitorCommand(struct qemud_server *server ATTRIBUTE_UNUSED,
-                           struct qemud_client *client ATTRIBUTE_UNUSED,
-                           virConnectPtr conn,
-                           remote_message_header *hdr ATTRIBUTE_UNUSED,
-                           remote_error *rerr,
+qemuDispatchMonitorCommand(virNetServerPtr server ATTRIBUTE_UNUSED,
+                           virNetServerClientPtr client ATTRIBUTE_UNUSED,
+                           virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+                           virNetMessageErrorPtr rerr,
                            qemu_monitor_command_args *args,
                            qemu_monitor_command_ret *ret)
 {
     virDomainPtr dom = NULL;
     int rv = -1;
+    struct daemonClientPrivate *priv =
+        virNetServerClientGetPrivateData(client);
 
-    if (!conn) {
+    if (!priv->conn) {
         virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
         goto cleanup;
     }
 
-    if (!(dom = get_nonnull_domain(conn, args->dom)))
+    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
         goto cleanup;
 
     if (virDomainQemuMonitorCommand(dom, args->cmd, &ret->result,
@@ -2775,23 +2592,18 @@ qemuDispatchMonitorCommand(struct qemud_server *server ATTRIBUTE_UNUSED,
 
 cleanup:
     if (rv < 0)
-        remoteDispatchError(rerr);
+        virNetMessageSaveError(rerr);
     if (dom)
         virDomainFree(dom);
     return rv;
 }
 
 
-#include "remote_dispatch_bodies.h"
-#include "qemu_dispatch_bodies.h"
-
-
 static int
-remoteDispatchDomainMigrateBegin3(struct qemud_server *server ATTRIBUTE_UNUSED,
-                                  struct qemud_client *client ATTRIBUTE_UNUSED,
-                                  virConnectPtr conn,
-                                  remote_message_header *hdr ATTRIBUTE_UNUSED,
-                                  remote_error *rerr,
+remoteDispatchDomainMigrateBegin3(virNetServerPtr server ATTRIBUTE_UNUSED,
+                                  virNetServerClientPtr client ATTRIBUTE_UNUSED,
+                                  virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+                                  virNetMessageErrorPtr rerr,
                                   remote_domain_migrate_begin3_args *args,
                                   remote_domain_migrate_begin3_ret *ret)
 {
@@ -2802,13 +2614,15 @@ remoteDispatchDomainMigrateBegin3(struct qemud_server *server ATTRIBUTE_UNUSED,
     char *cookieout = NULL;
     int cookieoutlen = 0;
     int rv = -1;
+    struct daemonClientPrivate *priv =
+        virNetServerClientGetPrivateData(client);
 
-    if (!conn) {
+    if (!priv->conn) {
         virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
         goto cleanup;
     }
 
-    if (!(dom = get_nonnull_domain(conn, args->dom)))
+    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
         goto cleanup;
 
     xmlin = args->xmlin == NULL ? NULL : *args->xmlin;
@@ -2830,7 +2644,7 @@ remoteDispatchDomainMigrateBegin3(struct qemud_server *server ATTRIBUTE_UNUSED,
 
 cleanup:
     if (rv < 0)
-        remoteDispatchError(rerr);
+        virNetMessageSaveError(rerr);
     if (dom)
         virDomainFree(dom);
     return rv;
@@ -2838,11 +2652,10 @@ cleanup:
 
 
 static int
-remoteDispatchDomainMigratePrepare3(struct qemud_server *server ATTRIBUTE_UNUSED,
-                                    struct qemud_client *client ATTRIBUTE_UNUSED,
-                                    virConnectPtr conn,
-                                    remote_message_header *hdr ATTRIBUTE_UNUSED,
-                                    remote_error *rerr,
+remoteDispatchDomainMigratePrepare3(virNetServerPtr server ATTRIBUTE_UNUSED,
+                                    virNetServerClientPtr client ATTRIBUTE_UNUSED,
+                                    virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+                                    virNetMessageErrorPtr rerr,
                                     remote_domain_migrate_prepare3_args *args,
                                     remote_domain_migrate_prepare3_ret *ret)
 {
@@ -2852,8 +2665,10 @@ remoteDispatchDomainMigratePrepare3(struct qemud_server *server ATTRIBUTE_UNUSED
     char **uri_out;
     char *dname;
     int rv = -1;
+    struct daemonClientPrivate *priv =
+        virNetServerClientGetPrivateData(client);
 
-    if (!conn) {
+    if (!priv->conn) {
         virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
         goto cleanup;
     }
@@ -2867,7 +2682,7 @@ remoteDispatchDomainMigratePrepare3(struct qemud_server *server ATTRIBUTE_UNUSED
         goto cleanup;
     }
 
-    if (virDomainMigratePrepare3(conn,
+    if (virDomainMigratePrepare3(priv->conn,
                                  args->cookie_in.cookie_in_val,
                                  args->cookie_in.cookie_in_len,
                                  &cookieout, &cookieoutlen,
@@ -2887,18 +2702,18 @@ remoteDispatchDomainMigratePrepare3(struct qemud_server *server ATTRIBUTE_UNUSED
 
 cleanup:
     if (rv < 0) {
-        remoteDispatchError(rerr);
+        virNetMessageSaveError(rerr);
         VIR_FREE(uri_out);
     }
     return rv;
 }
 
+
 static int
-remoteDispatchDomainMigratePerform3(struct qemud_server *server ATTRIBUTE_UNUSED,
-                                    struct qemud_client *client ATTRIBUTE_UNUSED,
-                                    virConnectPtr conn,
-                                    remote_message_header *hdr ATTRIBUTE_UNUSED,
-                                    remote_error *rerr,
+remoteDispatchDomainMigratePerform3(virNetServerPtr server ATTRIBUTE_UNUSED,
+                                    virNetServerClientPtr client ATTRIBUTE_UNUSED,
+                                    virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+                                    virNetMessageErrorPtr rerr,
                                     remote_domain_migrate_perform3_args *args,
                                     remote_domain_migrate_perform3_ret *ret)
 {
@@ -2910,13 +2725,15 @@ remoteDispatchDomainMigratePerform3(struct qemud_server *server ATTRIBUTE_UNUSED
     char *cookieout = NULL;
     int cookieoutlen = 0;
     int rv = -1;
+    struct daemonClientPrivate *priv =
+        virNetServerClientGetPrivateData(client);
 
-    if (!conn) {
+    if (!priv->conn) {
         virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
         goto cleanup;
     }
 
-    if (!(dom = get_nonnull_domain(conn, args->dom)))
+    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
         goto cleanup;
 
     xmlin = args->xmlin == NULL ? NULL : *args->xmlin;
@@ -2941,7 +2758,7 @@ remoteDispatchDomainMigratePerform3(struct qemud_server *server ATTRIBUTE_UNUSED
 
 cleanup:
     if (rv < 0)
-        remoteDispatchError(rerr);
+        virNetMessageSaveError(rerr);
     if (dom)
         virDomainFree(dom);
     return rv;
@@ -2949,11 +2766,10 @@ cleanup:
 
 
 static int
-remoteDispatchDomainMigrateFinish3(struct qemud_server *server ATTRIBUTE_UNUSED,
-                                   struct qemud_client *client ATTRIBUTE_UNUSED,
-                                   virConnectPtr conn,
-                                   remote_message_header *hdr ATTRIBUTE_UNUSED,
-                                   remote_error *rerr,
+remoteDispatchDomainMigrateFinish3(virNetServerPtr server ATTRIBUTE_UNUSED,
+                                   virNetServerClientPtr client ATTRIBUTE_UNUSED,
+                                   virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+                                   virNetMessageErrorPtr rerr,
                                    remote_domain_migrate_finish3_args *args,
                                    remote_domain_migrate_finish3_ret *ret)
 {
@@ -2963,8 +2779,10 @@ remoteDispatchDomainMigrateFinish3(struct qemud_server *server ATTRIBUTE_UNUSED,
     char *uri;
     char *dconnuri;
     int rv = -1;
+    struct daemonClientPrivate *priv =
+        virNetServerClientGetPrivateData(client);
 
-    if (!conn) {
+    if (!priv->conn) {
         virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
         goto cleanup;
     }
@@ -2972,7 +2790,7 @@ remoteDispatchDomainMigrateFinish3(struct qemud_server *server ATTRIBUTE_UNUSED,
     uri = args->uri == NULL ? NULL : *args->uri;
     dconnuri = args->dconnuri == NULL ? NULL : *args->dconnuri;
 
-    if (!(dom = virDomainMigrateFinish3(conn, args->dname,
+    if (!(dom = virDomainMigrateFinish3(priv->conn, args->dname,
                                         args->cookie_in.cookie_in_val,
                                         args->cookie_in.cookie_in_len,
                                         &cookieout, &cookieoutlen,
@@ -2992,7 +2810,7 @@ remoteDispatchDomainMigrateFinish3(struct qemud_server *server ATTRIBUTE_UNUSED,
 
 cleanup:
     if (rv < 0) {
-        remoteDispatchError(rerr);
+        virNetMessageSaveError(rerr);
         VIR_FREE(cookieout);
     }
     if (dom)
@@ -3002,23 +2820,23 @@ cleanup:
 
 
 static int
-remoteDispatchDomainMigrateConfirm3(struct qemud_server *server ATTRIBUTE_UNUSED,
-                                    struct qemud_client *client ATTRIBUTE_UNUSED,
-                                    virConnectPtr conn,
-                                    remote_message_header *hdr ATTRIBUTE_UNUSED,
-                                    remote_error *rerr,
-                                    remote_domain_migrate_confirm3_args *args,
-                                    void *ret ATTRIBUTE_UNUSED)
+remoteDispatchDomainMigrateConfirm3(virNetServerPtr server ATTRIBUTE_UNUSED,
+                                    virNetServerClientPtr client ATTRIBUTE_UNUSED,
+                                    virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+                                    virNetMessageErrorPtr rerr,
+                                    remote_domain_migrate_confirm3_args *args)
 {
     virDomainPtr dom = NULL;
     int rv = -1;
+    struct daemonClientPrivate *priv =
+        virNetServerClientGetPrivateData(client);
 
-    if (!conn) {
+    if (!priv->conn) {
         virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
         goto cleanup;
     }
 
-    if (!(dom = get_nonnull_domain(conn, args->dom)))
+    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
         goto cleanup;
 
     if (virDomainMigrateConfirm3(dom,
@@ -3031,7 +2849,7 @@ remoteDispatchDomainMigrateConfirm3(struct qemud_server *server ATTRIBUTE_UNUSED
 
 cleanup:
     if (rv < 0)
-        remoteDispatchError(rerr);
+        virNetMessageSaveError(rerr);
     if (dom)
         virDomainFree(dom);
     return rv;
diff --git a/daemon/remote.h b/daemon/remote.h
index 1eb8386..c9bf5d7 100644
--- a/daemon/remote.h
+++ b/daemon/remote.h
@@ -24,62 +24,20 @@
 #ifndef __LIBVIRTD_REMOTE_H__
 # define __LIBVIRTD_REMOTE_H__
 
+# include "remote_protocol.h"
+# include "rpc/virnetserverprogram.h"
+# include "rpc/virnetserverclient.h"
 
-# include "libvirtd.h"
 
-typedef union {
-# include "remote_dispatch_args.h"
-} dispatch_args;
-verify(sizeof(dispatch_args) > 0);
-
-typedef union {
-# include "remote_dispatch_ret.h"
-} dispatch_ret;
-verify(sizeof(dispatch_ret) > 0);
-
-typedef union {
-# include "qemu_dispatch_args.h"
-} qemu_dispatch_args;
-verify(sizeof(qemu_dispatch_args) > 0);
-
-typedef union {
-# include "qemu_dispatch_ret.h"
-} qemu_dispatch_ret;
-verify(sizeof(qemu_dispatch_ret) > 0);
-
-
-
-/**
- * When the RPC handler is called:
- *
- *  - Server object is unlocked
- *  - Client object is unlocked
- *
- * Both must be locked before use. Server lock must
- * be held before attempting to lock client.
- *
- * Without any locking, it is safe to use:
- *
- *   'conn', 'rerr', 'args and 'ret'
- */
-typedef int (*dispatch_fn) (struct qemud_server *server,
-                            struct qemud_client *client,
-                            virConnectPtr conn,
-                            remote_message_header *hdr,
-                            remote_error *err,
-                            dispatch_args *args,
-                            dispatch_ret *ret);
-
-typedef struct {
-    dispatch_fn fn;
-    xdrproc_t args_filter;
-    xdrproc_t ret_filter;
-} dispatch_data;
-
-
-const dispatch_data const *remoteGetDispatchData(int proc);
-const dispatch_data const *qemuGetDispatchData(int proc);
+extern virNetServerProgramProc remoteProcs[];
+extern size_t remoteNProcs;
+extern virNetServerProgramErrorHander remoteErr;
 
+extern virNetServerProgramProc qemuProcs[];
+extern size_t qemuNProcs;
+extern virNetServerProgramErrorHander qemuErr;
 
+int remoteClientInitHook(virNetServerPtr srv,
+                         virNetServerClientPtr client);
 
 #endif /* __LIBVIRTD_REMOTE_H__ */
diff --git a/daemon/stream.c b/daemon/stream.c
index 48085da..89ad42f 100644
--- a/daemon/stream.c
+++ b/daemon/stream.c
@@ -24,32 +24,57 @@
 #include <config.h>
 
 #include "stream.h"
+#include "remote.h"
 #include "memory.h"
-#include "dispatch.h"
 #include "logging.h"
+#include "virnetserverclient.h"
 #include "virterror_internal.h"
 
 #define VIR_FROM_THIS VIR_FROM_STREAMS
 
+#define virNetError(code, ...)                                    \
+    virReportErrorHelper(VIR_FROM_THIS, code, __FILE__,           \
+                         __FUNCTION__, __LINE__, __VA_ARGS__)
+
+struct daemonClientStream {
+    daemonClientPrivatePtr priv;
+
+    virNetServerProgramPtr prog;
+
+    virStreamPtr st;
+    int procedure;
+    int serial;
+
+    unsigned int recvEOF : 1;
+    unsigned int closed : 1;
+
+    int filterID;
+
+    virNetMessagePtr rx;
+    int tx;
+
+    daemonClientStreamPtr next;
+};
+
 static int
-remoteStreamHandleWrite(struct qemud_client *client,
-                        struct qemud_client_stream *stream);
+daemonStreamHandleWrite(virNetServerClientPtr client,
+                        daemonClientStream *stream);
 static int
-remoteStreamHandleRead(struct qemud_client *client,
-                       struct qemud_client_stream *stream);
+daemonStreamHandleRead(virNetServerClientPtr client,
+                       daemonClientStream *stream);
 static int
-remoteStreamHandleFinish(struct qemud_client *client,
-                         struct qemud_client_stream *stream,
-                         struct qemud_client_message *msg);
+daemonStreamHandleFinish(virNetServerClientPtr client,
+                         daemonClientStream *stream,
+                         virNetMessagePtr msg);
 static int
-remoteStreamHandleAbort(struct qemud_client *client,
-                        struct qemud_client_stream *stream,
-                        struct qemud_client_message *msg);
+daemonStreamHandleAbort(virNetServerClientPtr client,
+                        daemonClientStream *stream,
+                        virNetMessagePtr msg);
 
 
 
 static void
-remoteStreamUpdateEvents(struct qemud_client_stream *stream)
+daemonStreamUpdateEvents(daemonClientStream *stream)
 {
     int newEvents = 0;
     if (stream->rx)
@@ -65,19 +90,15 @@ remoteStreamUpdateEvents(struct qemud_client_stream *stream)
  * Callback that gets invoked when a stream becomes writable/readable
  */
 static void
-remoteStreamEvent(virStreamPtr st, int events, void *opaque)
+daemonStreamEvent(virStreamPtr st, int events, void *opaque)
 {
-    struct qemud_client *client = opaque;
-    struct qemud_client_stream *stream;
+    virNetServerClientPtr client = opaque;
+    daemonClientStream *stream;
+    daemonClientPrivatePtr priv = virNetServerClientGetPrivateData(client);
 
-    /* XXX sub-optimal - we really should be taking the server lock
-     * first, but we have no handle to the server object
-     * We're lucky to get away with it for now, due to this callback
-     * executing in the main thread, but this should really be fixed
-     */
-    virMutexLock(&client->lock);
+    virMutexLock(&priv->lock);
 
-    stream = remoteFindClientStream(client, st);
+    stream = daemonFindClientStream(client, st);
 
     if (!stream) {
         VIR_WARN("event for client=%p stream st=%p, but missing stream state", client, st);
@@ -88,9 +109,9 @@ remoteStreamEvent(virStreamPtr st, int events, void *opaque)
     VIR_DEBUG("st=%p events=%d", st, events);
 
     if (events & VIR_STREAM_EVENT_WRITABLE) {
-        if (remoteStreamHandleWrite(client, stream) < 0) {
-            remoteRemoveClientStream(client, stream);
-            qemudDispatchClientFailure(client);
+        if (daemonStreamHandleWrite(client, stream) < 0) {
+            daemonRemoveClientStream(client, stream);
+            virNetServerClientClose(client);
             goto cleanup;
         }
     }
@@ -98,9 +119,9 @@ remoteStreamEvent(virStreamPtr st, int events, void *opaque)
     if (!stream->recvEOF &&
         (events & (VIR_STREAM_EVENT_READABLE | VIR_STREAM_EVENT_HANGUP))) {
         events = events & ~(VIR_STREAM_EVENT_READABLE | VIR_STREAM_EVENT_HANGUP);
-        if (remoteStreamHandleRead(client, stream) < 0) {
-            remoteRemoveClientStream(client, stream);
-            qemudDispatchClientFailure(client);
+        if (daemonStreamHandleRead(client, stream) < 0) {
+            daemonRemoveClientStream(client, stream);
+            virNetServerClientClose(client);
             goto cleanup;
         }
     }
@@ -108,30 +129,45 @@ remoteStreamEvent(virStreamPtr st, int events, void *opaque)
     if (!stream->closed &&
         (events & (VIR_STREAM_EVENT_ERROR | VIR_STREAM_EVENT_HANGUP))) {
         int ret;
-        remote_error rerr;
-        memset(&rerr, 0, sizeof rerr);
+        virNetMessagePtr msg;
+        virNetMessageError rerr;
+
+        memset(&rerr, 0, sizeof(rerr));
         stream->closed = 1;
         virStreamEventRemoveCallback(stream->st);
         virStreamAbort(stream->st);
         if (events & VIR_STREAM_EVENT_HANGUP)
-            remoteDispatchFormatError(&rerr, "%s", _("stream had unexpected termination"));
+            virNetError(VIR_ERR_RPC,
+                        "%s", _("stream had unexpected termination"));
         else
-            remoteDispatchFormatError(&rerr, "%s", _("stream had I/O failure"));
-        ret = remoteSerializeStreamError(client, &rerr, stream->procedure, stream->serial);
-        remoteRemoveClientStream(client, stream);
+            virNetError(VIR_ERR_RPC,
+                        "%s", _("stream had I/O failure"));
+
+        msg = virNetMessageNew();
+        if (!msg) {
+            ret = -1;
+        } else {
+            ret = virNetServerProgramSendStreamError(remoteProgram,
+                                                     client,
+                                                     msg,
+                                                     &rerr,
+                                                     stream->procedure,
+                                                     stream->serial);
+        }
+        daemonRemoveClientStream(client, stream);
         if (ret < 0)
-            qemudDispatchClientFailure(client);
+            virNetServerClientClose(client);
         goto cleanup;
     }
 
     if (stream->closed) {
-        remoteRemoveClientStream(client, stream);
+        daemonRemoveClientStream(client, stream);
     } else {
-        remoteStreamUpdateEvents(stream);
+        daemonStreamUpdateEvents(stream);
     }
 
 cleanup:
-    virMutexUnlock(&client->lock);
+    virMutexUnlock(&priv->lock);
 }
 
 
@@ -144,90 +180,70 @@ cleanup:
  * -1 on fatal client error
  */
 static int
-remoteStreamFilter(struct qemud_client *client,
-                   struct qemud_client_message *msg, void *opaque)
+daemonStreamFilter(virNetServerClientPtr client ATTRIBUTE_UNUSED,
+                   virNetMessagePtr msg,
+                   void *opaque)
 {
-    struct qemud_client_stream *stream = opaque;
-
-    if (msg->hdr.serial == stream->serial &&
-        msg->hdr.proc == stream->procedure &&
-        msg->hdr.type == REMOTE_STREAM) {
-        VIR_DEBUG("Incoming rx=%p serial=%d proc=%d status=%d",
-              stream->rx, msg->hdr.proc, msg->hdr.serial, msg->hdr.status);
-
-        /* If there are queued packets, we need to queue all further
-         * messages, since they must be processed strictly in order.
-         * If there are no queued packets, then OK/ERROR messages
-         * should be processed immediately. Data packets are still
-         * queued to only be processed when the stream is marked as
-         * writable.
-         */
-        if (stream->rx) {
-            qemudClientMessageQueuePush(&stream->rx, msg);
-            remoteStreamUpdateEvents(stream);
-        } else {
-            int ret = 0;
-            switch (msg->hdr.status) {
-            case REMOTE_OK:
-                ret = remoteStreamHandleFinish(client, stream, msg);
-                if (ret == 0)
-                    qemudClientMessageRelease(client, msg);
-                break;
-
-            case REMOTE_CONTINUE:
-                qemudClientMessageQueuePush(&stream->rx, msg);
-                remoteStreamUpdateEvents(stream);
-                break;
-
-            case REMOTE_ERROR:
-            default:
-                ret = remoteStreamHandleAbort(client, stream, msg);
-                if (ret == 0)
-                    qemudClientMessageRelease(client, msg);
-                break;
-            }
-
-            if (ret < 0)
-                return -1;
-        }
-        return 1;
-    }
-    return 0;
+    daemonClientStream *stream = opaque;
+    int ret = 0;
+
+    virMutexLock(&stream->priv->lock);
+
+    if (msg->header.type != VIR_NET_STREAM)
+        goto cleanup;
+
+    if (!virNetServerProgramMatches(stream->prog, msg))
+        goto cleanup;
+
+    if (msg->header.proc != stream->procedure ||
+        msg->header.serial != stream->serial)
+        goto cleanup;
+
+    VIR_DEBUG("Incoming rx=%p serial=%d proc=%d status=%d",
+              stream->rx, msg->header.proc, msg->header.serial, msg->header.status);
+
+    virNetMessageQueuePush(&stream->rx, msg);
+    daemonStreamUpdateEvents(stream);
+    ret = 1;
+
+cleanup:
+    virMutexUnlock(&stream->priv->lock);
+    return ret;
 }
 
 
 /*
  * @conn: a connection object to associate the stream with
- * @hdr: the method call to associate with the stram
+ * @header: the method call to associate with the stram
  *
  * Creates a new stream for this conn
  *
  * Returns a new stream object, or NULL upon OOM
  */
-struct qemud_client_stream *
-remoteCreateClientStream(virConnectPtr conn,
-                         remote_message_header *hdr)
+daemonClientStream *
+daemonCreateClientStream(virNetServerClientPtr client,
+                         virStreamPtr st,
+                         virNetServerProgramPtr prog,
+                         virNetMessageHeaderPtr header)
 {
-    struct qemud_client_stream *stream;
+    daemonClientStream *stream;
+    daemonClientPrivatePtr priv = virNetServerClientGetPrivateData(client);
 
-    VIR_DEBUG("proc=%d serial=%d", hdr->proc, hdr->serial);
+    VIR_DEBUG("proc=%d serial=%d", header->proc, header->serial);
 
     if (VIR_ALLOC(stream) < 0) {
         virReportOOMError();
         return NULL;
     }
 
-    stream->procedure = hdr->proc;
-    stream->serial = hdr->serial;
-
-    stream->st = virStreamNew(conn, VIR_STREAM_NONBLOCK);
-    if (!stream->st) {
-        VIR_FREE(stream);
-        return NULL;
-    }
+    stream->priv = priv;
+    stream->prog = prog;
+    stream->procedure = header->proc;
+    stream->serial = header->serial;
+    stream->filterID = -1;
+    stream->st = st;
 
-    stream->filter.query = remoteStreamFilter;
-    stream->filter.opaque = stream;
+    virNetServerProgramRef(prog);
 
     return stream;
 }
@@ -238,25 +254,36 @@ remoteCreateClientStream(virConnectPtr conn,
  * Frees the memory associated with this inactive client
  * stream
  */
-void remoteFreeClientStream(struct qemud_client *client,
-                            struct qemud_client_stream *stream)
+int daemonFreeClientStream(virNetServerClientPtr client,
+                           daemonClientStream *stream)
 {
-    struct qemud_client_message *msg;
+    virNetMessagePtr msg;
+    int ret = 0;
 
     if (!stream)
-        return;
+        return 0;
 
     VIR_DEBUG("proc=%d serial=%d", stream->procedure, stream->serial);
 
+    virNetServerProgramFree(stream->prog);
+
     msg = stream->rx;
     while (msg) {
-        struct qemud_client_message *tmp = msg->next;
-        qemudClientMessageRelease(client, msg);
+        virNetMessagePtr tmp = msg->next;
+        /* Send a dummy reply to free up 'msg' & unblock client rx */
+        memset(msg, 0, sizeof(*msg));
+        if (virNetServerClientSendMessage(client, msg) < 0) {
+            virNetServerClientMarkClose(client);
+            virNetMessageFree(msg);
+            ret = -1;
+        }
         msg = tmp;
     }
 
     virStreamFree(stream->st);
     VIR_FREE(stream);
+
+    return ret;
 }
 
 
@@ -264,33 +291,32 @@ void remoteFreeClientStream(struct qemud_client *client,
  * @client: a locked client to add the stream to
  * @stream: a stream to add
  */
-int remoteAddClientStream(struct qemud_client *client,
-                          struct qemud_client_stream *stream,
+int daemonAddClientStream(virNetServerClientPtr client,
+                          daemonClientStream *stream,
                           int transmit)
 {
-    struct qemud_client_stream *tmp = client->streams;
-
     VIR_DEBUG("client=%p proc=%d serial=%d", client, stream->procedure, stream->serial);
 
+    if (stream->filterID != -1) {
+        VIR_WARN("Filter already added to client %p", client);
+        return -1;
+    }
+
     if (virStreamEventAddCallback(stream->st, 0,
-                                  remoteStreamEvent, client, NULL) < 0)
+                                  daemonStreamEvent, client, NULL) < 0)
         return -1;
 
-    if (tmp) {
-        while (tmp->next)
-            tmp = tmp->next;
-        tmp->next = stream;
-    } else {
-        client->streams = stream;
+    if ((stream->filterID = virNetServerClientAddFilter(client,
+                                                        daemonStreamFilter,
+                                                        stream)) < 0) {
+        virStreamEventRemoveCallback(stream->st);
+        return -1;
     }
 
-    stream->filter.next = client->filters;
-    client->filters = &stream->filter;
-
     if (transmit)
         stream->tx = 1;
 
-    remoteStreamUpdateEvents(stream);
+    daemonStreamUpdateEvents(stream);
 
     return 0;
 }
@@ -305,11 +331,12 @@ int remoteAddClientStream(struct qemud_client *client,
  *
  * Returns a stream object matching the procedure+serial number, or NULL
  */
-struct qemud_client_stream *
-remoteFindClientStream(struct qemud_client *client,
+daemonClientStream *
+daemonFindClientStream(virNetServerClientPtr client,
                        virStreamPtr st)
 {
-    struct qemud_client_stream *stream = client->streams;
+    daemonClientPrivatePtr priv = virNetServerClientGetPrivateData(client);
+    daemonClientStream *stream = priv->streams;
 
     while (stream) {
         if (stream->st == st)
@@ -330,26 +357,18 @@ remoteFindClientStream(struct qemud_client *client,
  * Returns 0 if the stream was removd, -1 if it doesn't exist
  */
 int
-remoteRemoveClientStream(struct qemud_client *client,
-                         struct qemud_client_stream *stream)
+daemonRemoveClientStream(virNetServerClientPtr client,
+                         daemonClientStream *stream)
 {
     VIR_DEBUG("client=%p proc=%d serial=%d", client, stream->procedure, stream->serial);
-
-    struct qemud_client_stream *curr = client->streams;
-    struct qemud_client_stream *prev = NULL;
-    struct qemud_client_filter *filter = NULL;
-
-    if (client->filters == &stream->filter) {
-        client->filters = client->filters->next;
-    } else {
-        filter = client->filters;
-        while (filter) {
-            if (filter->next == &stream->filter) {
-                filter->next = filter->next->next;
-                break;
-            }
-            filter = filter->next;
-        }
+    daemonClientPrivatePtr priv = virNetServerClientGetPrivateData(client);
+    daemonClientStream *curr = priv->streams;
+    daemonClientStream *prev = NULL;
+
+    if (stream->filterID != -1) {
+        virNetServerClientRemoveFilter(client,
+                                       stream->filterID);
+        stream->filterID = -1;
     }
 
     if (!stream->closed) {
@@ -362,9 +381,8 @@ remoteRemoveClientStream(struct qemud_client *client,
             if (prev)
                 prev->next = curr->next;
             else
-                client->streams = curr->next;
-            remoteFreeClientStream(client, stream);
-            return 0;
+                priv->streams = curr->next;
+            return daemonFreeClientStream(client, stream);
         }
         prev = curr;
         curr = curr->next;
@@ -380,17 +398,15 @@ remoteRemoveClientStream(struct qemud_client *client,
  *    1  if message is still being processed
  */
 static int
-remoteStreamHandleWriteData(struct qemud_client *client,
-                            struct qemud_client_stream *stream,
-                            struct qemud_client_message *msg)
+daemonStreamHandleWriteData(virNetServerClientPtr client,
+                            daemonClientStream *stream,
+                            virNetMessagePtr msg)
 {
-    remote_error rerr;
     int ret;
 
-    VIR_DEBUG("stream=%p proc=%d serial=%d len=%d offset=%d",
-          stream, msg->hdr.proc, msg->hdr.serial, msg->bufferLength, msg->bufferOffset);
-
-    memset(&rerr, 0, sizeof rerr);
+    VIR_DEBUG("stream=%p proc=%d serial=%d len=%zu offset=%zu",
+              stream, msg->header.proc, msg->header.serial,
+              msg->bufferLength, msg->bufferOffset);
 
     ret = virStreamSend(stream->st,
                         msg->buffer + msg->bufferOffset,
@@ -402,14 +418,25 @@ remoteStreamHandleWriteData(struct qemud_client *client,
         /* Partial write, so indicate we have more todo later */
         if (msg->bufferOffset < msg->bufferLength)
             return 1;
+
+        /* A dummy 'send' just to free up 'msg' object */
+        memset(msg, 0, sizeof(*msg));
+        return virNetServerClientSendMessage(client, msg);
     } else if (ret == -2) {
         /* Blocking, so indicate we have more todo later */
         return 1;
     } else {
+        virNetMessageError rerr;
+
+        memset(&rerr, 0, sizeof(rerr));
+
         VIR_INFO("Stream send failed");
         stream->closed = 1;
-        remoteDispatchError(&rerr);
-        return remoteSerializeReplyError(client, &rerr, &msg->hdr);
+        return virNetServerProgramSendReplyError(stream->prog,
+                                                 client,
+                                                 msg,
+                                                 &rerr,
+                                                 &msg->header);
     }
 
     return 0;
@@ -419,38 +446,42 @@ remoteStreamHandleWriteData(struct qemud_client *client,
 /*
  * Process an finish handshake from the client.
  *
- * Returns a REMOTE_OK confirmation if successful, or a REMOTE_ERROR
+ * Returns a VIR_NET_OK confirmation if successful, or a VIR_NET_ERROR
  * if there was a stream error
  *
  * Returns 0 if successfully sent RPC reply, -1 upon fatal error
  */
 static int
-remoteStreamHandleFinish(struct qemud_client *client,
-                         struct qemud_client_stream *stream,
-                         struct qemud_client_message *msg)
+daemonStreamHandleFinish(virNetServerClientPtr client,
+                         daemonClientStream *stream,
+                         virNetMessagePtr msg)
 {
-    remote_error rerr;
     int ret;
 
     VIR_DEBUG("stream=%p proc=%d serial=%d",
-          stream, msg->hdr.proc, msg->hdr.serial);
-
-    memset(&rerr, 0, sizeof rerr);
+              stream, msg->header.proc, msg->header.serial);
 
     stream->closed = 1;
     virStreamEventRemoveCallback(stream->st);
     ret = virStreamFinish(stream->st);
 
     if (ret < 0) {
-        remoteDispatchError(&rerr);
-        return remoteSerializeReplyError(client, &rerr, &msg->hdr);
+        virNetMessageError rerr;
+        memset(&rerr, 0, sizeof(rerr));
+        return virNetServerProgramSendReplyError(stream->prog,
+                                                 client,
+                                                 msg,
+                                                 &rerr,
+                                                 &msg->header);
     } else {
         /* Send zero-length confirm */
-        if (remoteSendStreamData(client, stream, NULL, 0) < 0)
-            return -1;
+        return virNetServerProgramSendStreamData(stream->prog,
+                                                 client,
+                                                 msg,
+                                                 stream->procedure,
+                                                 stream->serial,
+                                                 NULL, 0);
     }
-
-    return 0;
 }
 
 
@@ -460,30 +491,35 @@ remoteStreamHandleFinish(struct qemud_client *client,
  * Returns 0 if successfully aborted, -1 upon error
  */
 static int
-remoteStreamHandleAbort(struct qemud_client *client,
-                        struct qemud_client_stream *stream,
-                        struct qemud_client_message *msg)
+daemonStreamHandleAbort(virNetServerClientPtr client,
+                        daemonClientStream *stream,
+                        virNetMessagePtr msg)
 {
-    remote_error rerr;
-
     VIR_DEBUG("stream=%p proc=%d serial=%d",
-          stream, msg->hdr.proc, msg->hdr.serial);
+              stream, msg->header.proc, msg->header.serial);
+    virNetMessageError rerr;
 
-    memset(&rerr, 0, sizeof rerr);
+    memset(&rerr, 0, sizeof(rerr));
 
     stream->closed = 1;
     virStreamEventRemoveCallback(stream->st);
     virStreamAbort(stream->st);
 
-    if (msg->hdr.status == REMOTE_ERROR)
-        remoteDispatchFormatError(&rerr, "%s", _("stream aborted at client request"));
+    if (msg->header.status == VIR_NET_ERROR)
+        virNetError(VIR_ERR_RPC,
+                    "%s", _("stream aborted at client request"));
     else {
-        VIR_WARN("unexpected stream status %d", msg->hdr.status);
-        remoteDispatchFormatError(&rerr, _("stream aborted with unexpected status %d"),
-                                  msg->hdr.status);
+        VIR_WARN("unexpected stream status %d", msg->header.status);
+        virNetError(VIR_ERR_RPC,
+                    _("stream aborted with unexpected status %d"),
+                    msg->header.status);
     }
 
-    return remoteSerializeReplyError(client, &rerr, &msg->hdr);
+    return virNetServerProgramSendReplyError(remoteProgram,
+                                             client,
+                                             msg,
+                                             &rerr,
+                                             &msg->header);
 }
 
 
@@ -496,41 +532,39 @@ remoteStreamHandleAbort(struct qemud_client *client,
  * Returns 0 on success, or -1 upon fatal error
  */
 static int
-remoteStreamHandleWrite(struct qemud_client *client,
-                        struct qemud_client_stream *stream)
+daemonStreamHandleWrite(virNetServerClientPtr client,
+                        daemonClientStream *stream)
 {
-    struct qemud_client_message *msg, *tmp;
-
     VIR_DEBUG("stream=%p", stream);
 
-    msg = stream->rx;
-    while (msg && !stream->closed) {
+    while (stream->rx && !stream->closed) {
+        virNetMessagePtr msg = stream->rx;
         int ret;
-        switch (msg->hdr.status) {
-        case REMOTE_OK:
-            ret = remoteStreamHandleFinish(client, stream, msg);
+
+        switch (msg->header.status) {
+        case VIR_NET_OK:
+            ret = daemonStreamHandleFinish(client, stream, msg);
             break;
 
-        case REMOTE_CONTINUE:
-            ret = remoteStreamHandleWriteData(client, stream, msg);
+        case VIR_NET_CONTINUE:
+            ret = daemonStreamHandleWriteData(client, stream, msg);
             break;
 
-        case REMOTE_ERROR:
+        case VIR_NET_ERROR:
         default:
-            ret = remoteStreamHandleAbort(client, stream, msg);
+            ret = daemonStreamHandleAbort(client, stream, msg);
             break;
         }
 
-        if (ret == 0)
-            qemudClientMessageQueueServe(&stream->rx);
-        else if (ret < 0)
-            return -1;
-        else
-            break; /* still processing data */
+        if (ret > 0)
+            break;  /* still processing data from msg */
 
-        tmp = msg->next;
-        qemudClientMessageRelease(client, msg);
-        msg = tmp;
+        virNetMessageQueueServe(&stream->rx);
+        if (ret < 0) {
+            virNetMessageFree(msg);
+            virNetServerClientMarkClose(client);
+            return -1;
+        }
     }
 
     return 0;
@@ -549,11 +583,11 @@ remoteStreamHandleWrite(struct qemud_client *client,
  * be killed
  */
 static int
-remoteStreamHandleRead(struct qemud_client *client,
-                       struct qemud_client_stream *stream)
+daemonStreamHandleRead(virNetServerClientPtr client,
+                       daemonClientStream *stream)
 {
     char *buffer;
-    size_t bufferLen = REMOTE_MESSAGE_PAYLOAD_MAX;
+    size_t bufferLen = VIR_NET_MESSAGE_PAYLOAD_MAX;
     int ret;
 
     VIR_DEBUG("stream=%p", stream);
@@ -572,16 +606,34 @@ remoteStreamHandleRead(struct qemud_client *client,
          * we're readable, but hey things change... */
         ret = 0;
     } else if (ret < 0) {
-        remote_error rerr;
-        memset(&rerr, 0, sizeof rerr);
-        remoteDispatchError(&rerr);
+        virNetMessagePtr msg;
+        virNetMessageError rerr;
+
+        memset(&rerr, 0, sizeof(rerr));
 
-        ret = remoteSerializeStreamError(client, &rerr, stream->procedure, stream->serial);
+        if (!(msg = virNetMessageNew()))
+            ret = -1;
+        else
+            ret = virNetServerProgramSendStreamError(remoteProgram,
+                                                     client,
+                                                     msg,
+                                                     &rerr,
+                                                     stream->procedure,
+                                                     stream->serial);
     } else {
+        virNetMessagePtr msg;
         stream->tx = 0;
         if (ret == 0)
             stream->recvEOF = 1;
-        ret = remoteSendStreamData(client, stream, buffer, ret);
+        if (!(msg = virNetMessageNew()))
+            ret = -1;
+        else
+            ret = virNetServerProgramSendStreamData(remoteProgram,
+                                                    client,
+                                                    msg,
+                                                    stream->procedure,
+                                                    stream->serial,
+                                                    buffer, ret);
     }
 
     VIR_FREE(buffer);
@@ -597,22 +649,23 @@ remoteStreamHandleRead(struct qemud_client *client,
  * fast stream, but slow client
  */
 void
-remoteStreamMessageFinished(struct qemud_client *client,
-                            struct qemud_client_message *msg)
+daemonStreamMessageFinished(virNetServerClientPtr client,
+                            virNetMessagePtr msg)
 {
-    struct qemud_client_stream *stream = client->streams;
+    daemonClientPrivatePtr priv = virNetServerClientGetPrivateData(client);
+    daemonClientStream *stream = priv->streams;
 
     while (stream) {
-        if (msg->hdr.proc == stream->procedure &&
-            msg->hdr.serial == stream->serial)
+        if (msg->header.proc == stream->procedure &&
+            msg->header.serial == stream->serial)
             break;
         stream = stream->next;
     }
 
-    VIR_DEBUG("Message client=%p stream=%p proc=%d serial=%d", client, stream, msg->hdr.proc, msg->hdr.serial);
+    VIR_DEBUG("Message client=%p stream=%p proc=%d serial=%d", client, stream, msg->header.proc, msg->header.serial);
 
     if (stream) {
         stream->tx = 1;
-        remoteStreamUpdateEvents(stream);
+        daemonStreamUpdateEvents(stream);
     }
 }
diff --git a/daemon/stream.h b/daemon/stream.h
index 767a763..3855c89 100644
--- a/daemon/stream.h
+++ b/daemon/stream.h
@@ -28,27 +28,29 @@
 
 
 
-struct qemud_client_stream *
-remoteCreateClientStream(virConnectPtr conn,
-                         remote_message_header *hdr);
+daemonClientStream *
+daemonCreateClientStream(virNetServerClientPtr client,
+                         virStreamPtr st,
+                         virNetServerProgramPtr prog,
+                         virNetMessageHeaderPtr hdr);
 
-void remoteFreeClientStream(struct qemud_client *client,
-                            struct qemud_client_stream *stream);
+int daemonFreeClientStream(virNetServerClientPtr client,
+                           daemonClientStream *stream);
 
-int remoteAddClientStream(struct qemud_client *client,
-                          struct qemud_client_stream *stream,
+int daemonAddClientStream(virNetServerClientPtr client,
+                          daemonClientStream *stream,
                           int transmit);
 
-struct qemud_client_stream *
-remoteFindClientStream(struct qemud_client *client,
+daemonClientStream *
+daemonFindClientStream(virNetServerClientPtr client,
                        virStreamPtr stream);
 
 int
-remoteRemoveClientStream(struct qemud_client *client,
-                         struct qemud_client_stream *stream);
+daemonRemoveClientStream(virNetServerClientPtr client,
+                         daemonClientStream *stream);
 
 void
-remoteStreamMessageFinished(struct qemud_client *client,
-                            struct qemud_client_message *msg);
+daemonStreamMessageFinished(virNetServerClientPtr client,
+                            virNetMessagePtr msg);
 
 #endif /* __LIBVIRTD_STREAM_H__ */
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 6b07386..a81fc55 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -1,4 +1,3 @@
-daemon/dispatch.c
 daemon/libvirtd.c
 daemon/remote.c
 daemon/remote_dispatch_bodies.h
diff --git a/src/rpc/gendispatch.pl b/src/rpc/gendispatch.pl
index d6264b9..2fd5ba8 100755
--- a/src/rpc/gendispatch.pl
+++ b/src/rpc/gendispatch.pl
@@ -258,80 +258,6 @@ if ($opt_d) {
     }
 }
 
-# Prototypes for dispatch functions ("remote_dispatch_prototypes.h").
-elsif ($opt_p) {
-    my @keys = sort (keys %calls);
-    foreach (@keys) {
-        # Skip things which are REMOTE_MESSAGE
-        next if $calls{$_}->{msg};
-
-        print "static int ${structprefix}Dispatch$calls{$_}->{ProcName}(\n";
-        print "    struct qemud_server *server,\n";
-        print "    struct qemud_client *client,\n";
-        print "    virConnectPtr conn,\n";
-        print "    remote_message_header *hdr,\n";
-        print "    remote_error *rerr,\n";
-        print "    $calls{$_}->{args} *args,\n";
-        print "    $calls{$_}->{ret} *ret);\n";
-    }
-}
-
-# Union of all arg types
-# ("remote_dispatch_args.h").
-elsif ($opt_a) {
-    for ($id = 0 ; $id <= $#calls ; $id++) {
-        if (defined $calls[$id] &&
-            !$calls[$id]->{msg} &&
-            $calls[$id]->{args} ne "void") {
-            print "    $calls[$id]->{args} val_$calls[$id]->{args};\n";
-        }
-    }
-}
-
-# Union of all arg types
-# ("remote_dispatch_ret.h").
-elsif ($opt_r) {
-    for ($id = 0 ; $id <= $#calls ; $id++) {
-        if (defined $calls[$id] &&
-            !$calls[$id]->{msg} &&
-            $calls[$id]->{ret} ne "void") {
-            print "    $calls[$id]->{ret} val_$calls[$id]->{ret};\n";
-        }
-    }
-}
-
-# Inside the switch statement, prepare the 'fn', 'args_filter', etc
-# ("remote_dispatch_table.h").
-elsif ($opt_t) {
-    for ($id = 0 ; $id <= $#calls ; $id++) {
-        if (defined $calls[$id] && !$calls[$id]->{msg}) {
-            print "{   /* $calls[$id]->{ProcName} => $id */\n";
-            print "    .fn = (dispatch_fn) ${structprefix}Dispatch$calls[$id]->{ProcName},\n";
-            if ($calls[$id]->{args} ne "void") {
-                print "    .args_filter = (xdrproc_t) xdr_$calls[$id]->{args},\n";
-            } else {
-                print "    .args_filter = (xdrproc_t) xdr_void,\n";
-            }
-            if ($calls[$id]->{ret} ne "void") {
-                print "    .ret_filter = (xdrproc_t) xdr_$calls[$id]->{ret},\n";
-            } else {
-                print "    .ret_filter = (xdrproc_t) xdr_void,\n";
-            }
-            print "},\n";
-        } else {
-            if ($calls[$id]->{msg}) {
-                print "{   /* Async event $calls[$id]->{ProcName} => $id */\n";
-            } else {
-                print "{   /* (unused) => $id */\n";
-            }
-            print "    .fn = NULL,\n";
-            print "    .args_filter = (xdrproc_t) xdr_void,\n";
-            print "    .ret_filter = (xdrproc_t) xdr_void,\n";
-            print "},\n";
-        }
-    }
-}
-
 # Bodies for dispatch functions ("remote_dispatch_bodies.h").
 elsif ($opt_b) {
     my %generate = map { $_ => 1 } @autogen;
@@ -343,8 +269,58 @@ elsif ($opt_b) {
         # skip things which are REMOTE_MESSAGE
         next if $call->{msg};
 
-        # skip procedures not on generate list
-        next if ! exists($generate{$call->{ProcName}});
+	my $name = $structprefix . "Dispatch" . $call->{ProcName};
+	my $argtype = $call->{args};
+	my $rettype = $call->{ret};
+
+	my $argann = $argtype ne "void" ? "" : " ATTRIBUTE_UNUSED";
+	my $retann = $rettype ne "void" ? "" : " ATTRIBUTE_UNUSED";
+
+	# First we print out a function declaration for the
+	# real dispatcher body
+	print "static int ${name}(\n";
+	print "    virNetServerPtr server,\n";
+	print "    virNetServerClientPtr client,\n";
+	print "    virNetMessageHeaderPtr hdr,\n";
+	print "    virNetMessageErrorPtr rerr";
+	if ($argtype ne "void") {
+	    print ",\n    $argtype *args";
+	}
+	if ($rettype ne "void") {
+	    print ",\n    $rettype *ret";
+	}
+	print ");\n";
+
+
+	# Next we print out a generic wrapper method which has
+	# fixed function signature, for use in the dispatcher
+	# table. This simply callers the real dispatcher method
+	print "static int ${name}Helper(\n";
+	print "    virNetServerPtr server,\n";
+	print "    virNetServerClientPtr client,\n";
+	print "    virNetMessageHeaderPtr hdr,\n";
+	print "    virNetMessageErrorPtr rerr,\n";
+	print "    void *args$argann,\n";
+	print "    void *ret$retann)\n";
+	print "{\n";
+	print "  VIR_DEBUG(\"server=%p client=%p hdr=%p rerr=%p args=%p ret=%p\", server, client, hdr, rerr, args, ret);\n";
+	print "  return $name(server, client, hdr, rerr";
+	if ($argtype ne "void") {
+	    print ", args";
+	}
+	if ($rettype ne "void") {
+	    print ", ret";
+	}
+	print ");\n";
+	print "}\n";
+
+	# Finally we print out the dispatcher method body impl
+	# (if possible)
+        if (!exists($generate{$call->{ProcName}})) {
+            print "/* ${structprefix}Dispatch$call->{ProcName} body has " .
+                  "to be implemented manually */\n\n\n\n";
+            next;
+        }
 
         my $has_node_device = 0;
         my @vars_list = ();
@@ -354,18 +330,18 @@ elsif ($opt_b) {
         my @prepare_ret_list = ();
         my @ret_list = ();
         my @free_list = ();
-        my @free_list_on_error = ("remoteDispatchError(rerr);");
+        my @free_list_on_error = ("virNetMessageSaveError(rerr);");
 
         # handle arguments to the function
-        if ($call->{args} ne "void") {
+        if ($argtype ne "void") {
             # node device is special, as it's identified by name
-            if ($call->{args} =~ m/^remote_node_device_/ and
-                !($call->{args} =~ m/^remote_node_device_lookup_by_name_/) and
-                !($call->{args} =~ m/^remote_node_device_create_xml_/)) {
+            if ($argtype =~ m/^remote_node_device_/ and
+                !($argtype =~ m/^remote_node_device_lookup_by_name_/) and
+                !($argtype =~ m/^remote_node_device_create_xml_/)) {
                 $has_node_device = 1;
                 push(@vars_list, "virNodeDevicePtr dev = NULL");
                 push(@getters_list,
-                     "    if (!(dev = virNodeDeviceLookupByName(conn, args->name)))\n" .
+                     "    if (!(dev = virNodeDeviceLookupByName(priv->conn, args->name)))\n" .
                      "        goto cleanup;\n");
                 push(@args_list, "dev");
                 push(@free_list,
@@ -382,7 +358,7 @@ elsif ($opt_b) {
 
                     push(@vars_list, "vir${type_name}Ptr $2 = NULL");
                     push(@getters_list,
-                         "    if (!($2 = get_nonnull_$1(conn, args->$2)))\n" .
+                         "    if (!($2 = get_nonnull_$1(priv->conn, args->$2)))\n" .
                          "        goto cleanup;\n");
                     push(@args_list, "$2");
                     push(@free_list,
@@ -392,7 +368,7 @@ elsif ($opt_b) {
                     push(@vars_list, "virDomainPtr dom = NULL");
                     push(@vars_list, "virDomainSnapshotPtr snapshot = NULL");
                     push(@getters_list,
-                         "    if (!(dom = get_nonnull_domain(conn, args->snap.dom)))\n" .
+                         "    if (!(dom = get_nonnull_domain(priv->conn, args->snap.dom)))\n" .
                          "        goto cleanup;\n" .
                          "\n" .
                          "    if (!(snapshot = get_nonnull_domain_snapshot(dom, args->snap)))\n" .
@@ -405,14 +381,14 @@ elsif ($opt_b) {
                          "        virDomainFree(dom);");
                 } elsif ($args_member =~ m/^(?:remote_string|remote_uuid) (\S+)<\S+>;/) {
                     if (! @args_list) {
-                        push(@args_list, "conn");
+                        push(@args_list, "priv->conn");
                     }
 
                     push(@args_list, "args->$1.$1_val");
                     push(@args_list, "args->$1.$1_len");
                 } elsif ($args_member =~ m/^(?:opaque|remote_nonnull_string) (\S+)<\S+>;(.*)$/) {
                     if (! @args_list) {
-                        push(@args_list, "conn");
+                        push(@args_list, "priv->conn");
                     }
 
                     my $cast = "";
@@ -431,7 +407,7 @@ elsif ($opt_b) {
                     push(@args_list, "args->$arg_name.${arg_name}_len");
                 } elsif ($args_member =~ m/^(?:unsigned )?int (\S+)<\S+>;/) {
                     if (! @args_list) {
-                        push(@args_list, "conn");
+                        push(@args_list, "priv->conn");
                     }
 
                     push(@args_list, "args->$1.$1_val");
@@ -452,13 +428,13 @@ elsif ($opt_b) {
                     die "unhandled type for argument value: $args_member";
                 } elsif ($args_member =~ m/^remote_uuid (\S+);/) {
                     if (! @args_list) {
-                        push(@args_list, "conn");
+                        push(@args_list, "priv->conn");
                     }
 
                     push(@args_list, "(unsigned char *) args->$1");
                 } elsif ($args_member =~ m/^remote_string (\S+);/) {
                     if (! @args_list) {
-                        push(@args_list, "conn");
+                        push(@args_list, "priv->conn");
                     }
 
                     push(@vars_list, "char *$1");
@@ -466,19 +442,19 @@ elsif ($opt_b) {
                     push(@args_list, "$1");
                 } elsif ($args_member =~ m/^remote_nonnull_string (\S+);/) {
                     if (! @args_list) {
-                        push(@args_list, "conn");
+                        push(@args_list, "priv->conn");
                     }
 
                     push(@args_list, "args->$1");
                 } elsif ($args_member =~ m/^(unsigned )?int (\S+);/) {
                     if (! @args_list) {
-                        push(@args_list, "conn");
+                        push(@args_list, "priv->conn");
                     }
 
                     push(@args_list, "args->$2");
                 } elsif ($args_member =~ m/^(unsigned )?hyper (\S+);/) {
                     if (! @args_list) {
-                        push(@args_list, "conn");
+                        push(@args_list, "priv->conn");
                     }
 
                     my $arg_name = $2;
@@ -511,12 +487,12 @@ elsif ($opt_b) {
         my $single_ret_list_max_define = "undefined";
         my $multi_ret = 0;
 
-        if ($call->{ret} ne "void" and
+        if ($rettype ne "void" and
             scalar(@{$call->{ret_members}}) > 1) {
             $multi_ret = 1;
         }
 
-        if ($call->{ret} ne "void") {
+        if ($rettype ne "void") {
             foreach my $ret_member (@{$call->{ret_members}}) {
                 if ($multi_ret) {
                     if ($ret_member =~ m/^(unsigned )?(char|short|int|hyper) (\S+)\[\S+\];/) {
@@ -715,8 +691,8 @@ elsif ($opt_b) {
                 die "multi-return-value without insert@<offset> annotation: $call->{ret}";
             }
 
-            if (! args_list) {
-                push(@args_list, "conn");
+            if (! @args_list) {
+                push(@args_list, "priv->conn");
             }
 
             my $struct_name = $call->{ProcName};
@@ -737,36 +713,28 @@ elsif ($opt_b) {
         }
 
         if ($call->{streamflag} ne "none") {
-            splice(@args_list, $call->{streamoffset}, 0, ("stream->st"));
+            splice(@args_list, $call->{streamoffset}, 0, ("st"));
             push(@free_list_on_error, "if (stream) {");
-            push(@free_list_on_error, "    virStreamAbort(stream->st);");
-            push(@free_list_on_error, "    remoteFreeClientStream(client, stream);");
+            push(@free_list_on_error, "    virStreamAbort(st);");
+            push(@free_list_on_error, "    daemonFreeClientStream(client, stream);");
+            push(@free_list_on_error, "} else {");
+            push(@free_list_on_error, "    virStreamFree(st);");
             push(@free_list_on_error, "}");
         }
 
         # print functions signature
-        print "\n";
-        print "static int\n";
-        print "${structprefix}Dispatch$call->{ProcName}(\n";
-        print "    struct qemud_server *server ATTRIBUTE_UNUSED,\n";
-        print "    struct qemud_client *client ATTRIBUTE_UNUSED,\n";
-        print "    virConnectPtr conn,\n";
-        print "    remote_message_header *hdr ATTRIBUTE_UNUSED,\n";
-        print "    remote_error *rerr,\n";
-        print "    $call->{args} *args";
-
-        if ($call->{args} eq "void") {
-            print " ATTRIBUTE_UNUSED"
-        }
-
-        print ",\n";
-        print "    $call->{ret} *ret";
-
-        if ($call->{ret} eq "void") {
-            print " ATTRIBUTE_UNUSED"
-        }
-
-        print ")\n";
+	print "static int $name(\n";
+	print "    virNetServerPtr server ATTRIBUTE_UNUSED,\n";
+	print "    virNetServerClientPtr client,\n";
+	print "    virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,\n";
+	print "    virNetMessageErrorPtr rerr";
+        if ($argtype ne "void") {
+	    print ",\n    $argtype *args";
+	}
+        if ($rettype ne "void") {
+	    print ",\n    $rettype *ret";
+	}
+	print ")\n";
 
         # print function body
         print "{\n";
@@ -775,13 +743,16 @@ elsif ($opt_b) {
         foreach my $var (@vars_list) {
             print "    $var;\n";
         }
+	print "    struct daemonClientPrivate *priv =\n";
+        print "        virNetServerClientGetPrivateData(client);\n";
 
         if ($call->{streamflag} ne "none") {
-            print "    struct qemud_client_stream *stream = NULL;\n";
+            print "    virStreamPtr st = NULL;\n";
+            print "    daemonClientStreamPtr stream = NULL;\n";
         }
 
         print "\n";
-        print "    if (!conn) {\n";
+        print "    if (!priv->conn) {\n";
         print "        virNetError(VIR_ERR_INTERNAL_ERROR, \"%s\", _(\"connection not open\"));\n";
         print "        goto cleanup;\n";
         print "    }\n";
@@ -811,12 +782,12 @@ elsif ($opt_b) {
         }
 
         if ($call->{streamflag} ne "none") {
-            print "    if (!(stream = remoteCreateClientStream(conn, hdr)))\n";
+            print "    if (!(stream = daemonCreateClientStream(client, st, remoteProgram, hdr)))\n";
             print "        goto cleanup;\n";
             print "\n";
         }
 
-        if ($call->{ret} eq "void") {
+        if ($rettype eq "void") {
             print "    if (vir$call->{ProcName}(";
             print join(', ', @args_list);
             print ") < 0)\n";
@@ -827,7 +798,7 @@ elsif ($opt_b) {
             my $proc_name = $call->{ProcName};
 
             if (! @args_list) {
-                push(@args_list, "conn");
+                push(@args_list, "priv->conn");
 
                 if ($call->{ProcName} ne "NodeGetFreeMemory") {
                     $prefix = "Connect"
@@ -885,7 +856,7 @@ elsif ($opt_b) {
         }
 
         if ($call->{streamflag} ne "none") {
-            print "    if (remoteAddClientStream(client, stream, ";
+            print "    if (daemonAddClientStream(client, stream, ";
 
             if ($call->{streamflag} eq "write") {
                 print "0";
@@ -934,8 +905,46 @@ elsif ($opt_b) {
         }
 
         print "    return rv;\n";
-        print "}\n";
+        print "}\n\n\n\n";
     }
+
+
+    # Finally we write out the huge dispatch table which lists
+    # the dispatch helper method. the XDR proc for processing
+    # args and return values, and the size of the args and
+    # return value structs. All methods are marked as requiring
+    # authentication. Methods are selectively relaxed in the
+    # daemon code which registers the program.
+
+    print "virNetServerProgramProc ${structprefix}Procs[] = {\n";
+    for ($id = 0 ; $id <= $#calls ; $id++) {
+	my ($comment, $name, $argtype, $arglen, $argfilter, $retlen, $retfilter);
+
+	if (defined $calls[$id] && !$calls[$id]->{msg}) {
+	    $comment = "/* Method $calls[$id]->{ProcName} => $id */";
+	    $name = $structprefix . "Dispatch" . $calls[$id]->{ProcName} . "Helper";
+	    my $argtype = $calls[$id]->{args};
+	    my $rettype = $calls[$id]->{ret};
+	    $arglen = $argtype ne "void" ? "sizeof($argtype)" : "0";
+	    $retlen = $rettype ne "void" ? "sizeof($rettype)" : "0";
+	    $argfilter = $argtype ne "void" ? "xdr_$argtype" : "xdr_void";
+	    $retfilter = $rettype ne "void" ? "xdr_$rettype" : "xdr_void";
+	} else {
+	    if ($calls[$id]->{msg}) {
+		$comment = "/* Async event $calls[$id]->{ProcName} => $id */";
+	    } else {
+		$comment = "/* Unused $id */";
+	    }
+	    $name = "NULL";
+	    $arglen = $retlen = 0;
+	    $argfilter = "xdr_void";
+	    $retfilter = "xdr_void";
+	}
+
+	print "{ $comment\n   ${name},\n   $arglen,\n   (xdrproc_t)$argfilter,\n   $retlen,\n   (xdrproc_t)$retfilter,\n   true \n},\n";
+    }
+    print "};\n";
+    print "size_t ${structprefix}NProcs = ARRAY_CARDINALITY(${structprefix}Procs);\n";
 }
 
 # Bodies for client functions ("remote_client_bodies.h").
@@ -952,6 +961,9 @@ elsif ($opt_k) {
         # skip procedures not on generate list
         next if ! exists($generate{$call->{ProcName}});
 
+	my $argtype = $call->{args};
+	my $rettype = $call->{ret};
+
         # handle arguments to the function
         my @args_list = ();
         my @vars_list = ();
@@ -962,18 +974,18 @@ elsif ($opt_k) {
         my $priv_name = "privateData";
         my $call_args = "&args";
 
-        if ($call->{args} eq "void") {
+        if ($argtype eq "void") {
             $call_args = "NULL";
         } else {
-            push(@vars_list, "$call->{args} args");
+            push(@vars_list, "$argtype args");
 
             my $is_first_arg = 1;
             my $has_node_device = 0;
 
             # node device is special
-            if ($call->{args} =~ m/^remote_node_/ and
-                !($call->{args} =~ m/^remote_node_device_lookup_by_name_/) and
-                !($call->{args} =~ m/^remote_node_device_create_xml_/)) {
+            if ($argtype =~ m/^remote_node_/ and
+                !($argtype =~ m/^remote_node_device_lookup_by_name_/) and
+                !($argtype =~ m/^remote_node_device_create_xml_/)) {
                 $has_node_device = 1;
                 $priv_name = "devMonPrivateData";
             }
@@ -1150,15 +1162,15 @@ elsif ($opt_k) {
         my $single_ret_cleanup = 0;
         my $multi_ret = 0;
 
-        if ($call->{ret} ne "void" and
+        if ($rettype ne "void" and
             scalar(@{$call->{ret_members}}) > 1) {
             $multi_ret = 1;
         }
 
-        if ($call->{ret} eq "void") {
+        if ($rettype eq "void") {
             $call_ret = "NULL";
         } else {
-            push(@vars_list, "$call->{ret} ret");
+            push(@vars_list, "$rettype ret");
 
             foreach my $ret_member (@{$call->{ret_members}}) {
                 if ($multi_ret) {
@@ -1233,7 +1245,7 @@ elsif ($opt_k) {
                             push(@ret_list, "rv = get_nonnull_$name($priv_src, ret.$arg_name);");
                         }
 
-                        push(@ret_list, "xdr_free((xdrproc_t)xdr_$call->{ret}, (char *)&ret);");
+                        push(@ret_list, "xdr_free((xdrproc_t)xdr_$rettype, (char *)&ret);");
                         $single_ret_var = "vir${type_name}Ptr rv = NULL";
                         $single_ret_type = "vir${type_name}Ptr";
                     }
@@ -1397,15 +1409,15 @@ elsif ($opt_k) {
             print "\n";
         }
 
-        if ($call->{ret} ne "void") {
+        if ($rettype ne "void") {
             print "\n";
             print "    memset(&ret, 0, sizeof ret);\n";
         }
 
         print "\n";
         print "    if (call($priv_src, priv, 0, ${procprefix}_PROC_$call->{UC_NAME},\n";
-        print "             (xdrproc_t)xdr_$call->{args}, (char *)$call_args,\n";
-        print "             (xdrproc_t)xdr_$call->{ret}, (char *)$call_ret) == -1) {\n";
+        print "             (xdrproc_t)xdr_$argtype, (char *)$call_args,\n";
+        print "             (xdrproc_t)xdr_$rettype, (char *)$call_ret) == -1) {\n";
 
         if ($call->{streamflag} ne "none") {
             print "        virNetClientRemoveStream(priv->client, netst);\n";
-- 
1.7.4.4


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]