[libvirt] [PATCH 1/4] Convert the remote driver to new RPC client APIs

Daniel P. Berrange berrange at redhat.com
Mon Jun 27 14:24:36 UTC 2011


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            |    5 +-
 src/remote/remote_driver.c | 3452 ++++++++------------------------------------
 src/rpc/gendispatch.pl     |   14 +-
 3 files changed, 586 insertions(+), 2885 deletions(-)

diff --git a/src/Makefile.am b/src/Makefile.am
index 1e7b905..83d267f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -554,11 +554,11 @@ libvirt_la_BUILT_LIBADD += libvirt_driver_remote.la
 endif
 libvirt_driver_remote_la_CFLAGS =				\
 		$(GNUTLS_CFLAGS)				\
-		$(SASL_CFLAGS) $(XDR_CFLAGS)			\
 		-I at top_srcdir@/src/conf				\
+		-I at 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) libvirt-net-rpc-client.la libvirt-net-rpc.la
 if WITH_DRIVER_MODULES
 libvirt_driver_remote_la_LIBADD += ../gnulib/lib/libgnu.la
 libvirt_driver_remote_la_LDFLAGS += -module -avoid-version
@@ -1222,6 +1222,7 @@ endif
 libvirt_net_rpc_la_CFLAGS = \
 			$(GNUTLS_CFLAGS) \
 			$(SASL_CFLAGS) \
+			$(XDR_CFLAGS) \
 			$(AM_CFLAGS)
 libvirt_net_rpc_la_LDFLAGS = \
 			$(GNUTLS_LIBS) \
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index 84a5eab..21651f3 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -23,51 +23,14 @@
 
 #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 "virnetclientstream.h"
 #include "virterror_internal.h"
 #include "logging.h"
 #include "datatypes.h"
@@ -107,119 +70,27 @@
 
 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_stream_data {
-    unsigned int has_error : 1;
-    remote_error err;
-
-    unsigned int serial;
-    unsigned int proc_nr;
+struct private_data {
+    virMutex lock;
 
-    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;
-
-    char saslTemporary[8192]; /* temorary holds data to be decoded */
-#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;
 
     virDomainEventStatePtr domainEventState;
-
-    /* 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 {
-    REMOTE_CALL_IN_OPEN           = (1 << 0),
-    REMOTE_CALL_QUIET_MISSING_RPC = (1 << 1),
-    REMOTE_CALL_QEMU              = (1 << 2),
-    REMOTE_CALL_NONBLOCK          = (1 << 3),
+    REMOTE_CALL_QEMU              = (1 << 0),
 };
 
 
@@ -233,22 +104,18 @@ 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,
                  xdrproc_t ret_filter, char *ret);
-static int remoteAuthenticate (virConnectPtr conn, struct private_data *priv, int in_open,
+static int remoteAuthenticate (virConnectPtr conn, struct private_data *priv,
                                virConnectAuthPtr auth, const char *authtype);
 #if HAVE_SASL
-static int remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int in_open,
+static int remoteAuthSASL (virConnectPtr conn, struct private_data *priv,
                            virConnectAuthPtr auth, const char *mech);
 #endif
 #if HAVE_POLKIT
-static int remoteAuthPolkit (virConnectPtr conn, struct private_data *priv, int in_open,
+static int remoteAuthPolkit (virConnectPtr conn, struct private_data *priv,
                              virConnectAuthPtr auth);
 #endif /* HAVE_POLKIT */
 
@@ -273,18 +140,13 @@ static void make_nonnull_storage_vol (remote_nonnull_storage_vol *vol_dst, virSt
 static void make_nonnull_secret (remote_nonnull_secret *secret_dst, virSecretPtr secret_src);
 static void make_nonnull_nwfilter (remote_nonnull_nwfilter *nwfilter_dst, virNWFilterPtr nwfilter_src);
 static void make_nonnull_domain_snapshot (remote_nonnull_domain_snapshot *snapshot_dst, virDomainSnapshotPtr snapshot_src);
-void remoteDomainEventFired(int watch, int fd, int event, void *data);
-void remoteDomainEventQueueFlush(int timer, void *opaque);
-void remoteDomainEventQueue(struct private_data *priv, virDomainEventPtr event);
+static void remoteDomainEventQueueFlush(int timer, void *opaque);
+static void remoteDomainEventQueue(struct private_data *priv, virDomainEventPtr event);
 /*----------------------------------------------------------------------*/
 
 /* Helper functions for remoteOpen. */
 static char *get_transport_from_scheme (char *scheme);
 
-/* GnuTLS functions used by remoteOpen. */
-static int initialize_gnutls(char *pkipath, int flags);
-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)
@@ -299,7 +161,7 @@ remoteStartup(int privileged ATTRIBUTE_UNUSED)
 
 #ifndef WIN32
 /**
- * remoteFindServerPath:
+ * remoteFindDaemonPath:
  *
  * Tries to find the path to the libvirtd binary.
  *
@@ -326,37 +188,84 @@ 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();
-    virCommandPtr cmd = NULL;
-    int ret;
-
-    if (!daemonPath) {
-        remoteError(VIR_ERR_INTERNAL_ERROR, "%s",
-                    _("failed to find libvirtd binary"));
-        return -1;
-    }
-
-    cmd = virCommandNewArgList(daemonPath, "--timeout", "30", NULL);
-    virCommandClearCaps(cmd);
-    virCommandDaemonize(cmd);
-
-    ret = virCommandRun(cmd, NULL);
-    virCommandFree(cmd);
 
-    return ret;
-}
-#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 void
+remoteDomainBuildEventBlockPull(virNetClientProgramPtr prog,
+                                virNetClientPtr client,
+                                void *evdata, void *opaque);
+static void
+remoteDomainBuildEventControlError(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_msg },
+    { REMOTE_PROC_DOMAIN_EVENT_CONTROL_ERROR,
+      remoteDomainBuildEventControlError,
+      sizeof(remote_domain_event_control_error_msg),
+      (xdrproc_t)xdr_remote_domain_event_control_error_msg },
+    { REMOTE_PROC_DOMAIN_EVENT_BLOCK_PULL,
+      remoteDomainBuildEventBlockPull,
+      sizeof(remote_domain_event_block_pull_msg),
+      (xdrproc_t)xdr_remote_domain_event_block_pull_msg },
+};
 
 enum virDrvOpenRemoteFlags {
     VIR_DRV_OPEN_REMOTE_RO = (1 << 0),
@@ -389,7 +298,6 @@ doRemoteOpen (virConnectPtr conn,
               int flags)
 {
     struct qparam_set *vars = NULL;
-    int wakeupFD[2] = { -1, -1 };
     char *transport_str = NULL;
     enum {
         trans_tls,
@@ -445,7 +353,6 @@ doRemoteOpen (virConnectPtr conn,
     char *port = NULL, *authtype = NULL, *username = NULL;
     int no_verify = 0, no_tty = 0;
     char *pkipath = NULL;
-    virCommandPtr cmd = NULL;
 
     /* Return code from this function, and the private data. */
     int retcode = VIR_DRV_OPEN_ERROR;
@@ -524,12 +431,6 @@ 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 if (STRCASEEQ(var->name, "pkipath")) {
                 VIR_FREE(pkipath);
                 pkipath = strdup(var->value);
@@ -601,89 +502,34 @@ 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(pkipath, flags) == -1) goto failed;
-        priv->uses_tls = 1;
+        priv->tls = virNetTLSContextNewClientPath(pkipath,
+                                                  geteuid() != 0 ? true : false,
+                                                  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_DEBUG("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());
@@ -698,131 +544,59 @@ 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);
+        if (!(priv->client = virNetClientNewUNIX(sockname,
+                                                 flags & VIR_DRV_OPEN_REMOTE_AUTOSTART,
+                                                 remoteFindDaemonPath())))
             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);
-            goto failed;
-        }
-
         break;
-    }
 
-    case trans_ssh: {
-        cmd = virCommandNew(command ? command : "ssh");
-
-        /* Generate the final command argv[] array.
-         *   ssh [-p $port] [-l $username] $hostname $netcat -U $sockname */
+    case trans_ssh:
+        command = command ? command : strdup ("ssh");
+        if (command == NULL)
+            goto out_of_memory;
 
-        if (port) {
-            virCommandAddArgList(cmd, "-p", port, NULL);
-        }
-        if (username) {
-            virCommandAddArgList(cmd, "-l", username, NULL);
-        }
-        if (no_tty) {
-            virCommandAddArgList(cmd, "-T", "-o", "BatchMode=yes", "-e",
-                                 "none", 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;
         }
-        virCommandAddArgList(cmd, priv->hostname, netcat ? netcat : "nc",
-                             "-U", (sockname ? sockname :
-                                    (flags & VIR_CONNECT_RO
-                                     ? LIBVIRTD_PRIV_UNIX_SOCKET_RO
-                                     : LIBVIRTD_PRIV_UNIX_SOCKET)), NULL);
-
-        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"));
+        if (!(priv->client = virNetClientNewSSH(priv->hostname,
+                                                port,
+                                                command,
+                                                username,
+                                                no_tty,
+                                                netcat ? netcat : "nc",
+                                                sockname)))
             goto failed;
-        }
 
-        if (pipe(errfd) == -1) {
-            virReportSystemError(errno, "%s",
-                                 _("unable to create socket pair"));
-            goto failed;
-        }
+        priv->is_secure = 1;
+        break;
 
-        virCommandSetInputFD(cmd, sv[1]);
-        virCommandSetOutputFD(cmd, &(sv[1]));
-        virCommandSetErrorFD(cmd, &(errfd[1]));
-        virCommandClearCaps(cmd);
-        if (virCommandRunAsync(cmd, &pid) < 0)
+    case trans_ext: {
+        char const *cmd_argv[] = { command, NULL };
+        if (!(priv->client = virNetClientNewExternal(cmd_argv)))
             goto failed;
 
-        /* Parent continues here. */
-        VIR_FORCE_CLOSE(sv[1]);
-        VIR_FORCE_CLOSE(errfd[1]);
-        priv->sock = sv[0];
-        priv->errfd = errfd[0];
-        priv->pid = pid;
-
         /* 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,38 +608,36 @@ doRemoteOpen (virConnectPtr conn,
         goto failed;
 
 #endif /* WIN32 */
-
     } /* switch (transport) */
 
-    if (virSetNonBlock(priv->sock) < 0) {
-        virReportSystemError(errno, "%s",
-                             _("unable to make socket non-blocking"));
+    if (!(priv->remoteProgram = virNetClientProgramNew(REMOTE_PROGRAM,
+                                                       REMOTE_PROTOCOL_VERSION,
+                                                       remoteDomainEvents,
+                                                       ARRAY_CARDINALITY(remoteDomainEvents),
+                                                       conn)))
         goto failed;
-    }
-
-    if ((priv->errfd != -1) && virSetNonBlock(priv->errfd) < 0) {
-        virReportSystemError(errno, "%s",
-                             _("unable to make socket non-blocking"));
+    if (!(priv->qemuProgram = virNetClientProgramNew(QEMU_PROGRAM,
+                                                     QEMU_PROTOCOL_VERSION,
+                                                     NULL,
+                                                     0,
+                                                     NULL)))
         goto failed;
-    }
 
-    if (pipe(wakeupFD) < 0) {
-        virReportSystemError(errno, "%s",
-                             _("unable to make pipe"));
+    if (virNetClientAddProgram(priv->client, priv->remoteProgram) < 0 ||
+        virNetClientAddProgram(priv->client, priv->qemuProgram) < 0)
         goto failed;
-    }
-    priv->wakeupReadFD = wakeupFD[0];
-    priv->wakeupSendFD = wakeupFD[1];
 
     /* Try and authenticate with server */
-    if (remoteAuthenticate(conn, priv, 1, auth, authtype) == -1)
+    VIR_DEBUG("Trying authentication");
+    if (remoteAuthenticate(conn, priv, auth, authtype) == -1)
         goto failed;
 
     /* Finally we can call the remote side's open function. */
     {
         remote_open_args args = { &name, flags };
 
-        if (call (conn, priv, REMOTE_CALL_IN_OPEN, REMOTE_PROC_OPEN,
+        VIR_DEBUG("Trying to open URI %s", name);
+        if (call (conn, priv, 0, REMOTE_PROC_OPEN,
                   (xdrproc_t) xdr_remote_open_args, (char *) &args,
                   (xdrproc_t) xdr_void, (char *) NULL) == -1)
             goto failed;
@@ -874,26 +646,14 @@ doRemoteOpen (virConnectPtr conn,
     /* Now try and find out what URI the daemon used */
     if (conn->uri == NULL) {
         remote_get_uri_ret uriret;
-        int urierr;
 
+        VIR_DEBUG("Trying to query remote URI");
         memset (&uriret, 0, sizeof uriret);
-        urierr = call (conn, priv,
-                       REMOTE_CALL_IN_OPEN | REMOTE_CALL_QUIET_MISSING_RPC,
-                       REMOTE_PROC_GET_URI,
-                       (xdrproc_t) xdr_void, (char *) NULL,
-                       (xdrproc_t) xdr_remote_get_uri_ret, (char *) &uriret);
-        if (urierr == -2) {
-            /* Should not really happen, since we only probe local libvirtd's,
-               & the library should always match the daemon. Only case is post
-               RPM upgrade where an old daemon instance is still running with
-               new client. Too bad. It is not worth the hassle to fix this */
-            remoteError(VIR_ERR_INTERNAL_ERROR, "%s",
-                        _("unable to auto-detect URI"));
-            goto failed;
-        }
-        if (urierr == -1) {
+        if (call (conn, priv, 0,
+                  REMOTE_PROC_GET_URI,
+                  (xdrproc_t) xdr_void, (char *) NULL,
+                  (xdrproc_t) xdr_remote_get_uri_ret, (char *) &uriret) < 0)
             goto failed;
-        }
 
         VIR_DEBUG("Auto-probed URI is %s", uriret.uri);
         conn->uri = xmlParseURI(uriret.uri);
@@ -904,27 +664,11 @@ doRemoteOpen (virConnectPtr conn,
         }
     }
 
-    /* Set up a callback to listen on the socket data */
-    if ((priv->watch = virEventAddHandle(priv->sock,
-                                         VIR_EVENT_HANDLE_READABLE,
-                                         remoteDomainEventFired,
-                                         conn, NULL)) < 0) {
-        VIR_DEBUG("virEventAddHandle failed: No addHandleImpl defined."
-               " continuing without events.");
-        priv->watch = -1;
-    }
-
-    priv->domainEventState = virDomainEventStateNew(remoteDomainEventQueueFlush,
-                                                    conn,
-                                                    NULL,
-                                                    false);
-    if (!priv->domainEventState) {
+    if (!(priv->domainEventState = virDomainEventStateNew(remoteDomainEventQueueFlush,
+                                                          conn,
+                                                          NULL,
+                                                          false)))
         goto failed;
-    }
-    if (priv->domainEventState->timer < 0 && priv->watch != -1) {
-        virEventRemoveHandle(priv->watch);
-        priv->watch = -1;
-    }
 
     /* Successful. */
     retcode = VIR_DRV_OPEN_SUCCESS;
@@ -938,7 +682,6 @@ doRemoteOpen (virConnectPtr conn,
     VIR_FREE(netcat);
     VIR_FREE(username);
     VIR_FREE(port);
-    virCommandFree(cmd);
     VIR_FREE(pkipath);
 
     return retcode;
@@ -949,30 +692,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;
@@ -995,9 +716,6 @@ remoteAllocPrivateData(void)
     }
     remoteDriverLock(priv);
     priv->localUses = 1;
-    priv->watch = -1;
-    priv->sock = -1;
-    priv->errfd = -1;
 
     return priv;
 }
@@ -1109,577 +827,139 @@ 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)
+doRemoteClose (virConnectPtr conn, struct private_data *priv)
 {
-    if (access(file, R_OK)) {
-        virReportSystemError(errno,
-                             _("Cannot access %s '%s'"),
-                             type, file);
+    if (call (conn, priv, 0, REMOTE_PROC_CLOSE,
+              (xdrproc_t) xdr_void, (char *) NULL,
+              (xdrproc_t) xdr_void, (char *) NULL) == -1)
         return -1;
-    }
-    return 0;
-}
 
+    virNetTLSContextFree(priv->tls);
+    priv->tls = NULL;
+    virNetClientFree(priv->client);
+    priv->client = NULL;
+    virNetClientProgramFree(priv->remoteProgram);
+    virNetClientProgramFree(priv->qemuProgram);
+    priv->remoteProgram = priv->qemuProgram = NULL;
+
+    /* Free hostname copy */
+    VIR_FREE(priv->hostname);
+
+    /* See comment for remoteType. */
+    VIR_FREE(priv->type);
+
+    virDomainEventStateFree(priv->domainEventState);
 
-static void remote_debug_gnutls_log(int level, const char* str) {
-    VIR_DEBUG("%d %s", level, str);
+    return 0;
 }
 
 static int
-initialize_gnutls(char *pkipath, int flags)
+remoteClose (virConnectPtr conn)
 {
-    static int initialized = 0;
-    int err;
-    char *gnutlsdebug;
-    char *libvirt_cacert = NULL;
-    char *libvirt_clientkey = NULL;
-    char *libvirt_clientcert = NULL;
-    int ret = -1;
-    char *userdir = NULL;
-    char *user_pki_path = NULL;
-
-    if (initialized) return 0;
-
-    gnutls_global_init ();
+    int ret = 0;
+    struct private_data *priv = conn->privateData;
 
-    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);
+    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);
 
-    /* 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;
-    }
+    return ret;
+}
 
-    if (pkipath) {
-        if ((virAsprintf(&libvirt_cacert, "%s/%s", pkipath,
-                        "cacert.pem")) < 0)
-            goto out_of_memory;
 
-        if ((virAsprintf(&libvirt_clientkey, "%s/%s", pkipath,
-                        "clientkey.pem")) < 0)
-            goto out_of_memory;
+/* Unfortunately this function is defined to return a static string.
+ * Since the remote end always answers with the same type (for a
+ * single connection anyway) we cache the type in the connection's
+ * private data, and free it when we close the connection.
+ *
+ * See also:
+ * http://www.redhat.com/archives/libvir-list/2007-February/msg00096.html
+ */
+static const char *
+remoteType (virConnectPtr conn)
+{
+    char *rv = NULL;
+    remote_get_type_ret ret;
+    struct private_data *priv = conn->privateData;
 
-        if ((virAsprintf(&libvirt_clientcert, "%s/%s", pkipath,
-                        "clientcert.pem")) < 0)
-             goto out_of_memory;
-    } else if (flags & VIR_DRV_OPEN_REMOTE_USER || getuid() > 0) {
-        userdir = virGetUserDirectory(getuid());
+    remoteDriverLock(priv);
 
-        if (!userdir)
-            goto out_of_memory;
+    /* Cached? */
+    if (priv->type) {
+        rv = priv->type;
+        goto done;
+    }
 
-        if (virAsprintf(&user_pki_path, "%s/.pki/libvirt", userdir) < 0)
-            goto out_of_memory;
+    memset (&ret, 0, sizeof ret);
+    if (call (conn, priv, 0, REMOTE_PROC_GET_TYPE,
+              (xdrproc_t) xdr_void, (char *) NULL,
+              (xdrproc_t) xdr_remote_get_type_ret, (char *) &ret) == -1)
+        goto done;
 
-        if ((virAsprintf(&libvirt_cacert, "%s/%s", user_pki_path,
-                        "cacert.pem")) < 0)
-            goto out_of_memory;
+    /* Stash. */
+    rv = priv->type = ret.type;
 
-        if ((virAsprintf(&libvirt_clientkey, "%s/%s", user_pki_path,
-                        "clientkey.pem")) < 0)
-            goto out_of_memory;
+done:
+    remoteDriverUnlock(priv);
+    return rv;
+}
 
-        if ((virAsprintf(&libvirt_clientcert, "%s/%s", user_pki_path,
-                        "clientcert.pem")) < 0)
-            goto out_of_memory;
+static int remoteIsSecure(virConnectPtr conn)
+{
+    int rv = -1;
+    struct private_data *priv = conn->privateData;
+    remote_is_secure_ret ret;
+    remoteDriverLock(priv);
 
-        /* Use the default location of the CA certificate if it
-         * cannot be found in $HOME/.pki/libvirt
-         */
-        if (!virFileExists(libvirt_cacert)) {
-            VIR_FREE(libvirt_cacert);
+    memset (&ret, 0, sizeof ret);
+    if (call (conn, priv, 0, REMOTE_PROC_IS_SECURE,
+              (xdrproc_t) xdr_void, (char *) NULL,
+              (xdrproc_t) xdr_remote_is_secure_ret, (char *) &ret) == -1)
+        goto done;
 
-            libvirt_cacert = strdup(LIBVIRT_CACERT);
-            if (!libvirt_cacert) goto out_of_memory;
-        }
+    /* We claim to be secure, if the remote driver
+     * transport itself is secure, and the remote
+     * HV connection is secure
+     *
+     * ie, we don't want to claim to be secure if the
+     * remote driver is used to connect to a XenD
+     * driver using unencrypted HTTP:/// access
+     */
+    rv = priv->is_secure && ret.secure ? 1 : 0;
 
-        /* Use default location as long as one of
-         * client key, and client certificate cannot be found in
-         * $HOME/.pki/libvirt, we don't want to make user confused
-         * with one file is here, the other is there.
-         */
-        if (!virFileExists(libvirt_clientkey) ||
-            !virFileExists(libvirt_clientcert)) {
-            VIR_FREE(libvirt_clientkey);
-            VIR_FREE(libvirt_clientcert);
-
-            libvirt_clientkey = strdup(LIBVIRT_CLIENTKEY);
-            if (!libvirt_clientkey) goto out_of_memory;
-
-            libvirt_clientcert = strdup(LIBVIRT_CLIENTCERT);
-            if (!libvirt_clientcert) goto out_of_memory;
-        }
-    } else {
-        libvirt_cacert = strdup(LIBVIRT_CACERT);
-        if (!libvirt_cacert) goto out_of_memory;
+done:
+    remoteDriverUnlock(priv);
+    return rv;
+}
 
-        libvirt_clientkey = strdup(LIBVIRT_CLIENTKEY);
-        if (!libvirt_clientkey) goto out_of_memory;
+static int remoteIsEncrypted(virConnectPtr conn)
+{
+    int rv = -1;
+    int encrypted = 0;
+    struct private_data *priv = conn->privateData;
+    remote_is_secure_ret ret;
+    remoteDriverLock(priv);
 
-        libvirt_clientcert = strdup(LIBVIRT_CLIENTCERT);
-        if (!libvirt_clientcert) goto out_of_memory;
-    }
-
-    if (check_cert_file("CA certificate", libvirt_cacert) < 0)
-        goto error;
-    if (check_cert_file("client key", libvirt_clientkey) < 0)
-        goto error;
-    if (check_cert_file("client certificate", libvirt_clientcert) < 0)
-        goto error;
-
-    /* Set the trusted CA cert. */
-    VIR_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': %s"),
-                    libvirt_cacert, gnutls_strerror (err));
-        goto error;
-    }
-
-    /* Set the client certificate and private key. */
-    VIR_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 '%s' and/or "
-                    "certificate '%s': %s"), libvirt_clientkey,
-                    libvirt_clientcert, gnutls_strerror (err));
-        goto error;
-    }
-
-    initialized = 1;
-    ret = 0;
-
-cleanup:
-    VIR_FREE(libvirt_cacert);
-    VIR_FREE(libvirt_clientkey);
-    VIR_FREE(libvirt_clientcert);
-    VIR_FREE(userdir);
-    VIR_FREE(user_pki_path);
-    return ret;
-
-error:
-    ret = -1;
-    goto cleanup;
-
-out_of_memory:
-    ret = -1;
-    virReportOOMError();
-    goto cleanup;
-}
-
-static int verify_certificate (virConnectPtr conn, struct private_data *priv, gnutls_session_t session);
-
-#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);
-}
-
-static ssize_t
-custom_gnutls_pull(void *s, void *buf, size_t len)
-{
-    return recv((size_t)s, buf, len, 0);
-}
-#endif
-
-static gnutls_session_t
-negotiate_gnutls_on_connection (virConnectPtr conn,
-                                struct private_data *priv,
-                                int no_verify)
-{
-    bool success = false;
-    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;
-    }
-
-    /* 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));
-        goto cleanup;
-    }
-
-    /* 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));
-        goto cleanup;
-    }
-
-    gnutls_transport_set_ptr (session,
-                              (gnutls_transport_ptr_t) (long) priv->sock);
-
-#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
-
-    /* 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));
-        goto cleanup;
-    }
-
-    /* Verify certificate. */
-    if (verify_certificate (conn, priv, session) == -1) {
-        VIR_DEBUG("failed to verify peer's certificate");
-        if (!no_verify)
-            goto cleanup;
-    }
-
-    /* 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));
-        goto cleanup;
-    }
-    if (len != 1 || buf[0] != '\1') {
-        remoteError(VIR_ERR_RPC, "%s",
-                    _("server verification (of our certificate or IP "
-                      "address) failed"));
-        goto cleanup;
-    }
-
-#if 0
-    /* Print session info. */
-    print_info (session);
-#endif
-
-    success = true;
-
-cleanup:
-    if (!success) {
-        gnutls_deinit(session);
-        session = NULL;
-    }
-
-    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)
-{
-    /* Remove timer before closing the connection, to avoid possible
-     * remoteDomainEventFired with a free'd connection */
-    if (priv->domainEventState->timer >= 0) {
-        virEventRemoveTimeout(priv->domainEventState->timer);
-        virEventRemoveHandle(priv->watch);
-        priv->watch = -1;
-        priv->domainEventState->timer = -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);
-
-    virDomainEventStateFree(priv->domainEventState);
-
-    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;
-}
-
-/* Unfortunately this function is defined to return a static string.
- * Since the remote end always answers with the same type (for a
- * single connection anyway) we cache the type in the connection's
- * private data, and free it when we close the connection.
- *
- * See also:
- * http://www.redhat.com/archives/libvir-list/2007-February/msg00096.html
- */
-static const char *
-remoteType (virConnectPtr conn)
-{
-    char *rv = NULL;
-    remote_get_type_ret ret;
-    struct private_data *priv = conn->privateData;
-
-    remoteDriverLock(priv);
-
-    /* Cached? */
-    if (priv->type) {
-        rv = priv->type;
-        goto done;
-    }
-
-    memset (&ret, 0, sizeof ret);
-    if (call (conn, priv, 0, REMOTE_PROC_GET_TYPE,
-              (xdrproc_t) xdr_void, (char *) NULL,
-              (xdrproc_t) xdr_remote_get_type_ret, (char *) &ret) == -1)
-        goto done;
-
-    /* Stash. */
-    rv = priv->type = ret.type;
-
-done:
-    remoteDriverUnlock(priv);
-    return rv;
-}
-
-static int remoteIsSecure(virConnectPtr conn)
-{
-    int rv = -1;
-    struct private_data *priv = conn->privateData;
-    remote_is_secure_ret ret;
-    remoteDriverLock(priv);
-
-    memset (&ret, 0, sizeof ret);
-    if (call (conn, priv, 0, REMOTE_PROC_IS_SECURE,
-              (xdrproc_t) xdr_void, (char *) NULL,
-              (xdrproc_t) xdr_remote_is_secure_ret, (char *) &ret) == -1)
-        goto done;
-
-    /* We claim to be secure, if the remote driver
-     * transport itself is secure, and the remote
-     * HV connection is secure
-     *
-     * ie, we don't want to claim to be secure if the
-     * remote driver is used to connect to a XenD
-     * driver using unencrypted HTTP:/// access
-     */
-    rv = priv->is_secure && ret.secure ? 1 : 0;
-
-done:
-    remoteDriverUnlock(priv);
-    return rv;
-}
-
-static int remoteIsEncrypted(virConnectPtr conn)
-{
-    int rv = -1;
-    int encrypted = 0;
-    struct private_data *priv = conn->privateData;
-    remote_is_secure_ret ret;
-    remoteDriverLock(priv);
-
-    memset (&ret, 0, sizeof ret);
-    if (call (conn, priv, 0, REMOTE_PROC_IS_SECURE,
-              (xdrproc_t) xdr_void, (char *) NULL,
-              (xdrproc_t) xdr_remote_is_secure_ret, (char *) &ret) == -1)
-        goto done;
-
-    if (priv->uses_tls)
-        encrypted = 1;
-#if HAVE_SASL
-    else if (priv->saslconn)
-        encrypted = 1;
-#endif
+    memset (&ret, 0, sizeof ret);
+    if (call (conn, priv, 0, REMOTE_PROC_IS_SECURE,
+              (xdrproc_t) xdr_void, (char *) NULL,
+              (xdrproc_t) xdr_remote_is_secure_ret, (char *) &ret) == -1)
+        goto done;
 
+    if (virNetClientIsEncrypted(priv->client))
+        encrypted = 1;
 
     /* We claim to be encrypted, if the remote driver
      * transport itself is encrypted, and the remote
@@ -2967,7 +2247,6 @@ remoteNWFilterClose(virConnectPtr conn)
 
 static int
 remoteAuthenticate (virConnectPtr conn, struct private_data *priv,
-                    int in_open ATTRIBUTE_UNUSED,
                     virConnectAuthPtr auth ATTRIBUTE_UNUSED,
                     const char *authtype)
 {
@@ -2975,16 +2254,19 @@ remoteAuthenticate (virConnectPtr conn, struct private_data *priv,
     int err, type = REMOTE_AUTH_NONE;
 
     memset(&ret, 0, sizeof ret);
-    err = call (conn, priv,
-                REMOTE_CALL_IN_OPEN | REMOTE_CALL_QUIET_MISSING_RPC,
+    err = call (conn, priv, 0,
                 REMOTE_PROC_AUTH_LIST,
                 (xdrproc_t) xdr_void, (char *) NULL,
                 (xdrproc_t) xdr_remote_auth_list_ret, (char *) &ret);
-    if (err == -2) /* Missing RPC - old server - ignore */
-        return 0;
-
-    if (err < 0)
+    if (err < 0) {
+        virErrorPtr verr = virGetLastError();
+        if (verr && verr->code == VIR_ERR_NO_SUPPORT) {
+            /* Missing RPC - old server - ignore */
+            virResetLastError();
+            return 0;
+        }
         return -1;
+    }
 
     if (ret.types.types_len == 0)
         return 0;
@@ -3023,7 +2305,7 @@ remoteAuthenticate (virConnectPtr conn, struct private_data *priv,
             STRCASEEQLEN(authtype, "sasl.", 5))
             mech = authtype + 5;
 
-        if (remoteAuthSASL(conn, priv, in_open, auth, mech) < 0) {
+        if (remoteAuthSASL(conn, priv, auth, mech) < 0) {
             VIR_FREE(ret.types.types_val);
             return -1;
         }
@@ -3033,7 +2315,7 @@ remoteAuthenticate (virConnectPtr conn, struct private_data *priv,
 
 #if HAVE_POLKIT
     case REMOTE_AUTH_POLKIT:
-        if (remoteAuthPolkit(conn, priv, in_open, auth) < 0) {
+        if (remoteAuthPolkit(conn, priv, auth) < 0) {
             VIR_FREE(ret.types.types_val);
             return -1;
         }
@@ -3225,11 +2507,9 @@ static void remoteAuthFillInteract(virConnectCredentialPtr cred,
 /* Perform the SASL authentication process
  */
 static int
-remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int in_open,
+remoteAuthSASL (virConnectPtr conn, struct private_data *priv,
                 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;
@@ -3237,48 +2517,22 @@ 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;
+    virNetSASLContextPtr saslCtxt;
+    virNetSASLSessionPtr sasl;
 
     VIR_DEBUG("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)
+    if (!(saslCtxt = virNetSASLContextNewClient()))
         goto cleanup;
 
     if (auth) {
@@ -3289,63 +2543,37 @@ 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 = virNetSASLSessionNewClient(saslCtxt,
+                                            "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 */
 
         VIR_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 (virNetSASLSessionExtKeySize(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 (virNetSASLSessionSecProps(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);
-    if (call (conn, priv, in_open, REMOTE_PROC_AUTH_SASL_INIT,
+    if (call (conn, priv, 0, REMOTE_PROC_AUTH_SASL_INIT,
               (xdrproc_t) xdr_void, (char *)NULL,
               (xdrproc_t) xdr_remote_auth_sasl_init_ret, (char *) &iret) != 0)
         goto cleanup;
@@ -3365,22 +2593,16 @@ remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int in_open,
  restart:
     /* Start the auth negotiation on the client end first */
     VIR_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 = virNetSASLSessionClientStart(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_SASL_INTERACT) {
         const char *msg;
         if (cred) {
             remoteAuthFreeCredentials(cred, ncred);
@@ -3410,7 +2632,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 */
@@ -3419,11 +2641,12 @@ 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;
-    VIR_DEBUG("Server start negotiation with mech %s. Data %d bytes %p", mech, clientoutlen, clientout);
+    VIR_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);
-    if (call (conn, priv, in_open, REMOTE_PROC_AUTH_SASL_START,
+    if (call (conn, priv, 0, REMOTE_PROC_AUTH_SASL_START,
               (xdrproc_t) xdr_remote_auth_sasl_start_args, (char *) &sargs,
               (xdrproc_t) xdr_remote_auth_sasl_start_ret, (char *) &sret) != 0)
         goto cleanup;
@@ -3433,27 +2656,23 @@ remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int in_open,
     serverin = sret.nil ? NULL : sret.data.data_val;
     serverinlen = sret.data.data_len;
     VIR_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 = virNetSASLSessionClientStep(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_SASL_INTERACT) {
             const char *msg;
             if (cred) {
                 remoteAuthFreeCredentials(cred, ncred);
@@ -3479,10 +2698,11 @@ remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int in_open,
         }
 
         VIR_FREE(serverin);
-        VIR_DEBUG("Client step result %d. Data %d bytes %p", err, clientoutlen, clientout);
+        VIR_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_SASL_COMPLETE)
             break;
 
         /* Not done, prepare to talk with the server for another iteration */
@@ -3491,10 +2711,11 @@ 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;
-        VIR_DEBUG("Server step with %d bytes %p", clientoutlen, clientout);
+        VIR_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,
+        if (call (conn, priv, 0, REMOTE_PROC_AUTH_SASL_STEP,
                   (xdrproc_t) xdr_remote_auth_sasl_step_args, (char *) &pargs,
                   (xdrproc_t) xdr_remote_auth_sasl_step_ret, (char *) &pret) != 0)
             goto cleanup;
@@ -3505,10 +2726,10 @@ remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int in_open,
         serverinlen = pret.data.data_len;
 
         VIR_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_SASL_COMPLETE) {
             VIR_FREE(serverin);
             break;
         }
@@ -3516,14 +2737,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 = virNetSASLSessionGetKeySize(sasl)) < 0)
             goto cleanup;
-        }
-        ssf = *(const int *)val;
+
         VIR_DEBUG("SASL SSF value %d", ssf);
         if (ssf < 56) { /* 56 == DES level, good for Kerberos */
             remoteError(VIR_ERR_AUTH_FAILED,
@@ -3534,18 +2750,16 @@ remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int in_open,
     }
 
     VIR_DEBUG("SASL authentication complete");
-    priv->saslconn = saslconn;
+    virNetClientSetSASLSession(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);
+    virNetSASLSessionFree(sasl);
+    virNetSASLContextFree(saslCtxt);
 
     return ret;
 }
@@ -3555,14 +2769,14 @@ remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int in_open,
 #if HAVE_POLKIT
 # if HAVE_POLKIT1
 static int
-remoteAuthPolkit (virConnectPtr conn, struct private_data *priv, int in_open,
+remoteAuthPolkit (virConnectPtr conn, struct private_data *priv,
                   virConnectAuthPtr auth ATTRIBUTE_UNUSED)
 {
     remote_auth_polkit_ret ret;
     VIR_DEBUG("Client initialize PolicyKit-1 authentication");
 
     memset (&ret, 0, sizeof ret);
-    if (call (conn, priv, in_open, REMOTE_PROC_AUTH_POLKIT,
+    if (call (conn, priv, 0, REMOTE_PROC_AUTH_POLKIT,
               (xdrproc_t) xdr_void, (char *)NULL,
               (xdrproc_t) xdr_remote_auth_polkit_ret, (char *) &ret) != 0) {
         return -1; /* virError already set by call */
@@ -3575,7 +2789,7 @@ remoteAuthPolkit (virConnectPtr conn, struct private_data *priv, int in_open,
 /* Perform the PolicyKit authentication process
  */
 static int
-remoteAuthPolkit (virConnectPtr conn, struct private_data *priv, int in_open,
+remoteAuthPolkit (virConnectPtr conn, struct private_data *priv,
                   virConnectAuthPtr auth)
 {
     remote_auth_polkit_ret ret;
@@ -3613,7 +2827,7 @@ remoteAuthPolkit (virConnectPtr conn, struct private_data *priv, int in_open,
     }
 
     memset (&ret, 0, sizeof ret);
-    if (call (conn, priv, in_open, REMOTE_PROC_AUTH_POLKIT,
+    if (call (conn, priv, 0, REMOTE_PROC_AUTH_POLKIT,
               (xdrproc_t) xdr_void, (char *)NULL,
               (xdrproc_t) xdr_remote_auth_polkit_ret, (char *) &ret) != 0) {
         return -1; /* virError already set by call */
@@ -3694,184 +2908,155 @@ done:
     return rv;
 }
 
-/**
- * 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);
-
-    /* unmarshal parameters, and process it*/
-    if (! xdr_remote_domain_event_lifecycle_msg(xdr, &msg) ) {
-        remoteError(VIR_ERR_RPC, "%s",
-                    _("Unable to demarshal 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;
+
+    remoteDomainEventQueue(priv, 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);
-
-    /* unmarshal parameters, and process it*/
-    if (! xdr_remote_domain_event_reboot_msg(xdr, &msg) ) {
-        remoteError(VIR_ERR_RPC, "%s",
-                    _("Unable to demarshal 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;
+
+    remoteDomainEventQueue(priv, 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);
-
-    /* unmarshal parameters, and process it*/
-    if (! xdr_remote_domain_event_rtc_change_msg(xdr, &msg) ) {
-        remoteError(VIR_ERR_RPC, "%s",
-                    _("Unable to demarshal RTC change 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;
+
+    remoteDomainEventQueue(priv, 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);
-
-    /* unmarshal parameters, and process it*/
-    if (! xdr_remote_domain_event_watchdog_msg(xdr, &msg) ) {
-        remoteError(VIR_ERR_RPC, "%s",
-                    _("Unable to demarshal watchdog 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;
+
+    remoteDomainEventQueue(priv, 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);
-
-    /* unmarshal parameters, and process it*/
-    if (! xdr_remote_domain_event_io_error_msg(xdr, &msg) ) {
-        remoteError(VIR_ERR_RPC, "%s",
-                    _("Unable to demarshal IO error 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;
+
+    remoteDomainEventQueue(priv, 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;
+    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);
-
-    /* unmarshal parameters, and process it*/
-    if (! xdr_remote_domain_event_io_error_reason_msg(xdr, &msg) ) {
-        remoteError(VIR_ERR_RPC, "%s",
-                    _("Unable to demarshal IO error reason 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;
+
+    remoteDomainEventQueue(priv, 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;
@@ -3879,58 +3064,48 @@ remoteDomainReadEventGraphics(virConnectPtr conn, XDR *xdr)
     virDomainEventGraphicsSubjectPtr subject = NULL;
     int i;
 
-    memset (&msg, 0, sizeof msg);
-
-    /* unmarshal parameters, and process it*/
-    if (! xdr_remote_domain_event_graphics_msg(xdr, &msg) ) {
-        remoteError(VIR_ERR_RPC, "%s",
-                    _("Unable to demarshal graphics 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);
+    remoteDomainEventQueue(priv, event);
+    return;
 
+no_memory:
     if (localAddr) {
         VIR_FREE(localAddr->service);
         VIR_FREE(localAddr->node);
@@ -3949,34 +3124,31 @@ no_memory:
         VIR_FREE(subject->identities);
         VIR_FREE(subject);
     }
-    return NULL;
+    return;
 }
 
 
-static virDomainEventPtr
-remoteDomainReadEventControlError(virConnectPtr conn, XDR *xdr)
+static void
+remoteDomainBuildEventControlError(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
+                                   virNetClientPtr client ATTRIBUTE_UNUSED,
+                                   void *evdata, void *opaque)
 {
-    remote_domain_event_control_error_msg msg;
+    virConnectPtr conn = opaque;
+    struct private_data *priv = conn->privateData;
+    remote_domain_event_control_error_msg *msg = evdata;
     virDomainPtr dom;
     virDomainEventPtr event = NULL;
-    memset (&msg, 0, sizeof msg);
-
-    /* unmarshall parameters, and process it*/
-    if (! xdr_remote_domain_event_control_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 = virDomainEventControlErrorNewFromDom(dom);
     xdr_free ((xdrproc_t) &xdr_remote_domain_event_control_error_msg, (char *) &msg);
 
     virDomainFree(dom);
-    return event;
+
+    remoteDomainEventQueue(priv, event);
 }
 
 
@@ -4020,195 +3192,6 @@ done:
     return rv;
 }
 
-static struct private_stream_data *
-remoteStreamOpen(virStreamPtr st,
-                 unsigned int proc_nr,
-                 unsigned int serial)
-{
-    struct private_data *priv = st->conn->privateData;
-    struct private_stream_data *stpriv;
-
-    if (VIR_ALLOC(stpriv) < 0) {
-        virReportOOMError();
-        return NULL;
-    }
-
-    /* Initialize call object used to receive replies */
-    stpriv->proc_nr = proc_nr;
-    stpriv->serial = serial;
-
-    stpriv->next = priv->streams;
-    priv->streams = stpriv;
-
-    return stpriv;
-}
-
-
-static void
-remoteStreamEventTimerUpdate(struct private_stream_data *privst)
-{
-    if (!privst->cb)
-        return;
-
-    VIR_DEBUG("Check timer offset=%d %d", privst->incomingOffset, privst->cbEvents);
-    if ((privst->incomingOffset &&
-         (privst->cbEvents & VIR_STREAM_EVENT_READABLE)) ||
-        (privst->cbEvents & VIR_STREAM_EVENT_WRITABLE)) {
-        VIR_DEBUG("Enabling event timer");
-        virEventUpdateTimeout(privst->cbTimer, 0);
-    } else {
-        VIR_DEBUG("Disabling event timer");
-        virEventUpdateTimeout(privst->cbTimer, -1);
-    }
-}
-
-
-static int
-remoteStreamPacket(virStreamPtr st,
-                   int status,
-                   const char *data,
-                   size_t nbytes)
-{
-    VIR_DEBUG("st=%p status=%d data=%p nbytes=%zu", st, status, data, nbytes);
-    struct private_data *priv = st->conn->privateData;
-    struct private_stream_data *privst = st->privateData;
-    XDR xdr;
-    struct remote_thread_call *thiscall;
-    remote_message_header hdr;
-    int ret;
-
-    memset(&hdr, 0, sizeof hdr);
-
-    if (VIR_ALLOC(thiscall) < 0) {
-        virReportOOMError();
-        return -1;
-    }
-
-    thiscall->mode = REMOTE_MODE_WAIT_TX;
-    thiscall->serial = privst->serial;
-    thiscall->proc_nr = privst->proc_nr;
-    if (status == REMOTE_OK ||
-        status == REMOTE_ERROR)
-        thiscall->want_reply = 1;
-
-    if (virCondInit(&thiscall->cond) < 0) {
-        VIR_FREE(thiscall);
-        remoteError(VIR_ERR_INTERNAL_ERROR, "%s",
-                    _("cannot initialize mutex"));
-        return -1;
-    }
-
-    /* Don't fill in any other fields in 'thiscall' since
-     * we're not expecting a reply for this */
-
-    hdr.prog = REMOTE_PROGRAM;
-    hdr.vers = REMOTE_PROTOCOL_VERSION;
-    hdr.proc = privst->proc_nr;
-    hdr.type = REMOTE_STREAM;
-    hdr.serial = privst->serial;
-    hdr.status = status;
-
-
-    /* Length must include the length word itself (always encoded in
-     * 4 bytes as per RFC 4506), so offset start length. We write this
-     * later.
-     */
-    thiscall->bufferLength = REMOTE_MESSAGE_HEADER_XDR_LEN;
-
-    /* Serialise header followed by args. */
-    xdrmem_create (&xdr, thiscall->buffer + thiscall->bufferLength,
-                   REMOTE_MESSAGE_MAX, XDR_ENCODE);
-    if (!xdr_remote_message_header (&xdr, &hdr)) {
-        remoteError(VIR_ERR_RPC, "%s", _("xdr_remote_message_header failed"));
-        goto error;
-    }
-
-    thiscall->bufferLength += xdr_getpos (&xdr);
-    xdr_destroy (&xdr);
-
-    if (status == REMOTE_CONTINUE) {
-        if (((4 + REMOTE_MESSAGE_MAX) - thiscall->bufferLength) < nbytes) {
-            remoteError(VIR_ERR_RPC, _("data size %zu too large for payload %d"),
-                        nbytes, ((4 + REMOTE_MESSAGE_MAX) - thiscall->bufferLength));
-            goto error;
-        }
-
-        memcpy(thiscall->buffer + thiscall->bufferLength, data, nbytes);
-        thiscall->bufferLength += nbytes;
-    }
-
-    /* Go back to packet start and encode the length word. */
-    xdrmem_create (&xdr, thiscall->buffer, REMOTE_MESSAGE_HEADER_XDR_LEN, XDR_ENCODE);
-    if (!xdr_u_int (&xdr, &thiscall->bufferLength)) {
-        remoteError(VIR_ERR_RPC, "%s", _("xdr_u_int (length word)"));
-        goto error;
-    }
-    xdr_destroy (&xdr);
-
-    ret = remoteIO(st->conn, priv, 0, thiscall);
-    ignore_value(virCondDestroy(&thiscall->cond));
-    VIR_FREE(thiscall);
-    if (ret < 0)
-        return -1;
-
-    return nbytes;
-
-error:
-    xdr_destroy (&xdr);
-    ignore_value(virCondDestroy(&thiscall->cond));
-    VIR_FREE(thiscall);
-    return -1;
-}
-
-static int
-remoteStreamHasError(virStreamPtr st) {
-    struct private_stream_data *privst = st->privateData;
-    if (!privst->has_error) {
-        return 0;
-    }
-
-    VIR_DEBUG("Raising async error");
-    virRaiseErrorFull(__FILE__, __FUNCTION__, __LINE__,
-                      privst->err.domain,
-                      privst->err.code,
-                      privst->err.level,
-                      privst->err.str1 ? *privst->err.str1 : NULL,
-                      privst->err.str2 ? *privst->err.str2 : NULL,
-                      privst->err.str3 ? *privst->err.str3 : NULL,
-                      privst->err.int1,
-                      privst->err.int2,
-                      "%s", privst->err.message ? *privst->err.message : NULL);
-
-    return 1;
-}
-
-static void
-remoteStreamRelease(virStreamPtr st)
-{
-    struct private_data *priv = st->conn->privateData;
-    struct private_stream_data *privst = st->privateData;
-
-    if (priv->streams == privst)
-        priv->streams = privst->next;
-    else {
-        struct private_stream_data *tmp = priv->streams;
-        while (tmp && tmp->next) {
-            if (tmp->next == privst) {
-                tmp->next = privst->next;
-                break;
-            }
-        }
-    }
-
-    if (privst->has_error)
-        xdr_free((xdrproc_t)xdr_remote_error,  (char *)&privst->err);
-
-    VIR_FREE(privst);
-
-    st->driver = NULL;
-    st->privateData = NULL;
-}
-
 
 static int
 remoteStreamSend(virStreamPtr st,
@@ -4217,22 +3200,21 @@ remoteStreamSend(virStreamPtr st,
 {
     VIR_DEBUG("st=%p data=%p nbytes=%zu", st, data, nbytes);
     struct private_data *priv = st->conn->privateData;
+    virNetClientStreamPtr privst = st->privateData;
     int rv = -1;
 
     remoteDriverLock(priv);
 
-    if (remoteStreamHasError(st))
+    if (virNetClientStreamRaiseError(privst))
         goto cleanup;
 
-    rv = remoteStreamPacket(st,
-                            REMOTE_CONTINUE,
-                            data,
-                            nbytes);
+    rv = virNetClientStreamSendPacket(privst,
+                                      priv->client,
+                                      VIR_NET_CONTINUE,
+                                      data,
+                                      nbytes);
 
 cleanup:
-    if (rv == -1)
-        remoteStreamRelease(st);
-
     remoteDriverUnlock(priv);
 
     return rv;
@@ -4246,123 +3228,57 @@ remoteStreamRecv(virStreamPtr st,
 {
     VIR_DEBUG("st=%p data=%p nbytes=%zu", st, data, nbytes);
     struct private_data *priv = st->conn->privateData;
-    struct private_stream_data *privst = st->privateData;
+    virNetClientStreamPtr privst = st->privateData;
     int rv = -1;
 
     remoteDriverLock(priv);
 
-    if (remoteStreamHasError(st))
+    if (virNetClientStreamRaiseError(privst))
         goto cleanup;
 
-    if (!privst->incomingOffset) {
-        struct remote_thread_call *thiscall;
-        int ret;
-
-        if (st->flags & VIR_STREAM_NONBLOCK) {
-            VIR_DEBUG("Non-blocking mode and no data available");
-            rv = -2;
-            goto cleanup;
-        }
-
-        if (VIR_ALLOC(thiscall) < 0) {
-            virReportOOMError();
-            goto cleanup;
-        }
-
-        /* We're not really doing an RPC calls, so we're
-         * skipping straight to RX part */
-        thiscall->mode = REMOTE_MODE_WAIT_RX;
-        thiscall->serial = privst->serial;
-        thiscall->proc_nr = privst->proc_nr;
-        thiscall->want_reply = 1;
-
-        if (virCondInit(&thiscall->cond) < 0) {
-            VIR_FREE(thiscall);
-            remoteError(VIR_ERR_INTERNAL_ERROR, "%s",
-                        _("cannot initialize mutex"));
-            goto cleanup;
-        }
-
-        ret = remoteIO(st->conn, priv, 0, thiscall);
-        ignore_value(virCondDestroy(&thiscall->cond));
-        VIR_FREE(thiscall);
-        if (ret < 0)
-            goto cleanup;
-    }
-
-    VIR_DEBUG("After IO %d", privst->incomingOffset);
-    if (privst->incomingOffset) {
-        int want = privst->incomingOffset;
-        if (want > nbytes)
-            want = nbytes;
-        memcpy(data, privst->incoming, want);
-        if (want < privst->incomingOffset) {
-            memmove(privst->incoming, privst->incoming + want, privst->incomingOffset - want);
-            privst->incomingOffset -= want;
-        } else {
-            VIR_FREE(privst->incoming);
-            privst->incomingOffset = privst->incomingLength = 0;
-        }
-        rv = want;
-    } else {
-        rv = 0;
-    }
-
-    remoteStreamEventTimerUpdate(privst);
+    rv = virNetClientStreamRecvPacket(privst,
+                                      priv->client,
+                                      data,
+                                      nbytes,
+                                      (st->flags & VIR_STREAM_NONBLOCK));
 
     VIR_DEBUG("Done %d", rv);
 
 cleanup:
-    if (rv == -1)
-        remoteStreamRelease(st);
     remoteDriverUnlock(priv);
 
     return rv;
 }
 
+struct remoteStreamCallbackData {
+    virStreamPtr st;
+    virStreamEventCallback cb;
+    void *opaque;
+    virFreeCallback ff;
+};
 
-static void
-remoteStreamEventTimer(int timer ATTRIBUTE_UNUSED, void *opaque)
+static void remoteStreamEventCallback(virNetClientStreamPtr stream ATTRIBUTE_UNUSED,
+                                      int events,
+                                      void *opaque)
 {
-    virStreamPtr st = opaque;
-    struct private_data *priv = st->conn->privateData;
-    struct private_stream_data *privst = st->privateData;
-    int events = 0;
-
-    remoteDriverLock(priv);
-
-    if (privst->cb &&
-        (privst->cbEvents & VIR_STREAM_EVENT_READABLE) &&
-        privst->incomingOffset)
-        events |= VIR_STREAM_EVENT_READABLE;
-    if (privst->cb &&
-        (privst->cbEvents & VIR_STREAM_EVENT_WRITABLE))
-        events |= VIR_STREAM_EVENT_WRITABLE;
-    VIR_DEBUG("Got Timer dispatch %d %d offset=%d", events, privst->cbEvents, privst->incomingOffset);
-    if (events) {
-        virStreamEventCallback cb = privst->cb;
-        void *cbOpaque = privst->cbOpaque;
-        virFreeCallback cbFree = privst->cbFree;
-
-        privst->cbDispatch = 1;
-        remoteDriverUnlock(priv);
-        (cb)(st, events, cbOpaque);
-        remoteDriverLock(priv);
-        privst->cbDispatch = 0;
-
-        if (!privst->cb && cbFree)
-            (cbFree)(cbOpaque);
-    }
+    struct remoteStreamCallbackData *cbdata = opaque;
+    struct private_data *priv = cbdata->st->conn->privateData;
 
     remoteDriverUnlock(priv);
+    (cbdata->cb)(cbdata->st, events, cbdata->opaque);
+    remoteDriverLock(priv);
 }
 
 
-static void
-remoteStreamEventTimerFree(void *opaque)
+static void remoteStreamCallbackFree(void *opaque)
 {
-    virStreamPtr st = opaque;
-    virUnrefStream(st);
+    struct remoteStreamCallbackData *cbdata = opaque;
+
+    if (!cbdata->cb && cbdata->ff)
+        (cbdata->ff)(cbdata->opaque);
+
+    virStreamFree(cbdata->st);
+    VIR_FREE(opaque);
 }
 
 
@@ -4374,148 +3290,128 @@ remoteStreamEventAddCallback(virStreamPtr st,
                              virFreeCallback ff)
 {
     struct private_data *priv = st->conn->privateData;
-    struct private_stream_data *privst = st->privateData;
+    virNetClientStreamPtr privst = st->privateData;
     int ret = -1;
+    struct remoteStreamCallbackData *cbdata;
 
-    remoteDriverLock(priv);
-
-    if (privst->cb) {
-        remoteError(VIR_ERR_INTERNAL_ERROR,
-                    "%s", _("multiple stream callbacks not supported"));
-        goto cleanup;
+    if (VIR_ALLOC(cbdata) < 0) {
+        virReportOOMError();
+        return -1;
     }
-
+    cbdata->cb = cb;
+    cbdata->opaque = opaque;
+    cbdata->ff = ff;
+    cbdata->st = st;
     virStreamRef(st);
-    if ((privst->cbTimer =
-         virEventAddTimeout(-1,
-                            remoteStreamEventTimer,
-                            st,
-                            remoteStreamEventTimerFree)) < 0) {
-        virUnrefStream(st);
-        goto cleanup;
-    }
 
-    privst->cb = cb;
-    privst->cbOpaque = opaque;
-    privst->cbFree = ff;
-    privst->cbEvents = events;
-
-    remoteStreamEventTimerUpdate(privst);
+    remoteDriverLock(priv);
 
-    ret = 0;
+    if ((ret = virNetClientStreamEventAddCallback(privst,
+                                                  events,
+                                                  remoteStreamEventCallback,
+                                                  cbdata,
+                                                  remoteStreamCallbackFree)) < 0) {
+        VIR_FREE(cbdata);
+        goto cleanup;
+    }
 
 cleanup:
     remoteDriverUnlock(priv);
     return ret;
 }
 
+
 static int
 remoteStreamEventUpdateCallback(virStreamPtr st,
                                 int events)
 {
     struct private_data *priv = st->conn->privateData;
-    struct private_stream_data *privst = st->privateData;
+    virNetClientStreamPtr privst = st->privateData;
     int ret = -1;
 
     remoteDriverLock(priv);
 
-    if (!privst->cb) {
-        remoteError(VIR_ERR_INTERNAL_ERROR,
-                    "%s", _("no stream callback registered"));
-        goto cleanup;
-    }
+    ret = virNetClientStreamEventUpdateCallback(privst, events);
 
-    privst->cbEvents = events;
-
-    remoteStreamEventTimerUpdate(privst);
-
-    ret = 0;
-
-cleanup:
-    remoteDriverUnlock(priv);
-    return ret;
-}
+    remoteDriverUnlock(priv);
+    return ret;
+}
 
 
 static int
 remoteStreamEventRemoveCallback(virStreamPtr st)
 {
     struct private_data *priv = st->conn->privateData;
-    struct private_stream_data *privst = st->privateData;
+    virNetClientStreamPtr privst = st->privateData;
     int ret = -1;
 
     remoteDriverLock(priv);
 
-    if (!privst->cb) {
-        remoteError(VIR_ERR_INTERNAL_ERROR,
-                    "%s", _("no stream callback registered"));
-        goto cleanup;
-    }
-
-    if (!privst->cbDispatch &&
-        privst->cbFree)
-        (privst->cbFree)(privst->cbOpaque);
-    privst->cb = NULL;
-    privst->cbOpaque = NULL;
-    privst->cbFree = NULL;
-    privst->cbEvents = 0;
-    virEventRemoveTimeout(privst->cbTimer);
-
-    ret = 0;
+    ret = virNetClientStreamEventRemoveCallback(privst);
 
-cleanup:
     remoteDriverUnlock(priv);
     return ret;
 }
 
+
 static int
 remoteStreamFinish(virStreamPtr st)
 {
     struct private_data *priv = st->conn->privateData;
+    virNetClientStreamPtr privst = st->privateData;
     int ret = -1;
 
     remoteDriverLock(priv);
 
-    if (remoteStreamHasError(st))
+    if (virNetClientStreamRaiseError(privst))
         goto cleanup;
 
-    ret = remoteStreamPacket(st,
-                             REMOTE_OK,
-                             NULL,
-                             0);
+    ret = virNetClientStreamSendPacket(privst,
+                                       priv->client,
+                                       VIR_NET_OK,
+                                       NULL,
+                                       0);
 
 cleanup:
-    remoteStreamRelease(st);
+    virNetClientRemoveStream(priv->client, privst);
+    virNetClientStreamFree(privst);
+    st->privateData = NULL;
+    st->driver = NULL;
 
     remoteDriverUnlock(priv);
     return ret;
 }
 
+
 static int
 remoteStreamAbort(virStreamPtr st)
 {
     struct private_data *priv = st->conn->privateData;
+    virNetClientStreamPtr privst = st->privateData;
     int ret = -1;
 
     remoteDriverLock(priv);
 
-    if (remoteStreamHasError(st))
+    if (virNetClientStreamRaiseError(privst))
         goto cleanup;
 
-    ret = remoteStreamPacket(st,
-                             REMOTE_ERROR,
-                             NULL,
-                             0);
+    ret = virNetClientStreamSendPacket(privst,
+                                       priv->client,
+                                       VIR_NET_ERROR,
+                                       NULL,
+                                       0);
 
 cleanup:
-    remoteStreamRelease(st);
+    virNetClientRemoveStream(priv->client, privst);
+    virNetClientStreamFree(privst);
+    st->privateData = NULL;
+    st->driver = NULL;
 
     remoteDriverUnlock(priv);
     return ret;
 }
 
 
-
 static virStreamDriver remoteStreamDrv = {
     .streamRecv = remoteStreamRecv,
     .streamSend = remoteStreamSend,
@@ -4526,6 +3422,7 @@ static virStreamDriver remoteStreamDrv = {
     .streamRemoveCallback = remoteStreamEventRemoveCallback,
 };
 
+
 static int remoteDomainEventRegisterAny(virConnectPtr conn,
                                         virDomainPtr dom,
                                         int eventID,
@@ -4620,6 +3517,7 @@ done:
     return rv;
 }
 
+
 /*----------------------------------------------------------------------*/
 
 static int
@@ -4793,23 +3691,28 @@ remoteDomainMigratePrepareTunnel3(virConnectPtr dconn,
                                   const char *dom_xml)
 {
     struct private_data *priv = dconn->privateData;
-    struct private_stream_data *privst = NULL;
     int rv = -1;
     remote_domain_migrate_prepare_tunnel3_args args;
     remote_domain_migrate_prepare_tunnel3_ret ret;
+    virNetClientStreamPtr netst;
 
     remoteDriverLock(priv);
 
     memset(&args, 0, sizeof(args));
     memset(&ret, 0, sizeof(ret));
 
-    if (!(privst = remoteStreamOpen(st,
-                                    REMOTE_PROC_DOMAIN_MIGRATE_PREPARE_TUNNEL3,
-                                    priv->counter)))
+    if (!(netst = virNetClientStreamNew(priv->remoteProgram,
+                                        REMOTE_PROC_DOMAIN_MIGRATE_PREPARE_TUNNEL,
+                                        priv->counter)))
         goto done;
 
+    if (virNetClientAddStream(priv->client, netst) < 0) {
+        virNetClientStreamFree(netst);
+        goto done;
+    }
+
     st->driver = &remoteStreamDrv;
-    st->privateData = privst;
+    st->privateData = netst;
 
     args.cookie_in.cookie_in_val = (char *)cookiein;
     args.cookie_in.cookie_in_len = cookieinlen;
@@ -4821,7 +3724,8 @@ remoteDomainMigratePrepareTunnel3(virConnectPtr dconn,
     if (call(dconn, priv, 0, REMOTE_PROC_DOMAIN_MIGRATE_PREPARE_TUNNEL3,
              (xdrproc_t) xdr_remote_domain_migrate_prepare_tunnel3_args, (char *) &args,
              (xdrproc_t) xdr_remote_domain_migrate_prepare_tunnel3_ret, (char *) &ret) == -1) {
-        remoteStreamRelease(st);
+        virNetClientRemoveStream(priv->client, netst);
+        virNetClientStreamFree(netst);
         goto done;
     }
 
@@ -5006,1251 +3910,41 @@ done:
 #include "remote_client_bodies.h"
 #include "qemu_client_bodies.h"
 
-
-/*----------------------------------------------------------------------*/
-
-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,
-                    _("Unable to marshal arguments for program %d version %d procedure %d type %d status %d"),
-                    hdr.prog, hdr.vers, hdr.proc, hdr.type, hdr.status);
-        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);
-    ignore_value(virCondDestroy(&rv->cond));
-    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) {
-            int ret, err;
-            ret = remoteIOReadBuffer(priv, priv->saslTemporary,
-                                     sizeof(priv->saslTemporary));
-            if (ret < 0)
-                return -1;
-            if (ret == 0)
-                return 0;
-
-            err = sasl_decode(priv->saslconn, priv->saslTemporary, 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;
-    VIR_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 */
-        VIR_DEBUG("Dispatch event %d %d", hdr.proc, priv->bufferLength);
-        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,
-                        _("Unable to marshal reply for program %d version %d procedure %d type %d status %d"),
-                        hdr->prog, hdr->vers, hdr->proc, hdr->type, hdr->status);
-            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,
-                        _("Unable to marshal error for program %d version %d procedure %d type %d status %d"),
-                        hdr->prog, hdr->vers, hdr->proc, hdr->type, hdr->status);
-            return -1;
-        }
-        thecall->mode = REMOTE_MODE_ERROR;
-        return 0;
-
-    default:
-        remoteError(VIR_ERR_RPC, _("unknown status (received %x)"), hdr->status);
-        return -1;
-    }
-}
-
-static int
-processCallDispatchMessage(virConnectPtr conn, struct private_data *priv,
-                           int in_open,
-                           remote_message_header *hdr,
-                           XDR *xdr) {
-    virDomainEventPtr event = NULL;
-    /* An async message has come in while we were waiting for the
-     * response. Process it to pull it off the wire, and try again
-     */
-
-    if (in_open) {
-        VIR_DEBUG("Ignoring bogus event %d received while in open", hdr->proc);
-        return -1;
-    }
-
-    switch (hdr->proc) {
-    case REMOTE_PROC_DOMAIN_EVENT_LIFECYCLE:
-        event = remoteDomainReadEventLifecycle(conn, xdr);
-        break;
-
-    case REMOTE_PROC_DOMAIN_EVENT_REBOOT:
-        event = remoteDomainReadEventReboot(conn, xdr);
-        break;
-
-    case REMOTE_PROC_DOMAIN_EVENT_RTC_CHANGE:
-        event = remoteDomainReadEventRTCChange(conn, xdr);
-        break;
-
-    case REMOTE_PROC_DOMAIN_EVENT_WATCHDOG:
-        event = remoteDomainReadEventWatchdog(conn, xdr);
-        break;
-
-    case REMOTE_PROC_DOMAIN_EVENT_IO_ERROR:
-        event = remoteDomainReadEventIOError(conn, xdr);
-        break;
-
-    case REMOTE_PROC_DOMAIN_EVENT_IO_ERROR_REASON:
-        event = remoteDomainReadEventIOErrorReason(conn, xdr);
-        break;
-
-    case REMOTE_PROC_DOMAIN_EVENT_GRAPHICS:
-        event = remoteDomainReadEventGraphics(conn, xdr);
-        break;
-
-    case REMOTE_PROC_DOMAIN_EVENT_CONTROL_ERROR:
-        event = remoteDomainReadEventControlError(conn, xdr);
-        break;
-
-    default:
-        VIR_DEBUG("Unexpected event proc %d", hdr->proc);
-        break;
-    }
-    VIR_DEBUG("Event ready for queue %p %p", event, conn);
-
-    if (!event)
-        return -1;
-
-    remoteDomainEventQueue(priv, event);
-    return 0;
-}
-
-static int
-processCallDispatchStream(virConnectPtr conn ATTRIBUTE_UNUSED,
-                          struct private_data *priv,
-                          remote_message_header *hdr,
-                          XDR *xdr) {
-    struct private_stream_data *privst;
-    struct remote_thread_call *thecall;
-
-    /* Try and find a matching stream */
-    privst = priv->streams;
-    while (privst &&
-           privst->serial != hdr->serial &&
-           privst->proc_nr != hdr->proc)
-        privst = privst->next;
-
-    if (!privst) {
-        VIR_DEBUG("No registered stream matching serial=%d, proc=%d",
-                  hdr->serial, hdr->proc);
-        return -1;
-    }
-
-    /* See if there's also a (optional) call waiting for this reply */
-    thecall = priv->waitDispatch;
-    while (thecall &&
-           thecall->serial != hdr->serial)
-        thecall = thecall->next;
-
-
-    /* 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_CONTINUE: {
-        int avail = privst->incomingLength - privst->incomingOffset;
-        int need = priv->bufferLength - priv->bufferOffset;
-        VIR_DEBUG("Got a stream data packet");
-
-        /* XXX flag stream as complete somwhere if need==0 */
-
-        if (need > avail) {
-            int extra = need - avail;
-            if (VIR_REALLOC_N(privst->incoming,
-                              privst->incomingLength + extra) < 0) {
-                VIR_DEBUG("Out of memory handling stream data");
-                return -1;
-            }
-            privst->incomingLength += extra;
-        }
-
-        memcpy(privst->incoming + privst->incomingOffset,
-               priv->buffer + priv->bufferOffset,
-               priv->bufferLength - priv->bufferOffset);
-        privst->incomingOffset += (priv->bufferLength - priv->bufferOffset);
-
-        if (thecall && thecall->want_reply) {
-            VIR_DEBUG("Got sync data packet offset=%d", privst->incomingOffset);
-            thecall->mode = REMOTE_MODE_COMPLETE;
-        } else {
-            VIR_DEBUG("Got aysnc data packet offset=%d", privst->incomingOffset);
-            remoteStreamEventTimerUpdate(privst);
-        }
-        return 0;
-    }
-
-    case REMOTE_OK:
-        VIR_DEBUG("Got a synchronous confirm");
-        if (!thecall) {
-            VIR_DEBUG("Got unexpected stream finish confirmation");
-            return -1;
-        }
-        thecall->mode = REMOTE_MODE_COMPLETE;
-        return 0;
-
-    case REMOTE_ERROR:
-        if (thecall && thecall->want_reply) {
-            VIR_DEBUG("Got a synchronous error");
-            /* Give the error straight to this call */
-            memset (&thecall->err, 0, sizeof thecall->err);
-            if (!xdr_remote_error (xdr, &thecall->err)) {
-                remoteError(VIR_ERR_RPC, "%s", _("unmarshaling remote_error"));
-                return -1;
-            }
-            thecall->mode = REMOTE_MODE_ERROR;
-        } else {
-            VIR_DEBUG("Got a asynchronous error");
-            /* No call, so queue the error against the stream */
-            if (privst->has_error) {
-                VIR_DEBUG("Got unexpected duplicate stream error");
-                return -1;
-            }
-            privst->has_error = 1;
-            memset (&privst->err, 0, sizeof privst->err);
-            if (!xdr_remote_error (xdr, &privst->err)) {
-                VIR_DEBUG("Failed to unmarshal error");
-                return -1;
-            }
-        }
-        return 0;
-
-    default:
-        VIR_WARN("Stream with unexpected serial=%d, proc=%d, status=%d",
-                 hdr->serial, hdr->proc, hdr->status);
-        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, but we don't want to
-                 * spin around the loop forever if there are many
-                 * incoming async events, or replies for other
-                 * thread's RPC calls. We want to get out & let
-                 * any other thread take over as soon as we've
-                 * got our reply. When SASL is active though, we
-                 * may have read more data off the wire than we
-                 * initially wanted & cached it in memory. In this
-                 * case, poll() would not detect that there is more
-                 * ready todo.
-                 *
-                 * So if SASL is active *and* some SASL data is
-                 * already cached, then we'll process that now,
-                 * before returning.
-                 */
-#if HAVE_SASL
-                if (ret == 0 &&
-                    priv->saslconn &&
-                    priv->saslDecoded)
-                    continue;
-#endif
-                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
-        int timeout = -1;
-
-        /* If we have existing SASL decoded data we
-         * don't want to sleep in the poll(), just
-         * check if any other FDs are also ready
-         */
-#if HAVE_SASL
-        if (priv->saslDecoded)
-            timeout = 0;
-#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), timeout);
-        if (ret < 0 && errno == EAGAIN)
-            goto repoll;
-
-#ifdef HAVE_PTHREAD_SIGMASK
-        ignore_value(pthread_sigmask(SIG_SETMASK, &oldmask, NULL));
-#endif
-
-        remoteDriverLock(priv);
-
-        /* If we have existing SASL decoded data, pretend
-         * the socket became readable so we consume it
-         */
-#if HAVE_SASL
-        if (priv->saslDecoded)
-            fds[0].revents |= POLLIN;
-#endif
-
-        if (fds[1].revents) {
-            ssize_t s;
-            VIR_DEBUG("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...
-                 */
-                VIR_DEBUG("Waking up sleep %d %p %p", tmp->proc_nr, tmp, priv->waitDispatch);
-                virCondSignal(&tmp->cond);
-            } else {
-                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;
-            VIR_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) {
-                VIR_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;
-    VIR_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) {
-        VIR_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;
-
-    VIR_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;
-        }
-
-        VIR_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;
-        }
-
-        VIR_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;
-    }
-
-    VIR_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:
-    VIR_DEBUG("All done with our call %d %p %p", thiscall->proc_nr,
-          priv->waitDispatch, thiscall);
-    if (thiscall->mode == REMOTE_MODE_ERROR) {
-        /* Interop for virErrorNumber glitch in 0.8.0, if server is
-         * 0.7.1 through 0.7.7; see comments in virterror.h. */
-        switch (thiscall->err.code) {
-        case VIR_WAR_NO_NWFILTER:
-            /* no way to tell old VIR_WAR_NO_SECRET apart from
-             * VIR_WAR_NO_NWFILTER, but both are very similar
-             * warnings, so ignore the difference */
-            break;
-        case VIR_ERR_INVALID_NWFILTER:
-        case VIR_ERR_NO_NWFILTER:
-        case VIR_ERR_BUILD_FIREWALL:
-            /* server was trying to pass VIR_ERR_INVALID_SECRET,
-             * VIR_ERR_NO_SECRET, or VIR_ERR_CONFIG_UNSUPPORTED */
-            if (thiscall->err.domain != VIR_FROM_NWFILTER)
-                thiscall->err.code += 4;
-            break;
-        case VIR_WAR_NO_SECRET:
-            if (thiscall->err.domain == VIR_FROM_QEMU)
-                thiscall->err.code = VIR_ERR_OPERATION_TIMEOUT;
-            break;
-        case VIR_ERR_INVALID_SECRET:
-            if (thiscall->err.domain == VIR_FROM_XEN)
-                thiscall->err.code = VIR_ERR_MIGRATE_PERSIST_FAILED;
-            break;
-        default:
-            /* Nothing to alter. */
-            break;
-        }
-
-        /* 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(__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(__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) {
-        return -1;
-    }
+    /* 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--;
 
-    rv = remoteIO(conn, priv, flags, thiscall);
-    ignore_value(virCondDestroy(&thiscall->cond));
-    VIR_FREE(thiscall);
     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;
-
-    VIR_DEBUG("Event fired %d %d %d %X", watch, fd, event, event);
-
-    if (event & (VIR_EVENT_HANDLE_HANGUP | VIR_EVENT_HANDLE_ERROR)) {
-         VIR_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)
-        VIR_DEBUG("Something went wrong during async message processing");
-
-done:
-    remoteDriverUnlock(priv);
-}
-
 static void remoteDomainEventDispatchFunc(virConnectPtr conn,
                                           virDomainEventPtr event,
                                           virConnectDomainEventGenericCallback cb,
@@ -6266,7 +3960,7 @@ static void remoteDomainEventDispatchFunc(virConnectPtr conn,
     remoteDriverLock(priv);
 }
 
-void
+static void
 remoteDomainEventQueueFlush(int timer ATTRIBUTE_UNUSED, void *opaque)
 {
     virConnectPtr conn = opaque;
@@ -6282,7 +3976,7 @@ remoteDomainEventQueueFlush(int timer ATTRIBUTE_UNUSED, void *opaque)
     remoteDriverUnlock(priv);
 }
 
-void
+static void
 remoteDomainEventQueue(struct private_data *priv, virDomainEventPtr event)
 {
     virDomainEventStateQueue(priv->domainEventState, event);
diff --git a/src/rpc/gendispatch.pl b/src/rpc/gendispatch.pl
index 71085d9..d6264b9 100755
--- a/src/rpc/gendispatch.pl
+++ b/src/rpc/gendispatch.pl
@@ -1326,7 +1326,7 @@ elsif ($opt_k) {
         }
 
         if ($call->{streamflag} ne "none") {
-            print "    struct private_stream_data *privst = NULL;\n";
+            print "    virNetClientStreamPtr netst = NULL;\n";
         }
 
         print "\n";
@@ -1334,11 +1334,16 @@ elsif ($opt_k) {
 
         if ($call->{streamflag} ne "none") {
             print "\n";
-            print "    if (!(privst = remoteStreamOpen(st, REMOTE_PROC_$call->{UC_NAME}, priv->counter)))\n";
+            print "    if (!(netst = virNetClientStreamNew(priv->remoteProgram, REMOTE_PROC_$call->{UC_NAME}, priv->counter)))\n";
             print "       goto done;\n";
             print "\n";
+            print "    if (virNetClientAddStream(priv->client, netst) < 0) {";
+            print "       virNetClientStreamFree(netst);\n";
+            print "       goto done;\n";
+            print "    }";
+            print "\n";
             print "    st->driver = &remoteStreamDrv;\n";
-            print "    st->privateData = privst;\n";
+            print "    st->privateData = netst;\n";
         }
 
         if ($call->{ProcName} eq "SupportsFeature") {
@@ -1403,7 +1408,8 @@ elsif ($opt_k) {
         print "             (xdrproc_t)xdr_$call->{ret}, (char *)$call_ret) == -1) {\n";
 
         if ($call->{streamflag} ne "none") {
-            print "        remoteStreamRelease(st);\n";
+            print "        virNetClientRemoveStream(priv->client, netst);\n";
+            print "        virNetClientStreamFree(netst);\n";
         }
 
         print "        goto done;\n";
-- 
1.7.4.4




More information about the libvir-list mailing list