[PATCH 7/8] Convert the remote driver to new RPC client APIs

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

 



This guts the current remote driver, removing all its networking
handling code. Instead it calls out to the new virClientPtr and
virClientProgramPtr APIs for all RPC & networking work.
---
 src/Makefile.am            |    3 +-
 src/remote/remote_driver.c | 2530 ++++++++------------------------------------
 2 files changed, 419 insertions(+), 2114 deletions(-)

diff --git a/src/Makefile.am b/src/Makefile.am
index 4c6efa8..8986f22 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -475,9 +475,10 @@ libvirt_driver_remote_la_CFLAGS =				\
 		$(GNUTLS_CFLAGS)				\
 		$(SASL_CFLAGS)					\
 		-I@top_srcdir@/src/conf				\
+		-I@top_srcdir@/src/rpc				\
 		$(AM_CFLAGS)
 libvirt_driver_remote_la_LDFLAGS = $(AM_LDFLAGS)
-libvirt_driver_remote_la_LIBADD = $(GNUTLS_LIBS) $(SASL_LIBS)
+libvirt_driver_remote_la_LIBADD = $(GNUTLS_LIBS) $(SASL_LIBS) libvirt-net-client.la libvirt-net-rpc.la
 if WITH_DRIVER_MODULES
 libvirt_driver_remote_la_LDFLAGS += -module -avoid-version
 endif
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index e6eb9b5..8fd7949 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -23,51 +23,13 @@
 
 #include <config.h>
 
-#include <stdio.h>
-#include <stdlib.h>
 #include <unistd.h>
-#include <string.h>
 #include <assert.h>
-#include <signal.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <arpa/inet.h>
-#include <sys/wait.h>
-
-/* Windows socket compatibility functions. */
-#include <errno.h>
-#include <sys/socket.h>
-
-#ifndef HAVE_WINSOCK2_H /* Unix & Cygwin. */
-# include <sys/un.h>
-# include <net/if.h>
-# include <netinet/in.h>
-# include <netinet/tcp.h>
-#endif
-
-#ifdef HAVE_PWD_H
-# include <pwd.h>
-#endif
-
-#ifdef HAVE_PATHS_H
-# include <paths.h>
-#endif
 
-#include <rpc/types.h>
-#include <rpc/xdr.h>
-#include <gnutls/gnutls.h>
-#include <gnutls/x509.h>
-#include "gnutls_1_0_compat.h"
-#if HAVE_SASL
-# include <sasl/sasl.h>
-#endif
 #include <libxml/uri.h>
 
-#include <netdb.h>
-
-#include <poll.h>
-
+#include "virnetclient.h"
+#include "virnetclientprogram.h"
 #include "virterror_internal.h"
 #include "logging.h"
 #include "datatypes.h"
@@ -86,106 +48,24 @@
 
 #define VIR_FROM_THIS VIR_FROM_REMOTE
 
-#ifdef WIN32
-# define pipe(fds) _pipe(fds,4096, _O_BINARY)
-#endif
-
-
 static int inside_daemon = 0;
 
-struct remote_thread_call;
-
-
-enum {
-    REMOTE_MODE_WAIT_TX,
-    REMOTE_MODE_WAIT_RX,
-    REMOTE_MODE_COMPLETE,
-    REMOTE_MODE_ERROR,
-};
-
-struct remote_thread_call {
-    int mode;
-
-    /* Buffer for outgoing data packet
-     * 4 byte length, followed by RPC message header+body */
-    char buffer[4 + REMOTE_MESSAGE_MAX];
-    unsigned int bufferLength;
-    unsigned int bufferOffset;
-
-    unsigned int serial;
-    unsigned int proc_nr;
-
-    virCond cond;
-
-    int want_reply;
-    xdrproc_t ret_filter;
-    char *ret;
-
-    remote_error err;
-
-    struct remote_thread_call *next;
-};
+struct private_data {
+    virMutex lock;
 
-struct private_stream_data {
-    unsigned int has_error : 1;
-    remote_error err;
-
-    unsigned int serial;
-    unsigned int proc_nr;
-
-    virStreamEventCallback cb;
-    void *cbOpaque;
-    virFreeCallback cbFree;
-    int cbEvents;
-    int cbTimer;
-    int cbDispatch;
-
-    /* XXX this is potentially unbounded if the client
-     * app has domain events registered, since packets
-     * may be read off wire, while app isn't ready to
-     * recv them. Figure out how to address this some
-     * time....
-     */
-    char *incoming;
-    unsigned int incomingOffset;
-    unsigned int incomingLength;
+    virNetClientPtr client;
+    virNetClientProgramPtr remoteProgram;
+    virNetClientProgramPtr qemuProgram;
 
-    struct private_stream_data *next;
-};
+    int counter; /* Serial number for RPC */
 
-struct private_data {
-    virMutex lock;
+    virNetTLSContextPtr tls;
 
-    int sock;                   /* Socket. */
-    int errfd;                /* File handle connected to remote stderr */
     int watch;                  /* File handle watch */
-    pid_t pid;                  /* PID of tunnel process */
-    int uses_tls;               /* TLS enabled on socket? */
     int is_secure;              /* Secure if TLS or SASL or UNIX sockets */
-    gnutls_session_t session;   /* GnuTLS session (if uses_tls != 0). */
     char *type;                 /* Cached return from remoteType. */
-    int counter;                /* Generates serial numbers for RPC. */
     int localUses;              /* Ref count for private data */
     char *hostname;             /* Original hostname */
-    FILE *debugLog;             /* Debug remote protocol */
-
-#if HAVE_SASL
-    sasl_conn_t *saslconn;      /* SASL context */
-
-    const char *saslDecoded;
-    unsigned int saslDecodedLength;
-    unsigned int saslDecodedOffset;
-
-    const char *saslEncoded;
-    unsigned int saslEncodedLength;
-    unsigned int saslEncodedOffset;
-#endif
-
-    /* Buffer for incoming data packets
-     * 4 byte length, followed by RPC message header+body */
-    char buffer[4 + REMOTE_MESSAGE_MAX];
-    unsigned int bufferLength;
-    unsigned int bufferOffset;
 
     /* The list of domain event callbacks */
     virDomainEventCallbackListPtr callbackList;
@@ -196,15 +76,6 @@ struct private_data {
     int eventFlushTimer;
     /* Flag if we're in process of dispatching */
     int domainEventDispatching;
-
-    /* Self-pipe to wakeup threads waiting in poll() */
-    int wakeupSendFD;
-    int wakeupReadFD;
-
-    /* List of threads currently waiting for dispatch */
-    struct remote_thread_call *waitDispatch;
-
-    struct private_stream_data *streams;
 };
 
 enum {
@@ -225,10 +96,6 @@ static void remoteDriverUnlock(struct private_data *driver)
     virMutexUnlock(&driver->lock);
 }
 
-static int remoteIO(virConnectPtr conn,
-                    struct private_data *priv,
-                    int flags,
-                    struct remote_thread_call *thiscall);
 static int call (virConnectPtr conn, struct private_data *priv,
                  int flags, int proc_nr,
                  xdrproc_t args_filter, char *args,
@@ -272,10 +139,6 @@ void remoteDomainEventQueueFlush(int timer, void *opaque);
 /* Helper functions for remoteOpen. */
 static char *get_transport_from_scheme (char *scheme);
 
-/* GnuTLS functions used by remoteOpen. */
-static int initialize_gnutls(void);
-static gnutls_session_t negotiate_gnutls_on_connection (virConnectPtr conn, struct private_data *priv, int no_verify);
-
 #ifdef WITH_LIBVIRTD
 static int
 remoteStartup(int privileged ATTRIBUTE_UNUSED)
@@ -290,7 +153,7 @@ remoteStartup(int privileged ATTRIBUTE_UNUSED)
 
 #ifndef WIN32
 /**
- * remoteFindServerPath:
+ * remoteFindDaemonPath:
  *
  * Tries to find the path to the libvirtd binary.
  *
@@ -317,36 +180,68 @@ remoteFindDaemonPath(void)
     }
     return NULL;
 }
+#endif
 
-/**
- * qemuForkDaemon:
- *
- * Forks and try to launch the libvirtd daemon
- *
- * Returns 0 in case of success or -1 in case of detected error.
- */
-static int
-remoteForkDaemon(void)
-{
-    const char *daemonPath = remoteFindDaemonPath();
-    const char *const daemonargs[] = { daemonPath, "--timeout=30", NULL };
-    pid_t pid;
-
-    if (!daemonPath) {
-        remoteError(VIR_ERR_INTERNAL_ERROR, "%s",
-                    _("failed to find libvirtd binary"));
-        return -1;
-    }
-
-    if (virExecDaemonize(daemonargs, NULL, NULL,
-                         &pid, -1, NULL, NULL,
-                         VIR_EXEC_CLEAR_CAPS,
-                         NULL, NULL, NULL) < 0)
-        return -1;
 
-    return 0;
-}
-#endif
+static void
+remoteDomainBuildEventLifecycle(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
+                                virNetClientPtr client ATTRIBUTE_UNUSED,
+                                void *evdata, void *opaque);
+static void
+remoteDomainBuildEventReboot(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
+                             virNetClientPtr client ATTRIBUTE_UNUSED,
+                             void *evdata, void *opaque);
+static void
+remoteDomainBuildEventRTCChange(virNetClientProgramPtr prog,
+                                virNetClientPtr client,
+                                void *evdata, void *opaque);
+static void
+remoteDomainBuildEventWatchdog(virNetClientProgramPtr prog,
+                               virNetClientPtr client,
+                               void *evdata, void *opaque);
+static void
+remoteDomainBuildEventIOError(virNetClientProgramPtr prog,
+                              virNetClientPtr client,
+                              void *evdata, void *opaque);
+static void
+remoteDomainBuildEventIOErrorReason(virNetClientProgramPtr prog,
+                                    virNetClientPtr client,
+                                    void *evdata, void *opaque);
+static void
+remoteDomainBuildEventGraphics(virNetClientProgramPtr prog,
+                               virNetClientPtr client,
+                               void *evdata, void *opaque);
+
+static virNetClientProgramEvent remoteDomainEvents[] = {
+    { REMOTE_PROC_DOMAIN_EVENT_RTC_CHANGE,
+      remoteDomainBuildEventRTCChange,
+      sizeof(remote_domain_event_rtc_change_msg),
+      (xdrproc_t)xdr_remote_domain_event_rtc_change_msg },
+    { REMOTE_PROC_DOMAIN_EVENT_REBOOT,
+      remoteDomainBuildEventReboot,
+      sizeof(remote_domain_event_reboot_msg),
+      (xdrproc_t)xdr_remote_domain_event_reboot_msg },
+    { REMOTE_PROC_DOMAIN_EVENT_LIFECYCLE,
+      remoteDomainBuildEventLifecycle,
+      sizeof(remote_domain_event_lifecycle_msg),
+      (xdrproc_t)xdr_remote_domain_event_lifecycle_msg },
+    { REMOTE_PROC_DOMAIN_EVENT_WATCHDOG,
+      remoteDomainBuildEventWatchdog,
+      sizeof(remote_domain_event_watchdog_msg),
+      (xdrproc_t)xdr_remote_domain_event_watchdog_msg},
+    { REMOTE_PROC_DOMAIN_EVENT_IO_ERROR,
+      remoteDomainBuildEventIOError,
+      sizeof(remote_domain_event_io_error_msg),
+      (xdrproc_t)xdr_remote_domain_event_io_error_msg },
+    { REMOTE_PROC_DOMAIN_EVENT_IO_ERROR_REASON,
+      remoteDomainBuildEventIOErrorReason,
+      sizeof(remote_domain_event_io_error_reason_msg),
+      (xdrproc_t)xdr_remote_domain_event_io_error_reason_msg },
+    { REMOTE_PROC_DOMAIN_EVENT_GRAPHICS,
+      remoteDomainBuildEventGraphics,
+      sizeof(remote_domain_event_graphics_msg),
+      (xdrproc_t)xdr_remote_domain_event_graphics_address },
+};
 
 enum virDrvOpenRemoteFlags {
     VIR_DRV_OPEN_REMOTE_RO = (1 << 0),
@@ -379,7 +274,6 @@ doRemoteOpen (virConnectPtr conn,
               int flags)
 {
     struct qparam_set *vars = NULL;
-    int wakeupFD[2] = { -1, -1 };
     char *transport_str = NULL;
     enum {
         trans_tls,
@@ -508,15 +402,10 @@ doRemoteOpen (virConnectPtr conn,
             } else if (STRCASEEQ (var->name, "no_tty")) {
                 no_tty = atoi (var->value);
                 var->ignore = 1;
-            } else if (STRCASEEQ (var->name, "debug")) {
-                if (var->value &&
-                    STRCASEEQ (var->value, "stdout"))
-                    priv->debugLog = stdout;
-                else
-                    priv->debugLog = stderr;
-            } else
+            } else {
                 DEBUG("passing through variable '%s' ('%s') to remote end",
                       var->name, var->value);
+            }
         }
 
         /* Construct the original name. */
@@ -579,89 +468,35 @@ doRemoteOpen (virConnectPtr conn,
         goto failed;
     }
 
+
+    VIR_DEBUG("Connecting with transport %d", transport);
     /* Connect to the remote service. */
     switch (transport) {
     case trans_tls:
-        if (initialize_gnutls() == -1) goto failed;
-        priv->uses_tls = 1;
+        priv->tls = virNetTLSContextNewClient(LIBVIRT_CACERT,
+                                              LIBVIRT_CLIENTCERT,
+                                              LIBVIRT_CLIENTKEY,
+                                              no_verify ? false : true);
+        if (!priv->tls)
+            goto failed;
         priv->is_secure = 1;
 
         /*FALLTHROUGH*/
-    case trans_tcp: {
-        // http://people.redhat.com/drepper/userapi-ipv6.html
-        struct addrinfo *res, *r;
-        struct addrinfo hints;
-        int saved_errno = EINVAL;
-        memset (&hints, 0, sizeof hints);
-        hints.ai_socktype = SOCK_STREAM;
-        hints.ai_flags = AI_ADDRCONFIG;
-        int e = getaddrinfo (priv->hostname, port, &hints, &res);
-        if (e != 0) {
-            remoteError(VIR_ERR_SYSTEM_ERROR,
-                        _("unable to resolve hostname '%s': %s"),
-                        priv->hostname, gai_strerror (e));
+    case trans_tcp:
+        priv->client = virNetClientNewTCP(priv->hostname, port);
+        if (!priv->client)
             goto failed;
-        }
 
-        /* Try to connect to each returned address in turn. */
-        /* XXX This loop contains a subtle problem.  In the case
-         * where a host is accessible over IPv4 and IPv6, it will
-         * try the IPv4 and IPv6 addresses in turn.  However it
-         * should be able to present different client certificates
-         * (because the commonName field in a client cert contains
-         * the client IP address, which is different for IPv4 and
-         * IPv6).  At the moment we only have a single client
-         * certificate, and no way to specify what address family
-         * that certificate belongs to.
-         */
-        for (r = res; r; r = r->ai_next) {
-            int no_slow_start = 1;
-
-            priv->sock = socket (r->ai_family, SOCK_STREAM, 0);
-            if (priv->sock == -1) {
-                saved_errno = errno;
-                continue;
-            }
-
-            /* Disable Nagle - Dan Berrange. */
-            setsockopt (priv->sock,
-                        IPPROTO_TCP, TCP_NODELAY, (void *)&no_slow_start,
-                        sizeof no_slow_start);
-
-            if (connect (priv->sock, r->ai_addr, r->ai_addrlen) == -1) {
-                saved_errno = errno;
-                VIR_FORCE_CLOSE(priv->sock);
-                continue;
-            }
-
-            if (priv->uses_tls) {
-                priv->session =
-                    negotiate_gnutls_on_connection
-                      (conn, priv, no_verify);
-                if (!priv->session) {
-                    VIR_FORCE_CLOSE(priv->sock);
-                    goto failed;
-                }
-            }
-            goto tcp_connected;
+        if (priv->tls) {
+            VIR_DEBUG0("Starting TLS session");
+            if (virNetClientSetTLSSession(priv->client, priv->tls) < 0)
+                goto failed;
         }
 
-        freeaddrinfo (res);
-        virReportSystemError(saved_errno,
-                             _("unable to connect to libvirtd at '%s'"),
-                             priv->hostname);
-        goto failed;
-
-       tcp_connected:
-        freeaddrinfo (res);
-
-        // NB. All versioning is done by the RPC headers, so we don't
-        // need to worry (at this point anyway) about versioning.
         break;
-    }
 
 #ifndef WIN32
-    case trans_unix: {
+    case trans_unix:
         if (!sockname) {
             if (flags & VIR_DRV_OPEN_REMOTE_USER) {
                 char *userdir = virGetUserDirectory(getuid());
@@ -676,153 +511,57 @@ doRemoteOpen (virConnectPtr conn,
                 VIR_FREE(userdir);
             } else {
                 if (flags & VIR_DRV_OPEN_REMOTE_RO)
-                    sockname = strdup (LIBVIRTD_PRIV_UNIX_SOCKET_RO);
+                    sockname = strdup(LIBVIRTD_PRIV_UNIX_SOCKET_RO);
                 else
-                    sockname = strdup (LIBVIRTD_PRIV_UNIX_SOCKET);
+                    sockname = strdup(LIBVIRTD_PRIV_UNIX_SOCKET);
                 if (sockname == NULL)
                     goto out_of_memory;
             }
+            VIR_DEBUG("Proceeding with sockname %s", sockname);
         }
 
-# ifndef UNIX_PATH_MAX
-#  define UNIX_PATH_MAX(addr) (sizeof (addr).sun_path)
-# endif
-        struct sockaddr_un addr;
-        int trials = 0;
-
-        memset (&addr, 0, sizeof addr);
-        addr.sun_family = AF_UNIX;
-        if (virStrcpyStatic(addr.sun_path, sockname) == NULL) {
-            remoteError(VIR_ERR_INTERNAL_ERROR,
-                        _("Socket %s too big for destination"), sockname);
-            goto failed;
-        }
-        if (addr.sun_path[0] == '@')
-            addr.sun_path[0] = '\0';
-
-      autostart_retry:
-        priv->is_secure = 1;
-        priv->sock = socket (AF_UNIX, SOCK_STREAM, 0);
-        if (priv->sock == -1) {
-            virReportSystemError(errno, "%s",
-                                 _("unable to create socket"));
-            goto failed;
-        }
-        if (connect (priv->sock, (struct sockaddr *) &addr, sizeof addr) == -1) {
-            /* We might have to autostart the daemon in some cases....
-             * It takes a short while for the daemon to startup, hence we
-             * have a number of retries, with a small sleep. This will
-             * sometimes cause multiple daemons to be started - this is
-             * ok because the duplicates will fail to bind to the socket
-             * and immediately exit, leaving just one daemon.
-             */
-            if (errno == ECONNREFUSED &&
-                flags & VIR_DRV_OPEN_REMOTE_AUTOSTART &&
-                trials < 20) {
-                VIR_FORCE_CLOSE(priv->sock);
-                if (trials > 0 ||
-                    remoteForkDaemon() == 0) {
-                    trials++;
-                    usleep(1000 * 100 * trials);
-                    goto autostart_retry;
-                }
-            }
-            virReportSystemError(errno,
-              _("unable to connect to '%s', libvirtd may need to be started"),
-              sockname);
+        if (!(priv->client = virNetClientNewUNIX(sockname,
+                                                 flags & VIR_DRV_OPEN_REMOTE_AUTOSTART,
+                                                 remoteFindDaemonPath())))
             goto failed;
-        }
 
         break;
-    }
-
-    case trans_ssh: {
-        int j, nr_args = 6;
-
-        if (username) nr_args += 2; /* For -l username */
-        if (no_tty) nr_args += 5;   /* For -T -o BatchMode=yes -e none */
-        if (port) nr_args += 2;     /* For -p port */
 
+    case trans_ssh:
         command = command ? command : strdup ("ssh");
         if (command == NULL)
             goto out_of_memory;
 
-        // Generate the final command argv[] array.
-        //   ssh [-p $port] [-l $username] $hostname $netcat -U $sockname [NULL]
-        if (VIR_ALLOC_N(cmd_argv, nr_args) < 0)
-            goto out_of_memory;
-
-        j = 0;
-        cmd_argv[j++] = strdup (command);
-        if (port) {
-            cmd_argv[j++] = strdup ("-p");
-            cmd_argv[j++] = strdup (port);
-        }
-        if (username) {
-            cmd_argv[j++] = strdup ("-l");
-            cmd_argv[j++] = strdup (username);
-        }
-        if (no_tty) {
-            cmd_argv[j++] = strdup ("-T");
-            cmd_argv[j++] = strdup ("-o");
-            cmd_argv[j++] = strdup ("BatchMode=yes");
-            cmd_argv[j++] = strdup ("-e");
-            cmd_argv[j++] = strdup ("none");
-        }
-        cmd_argv[j++] = strdup (priv->hostname);
-        cmd_argv[j++] = strdup (netcat ? netcat : "nc");
-        cmd_argv[j++] = strdup ("-U");
-        cmd_argv[j++] = strdup (sockname ? sockname :
-                                (flags & VIR_CONNECT_RO
-                                 ? LIBVIRTD_PRIV_UNIX_SOCKET_RO
-                                 : LIBVIRTD_PRIV_UNIX_SOCKET));
-        cmd_argv[j++] = 0;
-        assert (j == nr_args);
-        for (j = 0; j < (nr_args-1); j++)
-            if (cmd_argv[j] == NULL)
+        if (!sockname) {
+            if (flags & VIR_DRV_OPEN_REMOTE_RO)
+                sockname = strdup(LIBVIRTD_PRIV_UNIX_SOCKET_RO);
+            else
+                sockname = strdup(LIBVIRTD_PRIV_UNIX_SOCKET);
+            if (sockname == NULL)
                 goto out_of_memory;
-
-        priv->is_secure = 1;
-    }
-
-        /*FALLTHROUGH*/
-    case trans_ext: {
-        pid_t pid;
-        int sv[2];
-        int errfd[2];
-
-        /* Fork off the external process.  Use socketpair to create a private
-         * (unnamed) Unix domain socket to the child process so we don't have
-         * to faff around with two file descriptors (a la 'pipe(2)').
-         */
-        if (socketpair (PF_UNIX, SOCK_STREAM, 0, sv) == -1) {
-            virReportSystemError(errno, "%s",
-                                 _("unable to create socket pair"));
-            goto failed;
         }
 
-        if (pipe(errfd) == -1) {
-            virReportSystemError(errno, "%s",
-                                 _("unable to create socket pair"));
+        if (!(priv->client = virNetClientNewSSH(priv->hostname,
+                                                port,
+                                                command,
+                                                username,
+                                                no_tty,
+                                                netcat ? netcat : "nc",
+                                                sockname)))
             goto failed;
-        }
 
-        if (virExec((const char**)cmd_argv, NULL, NULL,
-                    &pid, sv[1], &(sv[1]), &(errfd[1]),
-                    VIR_EXEC_CLEAR_CAPS) < 0)
-            goto failed;
+        priv->is_secure = 1;
+        break;
 
-        /* Parent continues here. */
-        VIR_FORCE_CLOSE(sv[1]);
-        VIR_FORCE_CLOSE(errfd[1]);
-        priv->sock = sv[0];
-        priv->errfd = errfd[0];
-        priv->pid = pid;
+    case trans_ext:
+        if (!(priv->client = virNetClientNewCommand((const char **)cmd_argv, NULL)))
+            goto failed;
 
         /* Do not set 'is_secure' flag since we can't guarentee
          * an external program is secure, and this flag must be
          * pessimistic */
-    }
+        break;
+
 #else /* WIN32 */
 
     case trans_unix:
@@ -834,36 +573,32 @@ doRemoteOpen (virConnectPtr conn,
         goto failed;
 
 #endif /* WIN32 */
-
     } /* switch (transport) */
 
-    if (virSetNonBlock(priv->sock) < 0) {
-        virReportSystemError(errno, "%s",
-                             _("unable to make socket non-blocking"));
-        goto failed;
-    }
-
-    if ((priv->errfd != -1) && virSetNonBlock(priv->errfd) < 0) {
-        virReportSystemError(errno, "%s",
-                             _("unable to make socket non-blocking"));
+    if (!(priv->remoteProgram = virNetClientProgramNew(REMOTE_PROGRAM,
+                                                       REMOTE_PROTOCOL_VERSION,
+                                                       remoteDomainEvents,
+                                                       ARRAY_CARDINALITY(remoteDomainEvents),
+                                                       conn,
+                                                       NULL)))
         goto failed;
-    }
-
-    if (pipe(wakeupFD) < 0) {
-        virReportSystemError(errno, "%s",
-                             _("unable to make pipe"));
+    if (!(priv->qemuProgram = virNetClientProgramNew(QEMU_PROGRAM,
+                                                     QEMU_PROTOCOL_VERSION,
+                                                     NULL,
+                                                     0,
+                                                     NULL,
+                                                     NULL)))
         goto failed;
-    }
-    priv->wakeupReadFD = wakeupFD[0];
-    priv->wakeupSendFD = wakeupFD[1];
 
     /* Try and authenticate with server */
+    VIR_DEBUG0("Trying authentication");
     if (remoteAuthenticate(conn, priv, 1, auth, authtype) == -1)
         goto failed;
 
     /* Finally we can call the remote side's open function. */
     remote_open_args args = { &name, flags };
 
+    VIR_DEBUG("Trying to open URI %s", name);
     if (call (conn, priv, REMOTE_CALL_IN_OPEN, REMOTE_PROC_OPEN,
               (xdrproc_t) xdr_remote_open_args, (char *) &args,
               (xdrproc_t) xdr_void, (char *) NULL) == -1)
@@ -874,6 +609,7 @@ doRemoteOpen (virConnectPtr conn,
         remote_get_uri_ret uriret;
         int urierr;
 
+        VIR_DEBUG0("Trying to query remote URI");
         memset (&uriret, 0, sizeof uriret);
         urierr = call (conn, priv,
                        REMOTE_CALL_IN_OPEN | REMOTE_CALL_QUIET_MISSING_RPC,
@@ -902,36 +638,23 @@ doRemoteOpen (virConnectPtr conn,
         }
     }
 
-    if(VIR_ALLOC(priv->callbackList)<0) {
+    if (VIR_ALLOC(priv->callbackList)<0) {
         virReportOOMError();
         goto failed;
     }
 
-    if(VIR_ALLOC(priv->domainEvents)<0) {
+    if (VIR_ALLOC(priv->domainEvents)<0) {
         virReportOOMError();
         goto failed;
     }
 
-    DEBUG0("Adding Handler for remote events");
-    /* Set up a callback to listen on the socket data */
-    if ((priv->watch = virEventAddHandle(priv->sock,
-                                         VIR_EVENT_HANDLE_READABLE,
-                                         remoteDomainEventFired,
-                                         conn, NULL)) < 0) {
-        DEBUG0("virEventAddHandle failed: No addHandleImpl defined."
-               " continuing without events.");
-    } else {
-
-        DEBUG0("Adding Timeout for remote event queue flushing");
-        if ( (priv->eventFlushTimer = virEventAddTimeout(-1,
-                                                         remoteDomainEventQueueFlush,
-                                                         conn, NULL)) < 0) {
-            DEBUG0("virEventAddTimeout failed: No addTimeoutImpl defined. "
-                    "continuing without events.");
-            virEventRemoveHandle(priv->watch);
-            priv->watch = -1;
-        }
+    DEBUG0("Adding Timeout for remote event queue flushing");
+    if ((priv->eventFlushTimer = virEventAddTimeout(-1,
+                                                    remoteDomainEventQueueFlush,
+                                                    conn, NULL)) < 0) {
+        DEBUG0("Failed to add timer for dispatching events, disabling events");
     }
+
     /* Successful. */
     retcode = VIR_DRV_OPEN_SUCCESS;
 
@@ -961,30 +684,8 @@ doRemoteOpen (virConnectPtr conn,
         free_qparam_set (vars);
 
  failed:
-    /* Close the socket if we failed. */
-    VIR_FORCE_CLOSE(priv->errfd);
-
-    if (priv->sock >= 0) {
-        if (priv->uses_tls && priv->session) {
-            gnutls_bye (priv->session, GNUTLS_SHUT_RDWR);
-            gnutls_deinit (priv->session);
-        }
-        VIR_FORCE_CLOSE(priv->sock);
-#ifndef WIN32
-        if (priv->pid > 0) {
-            pid_t reap;
-            do {
-retry:
-                reap = waitpid(priv->pid, NULL, 0);
-                if (reap == -1 && errno == EINTR)
-                    goto retry;
-            } while (reap != -1 && reap != priv->pid);
-        }
-#endif
-    }
-
-    VIR_FORCE_CLOSE(wakeupFD[0]);
-    VIR_FORCE_CLOSE(wakeupFD[1]);
+    virNetClientFree(priv->client);
+    priv->client = NULL;
 
     VIR_FREE(priv->hostname);
     goto cleanup;
@@ -1008,8 +709,6 @@ remoteAllocPrivateData(void)
     remoteDriverLock(priv);
     priv->localUses = 1;
     priv->watch = -1;
-    priv->sock = -1;
-    priv->errfd = -1;
 
     return priv;
 }
@@ -1121,435 +820,98 @@ get_transport_from_scheme (char *scheme)
     return p ? p+1 : 0;
 }
 
-/* GnuTLS functions used by remoteOpen. */
-static gnutls_certificate_credentials_t x509_cred;
-
-
-static int
-check_cert_file(const char *type, const char *file)
-{
-    struct stat sb;
-    if (stat(file, &sb) < 0) {
-        virReportSystemError(errno,
-                             _("Cannot access %s '%s'"),
-                             type, file);
-        return -1;
-    }
-    return 0;
-}
-
+/*----------------------------------------------------------------------*/
 
-static void remote_debug_gnutls_log(int level, const char* str) {
-    DEBUG("%d %s", level, str);
-}
 
 static int
-initialize_gnutls(void)
+doRemoteClose (virConnectPtr conn, struct private_data *priv)
 {
-    static int initialized = 0;
-    int err;
-    char *gnutlsdebug;
-
-    if (initialized) return 0;
-
-    gnutls_global_init ();
-
-    if ((gnutlsdebug = getenv("LIBVIRT_GNUTLS_DEBUG")) != NULL) {
-        int val;
-        if (virStrToLong_i(gnutlsdebug, NULL, 10, &val) < 0)
-            val = 10;
-        gnutls_global_set_log_level(val);
-        gnutls_global_set_log_function(remote_debug_gnutls_log);
-    }
-
-    /* X509 stuff */
-    err = gnutls_certificate_allocate_credentials (&x509_cred);
-    if (err) {
-        remoteError(VIR_ERR_GNUTLS_ERROR,
-                    _("unable to allocate TLS credentials: %s"),
-                    gnutls_strerror (err));
-        return -1;
+    if (priv->eventFlushTimer >= 0) {
+        /* Remove timeout */
+        virEventRemoveTimeout(priv->eventFlushTimer);
+        /* Remove handle for remote events */
+        virEventRemoveHandle(priv->watch);
+        priv->watch = -1;
     }
 
-
-    if (check_cert_file("CA certificate", LIBVIRT_CACERT) < 0)
-        return -1;
-    if (check_cert_file("client key", LIBVIRT_CLIENTKEY) < 0)
-        return -1;
-    if (check_cert_file("client certificate", LIBVIRT_CLIENTCERT) < 0)
+    if (call (conn, priv, 0, REMOTE_PROC_CLOSE,
+              (xdrproc_t) xdr_void, (char *) NULL,
+              (xdrproc_t) xdr_void, (char *) NULL) == -1)
         return -1;
 
-    /* Set the trusted CA cert. */
-    DEBUG("loading CA file %s", LIBVIRT_CACERT);
-    err =
-        gnutls_certificate_set_x509_trust_file (x509_cred, LIBVIRT_CACERT,
-                                                GNUTLS_X509_FMT_PEM);
-    if (err < 0) {
-        remoteError(VIR_ERR_GNUTLS_ERROR,
-                    _("unable to load CA certificate: %s"),
-                    gnutls_strerror (err));
-        return -1;
-    }
+    virNetTLSContextFree(priv->tls);
+    priv->tls = NULL;
+    virNetClientFree(priv->client);
+    priv->client = NULL;
+    virNetClientProgramFree(priv->remoteProgram);
+    virNetClientProgramFree(priv->qemuProgram);
+    priv->remoteProgram = priv->qemuProgram = NULL;
 
-    /* Set the client certificate and private key. */
-    DEBUG("loading client cert and key from files %s and %s",
-          LIBVIRT_CLIENTCERT, LIBVIRT_CLIENTKEY);
-    err =
-        gnutls_certificate_set_x509_key_file (x509_cred,
-                                              LIBVIRT_CLIENTCERT,
-                                              LIBVIRT_CLIENTKEY,
-                                              GNUTLS_X509_FMT_PEM);
-    if (err < 0) {
-        remoteError(VIR_ERR_GNUTLS_ERROR,
-                    _("unable to load private key/certificate: %s"),
-                    gnutls_strerror (err));
-        return -1;
-    }
+    /* Free hostname copy */
+    VIR_FREE(priv->hostname);
 
-    initialized = 1;
-    return 0;
-}
+    /* See comment for remoteType. */
+    VIR_FREE(priv->type);
 
-static int verify_certificate (virConnectPtr conn, struct private_data *priv, gnutls_session_t session);
+    /* Free callback list */
+    virDomainEventCallbackListFree(priv->callbackList);
 
-#if HAVE_WINSOCK2_H
-static ssize_t
-custom_gnutls_push(void *s, const void *buf, size_t len)
-{
-    return send((size_t)s, buf, len, 0);
-}
+    /* Free queued events */
+    virDomainEventQueueFree(priv->domainEvents);
 
-static ssize_t
-custom_gnutls_pull(void *s, void *buf, size_t len)
-{
-    return recv((size_t)s, buf, len, 0);
+    return 0;
 }
-#endif
 
-static gnutls_session_t
-negotiate_gnutls_on_connection (virConnectPtr conn,
-                                struct private_data *priv,
-                                int no_verify)
+static int
+remoteClose (virConnectPtr conn)
 {
-    const int cert_type_priority[3] = {
-        GNUTLS_CRT_X509,
-        GNUTLS_CRT_OPENPGP,
-        0
-    };
-    int err;
-    gnutls_session_t session;
-
-    /* Initialize TLS session
-     */
-    err = gnutls_init (&session, GNUTLS_CLIENT);
-    if (err) {
-        remoteError(VIR_ERR_GNUTLS_ERROR,
-                    _("unable to initialize TLS client: %s"),
-                    gnutls_strerror (err));
-        return NULL;
-    }
+    int ret = 0;
+    struct private_data *priv = conn->privateData;
 
-    /* Use default priorities */
-    err = gnutls_set_default_priority (session);
-    if (err) {
-        remoteError(VIR_ERR_GNUTLS_ERROR,
-                    _("unable to set TLS algorithm priority: %s"),
-                    gnutls_strerror (err));
-        return NULL;
-    }
-    err =
-        gnutls_certificate_type_set_priority (session,
-                                              cert_type_priority);
-    if (err) {
-        remoteError(VIR_ERR_GNUTLS_ERROR,
-                    _("unable to set certificate priority: %s"),
-                    gnutls_strerror (err));
-        return NULL;
+    remoteDriverLock(priv);
+    priv->localUses--;
+    if (!priv->localUses) {
+        ret = doRemoteClose(conn, priv);
+        conn->privateData = NULL;
+        remoteDriverUnlock(priv);
+        virMutexDestroy(&priv->lock);
+        VIR_FREE (priv);
     }
+    if (priv)
+        remoteDriverUnlock(priv);
 
-    /* put the x509 credentials to the current session
-     */
-    err = gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, x509_cred);
-    if (err) {
-        remoteError(VIR_ERR_GNUTLS_ERROR,
-                    _("unable to set session credentials: %s"),
-                    gnutls_strerror (err));
-        return NULL;
-    }
+    return ret;
+}
 
-    gnutls_transport_set_ptr (session,
-                              (gnutls_transport_ptr_t) (long) priv->sock);
+static int
+remoteSupportsFeature (virConnectPtr conn, int feature)
+{
+    int rv = -1;
+    remote_supports_feature_args args;
+    remote_supports_feature_ret ret;
+    struct private_data *priv = conn->privateData;
 
-#if HAVE_WINSOCK2_H
-    /* Make sure GnuTLS uses gnulib's replacment functions for send() and
-     * recv() on Windows */
-    gnutls_transport_set_push_function(session, custom_gnutls_push);
-    gnutls_transport_set_pull_function(session, custom_gnutls_pull);
-#endif
+    remoteDriverLock(priv);
 
-    /* Perform the TLS handshake. */
- again:
-    err = gnutls_handshake (session);
-    if (err < 0) {
-        if (err == GNUTLS_E_AGAIN || err == GNUTLS_E_INTERRUPTED)
-            goto again;
-        remoteError(VIR_ERR_GNUTLS_ERROR,
-                    _("unable to complete TLS handshake: %s"),
-                    gnutls_strerror (err));
-        return NULL;
+    /* VIR_DRV_FEATURE_REMOTE* features are handled directly. */
+    if (feature == VIR_DRV_FEATURE_REMOTE) {
+        rv = 1;
+        goto done;
     }
 
-    /* Verify certificate. */
-    if (verify_certificate (conn, priv, session) == -1) {
-        DEBUG0("failed to verify peer's certificate");
-        if (!no_verify) return NULL;
-    }
+    args.feature = feature;
 
-    /* At this point, the server is verifying _our_ certificate, IP address,
-     * etc.  If we make the grade, it will send us a '\1' byte.
-     */
-    char buf[1];
-    int len;
- again_2:
-    len = gnutls_record_recv (session, buf, 1);
-    if (len < 0 && len != GNUTLS_E_UNEXPECTED_PACKET_LENGTH) {
-        if (len == GNUTLS_E_AGAIN || len == GNUTLS_E_INTERRUPTED)
-            goto again_2;
-        remoteError(VIR_ERR_GNUTLS_ERROR,
-                    _("unable to complete TLS initialization: %s"),
-                    gnutls_strerror (len));
-        return NULL;
-    }
-    if (len != 1 || buf[0] != '\1') {
-        remoteError(VIR_ERR_RPC, "%s",
-                    _("server verification (of our certificate or IP "
-                      "address) failed"));
-        return NULL;
-    }
+    memset (&ret, 0, sizeof ret);
+    if (call (conn, priv, 0, REMOTE_PROC_SUPPORTS_FEATURE,
+              (xdrproc_t) xdr_remote_supports_feature_args, (char *) &args,
+              (xdrproc_t) xdr_remote_supports_feature_ret, (char *) &ret) == -1)
+        goto done;
 
-#if 0
-    /* Print session info. */
-    print_info (session);
-#endif
+    rv = ret.supported;
 
-    return session;
-}
-
-static int
-verify_certificate (virConnectPtr conn ATTRIBUTE_UNUSED,
-                    struct private_data *priv,
-                    gnutls_session_t session)
-{
-    int ret;
-    unsigned int status;
-    const gnutls_datum_t *certs;
-    unsigned int nCerts, i;
-    time_t now;
-
-    if ((ret = gnutls_certificate_verify_peers2 (session, &status)) < 0) {
-        remoteError(VIR_ERR_GNUTLS_ERROR,
-                    _("unable to verify server certificate: %s"),
-                    gnutls_strerror (ret));
-        return -1;
-    }
-
-    if ((now = time(NULL)) == ((time_t)-1)) {
-        virReportSystemError(errno, "%s",
-                             _("cannot get current time"));
-        return -1;
-    }
-
-    if (status != 0) {
-        const char *reason = _("Invalid certificate");
-
-        if (status & GNUTLS_CERT_INVALID)
-            reason = _("The certificate is not trusted.");
-
-        if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
-            reason = _("The certificate hasn't got a known issuer.");
-
-        if (status & GNUTLS_CERT_REVOKED)
-            reason = _("The certificate has been revoked.");
-
-#ifndef GNUTLS_1_0_COMPAT
-        if (status & GNUTLS_CERT_INSECURE_ALGORITHM)
-            reason = _("The certificate uses an insecure algorithm");
-#endif
-
-        remoteError(VIR_ERR_RPC,
-                    _("server certificate failed validation: %s"),
-                    reason);
-        return -1;
-    }
-
-    if (gnutls_certificate_type_get(session) != GNUTLS_CRT_X509) {
-        remoteError(VIR_ERR_RPC,  "%s",_("Certificate type is not X.509"));
-        return -1;
-    }
-
-    if (!(certs = gnutls_certificate_get_peers(session, &nCerts))) {
-        remoteError(VIR_ERR_RPC,  "%s",_("gnutls_certificate_get_peers failed"));
-        return -1;
-    }
-
-    for (i = 0 ; i < nCerts ; i++) {
-        gnutls_x509_crt_t cert;
-
-        ret = gnutls_x509_crt_init (&cert);
-        if (ret < 0) {
-            remoteError(VIR_ERR_GNUTLS_ERROR,
-                        _("unable to initialize certificate: %s"),
-                        gnutls_strerror (ret));
-            return -1;
-        }
-
-        ret = gnutls_x509_crt_import (cert, &certs[i], GNUTLS_X509_FMT_DER);
-        if (ret < 0) {
-            remoteError(VIR_ERR_GNUTLS_ERROR,
-                        _("unable to import certificate: %s"),
-                        gnutls_strerror (ret));
-            gnutls_x509_crt_deinit (cert);
-            return -1;
-        }
-
-        if (gnutls_x509_crt_get_expiration_time (cert) < now) {
-            remoteError(VIR_ERR_RPC, "%s", _("The certificate has expired"));
-            gnutls_x509_crt_deinit (cert);
-            return -1;
-        }
-
-        if (gnutls_x509_crt_get_activation_time (cert) > now) {
-            remoteError(VIR_ERR_RPC, "%s",
-                        _("The certificate is not yet activated"));
-            gnutls_x509_crt_deinit (cert);
-            return -1;
-        }
-
-        if (i == 0) {
-            if (!gnutls_x509_crt_check_hostname (cert, priv->hostname)) {
-                remoteError(VIR_ERR_RPC,
-                            _("Certificate's owner does not match the hostname (%s)"),
-                            priv->hostname);
-                gnutls_x509_crt_deinit (cert);
-                return -1;
-            }
-        }
-    }
-
-    return 0;
-}
-
-/*----------------------------------------------------------------------*/
-
-
-static int
-doRemoteClose (virConnectPtr conn, struct private_data *priv)
-{
-    if (priv->eventFlushTimer >= 0) {
-        /* Remove timeout */
-        virEventRemoveTimeout(priv->eventFlushTimer);
-        /* Remove handle for remote events */
-        virEventRemoveHandle(priv->watch);
-        priv->watch = -1;
-    }
-
-    if (call (conn, priv, 0, REMOTE_PROC_CLOSE,
-              (xdrproc_t) xdr_void, (char *) NULL,
-              (xdrproc_t) xdr_void, (char *) NULL) == -1)
-        return -1;
-
-    /* Close socket. */
-    if (priv->uses_tls && priv->session) {
-        gnutls_bye (priv->session, GNUTLS_SHUT_RDWR);
-        gnutls_deinit (priv->session);
-    }
-#if HAVE_SASL
-    if (priv->saslconn)
-        sasl_dispose (&priv->saslconn);
-#endif
-    VIR_FORCE_CLOSE(priv->sock);
-    VIR_FORCE_CLOSE(priv->errfd);
-
-#ifndef WIN32
-    if (priv->pid > 0) {
-        pid_t reap;
-        do {
-retry:
-            reap = waitpid(priv->pid, NULL, 0);
-            if (reap == -1 && errno == EINTR)
-                goto retry;
-        } while (reap != -1 && reap != priv->pid);
-    }
-#endif
-    VIR_FORCE_CLOSE(priv->wakeupReadFD);
-    VIR_FORCE_CLOSE(priv->wakeupSendFD);
-
-
-    /* Free hostname copy */
-    VIR_FREE(priv->hostname);
-
-    /* See comment for remoteType. */
-    VIR_FREE(priv->type);
-
-    /* Free callback list */
-    virDomainEventCallbackListFree(priv->callbackList);
-
-    /* Free queued events */
-    virDomainEventQueueFree(priv->domainEvents);
-
-    return 0;
-}
-
-static int
-remoteClose (virConnectPtr conn)
-{
-    int ret = 0;
-    struct private_data *priv = conn->privateData;
-
-    remoteDriverLock(priv);
-    priv->localUses--;
-    if (!priv->localUses) {
-        ret = doRemoteClose(conn, priv);
-        conn->privateData = NULL;
-        remoteDriverUnlock(priv);
-        virMutexDestroy(&priv->lock);
-        VIR_FREE (priv);
-    }
-    if (priv)
-        remoteDriverUnlock(priv);
-
-    return ret;
-}
-
-static int
-remoteSupportsFeature (virConnectPtr conn, int feature)
-{
-    int rv = -1;
-    remote_supports_feature_args args;
-    remote_supports_feature_ret ret;
-    struct private_data *priv = conn->privateData;
-
-    remoteDriverLock(priv);
-
-    /* VIR_DRV_FEATURE_REMOTE* features are handled directly. */
-    if (feature == VIR_DRV_FEATURE_REMOTE) {
-        rv = 1;
-        goto done;
-    }
-
-    args.feature = feature;
-
-    memset (&ret, 0, sizeof ret);
-    if (call (conn, priv, 0, REMOTE_PROC_SUPPORTS_FEATURE,
-              (xdrproc_t) xdr_remote_supports_feature_args, (char *) &args,
-              (xdrproc_t) xdr_remote_supports_feature_ret, (char *) &ret) == -1)
-        goto done;
-
-    rv = ret.supported;
-
-done:
-    remoteDriverUnlock(priv);
-    return rv;
+done:
+    remoteDriverUnlock(priv);
+    return rv;
 }
 
 /* Unfortunately this function is defined to return a static string.
@@ -1701,13 +1063,8 @@ static int remoteIsEncrypted(virConnectPtr conn)
               (xdrproc_t) xdr_remote_is_secure_ret, (char *) &ret) == -1)
         goto done;
 
-    if (priv->uses_tls)
+    if (virNetClientIsEncrypted(priv->client))
         encrypted = 1;
-#if HAVE_SASL
-    else if (priv->saslconn)
-        encrypted = 1;
-#endif
-
 
     /* We claim to be encrypted, if the remote driver
      * transport itself is encrypted, and the remote
@@ -7103,8 +6460,6 @@ static int
 remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int in_open,
                 virConnectAuthPtr auth, const char *wantmech)
 {
-    sasl_conn_t *saslconn = NULL;
-    sasl_security_properties_t secprops;
     remote_auth_sasl_init_ret iret;
     remote_auth_sasl_start_args sargs;
     remote_auth_sasl_start_ret sret;
@@ -7112,49 +6467,19 @@ remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int in_open,
     remote_auth_sasl_step_ret pret;
     const char *clientout;
     char *serverin = NULL;
-    unsigned int clientoutlen, serverinlen;
+    size_t clientoutlen, serverinlen;
     const char *mech;
     int err, complete;
-    virSocketAddr sa;
-    char *localAddr = NULL, *remoteAddr = NULL;
-    const void *val;
-    sasl_ssf_t ssf;
+    int ssf;
     sasl_callback_t *saslcb = NULL;
     sasl_interact_t *interact = NULL;
     virConnectCredentialPtr cred = NULL;
     int ncred = 0;
     int ret = -1;
     const char *mechlist;
+    virNetClientSaslContextPtr sasl;
 
     DEBUG0("Client initialize SASL authentication");
-    /* Sets up the SASL library as a whole */
-    err = sasl_client_init(NULL);
-    if (err != SASL_OK) {
-        remoteError(VIR_ERR_AUTH_FAILED,
-                    _("failed to initialize SASL library: %d (%s)"),
-                    err, sasl_errstring(err, NULL, NULL));
-        goto cleanup;
-    }
-
-    /* Get local address in form  IPADDR:PORT */
-    sa.len = sizeof(sa.data.stor);
-    if (getsockname(priv->sock, &sa.data.sa, &sa.len) < 0) {
-        virReportSystemError(errno, "%s",
-                             _("failed to get sock address"));
-        goto cleanup;
-    }
-    if ((localAddr = virSocketFormatAddrFull(&sa, true, ";")) == NULL)
-        goto cleanup;
-
-    /* Get remote address in form  IPADDR:PORT */
-    sa.len = sizeof(sa.data.stor);
-    if (getpeername(priv->sock, &sa.data.sa, &sa.len) < 0) {
-        virReportSystemError(errno, "%s",
-                             _("failed to get peer address"));
-        goto cleanup;
-    }
-    if ((remoteAddr = virSocketFormatAddrFull(&sa, true, ";")) == NULL)
-        goto cleanup;
 
     if (auth) {
         if ((saslcb = remoteAuthMakeCallbacks(auth->credtype, auth->ncredtype)) == NULL)
@@ -7164,59 +6489,32 @@ remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int in_open,
     }
 
     /* Setup a handle for being a client */
-    err = sasl_client_new("libvirt",
-                          priv->hostname,
-                          localAddr,
-                          remoteAddr,
-                          saslcb,
-                          SASL_SUCCESS_DATA,
-                          &saslconn);
-
-    if (err != SASL_OK) {
-        remoteError(VIR_ERR_AUTH_FAILED,
-                    _("Failed to create SASL client context: %d (%s)"),
-                    err, sasl_errstring(err, NULL, NULL));
+    if (!(sasl = virNetClientSaslContextNew("libvirt",
+                                            priv->hostname,
+                                            virNetClientLocalAddrString(priv->client),
+                                            virNetClientRemoteAddrString(priv->client),
+                                            saslcb)))
         goto cleanup;
-    }
 
     /* Initialize some connection props we care about */
-    if (priv->uses_tls) {
-        gnutls_cipher_algorithm_t cipher;
-
-        cipher = gnutls_cipher_get(priv->session);
-        if (!(ssf = (sasl_ssf_t)gnutls_cipher_get_key_size(cipher))) {
-            remoteError(VIR_ERR_INTERNAL_ERROR, "%s",
-                        _("invalid cipher size for TLS session"));
+    if (priv->tls) {
+        if ((ssf = virNetClientGetTLSKeySize(priv->client)) < 0)
             goto cleanup;
-        }
+
         ssf *= 8; /* key size is bytes, sasl wants bits */
 
         DEBUG("Setting external SSF %d", ssf);
-        err = sasl_setprop(saslconn, SASL_SSF_EXTERNAL, &ssf);
-        if (err != SASL_OK) {
-            remoteError(VIR_ERR_INTERNAL_ERROR,
-                        _("cannot set external SSF %d (%s)"),
-                        err, sasl_errstring(err, NULL, NULL));
+        if (virNetClientSaslContextExtKeySize(sasl, ssf) < 0)
             goto cleanup;
-        }
     }
 
-    memset (&secprops, 0, sizeof secprops);
     /* If we've got a secure channel (TLS or UNIX sock), we don't care about SSF */
-    secprops.min_ssf = priv->is_secure ? 0 : 56; /* Equiv to DES supported by all Kerberos */
-    secprops.max_ssf = priv->is_secure ? 0 : 100000; /* Very strong ! AES == 256 */
-    secprops.maxbufsize = 100000;
     /* If we're not secure, then forbid any anonymous or trivially crackable auth */
-    secprops.security_flags = priv->is_secure ? 0 :
-        SASL_SEC_NOANONYMOUS | SASL_SEC_NOPLAINTEXT;
-
-    err = sasl_setprop(saslconn, SASL_SEC_PROPS, &secprops);
-    if (err != SASL_OK) {
-        remoteError(VIR_ERR_INTERNAL_ERROR,
-                    _("cannot set security props %d (%s)"),
-                    err, sasl_errstring(err, NULL, NULL));
+    if (virNetClientSaslContextSecProps(sasl,
+                                        priv->is_secure ? 0 : 56, /* Equiv to DES supported by all Kerberos */
+                                        priv->is_secure ? 0 : 100000, /* Very strong ! AES == 256 */
+                                        priv->is_secure ? true : false) < 0)
         goto cleanup;
-    }
 
     /* First call is to inquire about supported mechanisms in the server */
     memset (&iret, 0, sizeof iret);
@@ -7240,22 +6538,16 @@ remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int in_open,
  restart:
     /* Start the auth negotiation on the client end first */
     DEBUG("Client start negotiation mechlist '%s'", mechlist);
-    err = sasl_client_start(saslconn,
-                            mechlist,
-                            &interact,
-                            &clientout,
-                            &clientoutlen,
-                            &mech);
-    if (err != SASL_OK && err != SASL_CONTINUE && err != SASL_INTERACT) {
-        remoteError(VIR_ERR_AUTH_FAILED,
-                    _("Failed to start SASL negotiation: %d (%s)"),
-                    err, sasl_errdetail(saslconn));
-        VIR_FREE(iret.mechlist);
+    if ((err = virNetClientSaslContextStart(sasl,
+                                            mechlist,
+                                            &interact,
+                                            &clientout,
+                                            &clientoutlen,
+                                            &mech)) < 0)
         goto cleanup;
-    }
 
     /* Need to gather some credentials from the client */
-    if (err == SASL_INTERACT) {
+    if (err == VIR_NET_CLIENT_SASL_INTERACT) {
         const char *msg;
         if (cred) {
             remoteAuthFreeCredentials(cred, ncred);
@@ -7285,7 +6577,7 @@ remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int in_open,
     if (clientoutlen > REMOTE_AUTH_SASL_DATA_MAX) {
         remoteError(VIR_ERR_AUTH_FAILED,
                     _("SASL negotiation data too long: %d bytes"),
-                    clientoutlen);
+                    (int)clientoutlen);
         goto cleanup;
     }
     /* NB, distinction of NULL vs "" is *critical* in SASL */
@@ -7294,7 +6586,8 @@ remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int in_open,
     sargs.data.data_val = (char*)clientout;
     sargs.data.data_len = clientoutlen;
     sargs.mech = (char*)mech;
-    DEBUG("Server start negotiation with mech %s. Data %d bytes %p", mech, clientoutlen, clientout);
+    DEBUG("Server start negotiation with mech %s. Data %d bytes %p",
+          mech, (int)clientoutlen, clientout);
 
     /* Now send the initial auth data to the server */
     memset (&sret, 0, sizeof sret);
@@ -7308,27 +6601,23 @@ remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int in_open,
     serverin = sret.nil ? NULL : sret.data.data_val;
     serverinlen = sret.data.data_len;
     DEBUG("Client step result complete: %d. Data %d bytes %p",
-          complete, serverinlen, serverin);
+          complete, (int)serverinlen, serverin);
 
     /* Loop-the-loop...
      * Even if the server has completed, the client must *always* do at least one step
      * in this loop to verify the server isn't lying about something. Mutual auth */
     for (;;) {
     restep:
-        err = sasl_client_step(saslconn,
-                               serverin,
-                               serverinlen,
-                               &interact,
-                               &clientout,
-                               &clientoutlen);
-        if (err != SASL_OK && err != SASL_CONTINUE && err != SASL_INTERACT) {
-            remoteError(VIR_ERR_AUTH_FAILED,
-                        _("Failed SASL step: %d (%s)"),
-                        err, sasl_errdetail(saslconn));
+        if ((err = virNetClientSaslContextStep(sasl,
+                                               serverin,
+                                               serverinlen,
+                                               &interact,
+                                               &clientout,
+                                               &clientoutlen)) < 0)
             goto cleanup;
-        }
+
         /* Need to gather some credentials from the client */
-        if (err == SASL_INTERACT) {
+        if (err == VIR_NET_CLIENT_SASL_INTERACT) {
             const char *msg;
             if (cred) {
                 remoteAuthFreeCredentials(cred, ncred);
@@ -7354,10 +6643,11 @@ remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int in_open,
         }
 
         VIR_FREE(serverin);
-        DEBUG("Client step result %d. Data %d bytes %p", err, clientoutlen, clientout);
+        DEBUG("Client step result %d. Data %d bytes %p",
+              err, (int)clientoutlen, clientout);
 
         /* Previous server call showed completion & we're now locally complete too */
-        if (complete && err == SASL_OK)
+        if (complete && err == VIR_NET_CLIENT_SASL_COMPLETE)
             break;
 
         /* Not done, prepare to talk with the server for another iteration */
@@ -7366,7 +6656,8 @@ remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int in_open,
         pargs.nil = clientout ? 0 : 1;
         pargs.data.data_val = (char*)clientout;
         pargs.data.data_len = clientoutlen;
-        DEBUG("Server step with %d bytes %p", clientoutlen, clientout);
+        DEBUG("Server step with %d bytes %p",
+              (int)clientoutlen, clientout);
 
         memset (&pret, 0, sizeof pret);
         if (call (conn, priv, in_open, REMOTE_PROC_AUTH_SASL_STEP,
@@ -7380,10 +6671,10 @@ remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int in_open,
         serverinlen = pret.data.data_len;
 
         DEBUG("Client step result complete: %d. Data %d bytes %p",
-              complete, serverinlen, serverin);
+              complete, (int)serverinlen, serverin);
 
         /* This server call shows complete, and earlier client step was OK */
-        if (complete && err == SASL_OK) {
+        if (complete && err == VIR_NET_CLIENT_SASL_COMPLETE) {
             VIR_FREE(serverin);
             break;
         }
@@ -7391,14 +6682,9 @@ remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int in_open,
 
     /* Check for suitable SSF if not already secure (TLS or UNIX sock) */
     if (!priv->is_secure) {
-        err = sasl_getprop(saslconn, SASL_SSF, &val);
-        if (err != SASL_OK) {
-            remoteError(VIR_ERR_AUTH_FAILED,
-                        _("cannot query SASL ssf on connection %d (%s)"),
-                        err, sasl_errstring(err, NULL, NULL));
+        if ((ssf = virNetClientSaslContextGetKeySize(sasl)) < 0)
             goto cleanup;
-        }
-        ssf = *(const int *)val;
+
         DEBUG("SASL SSF value %d", ssf);
         if (ssf < 56) { /* 56 == DES level, good for Kerberos */
             remoteError(VIR_ERR_AUTH_FAILED,
@@ -7409,18 +6695,15 @@ remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int in_open,
     }
 
     DEBUG0("SASL authentication complete");
-    priv->saslconn = saslconn;
+    virNetClientSetSASLContext(priv->client, sasl);
     ret = 0;
 
  cleanup:
-    VIR_FREE(localAddr);
-    VIR_FREE(remoteAddr);
     VIR_FREE(serverin);
 
     VIR_FREE(saslcb);
     remoteAuthFreeCredentials(cred, ncred);
-    if (ret != 0 && saslconn)
-        sasl_dispose(&saslconn);
+    virNetClientSaslContextFree(sasl);
 
     return ret;
 }
@@ -7573,184 +6856,187 @@ done:
     return rv;
 }
 
+
+static int remoteDomainEventQueuePush(struct private_data *priv,
+                                      virDomainEventPtr event)
+{
+    int ret = -1;
+    remoteDriverLock(priv);
+
+    if (virDomainEventQueuePush(priv->domainEvents,
+                                event) < 0) {
+        DEBUG0("Error adding event to queue");
+        goto cleanup;
+    }
+
+    ret = 0;
+    virEventUpdateTimeout(priv->eventFlushTimer, 0);
+
+cleanup:
+    remoteDriverUnlock(priv);
+    return ret;
+}
+
+
 /**
  * remoteDomainReadEventLifecycle
  *
  * Read the domain lifecycle event data off the wire
  */
-static virDomainEventPtr
-remoteDomainReadEventLifecycle(virConnectPtr conn, XDR *xdr)
+static void
+remoteDomainBuildEventLifecycle(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
+                                virNetClientPtr client ATTRIBUTE_UNUSED,
+                                void *evdata, void *opaque)
 {
-    remote_domain_event_lifecycle_msg msg;
+    virConnectPtr conn = opaque;
+    struct private_data *priv = conn->privateData;
+    remote_domain_event_lifecycle_msg *msg = evdata;
     virDomainPtr dom;
     virDomainEventPtr event = NULL;
-    memset (&msg, 0, sizeof msg);
-
-    /* unmarshall parameters, and process it*/
-    if (! xdr_remote_domain_event_lifecycle_msg(xdr, &msg) ) {
-        remoteError(VIR_ERR_RPC, "%s",
-                    _("unable to demarshall lifecycle event"));
-        return NULL;
-    }
 
-    dom = get_nonnull_domain(conn,msg.dom);
+    dom = get_nonnull_domain(conn, msg->dom);
     if (!dom)
-        return NULL;
-
-    event = virDomainEventNewFromDom(dom, msg.event, msg.detail);
-    xdr_free ((xdrproc_t) &xdr_remote_domain_event_lifecycle_msg, (char *) &msg);
+        return;
 
+    event = virDomainEventNewFromDom(dom, msg->event, msg->detail);
     virDomainFree(dom);
-    return event;
+
+    if (remoteDomainEventQueuePush(priv, event) < 0)
+        virDomainEventFree(event);
 }
 
 
-static virDomainEventPtr
-remoteDomainReadEventReboot(virConnectPtr conn, XDR *xdr)
+static void
+remoteDomainBuildEventReboot(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
+                             virNetClientPtr client ATTRIBUTE_UNUSED,
+                             void *evdata, void *opaque)
 {
-    remote_domain_event_reboot_msg msg;
+    virConnectPtr conn = opaque;
+    struct private_data *priv = conn->privateData;
+    remote_domain_event_reboot_msg *msg = evdata;
     virDomainPtr dom;
     virDomainEventPtr event = NULL;
-    memset (&msg, 0, sizeof msg);
-
-    /* unmarshall parameters, and process it*/
-    if (! xdr_remote_domain_event_reboot_msg(xdr, &msg) ) {
-        remoteError(VIR_ERR_RPC, "%s",
-                    _("unable to demarshall reboot event"));
-        return NULL;
-    }
 
-    dom = get_nonnull_domain(conn,msg.dom);
+    dom = get_nonnull_domain(conn, msg->dom);
     if (!dom)
-        return NULL;
+        return;
 
     event = virDomainEventRebootNewFromDom(dom);
-    xdr_free ((xdrproc_t) &xdr_remote_domain_event_reboot_msg, (char *) &msg);
-
     virDomainFree(dom);
-    return event;
+
+    if (remoteDomainEventQueuePush(priv, event) < 0)
+        virDomainEventFree(event);
 }
 
 
-static virDomainEventPtr
-remoteDomainReadEventRTCChange(virConnectPtr conn, XDR *xdr)
+static void
+remoteDomainBuildEventRTCChange(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
+                                virNetClientPtr client ATTRIBUTE_UNUSED,
+                                void *evdata, void *opaque)
 {
-    remote_domain_event_rtc_change_msg msg;
+    virConnectPtr conn = opaque;
+    struct private_data *priv = conn->privateData;
+    remote_domain_event_rtc_change_msg *msg = evdata;
     virDomainPtr dom;
     virDomainEventPtr event = NULL;
-    memset (&msg, 0, sizeof msg);
-
-    /* unmarshall parameters, and process it*/
-    if (! xdr_remote_domain_event_rtc_change_msg(xdr, &msg) ) {
-        remoteError(VIR_ERR_RPC, "%s",
-                    _("unable to demarshall reboot event"));
-        return NULL;
-    }
 
-    dom = get_nonnull_domain(conn,msg.dom);
+    dom = get_nonnull_domain(conn, msg->dom);
     if (!dom)
-        return NULL;
-
-    event = virDomainEventRTCChangeNewFromDom(dom, msg.offset);
-    xdr_free ((xdrproc_t) &xdr_remote_domain_event_rtc_change_msg, (char *) &msg);
+        return;
 
+    event = virDomainEventRTCChangeNewFromDom(dom, msg->offset);
     virDomainFree(dom);
-    return event;
+
+    if (remoteDomainEventQueuePush(priv, event) < 0)
+        virDomainEventFree(event);
 }
 
 
-static virDomainEventPtr
-remoteDomainReadEventWatchdog(virConnectPtr conn, XDR *xdr)
+static void
+remoteDomainBuildEventWatchdog(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
+                               virNetClientPtr client ATTRIBUTE_UNUSED,
+                               void *evdata, void *opaque)
 {
-    remote_domain_event_watchdog_msg msg;
+    virConnectPtr conn = opaque;
+    struct private_data *priv = conn->privateData;
+    remote_domain_event_watchdog_msg *msg = evdata;
     virDomainPtr dom;
     virDomainEventPtr event = NULL;
-    memset (&msg, 0, sizeof msg);
-
-    /* unmarshall parameters, and process it*/
-    if (! xdr_remote_domain_event_watchdog_msg(xdr, &msg) ) {
-        remoteError(VIR_ERR_RPC, "%s",
-                    _("unable to demarshall reboot event"));
-        return NULL;
-    }
 
-    dom = get_nonnull_domain(conn,msg.dom);
+    dom = get_nonnull_domain(conn, msg->dom);
     if (!dom)
-        return NULL;
-
-    event = virDomainEventWatchdogNewFromDom(dom, msg.action);
-    xdr_free ((xdrproc_t) &xdr_remote_domain_event_watchdog_msg, (char *) &msg);
+        return;
 
+    event = virDomainEventWatchdogNewFromDom(dom, msg->action);
     virDomainFree(dom);
-    return event;
+
+    if (remoteDomainEventQueuePush(priv, event) < 0)
+        virDomainEventFree(event);
 }
 
 
-static virDomainEventPtr
-remoteDomainReadEventIOError(virConnectPtr conn, XDR *xdr)
+static void
+remoteDomainBuildEventIOError(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
+                              virNetClientPtr client ATTRIBUTE_UNUSED,
+                              void *evdata, void *opaque)
 {
-    remote_domain_event_io_error_msg msg;
+    virConnectPtr conn = opaque;
+    struct private_data *priv = conn->privateData;
+    remote_domain_event_io_error_msg *msg = evdata;
     virDomainPtr dom;
     virDomainEventPtr event = NULL;
-    memset (&msg, 0, sizeof msg);
-
-    /* unmarshall parameters, and process it*/
-    if (! xdr_remote_domain_event_io_error_msg(xdr, &msg) ) {
-        remoteError(VIR_ERR_RPC, "%s",
-                    _("unable to demarshall reboot event"));
-        return NULL;
-    }
 
-    dom = get_nonnull_domain(conn,msg.dom);
+    dom = get_nonnull_domain(conn, msg->dom);
     if (!dom)
-        return NULL;
+        return;
 
     event = virDomainEventIOErrorNewFromDom(dom,
-                                            msg.srcPath,
-                                            msg.devAlias,
-                                            msg.action);
-    xdr_free ((xdrproc_t) &xdr_remote_domain_event_io_error_msg, (char *) &msg);
-
+                                            msg->srcPath,
+                                            msg->devAlias,
+                                            msg->action);
     virDomainFree(dom);
-    return event;
+
+    if (remoteDomainEventQueuePush(priv, event) < 0)
+        virDomainEventFree(event);
 }
 
 
-static virDomainEventPtr
-remoteDomainReadEventIOErrorReason(virConnectPtr conn, XDR *xdr)
+static void
+remoteDomainBuildEventIOErrorReason(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
+                                    virNetClientPtr client ATTRIBUTE_UNUSED,
+                                    void *evdata, void *opaque)
 {
-    remote_domain_event_io_error_reason_msg msg;
-    virDomainPtr dom;
+    virConnectPtr conn = opaque;
+    struct private_data *priv = conn->privateData;
+    remote_domain_event_io_error_reason_msg *msg = evdata;
+    virDomainPtr dom;
     virDomainEventPtr event = NULL;
-    memset (&msg, 0, sizeof msg);
-
-    /* unmarshall parameters, and process it*/
-    if (! xdr_remote_domain_event_io_error_reason_msg(xdr, &msg) ) {
-        remoteError(VIR_ERR_RPC, "%s",
-                    _("unable to demarshall reboot event"));
-        return NULL;
-    }
 
-    dom = get_nonnull_domain(conn,msg.dom);
+    dom = get_nonnull_domain(conn,msg->dom);
     if (!dom)
-        return NULL;
+        return;
 
     event = virDomainEventIOErrorReasonNewFromDom(dom,
-                                                  msg.srcPath,
-                                                  msg.devAlias,
-                                                  msg.action,
-                                                  msg.reason);
-    xdr_free ((xdrproc_t) &xdr_remote_domain_event_io_error_reason_msg, (char *) &msg);
+                                                  msg->srcPath,
+                                                  msg->devAlias,
+                                                  msg->action,
+                                                  msg->reason);
 
     virDomainFree(dom);
-    return event;
+
+    if (remoteDomainEventQueuePush(priv, event) < 0)
+        virDomainEventFree(event);
 }
 
 
-static virDomainEventPtr
-remoteDomainReadEventGraphics(virConnectPtr conn, XDR *xdr)
+static void
+remoteDomainBuildEventGraphics(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
+                               virNetClientPtr client ATTRIBUTE_UNUSED,
+                               void *evdata, void *opaque)
 {
-    remote_domain_event_graphics_msg msg;
+    virConnectPtr conn = opaque;
+    struct private_data *priv = conn->privateData;
+    remote_domain_event_graphics_msg *msg = evdata;
     virDomainPtr dom;
     virDomainEventPtr event = NULL;
     virDomainEventGraphicsAddressPtr localAddr = NULL;
@@ -7758,58 +7044,49 @@ remoteDomainReadEventGraphics(virConnectPtr conn, XDR *xdr)
     virDomainEventGraphicsSubjectPtr subject = NULL;
     int i;
 
-    memset (&msg, 0, sizeof msg);
-
-    /* unmarshall parameters, and process it*/
-    if (! xdr_remote_domain_event_graphics_msg(xdr, &msg) ) {
-        remoteError(VIR_ERR_RPC, "%s",
-                    _("unable to demarshall reboot event"));
-        return NULL;
-    }
-
-    dom = get_nonnull_domain(conn,msg.dom);
+    dom = get_nonnull_domain(conn, msg->dom);
     if (!dom)
-        return NULL;
+        return;
 
     if (VIR_ALLOC(localAddr) < 0)
         goto no_memory;
-    localAddr->family = msg.local.family;
-    if (!(localAddr->service = strdup(msg.local.service)) ||
-        !(localAddr->node = strdup(msg.local.node)))
+    localAddr->family = msg->local.family;
+    if (!(localAddr->service = strdup(msg->local.service)) ||
+        !(localAddr->node = strdup(msg->local.node)))
         goto no_memory;
 
     if (VIR_ALLOC(remoteAddr) < 0)
         goto no_memory;
-    remoteAddr->family = msg.remote.family;
-    if (!(remoteAddr->service = strdup(msg.remote.service)) ||
-        !(remoteAddr->node = strdup(msg.remote.node)))
+    remoteAddr->family = msg->remote.family;
+    if (!(remoteAddr->service = strdup(msg->remote.service)) ||
+        !(remoteAddr->node = strdup(msg->remote.node)))
         goto no_memory;
 
     if (VIR_ALLOC(subject) < 0)
         goto no_memory;
-    if (VIR_ALLOC_N(subject->identities, msg.subject.subject_len) < 0)
+    if (VIR_ALLOC_N(subject->identities, msg->subject.subject_len) < 0)
         goto no_memory;
-    subject->nidentity = msg.subject.subject_len;
+    subject->nidentity = msg->subject.subject_len;
     for (i = 0 ; i < subject->nidentity ; i++) {
-        if (!(subject->identities[i].type = strdup(msg.subject.subject_val[i].type)) ||
-            !(subject->identities[i].name = strdup(msg.subject.subject_val[i].name)))
+        if (!(subject->identities[i].type = strdup(msg->subject.subject_val[i].type)) ||
+            !(subject->identities[i].name = strdup(msg->subject.subject_val[i].name)))
             goto no_memory;
     }
 
     event = virDomainEventGraphicsNewFromDom(dom,
-                                             msg.phase,
+                                             msg->phase,
                                              localAddr,
                                              remoteAddr,
-                                             msg.authScheme,
+                                             msg->authScheme,
                                              subject);
-    xdr_free ((xdrproc_t) &xdr_remote_domain_event_graphics_msg, (char *) &msg);
 
     virDomainFree(dom);
-    return event;
 
-no_memory:
-    xdr_free ((xdrproc_t) &xdr_remote_domain_event_graphics_msg, (char *) &msg);
+    if (remoteDomainEventQueuePush(priv, event) < 0)
+        virDomainEventFree(event);
+    return;
 
+no_memory:
     if (localAddr) {
         VIR_FREE(localAddr->service);
         VIR_FREE(localAddr->node);
@@ -7828,7 +7105,7 @@ no_memory:
         VIR_FREE(subject->identities);
         VIR_FREE(subject);
     }
-    return NULL;
+    return;
 }
 
 
@@ -8165,7 +7442,7 @@ done:
     return rv;
 }
 
-
+#if 0
 static struct private_stream_data *
 remoteStreamOpen(virStreamPtr st,
                  int output ATTRIBUTE_UNUSED,
@@ -8712,7 +7989,7 @@ done:
 
     return rv;
 }
-
+#endif
 
 static int
 remoteCPUCompare(virConnectPtr conn, const char *xmlDesc,
@@ -9244,7 +8521,7 @@ done:
     return rv;
 }
 
-
+#if 0
 static int
 remoteDomainOpenConsole(virDomainPtr dom,
                         const char *devname,
@@ -9283,6 +8560,7 @@ done:
     return rv;
 
 }
+#endif
 
 
 /*----------------------------------------------------------------------*/
@@ -9325,534 +8603,7 @@ done:
     return rv;
 }
 
-/*----------------------------------------------------------------------*/
-
-static struct remote_thread_call *
-prepareCall(struct private_data *priv,
-            int flags,
-            int proc_nr,
-            xdrproc_t args_filter, char *args,
-            xdrproc_t ret_filter, char *ret)
-{
-    XDR xdr;
-    struct remote_message_header hdr;
-    struct remote_thread_call *rv;
-
-    if (VIR_ALLOC(rv) < 0) {
-        virReportOOMError();
-        return NULL;
-    }
-
-    if (virCondInit(&rv->cond) < 0) {
-        VIR_FREE(rv);
-        remoteError(VIR_ERR_INTERNAL_ERROR, "%s",
-                    _("cannot initialize mutex"));
-        return NULL;
-    }
-
-    /* Get a unique serial number for this message. */
-    rv->serial = priv->counter++;
-    rv->proc_nr = proc_nr;
-    rv->ret_filter = ret_filter;
-    rv->ret = ret;
-    rv->want_reply = 1;
-
-    if (flags & REMOTE_CALL_QEMU) {
-        hdr.prog = QEMU_PROGRAM;
-        hdr.vers = QEMU_PROTOCOL_VERSION;
-    }
-    else {
-        hdr.prog = REMOTE_PROGRAM;
-        hdr.vers = REMOTE_PROTOCOL_VERSION;
-    }
-    hdr.proc = proc_nr;
-    hdr.type = REMOTE_CALL;
-    hdr.serial = rv->serial;
-    hdr.status = REMOTE_OK;
-
-    /* Serialise header followed by args. */
-    xdrmem_create (&xdr, rv->buffer+4, REMOTE_MESSAGE_MAX, XDR_ENCODE);
-    if (!xdr_remote_message_header (&xdr, &hdr)) {
-        remoteError(VIR_ERR_RPC, "%s", _("xdr_remote_message_header failed"));
-        goto error;
-    }
-
-    if (!(*args_filter) (&xdr, args)) {
-        remoteError(VIR_ERR_RPC, "%s", _("marshalling args"));
-        goto error;
-    }
-
-    /* Get the length stored in buffer. */
-    rv->bufferLength = xdr_getpos (&xdr);
-    xdr_destroy (&xdr);
-
-    /* Length must include the length word itself (always encoded in
-     * 4 bytes as per RFC 4506).
-     */
-    rv->bufferLength += REMOTE_MESSAGE_HEADER_XDR_LEN;
-
-    /* Encode the length word. */
-    xdrmem_create (&xdr, rv->buffer, REMOTE_MESSAGE_HEADER_XDR_LEN, XDR_ENCODE);
-    if (!xdr_u_int (&xdr, &rv->bufferLength)) {
-        remoteError(VIR_ERR_RPC, "%s", _("xdr_u_int (length word)"));
-        goto error;
-    }
-    xdr_destroy (&xdr);
-
-    return rv;
-
-error:
-    xdr_destroy (&xdr);
-    VIR_FREE(rv);
-    return NULL;
-}
-
-
-
-static int
-remoteIOWriteBuffer(struct private_data *priv,
-                    const char *bytes, int len)
-{
-    int ret;
-
-    if (priv->uses_tls) {
-    tls_resend:
-        ret = gnutls_record_send (priv->session, bytes, len);
-        if (ret < 0) {
-            if (ret == GNUTLS_E_INTERRUPTED)
-                goto tls_resend;
-            if (ret == GNUTLS_E_AGAIN)
-                return 0;
-
-            remoteError(VIR_ERR_GNUTLS_ERROR, "%s", gnutls_strerror (ret));
-            return -1;
-        }
-    } else {
-    resend:
-        ret = send (priv->sock, bytes, len, 0);
-        if (ret == -1) {
-            if (errno == EINTR)
-                goto resend;
-            if (errno == EWOULDBLOCK)
-                return 0;
-
-            virReportSystemError(errno, "%s", _("cannot send data"));
-            return -1;
-
-        }
-    }
-
-    return ret;
-}
-
-
-static int
-remoteIOReadBuffer(struct private_data *priv,
-                   char *bytes, int len)
-{
-    int ret;
-
-    if (priv->uses_tls) {
-    tls_resend:
-        ret = gnutls_record_recv (priv->session, bytes, len);
-        if (ret == GNUTLS_E_INTERRUPTED)
-            goto tls_resend;
-        if (ret == GNUTLS_E_AGAIN)
-            return 0;
-
-        /* Treat 0 == EOF as an error */
-        if (ret <= 0) {
-            if (ret < 0)
-                remoteError(VIR_ERR_GNUTLS_ERROR,
-                            _("failed to read from TLS socket %s"),
-                            gnutls_strerror (ret));
-            else
-                remoteError(VIR_ERR_SYSTEM_ERROR, "%s",
-                            _("server closed connection"));
-            return -1;
-        }
-    } else {
-    resend:
-        ret = recv (priv->sock, bytes, len, 0);
-        if (ret <= 0) {
-            if (ret == -1) {
-                if (errno == EINTR)
-                    goto resend;
-                if (errno == EWOULDBLOCK)
-                    return 0;
-
-                char errout[1024] = "\0";
-                if (priv->errfd != -1) {
-                    if (saferead(priv->errfd, errout, sizeof(errout)) < 0) {
-                        virReportSystemError(errno, "%s",
-                                             _("cannot recv data"));
-                        return -1;
-                    }
-                }
-
-                virReportSystemError(errno,
-                                     _("cannot recv data: %s"), errout);
-
-            } else {
-                char errout[1024] = "\0";
-                if (priv->errfd != -1) {
-                    if (saferead(priv->errfd, errout, sizeof(errout)) < 0) {
-                        remoteError(VIR_ERR_SYSTEM_ERROR,
-                                    _("server closed connection: %s"),
-                                    virStrerror(errno, errout, sizeof errout));
-                        return -1;
-                    }
-                }
-
-                remoteError(VIR_ERR_SYSTEM_ERROR,
-                            _("server closed connection: %s"), errout);
-            }
-            return -1;
-        }
-    }
-
-    return ret;
-}
-
-
-static int
-remoteIOWriteMessage(struct private_data *priv,
-                     struct remote_thread_call *thecall)
-{
-#if HAVE_SASL
-    if (priv->saslconn) {
-        const char *output;
-        unsigned int outputlen;
-        int err, ret;
-
-        if (!priv->saslEncoded) {
-            err = sasl_encode(priv->saslconn,
-                              thecall->buffer + thecall->bufferOffset,
-                              thecall->bufferLength - thecall->bufferOffset,
-                              &output, &outputlen);
-            if (err != SASL_OK) {
-                remoteError(VIR_ERR_INTERNAL_ERROR,
-                            _("failed to encode SASL data: %s"),
-                            sasl_errstring(err, NULL, NULL));
-                return -1;
-            }
-            priv->saslEncoded = output;
-            priv->saslEncodedLength = outputlen;
-            priv->saslEncodedOffset = 0;
-
-            thecall->bufferOffset = thecall->bufferLength;
-        }
-
-        ret = remoteIOWriteBuffer(priv,
-                                  priv->saslEncoded + priv->saslEncodedOffset,
-                                  priv->saslEncodedLength - priv->saslEncodedOffset);
-        if (ret < 0)
-            return ret;
-        priv->saslEncodedOffset += ret;
-
-        if (priv->saslEncodedOffset == priv->saslEncodedLength) {
-            priv->saslEncoded = NULL;
-            priv->saslEncodedOffset = priv->saslEncodedLength = 0;
-            if (thecall->want_reply)
-                thecall->mode = REMOTE_MODE_WAIT_RX;
-            else
-                thecall->mode = REMOTE_MODE_COMPLETE;
-        }
-    } else {
-#endif
-        int ret;
-        ret = remoteIOWriteBuffer(priv,
-                                  thecall->buffer + thecall->bufferOffset,
-                                  thecall->bufferLength - thecall->bufferOffset);
-        if (ret < 0)
-            return ret;
-        thecall->bufferOffset += ret;
-
-        if (thecall->bufferOffset == thecall->bufferLength) {
-            thecall->bufferOffset = thecall->bufferLength = 0;
-            if (thecall->want_reply)
-                thecall->mode = REMOTE_MODE_WAIT_RX;
-            else
-                thecall->mode = REMOTE_MODE_COMPLETE;
-        }
-#if HAVE_SASL
-    }
-#endif
-    return 0;
-}
-
-
-static int
-remoteIOHandleOutput(struct private_data *priv) {
-    struct remote_thread_call *thecall = priv->waitDispatch;
-
-    while (thecall &&
-           thecall->mode != REMOTE_MODE_WAIT_TX)
-        thecall = thecall->next;
-
-    if (!thecall)
-        return -1; /* Shouldn't happen, but you never know... */
-
-    while (thecall) {
-        int ret = remoteIOWriteMessage(priv, thecall);
-        if (ret < 0)
-            return ret;
-
-        if (thecall->mode == REMOTE_MODE_WAIT_TX)
-            return 0; /* Blocking write, to back to event loop */
-
-        thecall = thecall->next;
-    }
-
-    return 0; /* No more calls to send, all done */
-}
-
-static int
-remoteIOReadMessage(struct private_data *priv) {
-    unsigned int wantData;
-
-    /* Start by reading length word */
-    if (priv->bufferLength == 0)
-        priv->bufferLength = 4;
-
-    wantData = priv->bufferLength - priv->bufferOffset;
-
-#if HAVE_SASL
-    if (priv->saslconn) {
-        if (priv->saslDecoded == NULL) {
-            char encoded[8192];
-            int ret, err;
-            ret = remoteIOReadBuffer(priv, encoded, sizeof(encoded));
-            if (ret < 0)
-                return -1;
-            if (ret == 0)
-                return 0;
-
-            err = sasl_decode(priv->saslconn, encoded, ret,
-                              &priv->saslDecoded, &priv->saslDecodedLength);
-            if (err != SASL_OK) {
-                remoteError(VIR_ERR_INTERNAL_ERROR,
-                            _("failed to decode SASL data: %s"),
-                            sasl_errstring(err, NULL, NULL));
-                return -1;
-            }
-            priv->saslDecodedOffset = 0;
-        }
-
-        if ((priv->saslDecodedLength - priv->saslDecodedOffset) < wantData)
-            wantData = (priv->saslDecodedLength - priv->saslDecodedOffset);
-
-        memcpy(priv->buffer + priv->bufferOffset,
-               priv->saslDecoded + priv->saslDecodedOffset,
-               wantData);
-        priv->saslDecodedOffset += wantData;
-        priv->bufferOffset += wantData;
-        if (priv->saslDecodedOffset == priv->saslDecodedLength) {
-            priv->saslDecodedOffset = priv->saslDecodedLength = 0;
-            priv->saslDecoded = NULL;
-        }
-
-        return wantData;
-    } else {
-#endif
-        int ret;
-
-        ret = remoteIOReadBuffer(priv,
-                                 priv->buffer + priv->bufferOffset,
-                                 wantData);
-        if (ret < 0)
-            return -1;
-        if (ret == 0)
-            return 0;
-
-        priv->bufferOffset += ret;
-
-        return ret;
-#if HAVE_SASL
-    }
-#endif
-}
-
-
-static int
-remoteIODecodeMessageLength(struct private_data *priv) {
-    XDR xdr;
-    unsigned int len;
-
-    xdrmem_create (&xdr, priv->buffer, priv->bufferLength, XDR_DECODE);
-    if (!xdr_u_int (&xdr, &len)) {
-        remoteError(VIR_ERR_RPC, "%s", _("xdr_u_int (length word, reply)"));
-        return -1;
-    }
-    xdr_destroy (&xdr);
-
-    if (len < REMOTE_MESSAGE_HEADER_XDR_LEN) {
-        remoteError(VIR_ERR_RPC, "%s",
-                    _("packet received from server too small"));
-        return -1;
-    }
-
-    /* Length includes length word - adjust to real length to read. */
-    len -= REMOTE_MESSAGE_HEADER_XDR_LEN;
-
-    if (len > REMOTE_MESSAGE_MAX) {
-        remoteError(VIR_ERR_RPC, "%s",
-                    _("packet received from server too large"));
-        return -1;
-    }
-
-    /* Extend our declared buffer length and carry
-       on reading the header + payload */
-    priv->bufferLength += len;
-    DEBUG("Got length, now need %d total (%d more)", priv->bufferLength, len);
-    return 0;
-}
-
-
-static int
-processCallDispatchReply(virConnectPtr conn, struct private_data *priv,
-                         remote_message_header *hdr,
-                         XDR *xdr);
-
-static int
-processCallDispatchMessage(virConnectPtr conn, struct private_data *priv,
-                           int in_open,
-                           remote_message_header *hdr,
-                           XDR *xdr);
-
-static int
-processCallDispatchStream(virConnectPtr conn, struct private_data *priv,
-                          remote_message_header *hdr,
-                          XDR *xdr);
-
-
-static int
-processCallDispatch(virConnectPtr conn, struct private_data *priv,
-                    int flags) {
-    XDR xdr;
-    struct remote_message_header hdr;
-    int len = priv->bufferLength - 4;
-    int rv = -1;
-    int expectedprog;
-    int expectedvers;
-
-    /* Length word has already been read */
-    priv->bufferOffset = 4;
-
-    /* Deserialise reply header. */
-    xdrmem_create (&xdr, priv->buffer + priv->bufferOffset, len, XDR_DECODE);
-    if (!xdr_remote_message_header (&xdr, &hdr)) {
-        remoteError(VIR_ERR_RPC, "%s", _("invalid header in reply"));
-        return -1;
-    }
-
-    priv->bufferOffset += xdr_getpos(&xdr);
-
-    expectedprog = REMOTE_PROGRAM;
-    expectedvers = REMOTE_PROTOCOL_VERSION;
-    if (flags & REMOTE_CALL_QEMU) {
-        expectedprog = QEMU_PROGRAM;
-        expectedvers = QEMU_PROTOCOL_VERSION;
-    }
-
-    /* Check program, version, etc. are what we expect. */
-    if (hdr.prog != expectedprog) {
-        remoteError(VIR_ERR_RPC,
-                    _("unknown program (received %x, expected %x)"),
-                    hdr.prog, expectedprog);
-        return -1;
-    }
-    if (hdr.vers != expectedvers) {
-        remoteError(VIR_ERR_RPC,
-                    _("unknown protocol version (received %x, expected %x)"),
-                    hdr.vers, expectedvers);
-        return -1;
-    }
-
-
-    switch (hdr.type) {
-    case REMOTE_REPLY: /* Normal RPC replies */
-        rv = processCallDispatchReply(conn, priv, &hdr, &xdr);
-        break;
-
-    case REMOTE_MESSAGE: /* Async notifications */
-        rv = processCallDispatchMessage(conn, priv, flags & REMOTE_CALL_IN_OPEN,
-                                        &hdr, &xdr);
-        break;
-
-    case REMOTE_STREAM: /* Stream protocol */
-        rv = processCallDispatchStream(conn, priv, &hdr, &xdr);
-        break;
-
-    default:
-        remoteError(VIR_ERR_RPC,
-                    _("got unexpected RPC call %d from server"),
-                    hdr.proc);
-        rv = -1;
-        break;
-    }
-
-    xdr_destroy(&xdr);
-    return rv;
-}
-
-
-static int
-processCallDispatchReply(virConnectPtr conn ATTRIBUTE_UNUSED,
-                         struct private_data *priv,
-                         remote_message_header *hdr,
-                         XDR *xdr) {
-    struct remote_thread_call *thecall;
-
-    /* Ok, definitely got an RPC reply now find
-       out who's been waiting for it */
-    thecall = priv->waitDispatch;
-    while (thecall &&
-           thecall->serial != hdr->serial)
-        thecall = thecall->next;
-
-    if (!thecall) {
-        remoteError(VIR_ERR_RPC,
-                    _("no call waiting for reply with serial %d"),
-                    hdr->serial);
-        return -1;
-    }
-
-    if (hdr->proc != thecall->proc_nr) {
-        remoteError(VIR_ERR_RPC,
-                    _("unknown procedure (received %x, expected %x)"),
-                    hdr->proc, thecall->proc_nr);
-        return -1;
-    }
-
-    /* Status is either REMOTE_OK (meaning that what follows is a ret
-     * structure), or REMOTE_ERROR (and what follows is a remote_error
-     * structure).
-     */
-    switch (hdr->status) {
-    case REMOTE_OK:
-        if (!(*thecall->ret_filter) (xdr, thecall->ret)) {
-            remoteError(VIR_ERR_RPC, "%s", _("unmarshalling ret"));
-            return -1;
-        }
-        thecall->mode = REMOTE_MODE_COMPLETE;
-        return 0;
-
-    case REMOTE_ERROR:
-        memset (&thecall->err, 0, sizeof thecall->err);
-        if (!xdr_remote_error (xdr, &thecall->err)) {
-            remoteError(VIR_ERR_RPC, "%s", _("unmarshalling remote_error"));
-            return -1;
-        }
-        thecall->mode = REMOTE_MODE_ERROR;
-        return 0;
-
-    default:
-        remoteError(VIR_ERR_RPC, _("unknown status (received %x)"), hdr->status);
-        return -1;
-    }
-}
-
+#if 0
 static int
 processCallDispatchMessage(virConnectPtr conn, struct private_data *priv,
                            int in_open,
@@ -9871,31 +8622,31 @@ processCallDispatchMessage(virConnectPtr conn, struct private_data *priv,
 
     switch (hdr->proc) {
     case REMOTE_PROC_DOMAIN_EVENT_LIFECYCLE:
-        event = remoteDomainReadEventLifecycle(conn, xdr);
+        event = remoteDomainBuildEventLifecycle(conn, xdr);
         break;
 
     case REMOTE_PROC_DOMAIN_EVENT_REBOOT:
-        event = remoteDomainReadEventReboot(conn, xdr);
+        event = remoteDomainBuildEventReboot(conn, xdr);
         break;
 
     case REMOTE_PROC_DOMAIN_EVENT_RTC_CHANGE:
-        event = remoteDomainReadEventRTCChange(conn, xdr);
+        event = remoteDomainBuildEventRTCChange(conn, xdr);
         break;
 
     case REMOTE_PROC_DOMAIN_EVENT_WATCHDOG:
-        event = remoteDomainReadEventWatchdog(conn, xdr);
+        event = remoteDomainBuildEventWatchdog(conn, xdr);
         break;
 
     case REMOTE_PROC_DOMAIN_EVENT_IO_ERROR:
-        event = remoteDomainReadEventIOError(conn, xdr);
+        event = remoteDomainBuildEventIOError(conn, xdr);
         break;
 
     case REMOTE_PROC_DOMAIN_EVENT_IO_ERROR_REASON:
-        event = remoteDomainReadEventIOErrorReason(conn, xdr);
+        event = remoteDomainBuildEventIOErrorReason(conn, xdr);
         break;
 
     case REMOTE_PROC_DOMAIN_EVENT_GRAPHICS:
-        event = remoteDomainReadEventGraphics(conn, xdr);
+        event = remoteDomainBuildEventGraphics(conn, xdr);
         break;
 
     default:
@@ -9906,16 +8657,11 @@ processCallDispatchMessage(virConnectPtr conn, struct private_data *priv,
     if (!event)
         return -1;
 
-    if (virDomainEventQueuePush(priv->domainEvents,
-                                event) < 0) {
-        DEBUG0("Error adding event to queue");
-        virDomainEventFree(event);
-    }
-    virEventUpdateTimeout(priv->eventFlushTimer, 0);
-
     return 0;
 }
+#endif
 
+#if 0
 static int
 processCallDispatchStream(virConnectPtr conn ATTRIBUTE_UNUSED,
                           struct private_data *priv,
@@ -10022,485 +8768,43 @@ processCallDispatchStream(virConnectPtr conn ATTRIBUTE_UNUSED,
         return -1;
     }
 }
-
-static int
-remoteIOHandleInput(virConnectPtr conn, struct private_data *priv,
-                    int flags)
-{
-    /* Read as much data as is available, until we get
-     * EAGAIN
-     */
-    for (;;) {
-        int ret = remoteIOReadMessage(priv);
-
-        if (ret < 0)
-            return -1;
-        if (ret == 0)
-            return 0;  /* Blocking on read */
-
-        /* Check for completion of our goal */
-        if (priv->bufferOffset == priv->bufferLength) {
-            if (priv->bufferOffset == 4) {
-                ret = remoteIODecodeMessageLength(priv);
-                if (ret < 0)
-                    return -1;
-
-                /*
-                 * We'll carry on around the loop to immediately
-                 * process the message body, because it has probably
-                 * already arrived. Worst case, we'll get EAGAIN on
-                 * next iteration.
-                 */
-            } else {
-                ret = processCallDispatch(conn, priv, flags);
-                priv->bufferOffset = priv->bufferLength = 0;
-                /*
-                 * We've completed one call, so return even
-                 * though there might still be more data on
-                 * the wire. We need to actually let the caller
-                 * deal with this arrived message to keep good
-                 * response, and also to correctly handle EOF.
-                 */
-                return ret;
-            }
-        }
-    }
-}
-
-/*
- * Process all calls pending dispatch/receive until we
- * get a reply to our own call. Then quit and pass the buck
- * to someone else.
- */
-static int
-remoteIOEventLoop(virConnectPtr conn,
-                  struct private_data *priv,
-                  int flags,
-                  struct remote_thread_call *thiscall)
-{
-    struct pollfd fds[2];
-    int ret;
-
-    fds[0].fd = priv->sock;
-    fds[1].fd = priv->wakeupReadFD;
-
-    for (;;) {
-        struct remote_thread_call *tmp = priv->waitDispatch;
-        struct remote_thread_call *prev;
-        char ignore;
-#ifdef HAVE_PTHREAD_SIGMASK
-        sigset_t oldmask, blockedsigs;
-#endif
-
-        fds[0].events = fds[0].revents = 0;
-        fds[1].events = fds[1].revents = 0;
-
-        fds[1].events = POLLIN;
-        while (tmp) {
-            if (tmp->mode == REMOTE_MODE_WAIT_RX)
-                fds[0].events |= POLLIN;
-            if (tmp->mode == REMOTE_MODE_WAIT_TX)
-                fds[0].events |= POLLOUT;
-
-            tmp = tmp->next;
-        }
-
-        if (priv->streams)
-            fds[0].events |= POLLIN;
-
-        /* Release lock while poll'ing so other threads
-         * can stuff themselves on the queue */
-        remoteDriverUnlock(priv);
-
-        /* Block SIGWINCH from interrupting poll in curses programs,
-         * then restore the original signal mask again immediately
-         * after the call (RHBZ#567931).  Same for SIGCHLD and SIGPIPE
-         * at the suggestion of Paolo Bonzini and Daniel Berrange.
-         */
-#ifdef HAVE_PTHREAD_SIGMASK
-        sigemptyset (&blockedsigs);
-        sigaddset (&blockedsigs, SIGWINCH);
-        sigaddset (&blockedsigs, SIGCHLD);
-        sigaddset (&blockedsigs, SIGPIPE);
-        ignore_value(pthread_sigmask(SIG_BLOCK, &blockedsigs, &oldmask));
 #endif
 
-    repoll:
-        ret = poll(fds, ARRAY_CARDINALITY(fds), -1);
-        if (ret < 0 && errno == EAGAIN)
-            goto repoll;
-
-#ifdef HAVE_PTHREAD_SIGMASK
-        ignore_value(pthread_sigmask(SIG_SETMASK, &oldmask, NULL));
-#endif
-
-        remoteDriverLock(priv);
-
-        if (fds[1].revents) {
-            ssize_t s;
-            DEBUG0("Woken up from poll by other thread");
-            s = saferead(priv->wakeupReadFD, &ignore, sizeof(ignore));
-            if (s < 0) {
-                virReportSystemError(errno, "%s",
-                                     _("read on wakeup fd failed"));
-                goto error;
-            } else if (s != sizeof(ignore)) {
-                remoteError(VIR_ERR_INTERNAL_ERROR, "%s",
-                            _("read on wakeup fd failed"));
-                goto error;
-            }
-        }
-
-        if (ret < 0) {
-            if (errno == EWOULDBLOCK)
-                continue;
-            virReportSystemError(errno,
-                                 "%s", _("poll on socket failed"));
-            goto error;
-        }
-
-        if (fds[0].revents & POLLOUT) {
-            if (remoteIOHandleOutput(priv) < 0)
-                goto error;
-        }
-
-        if (fds[0].revents & POLLIN) {
-            if (remoteIOHandleInput(conn, priv, flags) < 0)
-                goto error;
-        }
-
-        /* Iterate through waiting threads and if
-         * any are complete then tell 'em to wakeup
-         */
-        tmp = priv->waitDispatch;
-        prev = NULL;
-        while (tmp) {
-            if (tmp != thiscall &&
-                (tmp->mode == REMOTE_MODE_COMPLETE ||
-                 tmp->mode == REMOTE_MODE_ERROR)) {
-                /* Take them out of the list */
-                if (prev)
-                    prev->next = tmp->next;
-                else
-                    priv->waitDispatch = tmp->next;
-
-                /* And wake them up....
-                 * ...they won't actually wakeup until
-                 * we release our mutex a short while
-                 * later...
-                 */
-                DEBUG("Waking up sleep %d %p %p", tmp->proc_nr, tmp, priv->waitDispatch);
-                virCondSignal(&tmp->cond);
-            }
-            prev = tmp;
-            tmp = tmp->next;
-        }
-
-        /* Now see if *we* are done */
-        if (thiscall->mode == REMOTE_MODE_COMPLETE ||
-            thiscall->mode == REMOTE_MODE_ERROR) {
-            /* We're at head of the list already, so
-             * remove us
-             */
-            priv->waitDispatch = thiscall->next;
-            DEBUG("Giving up the buck %d %p %p", thiscall->proc_nr, thiscall, priv->waitDispatch);
-            /* See if someone else is still waiting
-             * and if so, then pass the buck ! */
-            if (priv->waitDispatch) {
-                DEBUG("Passing the buck to %d %p", priv->waitDispatch->proc_nr, priv->waitDispatch);
-                virCondSignal(&priv->waitDispatch->cond);
-            }
-            return 0;
-        }
-
-
-        if (fds[0].revents & (POLLHUP | POLLERR)) {
-            remoteError(VIR_ERR_INTERNAL_ERROR, "%s",
-                        _("received hangup / error event on socket"));
-            goto error;
-        }
-    }
-
-
-error:
-    priv->waitDispatch = thiscall->next;
-    DEBUG("Giving up the buck due to I/O error %d %p %p", thiscall->proc_nr, thiscall, priv->waitDispatch);
-    /* See if someone else is still waiting
-     * and if so, then pass the buck ! */
-    if (priv->waitDispatch) {
-        DEBUG("Passing the buck to %d %p", priv->waitDispatch->proc_nr, priv->waitDispatch);
-        virCondSignal(&priv->waitDispatch->cond);
-    }
-    return -1;
-}
-
-/*
- * This function sends a message to remote server and awaits a reply
- *
- * NB. This does not free the args structure (not desirable, since you
- * often want this allocated on the stack or else it contains strings
- * which come from the user).  It does however free any intermediate
- * results, eg. the error structure if there is one.
- *
- * NB(2). Make sure to memset (&ret, 0, sizeof ret) before calling,
- * else Bad Things will happen in the XDR code.
- *
- * NB(3) You must have the private_data lock before calling this
- *
- * NB(4) This is very complicated. Due to connection cloning, multiple
- * threads can want to use the socket at once. Obviously only one of
- * them can. So if someone's using the socket, other threads are put
- * to sleep on condition variables. The existing thread may completely
- * send & receive their RPC call/reply while they're asleep. Or it
- * may only get around to dealing with sending the call. Or it may
- * get around to neither. So upon waking up from slumber, the other
- * thread may or may not have more work todo.
- *
- * We call this dance  'passing the buck'
- *
- *      http://en.wikipedia.org/wiki/Passing_the_buck
- *
- *   "Buck passing or passing the buck is the action of transferring
- *    responsibility or blame unto another person. It is also used as
- *    a strategy in power politics when the actions of one country/
- *    nation are blamed on another, providing an opportunity for war."
- *
- * NB(5) Don't Panic!
- */
-static int
-remoteIO(virConnectPtr conn,
-         struct private_data *priv,
-         int flags,
-         struct remote_thread_call *thiscall)
-{
-    int rv;
-
-    DEBUG("Do proc=%d serial=%d length=%d wait=%p",
-          thiscall->proc_nr, thiscall->serial,
-          thiscall->bufferLength, priv->waitDispatch);
-
-    /* Check to see if another thread is dispatching */
-    if (priv->waitDispatch) {
-        /* Stick ourselves on the end of the wait queue */
-        struct remote_thread_call *tmp = priv->waitDispatch;
-        char ignore = 1;
-        ssize_t s;
-        while (tmp && tmp->next)
-            tmp = tmp->next;
-        if (tmp)
-            tmp->next = thiscall;
-        else
-            priv->waitDispatch = thiscall;
-
-        /* Force other thread to wakeup from poll */
-        s = safewrite(priv->wakeupSendFD, &ignore, sizeof(ignore));
-        if (s < 0) {
-            char errout[1024];
-            remoteError(VIR_ERR_INTERNAL_ERROR,
-                        _("failed to wake up polling thread: %s"),
-                        virStrerror(errno, errout, sizeof errout));
-            return -1;
-        } else if (s != sizeof(ignore)) {
-            remoteError(VIR_ERR_INTERNAL_ERROR, "%s",
-                        _("failed to wake up polling thread"));
-            return -1;
-        }
-
-        DEBUG("Going to sleep %d %p %p", thiscall->proc_nr, priv->waitDispatch, thiscall);
-        /* Go to sleep while other thread is working... */
-        if (virCondWait(&thiscall->cond, &priv->lock) < 0) {
-            if (priv->waitDispatch == thiscall) {
-                priv->waitDispatch = thiscall->next;
-            } else {
-                tmp = priv->waitDispatch;
-                while (tmp && tmp->next &&
-                       tmp->next != thiscall) {
-                    tmp = tmp->next;
-                }
-                if (tmp && tmp->next == thiscall)
-                    tmp->next = thiscall->next;
-            }
-            remoteError(VIR_ERR_INTERNAL_ERROR, "%s",
-                        _("failed to wait on condition"));
-            return -1;
-        }
-
-        DEBUG("Wokeup from sleep %d %p %p", thiscall->proc_nr, priv->waitDispatch, thiscall);
-        /* Two reasons we can be woken up
-         *  1. Other thread has got our reply ready for us
-         *  2. Other thread is all done, and it is our turn to
-         *     be the dispatcher to finish waiting for
-         *     our reply
-         */
-        if (thiscall->mode == REMOTE_MODE_COMPLETE ||
-            thiscall->mode == REMOTE_MODE_ERROR) {
-            /*
-             * We avoided catching the buck and our reply is ready !
-             * We've already had 'thiscall' removed from the list
-             * so just need to (maybe) handle errors & free it
-             */
-            goto cleanup;
-        }
-
-        /* Grr, someone passed the buck onto us ... */
-
-    } else {
-        /* We're first to catch the buck */
-        priv->waitDispatch = thiscall;
-    }
-
-    DEBUG("We have the buck %d %p %p", thiscall->proc_nr, priv->waitDispatch, thiscall);
-    /*
-     * The buck stops here!
-     *
-     * At this point we're about to own the dispatch
-     * process...
-     */
-
-    /*
-     * Avoid needless wake-ups of the event loop in the
-     * case where this call is being made from a different
-     * thread than the event loop. These wake-ups would
-     * cause the event loop thread to be blocked on the
-     * mutex for the duration of the call
-     */
-    if (priv->watch >= 0)
-        virEventUpdateHandle(priv->watch, 0);
-
-    rv = remoteIOEventLoop(conn, priv, flags, thiscall);
-
-    if (priv->watch >= 0)
-        virEventUpdateHandle(priv->watch, VIR_EVENT_HANDLE_READABLE);
-
-    if (rv < 0)
-        return -1;
-
-cleanup:
-    DEBUG("All done with our call %d %p %p", thiscall->proc_nr, priv->waitDispatch, thiscall);
-    if (thiscall->mode == REMOTE_MODE_ERROR) {
-        /* See if caller asked us to keep quiet about missing RPCs
-         * eg for interop with older servers */
-        if (flags & REMOTE_CALL_QUIET_MISSING_RPC &&
-            thiscall->err.domain == VIR_FROM_REMOTE &&
-            thiscall->err.code == VIR_ERR_RPC &&
-            thiscall->err.level == VIR_ERR_ERROR &&
-            thiscall->err.message &&
-            STRPREFIX(*thiscall->err.message, "unknown procedure")) {
-            rv = -2;
-        } else if (thiscall->err.domain == VIR_FROM_REMOTE &&
-                   thiscall->err.code == VIR_ERR_RPC &&
-                   thiscall->err.level == VIR_ERR_ERROR &&
-                   thiscall->err.message &&
-                   STRPREFIX(*thiscall->err.message, "unknown procedure")) {
-            /*
-             * convert missing remote entry points into the unsupported
-             * feature error
-             */
-            virRaiseErrorFull(flags & REMOTE_CALL_IN_OPEN ? NULL : conn,
-                              __FILE__, __FUNCTION__, __LINE__,
-                              thiscall->err.domain,
-                              VIR_ERR_NO_SUPPORT,
-                              thiscall->err.level,
-                              thiscall->err.str1 ? *thiscall->err.str1 : NULL,
-                              thiscall->err.str2 ? *thiscall->err.str2 : NULL,
-                              thiscall->err.str3 ? *thiscall->err.str3 : NULL,
-                              thiscall->err.int1,
-                              thiscall->err.int2,
-                              "%s", *thiscall->err.message);
-            rv = -1;
-        } else {
-            virRaiseErrorFull(flags & REMOTE_CALL_IN_OPEN ? NULL : conn,
-                              __FILE__, __FUNCTION__, __LINE__,
-                              thiscall->err.domain,
-                              thiscall->err.code,
-                              thiscall->err.level,
-                              thiscall->err.str1 ? *thiscall->err.str1 : NULL,
-                              thiscall->err.str2 ? *thiscall->err.str2 : NULL,
-                              thiscall->err.str3 ? *thiscall->err.str3 : NULL,
-                              thiscall->err.int1,
-                              thiscall->err.int2,
-                              "%s", thiscall->err.message ? *thiscall->err.message : "unknown");
-            rv = -1;
-        }
-        xdr_free((xdrproc_t)xdr_remote_error,  (char *)&thiscall->err);
-    } else {
-        rv = 0;
-    }
-    return rv;
-}
-
 
 /*
  * Serial a set of arguments into a method call message,
  * send that to the server and wait for reply
  */
 static int
-call (virConnectPtr conn, struct private_data *priv,
+call (virConnectPtr conn ATTRIBUTE_UNUSED,
+      struct private_data *priv,
       int flags,
       int proc_nr,
       xdrproc_t args_filter, char *args,
       xdrproc_t ret_filter, char *ret)
 {
-    struct remote_thread_call *thiscall;
     int rv;
+    virNetClientProgramPtr prog = flags & REMOTE_CALL_QEMU ? priv->qemuProgram : priv->remoteProgram;
+    int counter = priv->counter++;
+    priv->localUses++;
 
-    thiscall = prepareCall(priv, flags, proc_nr, args_filter, args,
-                           ret_filter, ret);
-
-    if (!thiscall) {
-        virReportOOMError();
-        return -1;
-    }
-
-    rv = remoteIO(conn, priv, flags, thiscall);
-    VIR_FREE(thiscall);
+    /* Unlock, so that if we get any async events/stream data
+     * while processing the RPC, we don't deadlock when our
+     * callbacks for those are invoked
+     */
+    remoteDriverUnlock(priv);
+    rv = virNetClientProgramCall(prog,
+                                 priv->client,
+                                 counter,
+                                 proc_nr,
+                                 args_filter, args,
+                                 ret_filter, ret);
+    remoteDriverLock(priv);
+    priv->localUses--;
     return rv;
 }
 
 
-/** remoteDomainEventFired:
- *
- * The callback for monitoring the remote socket
- * for event data
- */
-void
-remoteDomainEventFired(int watch,
-                       int fd,
-                       int event,
-                       void *opaque)
-{
-    virConnectPtr        conn = opaque;
-    struct private_data *priv = conn->privateData;
-
-    remoteDriverLock(priv);
-
-    /* This should be impossible, but it doesn't hurt to check */
-    if (priv->waitDispatch)
-        goto done;
-
-    DEBUG("Event fired %d %d %d %X", watch, fd, event, event);
-
-    if (event & (VIR_EVENT_HANDLE_HANGUP | VIR_EVENT_HANDLE_ERROR)) {
-         DEBUG("%s : VIR_EVENT_HANDLE_HANGUP or "
-               "VIR_EVENT_HANDLE_ERROR encountered", __FUNCTION__);
-         virEventRemoveHandle(watch);
-         priv->watch = -1;
-         goto done;
-    }
-
-    if (fd != priv->sock) {
-        virEventRemoveHandle(watch);
-        priv->watch = -1;
-        goto done;
-    }
-
-    if (remoteIOHandleInput(conn, priv, 0) < 0)
-        DEBUG0("Something went wrong during async message processing");
-
-done:
-    remoteDriverUnlock(priv);
-}
-
 static void remoteDomainEventDispatchFunc(virConnectPtr conn,
                                           virDomainEventPtr event,
                                           virConnectDomainEventGenericCallback cb,
@@ -10753,7 +9057,7 @@ static virDriver remote_driver = {
     remoteNodeDeviceDettach, /* nodeDeviceDettach */
     remoteNodeDeviceReAttach, /* nodeDeviceReAttach */
     remoteNodeDeviceReset, /* nodeDeviceReset */
-    remoteDomainMigratePrepareTunnel, /* domainMigratePrepareTunnel */
+    NULL, //remoteDomainMigratePrepareTunnel, /* domainMigratePrepareTunnel */
     remoteIsEncrypted, /* isEncrypted */
     remoteIsSecure, /* isSecure */
     remoteDomainIsActive, /* domainIsActive */
@@ -10781,7 +9085,7 @@ static virDriver remote_driver = {
     remoteQemuDomainMonitorCommand, /* qemuDomainMonitorCommand */
     remoteDomainSetMemoryParameters, /* domainSetMemoryParameters */
     remoteDomainGetMemoryParameters, /* domainGetMemoryParameters */
-    remoteDomainOpenConsole, /* domainOpenConsole */
+    NULL, //remoteDomainOpenConsole, /* domainOpenConsole */
 };
 
 static virNetworkDriver network_driver = {
-- 
1.7.2.3

--
libvir-list mailing list
libvir-list@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/libvir-list


[Index of Archives]     [Virt Tools]     [Libvirt Users]     [Lib OS Info]     [Fedora Users]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [KDE Users]     [Fedora Tools]