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

[libvirt] [PATCH 10/15] Convert the remote driver to new RPC client APIs



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            |    4 +-
 src/remote/remote_driver.c | 2596 ++++++++------------------------------------
 2 files changed, 451 insertions(+), 2149 deletions(-)

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


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