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

Eric Blake eblake at redhat.com
Mon Jun 27 20:08:07 UTC 2011


On 06/27/2011 08:24 AM, Daniel P. Berrange wrote:
> This guts the current remote driver, removing all its networking
> handling code. Instead it calls out to the new virClientPtr and
> virClientProgramPtr APIs for all RPC & networking work.
> ---
>  src/Makefile.am            |    5 +-
>  src/remote/remote_driver.c | 3452 ++++++++------------------------------------
>  src/rpc/gendispatch.pl     |   14 +-
>  3 files changed, 586 insertions(+), 2885 deletions(-)
> @@ -1222,6 +1222,7 @@ endif
>  libvirt_net_rpc_la_CFLAGS = \
>  			$(GNUTLS_CFLAGS) \
>  			$(SASL_CFLAGS) \
> +			$(XDR_CFLAGS) \

Should this hunk be done as a separate patch?

> +++ b/src/remote/remote_driver.c
> @@ -23,51 +23,14 @@

> +#include "virnetclient.h"
> +#include "virnetclientprogram.h"
> +#include "virnetclientstream.h"
>  #include "virterror_internal.h"
>  #include "logging.h"
>  #include "datatypes.h"

'make syntax-check' is calling you for not removing the now-unused
#include "ignore-value.h".

Aargh.  This needs yet another rebase to pick up the revert of BlockPull
patches:

remote/remote_driver.c:263:7: error:
'REMOTE_PROC_DOMAIN_EVENT_BLOCK_PULL' undeclared here (not in a function)
remote/remote_driver.c:265:14: error:
'remote_domain_event_block_pull_msg' undeclared here (not in a function)
remote/remote_driver.c:266:18: error:
'xdr_remote_domain_event_block_pull_msg' undeclared here (not in a function)
cc1: warnings being treated as errors
remote/remote_driver.c:222:1: error: 'remoteDomainBuildEventBlockPull'
used but never defined

> @@ -107,119 +70,27 @@
>  
>  static int inside_daemon = 0;
>  
> -struct remote_thread_call;
> -
> -
> -enum {
> -    REMOTE_MODE_WAIT_TX,
> -    REMOTE_MODE_WAIT_RX,
> -    REMOTE_MODE_COMPLETE,
> -    REMOTE_MODE_ERROR,
> -};

Replaced by virnetclient.c, but that enum only has MODE_WAIT_TX,
MODE_WAIT_RX, and MODE_COMPLETE - I'm hoping that dropping the
MODE_ERROR works out.

> +static void
> +remoteDomainBuildEventLifecycle(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
> +                                virNetClientPtr client ATTRIBUTE_UNUSED,
> +                                void *evdata, void *opaque);

Is it worth rearranging this file to be in topological order, to avoid
having to use quite as many forward declarations?  But that should be a
separate followup patch.

> @@ -524,12 +431,6 @@ doRemoteOpen (virConnectPtr conn,
>              } else if (STRCASEEQ (var->name, "no_tty")) {
>                  no_tty = atoi (var->value);
>                  var->ignore = 1;
> -            } else if (STRCASEEQ (var->name, "debug")) {
> -                if (var->value &&
> -                    STRCASEEQ (var->value, "stdout"))
> -                    priv->debugLog = stdout;
> -                else
> -                    priv->debugLog = stderr;
>              } else if (STRCASEEQ(var->name, "pkipath")) {

I'm not sure why this hunk is here.

>  
>          /*FALLTHROUGH*/
> -    case trans_tcp: {
> -        /* http://people.redhat.com/drepper/userapi-ipv6.html */
> -        struct addrinfo *res, *r;
> -        struct addrinfo hints;
> -        int saved_errno = EINVAL;
> -        memset (&hints, 0, sizeof hints);
> -        hints.ai_socktype = SOCK_STREAM;
> -        hints.ai_flags = AI_ADDRCONFIG;
> -        int e = getaddrinfo (priv->hostname, port, &hints, &res);
> -        if (e != 0) {
> -            remoteError(VIR_ERR_SYSTEM_ERROR,
> -                        _("unable to resolve hostname '%s': %s"),
> -                        priv->hostname, gai_strerror (e));
> +    case trans_tcp:
> +        priv->client = virNetClientNewTCP(priv->hostname, port);
> +        if (!priv->client)
>              goto failed;
> -        }
>  
> -        /* Try to connect to each returned address in turn. */
> -        /* XXX This loop contains a subtle problem.  In the case
> -         * where a host is accessible over IPv4 and IPv6, it will
> -         * try the IPv4 and IPv6 addresses in turn.  However it
> -         * should be able to present different client certificates
> -         * (because the commonName field in a client cert contains
> -         * the client IP address, which is different for IPv4 and
> -         * IPv6).  At the moment we only have a single client
> -         * certificate, and no way to specify what address family
> -         * that certificate belongs to.
> -         */
> -        for (r = res; r; r = r->ai_next) {
> -            int no_slow_start = 1;
> -
> -            priv->sock = socket (r->ai_family, SOCK_STREAM, 0);
> -            if (priv->sock == -1) {
> -                saved_errno = errno;
> -                continue;
> -            }
> -
> -            /* Disable Nagle - Dan Berrange. */
> -            setsockopt (priv->sock,
> -                        IPPROTO_TCP, TCP_NODELAY, (void *)&no_slow_start,
> -                        sizeof no_slow_start);
> -
> -            if (connect (priv->sock, r->ai_addr, r->ai_addrlen) == -1) {
> -                saved_errno = errno;
> -                VIR_FORCE_CLOSE(priv->sock);
> -                continue;
> -            }
> -
> -            if (priv->uses_tls) {
> -                priv->session =
> -                    negotiate_gnutls_on_connection
> -                      (conn, priv, no_verify);
> -                if (!priv->session) {
> -                    VIR_FORCE_CLOSE(priv->sock);
> -                    goto failed;
> -                }
> -            }
> -            goto tcp_connected;
> +        if (priv->tls) {
> +            VIR_DEBUG("Starting TLS session");
> +            if (virNetClientSetTLSSession(priv->client, priv->tls) < 0)
> +                goto failed;
>          }
>  
> -        freeaddrinfo (res);
> -        virReportSystemError(saved_errno,
> -                             _("unable to connect to libvirtd at '%s'"),
> -                             priv->hostname);
> -        goto failed;
> -
> -       tcp_connected:
> -        freeaddrinfo (res);
> -
> -        /* NB. All versioning is done by the RPC headers, so we don't
> -         * need to worry (at this point anyway) about versioning. */
>          break;
> -    }
>  
>  #ifndef WIN32
> -    case trans_unix: {
> +    case trans_unix:
>          if (!sockname) {
>              if (flags & VIR_DRV_OPEN_REMOTE_USER) {
>                  char *userdir = virGetUserDirectory(getuid());
> @@ -698,131 +544,59 @@ doRemoteOpen (virConnectPtr conn,
>                  VIR_FREE(userdir);
>              } else {
>                  if (flags & VIR_DRV_OPEN_REMOTE_RO)
> -                    sockname = strdup (LIBVIRTD_PRIV_UNIX_SOCKET_RO);
> +                    sockname = strdup(LIBVIRTD_PRIV_UNIX_SOCKET_RO);
>                  else
> -                    sockname = strdup (LIBVIRTD_PRIV_UNIX_SOCKET);
> +                    sockname = strdup(LIBVIRTD_PRIV_UNIX_SOCKET);
>                  if (sockname == NULL)
>                      goto out_of_memory;
>              }
> +            VIR_DEBUG("Proceeding with sockname %s", sockname);
>          }
>  
> -# ifndef UNIX_PATH_MAX
> -#  define UNIX_PATH_MAX(addr) (sizeof (addr).sun_path)
> -# endif
> -        struct sockaddr_un addr;
> -        int trials = 0;
> -
> -        memset (&addr, 0, sizeof addr);
> -        addr.sun_family = AF_UNIX;
> -        if (virStrcpyStatic(addr.sun_path, sockname) == NULL) {
> -            remoteError(VIR_ERR_INTERNAL_ERROR,
> -                        _("Socket %s too big for destination"), sockname);
> +        if (!(priv->client = virNetClientNewUNIX(sockname,
> +                                                 flags & VIR_DRV_OPEN_REMOTE_AUTOSTART,
> +                                                 remoteFindDaemonPath())))
>              goto failed;
> -        }
> -        if (addr.sun_path[0] == '@')
> -            addr.sun_path[0] = '\0';
>  
> -      autostart_retry:
>          priv->is_secure = 1;
> -        priv->sock = socket (AF_UNIX, SOCK_STREAM, 0);
> -        if (priv->sock == -1) {
> -            virReportSystemError(errno, "%s",
> -                                 _("unable to create socket"));
> -            goto failed;
> -        }
> -        if (connect (priv->sock, (struct sockaddr *) &addr, sizeof addr) == -1) {
> -            /* We might have to autostart the daemon in some cases....
> -             * It takes a short while for the daemon to startup, hence we
> -             * have a number of retries, with a small sleep. This will
> -             * sometimes cause multiple daemons to be started - this is
> -             * ok because the duplicates will fail to bind to the socket
> -             * and immediately exit, leaving just one daemon.
> -             */
> -            if (errno == ECONNREFUSED &&
> -                flags & VIR_DRV_OPEN_REMOTE_AUTOSTART &&
> -                trials < 20) {
> -                VIR_FORCE_CLOSE(priv->sock);
> -                if (trials > 0 ||
> -                    remoteForkDaemon() == 0) {
> -                    trials++;
> -                    usleep(1000 * 100 * trials);
> -                    goto autostart_retry;
> -                }
> -            }
> -            virReportSystemError(errno,
> -              _("unable to connect to '%s', libvirtd may need to be started"),
> -              sockname);
> -            goto failed;
> -        }
> -
>          break;
> -    }
>  
> -    case trans_ssh: {
> -        cmd = virCommandNew(command ? command : "ssh");
> -
> -        /* Generate the final command argv[] array.
> -         *   ssh [-p $port] [-l $username] $hostname $netcat -U $sockname */
> +    case trans_ssh:
> +        command = command ? command : strdup ("ssh");
> +        if (command == NULL)
> +            goto out_of_memory;
>  
> -        if (port) {
> -            virCommandAddArgList(cmd, "-p", port, NULL);
> -        }
> -        if (username) {
> -            virCommandAddArgList(cmd, "-l", username, NULL);
> -        }
> -        if (no_tty) {
> -            virCommandAddArgList(cmd, "-T", "-o", "BatchMode=yes", "-e",
> -                                 "none", NULL);
> +        if (!sockname) {
> +            if (flags & VIR_DRV_OPEN_REMOTE_RO)
> +                sockname = strdup(LIBVIRTD_PRIV_UNIX_SOCKET_RO);
> +            else
> +                sockname = strdup(LIBVIRTD_PRIV_UNIX_SOCKET);
> +            if (sockname == NULL)
> +                goto out_of_memory;
>          }
> -        virCommandAddArgList(cmd, priv->hostname, netcat ? netcat : "nc",
> -                             "-U", (sockname ? sockname :
> -                                    (flags & VIR_CONNECT_RO
> -                                     ? LIBVIRTD_PRIV_UNIX_SOCKET_RO
> -                                     : LIBVIRTD_PRIV_UNIX_SOCKET)), NULL);
> -
> -        priv->is_secure = 1;
> -    }
>  
> -        /*FALLTHROUGH*/
> -    case trans_ext: {
> -        pid_t pid;
> -        int sv[2];
> -        int errfd[2];
> -
> -        /* Fork off the external process.  Use socketpair to create a private
> -         * (unnamed) Unix domain socket to the child process so we don't have
> -         * to faff around with two file descriptors (a la 'pipe(2)').
> -         */
> -        if (socketpair (PF_UNIX, SOCK_STREAM, 0, sv) == -1) {
> -            virReportSystemError(errno, "%s",
> -                                 _("unable to create socket pair"));
> +        if (!(priv->client = virNetClientNewSSH(priv->hostname,
> +                                                port,
> +                                                command,
> +                                                username,
> +                                                no_tty,
> +                                                netcat ? netcat : "nc",
> +                                                sockname)))
>              goto failed;
> -        }
>  
> -        if (pipe(errfd) == -1) {
> -            virReportSystemError(errno, "%s",
> -                                 _("unable to create socket pair"));
> -            goto failed;
> -        }
> +        priv->is_secure = 1;
> +        break;
>  
> -        virCommandSetInputFD(cmd, sv[1]);
> -        virCommandSetOutputFD(cmd, &(sv[1]));
> -        virCommandSetErrorFD(cmd, &(errfd[1]));
> -        virCommandClearCaps(cmd);
> -        if (virCommandRunAsync(cmd, &pid) < 0)
> +    case trans_ext: {
> +        char const *cmd_argv[] = { command, NULL };
> +        if (!(priv->client = virNetClientNewExternal(cmd_argv)))
>              goto failed;
>  
> -        /* Parent continues here. */
> -        VIR_FORCE_CLOSE(sv[1]);
> -        VIR_FORCE_CLOSE(errfd[1]);
> -        priv->sock = sv[0];
> -        priv->errfd = errfd[0];
> -        priv->pid = pid;
> -
>          /* Do not set 'is_secure' flag since we can't guarentee
>           * an external program is secure, and this flag must be
>           * pessimistic */
> -    }
> +    }   break;
> +
>  #else /* WIN32 */
>  
>      case trans_unix:
> @@ -834,38 +608,36 @@ doRemoteOpen (virConnectPtr conn,
>          goto failed;
>  
>  #endif /* WIN32 */
> -
>      } /* switch (transport) */
>  
> -    if (virSetNonBlock(priv->sock) < 0) {
> -        virReportSystemError(errno, "%s",
> -                             _("unable to make socket non-blocking"));
> +    if (!(priv->remoteProgram = virNetClientProgramNew(REMOTE_PROGRAM,
> +                                                       REMOTE_PROTOCOL_VERSION,
> +                                                       remoteDomainEvents,
> +                                                       ARRAY_CARDINALITY(remoteDomainEvents),
> +                                                       conn)))
>          goto failed;
> -    }
> -
> -    if ((priv->errfd != -1) && virSetNonBlock(priv->errfd) < 0) {
> -        virReportSystemError(errno, "%s",
> -                             _("unable to make socket non-blocking"));
> +    if (!(priv->qemuProgram = virNetClientProgramNew(QEMU_PROGRAM,
> +                                                     QEMU_PROTOCOL_VERSION,
> +                                                     NULL,
> +                                                     0,
> +                                                     NULL)))
>          goto failed;
> -    }
>  
> -    if (pipe(wakeupFD) < 0) {
> -        virReportSystemError(errno, "%s",
> -                             _("unable to make pipe"));
> +    if (virNetClientAddProgram(priv->client, priv->remoteProgram) < 0 ||
> +        virNetClientAddProgram(priv->client, priv->qemuProgram) < 0)
>          goto failed;
> -    }
> -    priv->wakeupReadFD = wakeupFD[0];
> -    priv->wakeupSendFD = wakeupFD[1];
>  
>      /* Try and authenticate with server */
> -    if (remoteAuthenticate(conn, priv, 1, auth, authtype) == -1)
> +    VIR_DEBUG("Trying authentication");
> +    if (remoteAuthenticate(conn, priv, auth, authtype) == -1)
>          goto failed;
>  
>      /* Finally we can call the remote side's open function. */
>      {
>          remote_open_args args = { &name, flags };
>  
> -        if (call (conn, priv, REMOTE_CALL_IN_OPEN, REMOTE_PROC_OPEN,
> +        VIR_DEBUG("Trying to open URI %s", name);
> +        if (call (conn, priv, 0, REMOTE_PROC_OPEN,
>                    (xdrproc_t) xdr_remote_open_args, (char *) &args,
>                    (xdrproc_t) xdr_void, (char *) NULL) == -1)
>              goto failed;
> @@ -874,26 +646,14 @@ doRemoteOpen (virConnectPtr conn,
>      /* Now try and find out what URI the daemon used */
>      if (conn->uri == NULL) {
>          remote_get_uri_ret uriret;
> -        int urierr;
>  
> +        VIR_DEBUG("Trying to query remote URI");
>          memset (&uriret, 0, sizeof uriret);
> -        urierr = call (conn, priv,
> -                       REMOTE_CALL_IN_OPEN | REMOTE_CALL_QUIET_MISSING_RPC,
> -                       REMOTE_PROC_GET_URI,
> -                       (xdrproc_t) xdr_void, (char *) NULL,
> -                       (xdrproc_t) xdr_remote_get_uri_ret, (char *) &uriret);
> -        if (urierr == -2) {
> -            /* Should not really happen, since we only probe local libvirtd's,
> -               & the library should always match the daemon. Only case is post
> -               RPM upgrade where an old daemon instance is still running with
> -               new client. Too bad. It is not worth the hassle to fix this */
> -            remoteError(VIR_ERR_INTERNAL_ERROR, "%s",
> -                        _("unable to auto-detect URI"));
> -            goto failed;
> -        }
> -        if (urierr == -1) {
> +        if (call (conn, priv, 0,
> +                  REMOTE_PROC_GET_URI,
> +                  (xdrproc_t) xdr_void, (char *) NULL,
> +                  (xdrproc_t) xdr_remote_get_uri_ret, (char *) &uriret) < 0)
>              goto failed;
> -        }
>  
>          VIR_DEBUG("Auto-probed URI is %s", uriret.uri);
>          conn->uri = xmlParseURI(uriret.uri);
> @@ -904,27 +664,11 @@ doRemoteOpen (virConnectPtr conn,
>          }
>      }
>  
> -    /* Set up a callback to listen on the socket data */
> -    if ((priv->watch = virEventAddHandle(priv->sock,
> -                                         VIR_EVENT_HANDLE_READABLE,
> -                                         remoteDomainEventFired,
> -                                         conn, NULL)) < 0) {
> -        VIR_DEBUG("virEventAddHandle failed: No addHandleImpl defined."
> -               " continuing without events.");
> -        priv->watch = -1;
> -    }
> -
> -    priv->domainEventState = virDomainEventStateNew(remoteDomainEventQueueFlush,
> -                                                    conn,
> -                                                    NULL,
> -                                                    false);
> -    if (!priv->domainEventState) {
> +    if (!(priv->domainEventState = virDomainEventStateNew(remoteDomainEventQueueFlush,
> +                                                          conn,
> +                                                          NULL,
> +                                                          false)))
>          goto failed;
> -    }
> -    if (priv->domainEventState->timer < 0 && priv->watch != -1) {
> -        virEventRemoveHandle(priv->watch);
> -        priv->watch = -1;
> -    }
>  
>      /* Successful. */
>      retcode = VIR_DRV_OPEN_SUCCESS;
> @@ -938,7 +682,6 @@ doRemoteOpen (virConnectPtr conn,
>      VIR_FREE(netcat);
>      VIR_FREE(username);
>      VIR_FREE(port);
> -    virCommandFree(cmd);
>      VIR_FREE(pkipath);
>  
>      return retcode;
> @@ -949,30 +692,8 @@ doRemoteOpen (virConnectPtr conn,
>          free_qparam_set (vars);
>  
>   failed:
> -    /* Close the socket if we failed. */
> -    VIR_FORCE_CLOSE(priv->errfd);
> -
> -    if (priv->sock >= 0) {
> -        if (priv->uses_tls && priv->session) {
> -            gnutls_bye (priv->session, GNUTLS_SHUT_RDWR);
> -            gnutls_deinit (priv->session);
> -        }
> -        VIR_FORCE_CLOSE(priv->sock);
> -#ifndef WIN32
> -        if (priv->pid > 0) {
> -            pid_t reap;
> -            do {
> -retry:
> -                reap = waitpid(priv->pid, NULL, 0);
> -                if (reap == -1 && errno == EINTR)
> -                    goto retry;
> -            } while (reap != -1 && reap != priv->pid);
> -        }
> -#endif
> -    }
> -
> -    VIR_FORCE_CLOSE(wakeupFD[0]);
> -    VIR_FORCE_CLOSE(wakeupFD[1]);
> +    virNetClientFree(priv->client);
> +    priv->client = NULL;
>  
>      VIR_FREE(priv->hostname);
>      goto cleanup;
> @@ -995,9 +716,6 @@ remoteAllocPrivateData(void)
>      }
>      remoteDriverLock(priv);
>      priv->localUses = 1;
> -    priv->watch = -1;
> -    priv->sock = -1;
> -    priv->errfd = -1;
>  
>      return priv;
>  }
> @@ -1109,577 +827,139 @@ get_transport_from_scheme (char *scheme)
>      return p ? p+1 : 0;
>  }
>  
> -/* GnuTLS functions used by remoteOpen. */
> -static gnutls_certificate_credentials_t x509_cred;
> +/*----------------------------------------------------------------------*/
>  
>  
>  static int
> -check_cert_file(const char *type, const char *file)
> +doRemoteClose (virConnectPtr conn, struct private_data *priv)
>  {
> -    if (access(file, R_OK)) {
> -        virReportSystemError(errno,
> -                             _("Cannot access %s '%s'"),
> -                             type, file);
> +    if (call (conn, priv, 0, REMOTE_PROC_CLOSE,
> +              (xdrproc_t) xdr_void, (char *) NULL,
> +              (xdrproc_t) xdr_void, (char *) NULL) == -1)
>          return -1;
> -    }
> -    return 0;
> -}
>  
> +    virNetTLSContextFree(priv->tls);
> +    priv->tls = NULL;
> +    virNetClientFree(priv->client);
> +    priv->client = NULL;
> +    virNetClientProgramFree(priv->remoteProgram);
> +    virNetClientProgramFree(priv->qemuProgram);
> +    priv->remoteProgram = priv->qemuProgram = NULL;
> +
> +    /* Free hostname copy */
> +    VIR_FREE(priv->hostname);
> +
> +    /* See comment for remoteType. */
> +    VIR_FREE(priv->type);
> +
> +    virDomainEventStateFree(priv->domainEventState);
>  
> -static void remote_debug_gnutls_log(int level, const char* str) {
> -    VIR_DEBUG("%d %s", level, str);
> +    return 0;
>  }
>  
>  static int
> -initialize_gnutls(char *pkipath, int flags)
> +remoteClose (virConnectPtr conn)
>  {
> -    static int initialized = 0;
> -    int err;
> -    char *gnutlsdebug;
> -    char *libvirt_cacert = NULL;
> -    char *libvirt_clientkey = NULL;
> -    char *libvirt_clientcert = NULL;
> -    int ret = -1;
> -    char *userdir = NULL;
> -    char *user_pki_path = NULL;
> -
> -    if (initialized) return 0;
> -
> -    gnutls_global_init ();
> +    int ret = 0;
> +    struct private_data *priv = conn->privateData;
>  
> -    if ((gnutlsdebug = getenv("LIBVIRT_GNUTLS_DEBUG")) != NULL) {
> -        int val;
> -        if (virStrToLong_i(gnutlsdebug, NULL, 10, &val) < 0)
> -            val = 10;
> -        gnutls_global_set_log_level(val);
> -        gnutls_global_set_log_function(remote_debug_gnutls_log);
> +    remoteDriverLock(priv);
> +    priv->localUses--;
> +    if (!priv->localUses) {
> +        ret = doRemoteClose(conn, priv);
> +        conn->privateData = NULL;
> +        remoteDriverUnlock(priv);
> +        virMutexDestroy(&priv->lock);
> +        VIR_FREE (priv);
>      }
> +    if (priv)
> +        remoteDriverUnlock(priv);
>  
> -    /* X509 stuff */
> -    err = gnutls_certificate_allocate_credentials (&x509_cred);
> -    if (err) {
> -        remoteError(VIR_ERR_GNUTLS_ERROR,
> -                    _("unable to allocate TLS credentials: %s"),
> -                    gnutls_strerror (err));
> -        return -1;
> -    }
> +    return ret;
> +}
>  
> -    if (pkipath) {
> -        if ((virAsprintf(&libvirt_cacert, "%s/%s", pkipath,
> -                        "cacert.pem")) < 0)
> -            goto out_of_memory;
>  
> -        if ((virAsprintf(&libvirt_clientkey, "%s/%s", pkipath,
> -                        "clientkey.pem")) < 0)
> -            goto out_of_memory;
> +/* Unfortunately this function is defined to return a static string.
> + * Since the remote end always answers with the same type (for a
> + * single connection anyway) we cache the type in the connection's
> + * private data, and free it when we close the connection.
> + *
> + * See also:
> + * http://www.redhat.com/archives/libvir-list/2007-February/msg00096.html
> + */
> +static const char *
> +remoteType (virConnectPtr conn)
> +{
> +    char *rv = NULL;
> +    remote_get_type_ret ret;
> +    struct private_data *priv = conn->privateData;
>  
> -        if ((virAsprintf(&libvirt_clientcert, "%s/%s", pkipath,
> -                        "clientcert.pem")) < 0)
> -             goto out_of_memory;
> -    } else if (flags & VIR_DRV_OPEN_REMOTE_USER || getuid() > 0) {
> -        userdir = virGetUserDirectory(getuid());
> +    remoteDriverLock(priv);
>  
> -        if (!userdir)
> -            goto out_of_memory;
> +    /* Cached? */
> +    if (priv->type) {
> +        rv = priv->type;
> +        goto done;
> +    }
>  
> -        if (virAsprintf(&user_pki_path, "%s/.pki/libvirt", userdir) < 0)
> -            goto out_of_memory;
> +    memset (&ret, 0, sizeof ret);
> +    if (call (conn, priv, 0, REMOTE_PROC_GET_TYPE,
> +              (xdrproc_t) xdr_void, (char *) NULL,
> +              (xdrproc_t) xdr_remote_get_type_ret, (char *) &ret) == -1)
> +        goto done;
>  
> -        if ((virAsprintf(&libvirt_cacert, "%s/%s", user_pki_path,
> -                        "cacert.pem")) < 0)
> -            goto out_of_memory;
> +    /* Stash. */
> +    rv = priv->type = ret.type;
>  
> -        if ((virAsprintf(&libvirt_clientkey, "%s/%s", user_pki_path,
> -                        "clientkey.pem")) < 0)
> -            goto out_of_memory;
> +done:
> +    remoteDriverUnlock(priv);
> +    return rv;
> +}
>  
> -        if ((virAsprintf(&libvirt_clientcert, "%s/%s", user_pki_path,
> -                        "clientcert.pem")) < 0)
> -            goto out_of_memory;
> +static int remoteIsSecure(virConnectPtr conn)
> +{
> +    int rv = -1;
> +    struct private_data *priv = conn->privateData;
> +    remote_is_secure_ret ret;
> +    remoteDriverLock(priv);
>  
> -        /* Use the default location of the CA certificate if it
> -         * cannot be found in $HOME/.pki/libvirt
> -         */
> -        if (!virFileExists(libvirt_cacert)) {
> -            VIR_FREE(libvirt_cacert);
> +    memset (&ret, 0, sizeof ret);
> +    if (call (conn, priv, 0, REMOTE_PROC_IS_SECURE,
> +              (xdrproc_t) xdr_void, (char *) NULL,
> +              (xdrproc_t) xdr_remote_is_secure_ret, (char *) &ret) == -1)
> +        goto done;
>  
> -            libvirt_cacert = strdup(LIBVIRT_CACERT);
> -            if (!libvirt_cacert) goto out_of_memory;
> -        }
> +    /* We claim to be secure, if the remote driver
> +     * transport itself is secure, and the remote
> +     * HV connection is secure
> +     *
> +     * ie, we don't want to claim to be secure if the
> +     * remote driver is used to connect to a XenD
> +     * driver using unencrypted HTTP:/// access
> +     */
> +    rv = priv->is_secure && ret.secure ? 1 : 0;
>  
> -        /* Use default location as long as one of
> -         * client key, and client certificate cannot be found in
> -         * $HOME/.pki/libvirt, we don't want to make user confused
> -         * with one file is here, the other is there.
> -         */
> -        if (!virFileExists(libvirt_clientkey) ||
> -            !virFileExists(libvirt_clientcert)) {
> -            VIR_FREE(libvirt_clientkey);
> -            VIR_FREE(libvirt_clientcert);
> -
> -            libvirt_clientkey = strdup(LIBVIRT_CLIENTKEY);
> -            if (!libvirt_clientkey) goto out_of_memory;
> -
> -            libvirt_clientcert = strdup(LIBVIRT_CLIENTCERT);
> -            if (!libvirt_clientcert) goto out_of_memory;
> -        }
> -    } else {
> -        libvirt_cacert = strdup(LIBVIRT_CACERT);
> -        if (!libvirt_cacert) goto out_of_memory;
> +done:
> +    remoteDriverUnlock(priv);
> +    return rv;
> +}
>  
> -        libvirt_clientkey = strdup(LIBVIRT_CLIENTKEY);
> -        if (!libvirt_clientkey) goto out_of_memory;
> +static int remoteIsEncrypted(virConnectPtr conn)
> +{
> +    int rv = -1;
> +    int encrypted = 0;
> +    struct private_data *priv = conn->privateData;
> +    remote_is_secure_ret ret;
> +    remoteDriverLock(priv);
>  
> -        libvirt_clientcert = strdup(LIBVIRT_CLIENTCERT);
> -        if (!libvirt_clientcert) goto out_of_memory;
> -    }
> -
> -    if (check_cert_file("CA certificate", libvirt_cacert) < 0)
> -        goto error;
> -    if (check_cert_file("client key", libvirt_clientkey) < 0)
> -        goto error;
> -    if (check_cert_file("client certificate", libvirt_clientcert) < 0)
> -        goto error;
> -
> -    /* Set the trusted CA cert. */
> -    VIR_DEBUG("loading CA file %s", libvirt_cacert);
> -    err =
> -        gnutls_certificate_set_x509_trust_file (x509_cred, libvirt_cacert,
> -                                                GNUTLS_X509_FMT_PEM);
> -    if (err < 0) {
> -        remoteError(VIR_ERR_GNUTLS_ERROR,
> -                    _("unable to load CA certificate '%s': %s"),
> -                    libvirt_cacert, gnutls_strerror (err));
> -        goto error;
> -    }
> -
> -    /* Set the client certificate and private key. */
> -    VIR_DEBUG("loading client cert and key from files %s and %s",
> -          libvirt_clientcert, libvirt_clientkey);
> -    err =
> -        gnutls_certificate_set_x509_key_file (x509_cred,
> -                                              libvirt_clientcert,
> -                                              libvirt_clientkey,
> -                                              GNUTLS_X509_FMT_PEM);
> -    if (err < 0) {
> -        remoteError(VIR_ERR_GNUTLS_ERROR,
> -                    _("unable to load private key '%s' and/or "
> -                    "certificate '%s': %s"), libvirt_clientkey,
> -                    libvirt_clientcert, gnutls_strerror (err));
> -        goto error;
> -    }
> -
> -    initialized = 1;
> -    ret = 0;
> -
> -cleanup:
> -    VIR_FREE(libvirt_cacert);
> -    VIR_FREE(libvirt_clientkey);
> -    VIR_FREE(libvirt_clientcert);
> -    VIR_FREE(userdir);
> -    VIR_FREE(user_pki_path);
> -    return ret;
> -
> -error:
> -    ret = -1;
> -    goto cleanup;
> -
> -out_of_memory:
> -    ret = -1;
> -    virReportOOMError();
> -    goto cleanup;
> -}
> -
> -static int verify_certificate (virConnectPtr conn, struct private_data *priv, gnutls_session_t session);
> -
> -#if HAVE_WINSOCK2_H
> -static ssize_t
> -custom_gnutls_push(void *s, const void *buf, size_t len)
> -{
> -    return send((size_t)s, buf, len, 0);
> -}
> -
> -static ssize_t
> -custom_gnutls_pull(void *s, void *buf, size_t len)
> -{
> -    return recv((size_t)s, buf, len, 0);
> -}
> -#endif
> -
> -static gnutls_session_t
> -negotiate_gnutls_on_connection (virConnectPtr conn,
> -                                struct private_data *priv,
> -                                int no_verify)
> -{
> -    bool success = false;
> -    int err;
> -    gnutls_session_t session;
> -
> -    /* Initialize TLS session
> -     */
> -    err = gnutls_init (&session, GNUTLS_CLIENT);
> -    if (err) {
> -        remoteError(VIR_ERR_GNUTLS_ERROR,
> -                    _("unable to initialize TLS client: %s"),
> -                    gnutls_strerror (err));
> -        return NULL;
> -    }
> -
> -    /* Use default priorities */
> -    err = gnutls_set_default_priority (session);
> -    if (err) {
> -        remoteError(VIR_ERR_GNUTLS_ERROR,
> -                    _("unable to set TLS algorithm priority: %s"),
> -                    gnutls_strerror (err));
> -        goto cleanup;
> -    }
> -
> -    /* put the x509 credentials to the current session
> -     */
> -    err = gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, x509_cred);
> -    if (err) {
> -        remoteError(VIR_ERR_GNUTLS_ERROR,
> -                    _("unable to set session credentials: %s"),
> -                    gnutls_strerror (err));
> -        goto cleanup;
> -    }
> -
> -    gnutls_transport_set_ptr (session,
> -                              (gnutls_transport_ptr_t) (long) priv->sock);
> -
> -#if HAVE_WINSOCK2_H
> -    /* Make sure GnuTLS uses gnulib's replacment functions for send() and
> -     * recv() on Windows */
> -    gnutls_transport_set_push_function(session, custom_gnutls_push);
> -    gnutls_transport_set_pull_function(session, custom_gnutls_pull);
> -#endif
> -
> -    /* Perform the TLS handshake. */
> - again:
> -    err = gnutls_handshake (session);
> -    if (err < 0) {
> -        if (err == GNUTLS_E_AGAIN || err == GNUTLS_E_INTERRUPTED)
> -            goto again;
> -        remoteError(VIR_ERR_GNUTLS_ERROR,
> -                    _("unable to complete TLS handshake: %s"),
> -                    gnutls_strerror (err));
> -        goto cleanup;
> -    }
> -
> -    /* Verify certificate. */
> -    if (verify_certificate (conn, priv, session) == -1) {
> -        VIR_DEBUG("failed to verify peer's certificate");
> -        if (!no_verify)
> -            goto cleanup;
> -    }
> -
> -    /* At this point, the server is verifying _our_ certificate, IP address,
> -     * etc.  If we make the grade, it will send us a '\1' byte.
> -     */
> -    char buf[1];
> -    int len;
> - again_2:
> -    len = gnutls_record_recv (session, buf, 1);
> -    if (len < 0 && len != GNUTLS_E_UNEXPECTED_PACKET_LENGTH) {
> -        if (len == GNUTLS_E_AGAIN || len == GNUTLS_E_INTERRUPTED)
> -            goto again_2;
> -        remoteError(VIR_ERR_GNUTLS_ERROR,
> -                    _("unable to complete TLS initialization: %s"),
> -                    gnutls_strerror (len));
> -        goto cleanup;
> -    }
> -    if (len != 1 || buf[0] != '\1') {
> -        remoteError(VIR_ERR_RPC, "%s",
> -                    _("server verification (of our certificate or IP "
> -                      "address) failed"));
> -        goto cleanup;
> -    }
> -
> -#if 0
> -    /* Print session info. */
> -    print_info (session);
> -#endif
> -
> -    success = true;
> -
> -cleanup:
> -    if (!success) {
> -        gnutls_deinit(session);
> -        session = NULL;
> -    }
> -
> -    return session;
> -}
> -
> -static int
> -verify_certificate (virConnectPtr conn ATTRIBUTE_UNUSED,
> -                    struct private_data *priv,
> -                    gnutls_session_t session)
> -{
> -    int ret;
> -    unsigned int status;
> -    const gnutls_datum_t *certs;
> -    unsigned int nCerts, i;
> -    time_t now;
> -
> -    if ((ret = gnutls_certificate_verify_peers2 (session, &status)) < 0) {
> -        remoteError(VIR_ERR_GNUTLS_ERROR,
> -                    _("unable to verify server certificate: %s"),
> -                    gnutls_strerror (ret));
> -        return -1;
> -    }
> -
> -    if ((now = time(NULL)) == ((time_t)-1)) {
> -        virReportSystemError(errno, "%s",
> -                             _("cannot get current time"));
> -        return -1;
> -    }
> -
> -    if (status != 0) {
> -        const char *reason = _("Invalid certificate");
> -
> -        if (status & GNUTLS_CERT_INVALID)
> -            reason = _("The certificate is not trusted.");
> -
> -        if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
> -            reason = _("The certificate hasn't got a known issuer.");
> -
> -        if (status & GNUTLS_CERT_REVOKED)
> -            reason = _("The certificate has been revoked.");
> -
> -#ifndef GNUTLS_1_0_COMPAT
> -        if (status & GNUTLS_CERT_INSECURE_ALGORITHM)
> -            reason = _("The certificate uses an insecure algorithm");
> -#endif
> -
> -        remoteError(VIR_ERR_RPC,
> -                    _("server certificate failed validation: %s"),
> -                    reason);
> -        return -1;
> -    }
> -
> -    if (gnutls_certificate_type_get(session) != GNUTLS_CRT_X509) {
> -        remoteError(VIR_ERR_RPC,  "%s",_("Certificate type is not X.509"));
> -        return -1;
> -    }
> -
> -    if (!(certs = gnutls_certificate_get_peers(session, &nCerts))) {
> -        remoteError(VIR_ERR_RPC,  "%s",_("gnutls_certificate_get_peers failed"));
> -        return -1;
> -    }
> -
> -    for (i = 0 ; i < nCerts ; i++) {
> -        gnutls_x509_crt_t cert;
> -
> -        ret = gnutls_x509_crt_init (&cert);
> -        if (ret < 0) {
> -            remoteError(VIR_ERR_GNUTLS_ERROR,
> -                        _("unable to initialize certificate: %s"),
> -                        gnutls_strerror (ret));
> -            return -1;
> -        }
> -
> -        ret = gnutls_x509_crt_import (cert, &certs[i], GNUTLS_X509_FMT_DER);
> -        if (ret < 0) {
> -            remoteError(VIR_ERR_GNUTLS_ERROR,
> -                        _("unable to import certificate: %s"),
> -                        gnutls_strerror (ret));
> -            gnutls_x509_crt_deinit (cert);
> -            return -1;
> -        }
> -
> -        if (gnutls_x509_crt_get_expiration_time (cert) < now) {
> -            remoteError(VIR_ERR_RPC, "%s", _("The certificate has expired"));
> -            gnutls_x509_crt_deinit (cert);
> -            return -1;
> -        }
> -
> -        if (gnutls_x509_crt_get_activation_time (cert) > now) {
> -            remoteError(VIR_ERR_RPC, "%s",
> -                        _("The certificate is not yet activated"));
> -            gnutls_x509_crt_deinit (cert);
> -            return -1;
> -        }
> -
> -        if (i == 0) {
> -            if (!gnutls_x509_crt_check_hostname (cert, priv->hostname)) {
> -                remoteError(VIR_ERR_RPC,
> -                            _("Certificate's owner does not match the hostname (%s)"),
> -                            priv->hostname);
> -                gnutls_x509_crt_deinit (cert);
> -                return -1;
> -            }
> -        }
> -    }
> -
> -    return 0;
> -}
> -
> -/*----------------------------------------------------------------------*/
> -
> -
> -static int
> -doRemoteClose (virConnectPtr conn, struct private_data *priv)
> -{
> -    /* Remove timer before closing the connection, to avoid possible
> -     * remoteDomainEventFired with a free'd connection */
> -    if (priv->domainEventState->timer >= 0) {
> -        virEventRemoveTimeout(priv->domainEventState->timer);
> -        virEventRemoveHandle(priv->watch);
> -        priv->watch = -1;
> -        priv->domainEventState->timer = -1;
> -    }
> -
> -    if (call (conn, priv, 0, REMOTE_PROC_CLOSE,
> -              (xdrproc_t) xdr_void, (char *) NULL,
> -              (xdrproc_t) xdr_void, (char *) NULL) == -1)
> -        return -1;
> -
> -    /* Close socket. */
> -    if (priv->uses_tls && priv->session) {
> -        gnutls_bye (priv->session, GNUTLS_SHUT_RDWR);
> -        gnutls_deinit (priv->session);
> -    }
> -#if HAVE_SASL
> -    if (priv->saslconn)
> -        sasl_dispose (&priv->saslconn);
> -#endif
> -    VIR_FORCE_CLOSE(priv->sock);
> -    VIR_FORCE_CLOSE(priv->errfd);
> -
> -#ifndef WIN32
> -    if (priv->pid > 0) {
> -        pid_t reap;
> -        do {
> -retry:
> -            reap = waitpid(priv->pid, NULL, 0);
> -            if (reap == -1 && errno == EINTR)
> -                goto retry;
> -        } while (reap != -1 && reap != priv->pid);
> -    }
> -#endif
> -    VIR_FORCE_CLOSE(priv->wakeupReadFD);
> -    VIR_FORCE_CLOSE(priv->wakeupSendFD);
> -
> -
> -    /* Free hostname copy */
> -    VIR_FREE(priv->hostname);
> -
> -    /* See comment for remoteType. */
> -    VIR_FREE(priv->type);
> -
> -    virDomainEventStateFree(priv->domainEventState);
> -
> -    return 0;
> -}
> -
> -static int
> -remoteClose (virConnectPtr conn)
> -{
> -    int ret = 0;
> -    struct private_data *priv = conn->privateData;
> -
> -    remoteDriverLock(priv);
> -    priv->localUses--;
> -    if (!priv->localUses) {
> -        ret = doRemoteClose(conn, priv);
> -        conn->privateData = NULL;
> -        remoteDriverUnlock(priv);
> -        virMutexDestroy(&priv->lock);
> -        VIR_FREE (priv);
> -    }
> -    if (priv)
> -        remoteDriverUnlock(priv);
> -
> -    return ret;
> -}
> -
> -/* Unfortunately this function is defined to return a static string.
> - * Since the remote end always answers with the same type (for a
> - * single connection anyway) we cache the type in the connection's
> - * private data, and free it when we close the connection.
> - *
> - * See also:
> - * http://www.redhat.com/archives/libvir-list/2007-February/msg00096.html
> - */
> -static const char *
> -remoteType (virConnectPtr conn)
> -{
> -    char *rv = NULL;
> -    remote_get_type_ret ret;
> -    struct private_data *priv = conn->privateData;
> -
> -    remoteDriverLock(priv);
> -
> -    /* Cached? */
> -    if (priv->type) {
> -        rv = priv->type;
> -        goto done;
> -    }
> -
> -    memset (&ret, 0, sizeof ret);
> -    if (call (conn, priv, 0, REMOTE_PROC_GET_TYPE,
> -              (xdrproc_t) xdr_void, (char *) NULL,
> -              (xdrproc_t) xdr_remote_get_type_ret, (char *) &ret) == -1)
> -        goto done;
> -
> -    /* Stash. */
> -    rv = priv->type = ret.type;
> -
> -done:
> -    remoteDriverUnlock(priv);
> -    return rv;
> -}
> -
> -static int remoteIsSecure(virConnectPtr conn)
> -{
> -    int rv = -1;
> -    struct private_data *priv = conn->privateData;
> -    remote_is_secure_ret ret;
> -    remoteDriverLock(priv);
> -
> -    memset (&ret, 0, sizeof ret);
> -    if (call (conn, priv, 0, REMOTE_PROC_IS_SECURE,
> -              (xdrproc_t) xdr_void, (char *) NULL,
> -              (xdrproc_t) xdr_remote_is_secure_ret, (char *) &ret) == -1)
> -        goto done;
> -
> -    /* We claim to be secure, if the remote driver
> -     * transport itself is secure, and the remote
> -     * HV connection is secure
> -     *
> -     * ie, we don't want to claim to be secure if the
> -     * remote driver is used to connect to a XenD
> -     * driver using unencrypted HTTP:/// access
> -     */
> -    rv = priv->is_secure && ret.secure ? 1 : 0;
> -
> -done:
> -    remoteDriverUnlock(priv);
> -    return rv;
> -}
> -
> -static int remoteIsEncrypted(virConnectPtr conn)
> -{
> -    int rv = -1;
> -    int encrypted = 0;
> -    struct private_data *priv = conn->privateData;
> -    remote_is_secure_ret ret;
> -    remoteDriverLock(priv);
> -
> -    memset (&ret, 0, sizeof ret);
> -    if (call (conn, priv, 0, REMOTE_PROC_IS_SECURE,
> -              (xdrproc_t) xdr_void, (char *) NULL,
> -              (xdrproc_t) xdr_remote_is_secure_ret, (char *) &ret) == -1)
> -        goto done;
> -
> -    if (priv->uses_tls)
> -        encrypted = 1;
> -#if HAVE_SASL
> -    else if (priv->saslconn)
> -        encrypted = 1;
> -#endif
> +    memset (&ret, 0, sizeof ret);
> +    if (call (conn, priv, 0, REMOTE_PROC_IS_SECURE,
> +              (xdrproc_t) xdr_void, (char *) NULL,
> +              (xdrproc_t) xdr_remote_is_secure_ret, (char *) &ret) == -1)
> +        goto done;
>  
> +    if (virNetClientIsEncrypted(priv->client))
> +        encrypted = 1;
>  
>      /* We claim to be encrypted, if the remote driver
>       * transport itself is encrypted, and the remote
> @@ -2967,7 +2247,6 @@ remoteNWFilterClose(virConnectPtr conn)
>  
>  static int
>  remoteAuthenticate (virConnectPtr conn, struct private_data *priv,
> -                    int in_open ATTRIBUTE_UNUSED,
>                      virConnectAuthPtr auth ATTRIBUTE_UNUSED,
>                      const char *authtype)
>  {
> @@ -2975,16 +2254,19 @@ remoteAuthenticate (virConnectPtr conn, struct private_data *priv,
>      int err, type = REMOTE_AUTH_NONE;
>  
>      memset(&ret, 0, sizeof ret);
> -    err = call (conn, priv,
> -                REMOTE_CALL_IN_OPEN | REMOTE_CALL_QUIET_MISSING_RPC,
> +    err = call (conn, priv, 0,
>                  REMOTE_PROC_AUTH_LIST,
>                  (xdrproc_t) xdr_void, (char *) NULL,
>                  (xdrproc_t) xdr_remote_auth_list_ret, (char *) &ret);
> -    if (err == -2) /* Missing RPC - old server - ignore */
> -        return 0;
> -
> -    if (err < 0)
> +    if (err < 0) {
> +        virErrorPtr verr = virGetLastError();
> +        if (verr && verr->code == VIR_ERR_NO_SUPPORT) {
> +            /* Missing RPC - old server - ignore */
> +            virResetLastError();
> +            return 0;
> +        }
>          return -1;
> +    }
>  
>      if (ret.types.types_len == 0)
>          return 0;
> @@ -3023,7 +2305,7 @@ remoteAuthenticate (virConnectPtr conn, struct private_data *priv,
>              STRCASEEQLEN(authtype, "sasl.", 5))
>              mech = authtype + 5;
>  
> -        if (remoteAuthSASL(conn, priv, in_open, auth, mech) < 0) {
> +        if (remoteAuthSASL(conn, priv, auth, mech) < 0) {
>              VIR_FREE(ret.types.types_val);
>              return -1;
>          }
> @@ -3033,7 +2315,7 @@ remoteAuthenticate (virConnectPtr conn, struct private_data *priv,
>  
>  #if HAVE_POLKIT
>      case REMOTE_AUTH_POLKIT:
> -        if (remoteAuthPolkit(conn, priv, in_open, auth) < 0) {
> +        if (remoteAuthPolkit(conn, priv, auth) < 0) {
>              VIR_FREE(ret.types.types_val);
>              return -1;
>          }
> @@ -3225,11 +2507,9 @@ static void remoteAuthFillInteract(virConnectCredentialPtr cred,
>  /* Perform the SASL authentication process
>   */
>  static int
> -remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int in_open,
> +remoteAuthSASL (virConnectPtr conn, struct private_data *priv,
>                  virConnectAuthPtr auth, const char *wantmech)
>  {
> -    sasl_conn_t *saslconn = NULL;
> -    sasl_security_properties_t secprops;
>      remote_auth_sasl_init_ret iret;
>      remote_auth_sasl_start_args sargs;
>      remote_auth_sasl_start_ret sret;
> @@ -3237,48 +2517,22 @@ remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int in_open,
>      remote_auth_sasl_step_ret pret;
>      const char *clientout;
>      char *serverin = NULL;
> -    unsigned int clientoutlen, serverinlen;
> +    size_t clientoutlen, serverinlen;
>      const char *mech;
>      int err, complete;
> -    virSocketAddr sa;
> -    char *localAddr = NULL, *remoteAddr = NULL;
> -    const void *val;
> -    sasl_ssf_t ssf;
> +    int ssf;
>      sasl_callback_t *saslcb = NULL;
>      sasl_interact_t *interact = NULL;
>      virConnectCredentialPtr cred = NULL;
>      int ncred = 0;
>      int ret = -1;
>      const char *mechlist;
> +    virNetSASLContextPtr saslCtxt;
> +    virNetSASLSessionPtr sasl;
>  
>      VIR_DEBUG("Client initialize SASL authentication");
> -    /* Sets up the SASL library as a whole */
> -    err = sasl_client_init(NULL);
> -    if (err != SASL_OK) {
> -        remoteError(VIR_ERR_AUTH_FAILED,
> -                    _("failed to initialize SASL library: %d (%s)"),
> -                    err, sasl_errstring(err, NULL, NULL));
> -        goto cleanup;
> -    }
>  
> -    /* Get local address in form  IPADDR:PORT */
> -    sa.len = sizeof(sa.data.stor);
> -    if (getsockname(priv->sock, &sa.data.sa, &sa.len) < 0) {
> -        virReportSystemError(errno, "%s",
> -                             _("failed to get sock address"));
> -        goto cleanup;
> -    }
> -    if ((localAddr = virSocketFormatAddrFull(&sa, true, ";")) == NULL)
> -        goto cleanup;
> -
> -    /* Get remote address in form  IPADDR:PORT */
> -    sa.len = sizeof(sa.data.stor);
> -    if (getpeername(priv->sock, &sa.data.sa, &sa.len) < 0) {
> -        virReportSystemError(errno, "%s",
> -                             _("failed to get peer address"));
> -        goto cleanup;
> -    }
> -    if ((remoteAddr = virSocketFormatAddrFull(&sa, true, ";")) == NULL)
> +    if (!(saslCtxt = virNetSASLContextNewClient()))
>          goto cleanup;
>  
>      if (auth) {
> @@ -3289,63 +2543,37 @@ remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int in_open,
>      }
>  
>      /* Setup a handle for being a client */
> -    err = sasl_client_new("libvirt",
> -                          priv->hostname,
> -                          localAddr,
> -                          remoteAddr,
> -                          saslcb,
> -                          SASL_SUCCESS_DATA,
> -                          &saslconn);
> -
> -    if (err != SASL_OK) {
> -        remoteError(VIR_ERR_AUTH_FAILED,
> -                    _("Failed to create SASL client context: %d (%s)"),
> -                    err, sasl_errstring(err, NULL, NULL));
> +    if (!(sasl = virNetSASLSessionNewClient(saslCtxt,
> +                                            "libvirt",
> +                                            priv->hostname,
> +                                            virNetClientLocalAddrString(priv->client),
> +                                            virNetClientRemoteAddrString(priv->client),
> +                                            saslcb)))
>          goto cleanup;
> -    }
>  
>      /* Initialize some connection props we care about */
> -    if (priv->uses_tls) {
> -        gnutls_cipher_algorithm_t cipher;
> -
> -        cipher = gnutls_cipher_get(priv->session);
> -        if (!(ssf = (sasl_ssf_t)gnutls_cipher_get_key_size(cipher))) {
> -            remoteError(VIR_ERR_INTERNAL_ERROR, "%s",
> -                        _("invalid cipher size for TLS session"));
> +    if (priv->tls) {
> +        if ((ssf = virNetClientGetTLSKeySize(priv->client)) < 0)
>              goto cleanup;
> -        }
> +
>          ssf *= 8; /* key size is bytes, sasl wants bits */
>  
>          VIR_DEBUG("Setting external SSF %d", ssf);
> -        err = sasl_setprop(saslconn, SASL_SSF_EXTERNAL, &ssf);
> -        if (err != SASL_OK) {
> -            remoteError(VIR_ERR_INTERNAL_ERROR,
> -                        _("cannot set external SSF %d (%s)"),
> -                        err, sasl_errstring(err, NULL, NULL));
> +        if (virNetSASLSessionExtKeySize(sasl, ssf) < 0)
>              goto cleanup;
> -        }
>      }
>  
> -    memset (&secprops, 0, sizeof secprops);
>      /* If we've got a secure channel (TLS or UNIX sock), we don't care about SSF */
> -    secprops.min_ssf = priv->is_secure ? 0 : 56; /* Equiv to DES supported by all Kerberos */
> -    secprops.max_ssf = priv->is_secure ? 0 : 100000; /* Very strong ! AES == 256 */
> -    secprops.maxbufsize = 100000;
>      /* If we're not secure, then forbid any anonymous or trivially crackable auth */
> -    secprops.security_flags = priv->is_secure ? 0 :
> -        SASL_SEC_NOANONYMOUS | SASL_SEC_NOPLAINTEXT;
> -
> -    err = sasl_setprop(saslconn, SASL_SEC_PROPS, &secprops);
> -    if (err != SASL_OK) {
> -        remoteError(VIR_ERR_INTERNAL_ERROR,
> -                    _("cannot set security props %d (%s)"),
> -                    err, sasl_errstring(err, NULL, NULL));
> +    if (virNetSASLSessionSecProps(sasl,
> +                                  priv->is_secure ? 0 : 56, /* Equiv to DES supported by all Kerberos */
> +                                  priv->is_secure ? 0 : 100000, /* Very strong ! AES == 256 */
> +                                  priv->is_secure ? true : false) < 0)
>          goto cleanup;
> -    }
>  
>      /* First call is to inquire about supported mechanisms in the server */
>      memset (&iret, 0, sizeof iret);
> -    if (call (conn, priv, in_open, REMOTE_PROC_AUTH_SASL_INIT,
> +    if (call (conn, priv, 0, REMOTE_PROC_AUTH_SASL_INIT,
>                (xdrproc_t) xdr_void, (char *)NULL,
>                (xdrproc_t) xdr_remote_auth_sasl_init_ret, (char *) &iret) != 0)
>          goto cleanup;
> @@ -3365,22 +2593,16 @@ remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int in_open,
>   restart:
>      /* Start the auth negotiation on the client end first */
>      VIR_DEBUG("Client start negotiation mechlist '%s'", mechlist);
> -    err = sasl_client_start(saslconn,
> -                            mechlist,
> -                            &interact,
> -                            &clientout,
> -                            &clientoutlen,
> -                            &mech);
> -    if (err != SASL_OK && err != SASL_CONTINUE && err != SASL_INTERACT) {
> -        remoteError(VIR_ERR_AUTH_FAILED,
> -                    _("Failed to start SASL negotiation: %d (%s)"),
> -                    err, sasl_errdetail(saslconn));
> -        VIR_FREE(iret.mechlist);
> +    if ((err = virNetSASLSessionClientStart(sasl,
> +                                            mechlist,
> +                                            &interact,
> +                                            &clientout,
> +                                            &clientoutlen,
> +                                            &mech)) < 0)
>          goto cleanup;
> -    }
>  
>      /* Need to gather some credentials from the client */
> -    if (err == SASL_INTERACT) {
> +    if (err == VIR_NET_SASL_INTERACT) {
>          const char *msg;
>          if (cred) {
>              remoteAuthFreeCredentials(cred, ncred);
> @@ -3410,7 +2632,7 @@ remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int in_open,
>      if (clientoutlen > REMOTE_AUTH_SASL_DATA_MAX) {
>          remoteError(VIR_ERR_AUTH_FAILED,
>                      _("SASL negotiation data too long: %d bytes"),
> -                    clientoutlen);
> +                    (int)clientoutlen);
>          goto cleanup;
>      }
>      /* NB, distinction of NULL vs "" is *critical* in SASL */
> @@ -3419,11 +2641,12 @@ remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int in_open,
>      sargs.data.data_val = (char*)clientout;
>      sargs.data.data_len = clientoutlen;
>      sargs.mech = (char*)mech;
> -    VIR_DEBUG("Server start negotiation with mech %s. Data %d bytes %p", mech, clientoutlen, clientout);
> +    VIR_DEBUG("Server start negotiation with mech %s. Data %d bytes %p",
> +              mech, (int)clientoutlen, clientout);
>  
>      /* Now send the initial auth data to the server */
>      memset (&sret, 0, sizeof sret);
> -    if (call (conn, priv, in_open, REMOTE_PROC_AUTH_SASL_START,
> +    if (call (conn, priv, 0, REMOTE_PROC_AUTH_SASL_START,
>                (xdrproc_t) xdr_remote_auth_sasl_start_args, (char *) &sargs,
>                (xdrproc_t) xdr_remote_auth_sasl_start_ret, (char *) &sret) != 0)
>          goto cleanup;
> @@ -3433,27 +2656,23 @@ remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int in_open,
>      serverin = sret.nil ? NULL : sret.data.data_val;
>      serverinlen = sret.data.data_len;
>      VIR_DEBUG("Client step result complete: %d. Data %d bytes %p",
> -          complete, serverinlen, serverin);
> +              complete, (int)serverinlen, serverin);
>  
>      /* Loop-the-loop...
>       * Even if the server has completed, the client must *always* do at least one step
>       * in this loop to verify the server isn't lying about something. Mutual auth */
>      for (;;) {
>      restep:
> -        err = sasl_client_step(saslconn,
> -                               serverin,
> -                               serverinlen,
> -                               &interact,
> -                               &clientout,
> -                               &clientoutlen);
> -        if (err != SASL_OK && err != SASL_CONTINUE && err != SASL_INTERACT) {
> -            remoteError(VIR_ERR_AUTH_FAILED,
> -                        _("Failed SASL step: %d (%s)"),
> -                        err, sasl_errdetail(saslconn));
> +        if ((err = virNetSASLSessionClientStep(sasl,
> +                                               serverin,
> +                                               serverinlen,
> +                                               &interact,
> +                                               &clientout,
> +                                               &clientoutlen)) < 0)
>              goto cleanup;
> -        }
> +
>          /* Need to gather some credentials from the client */
> -        if (err == SASL_INTERACT) {
> +        if (err == VIR_NET_SASL_INTERACT) {
>              const char *msg;
>              if (cred) {
>                  remoteAuthFreeCredentials(cred, ncred);
> @@ -3479,10 +2698,11 @@ remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int in_open,
>          }
>  
>          VIR_FREE(serverin);
> -        VIR_DEBUG("Client step result %d. Data %d bytes %p", err, clientoutlen, clientout);
> +        VIR_DEBUG("Client step result %d. Data %d bytes %p",
> +                  err, (int)clientoutlen, clientout);
>  
>          /* Previous server call showed completion & we're now locally complete too */
> -        if (complete && err == SASL_OK)
> +        if (complete && err == VIR_NET_SASL_COMPLETE)
>              break;
>  
>          /* Not done, prepare to talk with the server for another iteration */
> @@ -3491,10 +2711,11 @@ remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int in_open,
>          pargs.nil = clientout ? 0 : 1;
>          pargs.data.data_val = (char*)clientout;
>          pargs.data.data_len = clientoutlen;
> -        VIR_DEBUG("Server step with %d bytes %p", clientoutlen, clientout);
> +        VIR_DEBUG("Server step with %d bytes %p",
> +                  (int)clientoutlen, clientout);
>  
>          memset (&pret, 0, sizeof pret);
> -        if (call (conn, priv, in_open, REMOTE_PROC_AUTH_SASL_STEP,
> +        if (call (conn, priv, 0, REMOTE_PROC_AUTH_SASL_STEP,
>                    (xdrproc_t) xdr_remote_auth_sasl_step_args, (char *) &pargs,
>                    (xdrproc_t) xdr_remote_auth_sasl_step_ret, (char *) &pret) != 0)
>              goto cleanup;
> @@ -3505,10 +2726,10 @@ remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int in_open,
>          serverinlen = pret.data.data_len;
>  
>          VIR_DEBUG("Client step result complete: %d. Data %d bytes %p",
> -              complete, serverinlen, serverin);
> +                  complete, (int)serverinlen, serverin);
>  
>          /* This server call shows complete, and earlier client step was OK */
> -        if (complete && err == SASL_OK) {
> +        if (complete && err == VIR_NET_SASL_COMPLETE) {
>              VIR_FREE(serverin);
>              break;
>          }
> @@ -3516,14 +2737,9 @@ remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int in_open,
>  
>      /* Check for suitable SSF if not already secure (TLS or UNIX sock) */
>      if (!priv->is_secure) {
> -        err = sasl_getprop(saslconn, SASL_SSF, &val);
> -        if (err != SASL_OK) {
> -            remoteError(VIR_ERR_AUTH_FAILED,
> -                        _("cannot query SASL ssf on connection %d (%s)"),
> -                        err, sasl_errstring(err, NULL, NULL));
> +        if ((ssf = virNetSASLSessionGetKeySize(sasl)) < 0)
>              goto cleanup;
> -        }
> -        ssf = *(const int *)val;
> +
>          VIR_DEBUG("SASL SSF value %d", ssf);
>          if (ssf < 56) { /* 56 == DES level, good for Kerberos */
>              remoteError(VIR_ERR_AUTH_FAILED,
> @@ -3534,18 +2750,16 @@ remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int in_open,
>      }
>  
>      VIR_DEBUG("SASL authentication complete");
> -    priv->saslconn = saslconn;
> +    virNetClientSetSASLSession(priv->client, sasl);
>      ret = 0;
>  
>   cleanup:
> -    VIR_FREE(localAddr);
> -    VIR_FREE(remoteAddr);
>      VIR_FREE(serverin);
>  
>      VIR_FREE(saslcb);
>      remoteAuthFreeCredentials(cred, ncred);
> -    if (ret != 0 && saslconn)
> -        sasl_dispose(&saslconn);
> +    virNetSASLSessionFree(sasl);
> +    virNetSASLContextFree(saslCtxt);
>  
>      return ret;
>  }
> @@ -3555,14 +2769,14 @@ remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int in_open,
>  #if HAVE_POLKIT
>  # if HAVE_POLKIT1
>  static int
> -remoteAuthPolkit (virConnectPtr conn, struct private_data *priv, int in_open,
> +remoteAuthPolkit (virConnectPtr conn, struct private_data *priv,
>                    virConnectAuthPtr auth ATTRIBUTE_UNUSED)
>  {
>      remote_auth_polkit_ret ret;
>      VIR_DEBUG("Client initialize PolicyKit-1 authentication");
>  
>      memset (&ret, 0, sizeof ret);
> -    if (call (conn, priv, in_open, REMOTE_PROC_AUTH_POLKIT,
> +    if (call (conn, priv, 0, REMOTE_PROC_AUTH_POLKIT,
>                (xdrproc_t) xdr_void, (char *)NULL,
>                (xdrproc_t) xdr_remote_auth_polkit_ret, (char *) &ret) != 0) {
>          return -1; /* virError already set by call */
> @@ -3575,7 +2789,7 @@ remoteAuthPolkit (virConnectPtr conn, struct private_data *priv, int in_open,
>  /* Perform the PolicyKit authentication process
>   */
>  static int
> -remoteAuthPolkit (virConnectPtr conn, struct private_data *priv, int in_open,
> +remoteAuthPolkit (virConnectPtr conn, struct private_data *priv,
>                    virConnectAuthPtr auth)
>  {
>      remote_auth_polkit_ret ret;
> @@ -3613,7 +2827,7 @@ remoteAuthPolkit (virConnectPtr conn, struct private_data *priv, int in_open,
>      }
>  
>      memset (&ret, 0, sizeof ret);
> -    if (call (conn, priv, in_open, REMOTE_PROC_AUTH_POLKIT,
> +    if (call (conn, priv, 0, REMOTE_PROC_AUTH_POLKIT,
>                (xdrproc_t) xdr_void, (char *)NULL,
>                (xdrproc_t) xdr_remote_auth_polkit_ret, (char *) &ret) != 0) {
>          return -1; /* virError already set by call */
> @@ -3694,184 +2908,155 @@ done:
>      return rv;
>  }
>  
> -/**
> - * remoteDomainReadEventLifecycle
> - *
> - * Read the domain lifecycle event data off the wire
> - */
> -static virDomainEventPtr
> -remoteDomainReadEventLifecycle(virConnectPtr conn, XDR *xdr)
> +
> +static void
> +remoteDomainBuildEventLifecycle(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
> +                                virNetClientPtr client ATTRIBUTE_UNUSED,
> +                                void *evdata, void *opaque)
>  {
> -    remote_domain_event_lifecycle_msg msg;
> +    virConnectPtr conn = opaque;
> +    struct private_data *priv = conn->privateData;
> +    remote_domain_event_lifecycle_msg *msg = evdata;
>      virDomainPtr dom;
>      virDomainEventPtr event = NULL;
> -    memset (&msg, 0, sizeof msg);
> -
> -    /* unmarshal parameters, and process it*/
> -    if (! xdr_remote_domain_event_lifecycle_msg(xdr, &msg) ) {
> -        remoteError(VIR_ERR_RPC, "%s",
> -                    _("Unable to demarshal lifecycle event"));
> -        return NULL;
> -    }
>  
> -    dom = get_nonnull_domain(conn,msg.dom);
> +    dom = get_nonnull_domain(conn, msg->dom);
>      if (!dom)
> -        return NULL;
> -
> -    event = virDomainEventNewFromDom(dom, msg.event, msg.detail);
> -    xdr_free ((xdrproc_t) &xdr_remote_domain_event_lifecycle_msg, (char *) &msg);
> +        return;
>  
> +    event = virDomainEventNewFromDom(dom, msg->event, msg->detail);
>      virDomainFree(dom);
> -    return event;
> +
> +    remoteDomainEventQueue(priv, event);
>  }
>  
>  
> -static virDomainEventPtr
> -remoteDomainReadEventReboot(virConnectPtr conn, XDR *xdr)
> +static void
> +remoteDomainBuildEventReboot(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
> +                             virNetClientPtr client ATTRIBUTE_UNUSED,
> +                             void *evdata, void *opaque)
>  {
> -    remote_domain_event_reboot_msg msg;
> +    virConnectPtr conn = opaque;
> +    struct private_data *priv = conn->privateData;
> +    remote_domain_event_reboot_msg *msg = evdata;
>      virDomainPtr dom;
>      virDomainEventPtr event = NULL;
> -    memset (&msg, 0, sizeof msg);
> -
> -    /* unmarshal parameters, and process it*/
> -    if (! xdr_remote_domain_event_reboot_msg(xdr, &msg) ) {
> -        remoteError(VIR_ERR_RPC, "%s",
> -                    _("Unable to demarshal reboot event"));
> -        return NULL;
> -    }
>  
> -    dom = get_nonnull_domain(conn,msg.dom);
> +    dom = get_nonnull_domain(conn, msg->dom);
>      if (!dom)
> -        return NULL;
> +        return;
>  
>      event = virDomainEventRebootNewFromDom(dom);
> -    xdr_free ((xdrproc_t) &xdr_remote_domain_event_reboot_msg, (char *) &msg);
> -
>      virDomainFree(dom);
> -    return event;
> +
> +    remoteDomainEventQueue(priv, event);
>  }
>  
>  
> -static virDomainEventPtr
> -remoteDomainReadEventRTCChange(virConnectPtr conn, XDR *xdr)
> +static void
> +remoteDomainBuildEventRTCChange(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
> +                                virNetClientPtr client ATTRIBUTE_UNUSED,
> +                                void *evdata, void *opaque)
>  {
> -    remote_domain_event_rtc_change_msg msg;
> +    virConnectPtr conn = opaque;
> +    struct private_data *priv = conn->privateData;
> +    remote_domain_event_rtc_change_msg *msg = evdata;
>      virDomainPtr dom;
>      virDomainEventPtr event = NULL;
> -    memset (&msg, 0, sizeof msg);
> -
> -    /* unmarshal parameters, and process it*/
> -    if (! xdr_remote_domain_event_rtc_change_msg(xdr, &msg) ) {
> -        remoteError(VIR_ERR_RPC, "%s",
> -                    _("Unable to demarshal RTC change event"));
> -        return NULL;
> -    }
>  
> -    dom = get_nonnull_domain(conn,msg.dom);
> +    dom = get_nonnull_domain(conn, msg->dom);
>      if (!dom)
> -        return NULL;
> -
> -    event = virDomainEventRTCChangeNewFromDom(dom, msg.offset);
> -    xdr_free ((xdrproc_t) &xdr_remote_domain_event_rtc_change_msg, (char *) &msg);
> +        return;
>  
> +    event = virDomainEventRTCChangeNewFromDom(dom, msg->offset);
>      virDomainFree(dom);
> -    return event;
> +
> +    remoteDomainEventQueue(priv, event);
>  }
>  
>  
> -static virDomainEventPtr
> -remoteDomainReadEventWatchdog(virConnectPtr conn, XDR *xdr)
> +static void
> +remoteDomainBuildEventWatchdog(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
> +                               virNetClientPtr client ATTRIBUTE_UNUSED,
> +                               void *evdata, void *opaque)
>  {
> -    remote_domain_event_watchdog_msg msg;
> +    virConnectPtr conn = opaque;
> +    struct private_data *priv = conn->privateData;
> +    remote_domain_event_watchdog_msg *msg = evdata;
>      virDomainPtr dom;
>      virDomainEventPtr event = NULL;
> -    memset (&msg, 0, sizeof msg);
> -
> -    /* unmarshal parameters, and process it*/
> -    if (! xdr_remote_domain_event_watchdog_msg(xdr, &msg) ) {
> -        remoteError(VIR_ERR_RPC, "%s",
> -                    _("Unable to demarshal watchdog event"));
> -        return NULL;
> -    }
>  
> -    dom = get_nonnull_domain(conn,msg.dom);
> +    dom = get_nonnull_domain(conn, msg->dom);
>      if (!dom)
> -        return NULL;
> -
> -    event = virDomainEventWatchdogNewFromDom(dom, msg.action);
> -    xdr_free ((xdrproc_t) &xdr_remote_domain_event_watchdog_msg, (char *) &msg);
> +        return;
>  
> +    event = virDomainEventWatchdogNewFromDom(dom, msg->action);
>      virDomainFree(dom);
> -    return event;
> +
> +    remoteDomainEventQueue(priv, event);
>  }
>  
>  
> -static virDomainEventPtr
> -remoteDomainReadEventIOError(virConnectPtr conn, XDR *xdr)
> +static void
> +remoteDomainBuildEventIOError(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
> +                              virNetClientPtr client ATTRIBUTE_UNUSED,
> +                              void *evdata, void *opaque)
>  {
> -    remote_domain_event_io_error_msg msg;
> +    virConnectPtr conn = opaque;
> +    struct private_data *priv = conn->privateData;
> +    remote_domain_event_io_error_msg *msg = evdata;
>      virDomainPtr dom;
>      virDomainEventPtr event = NULL;
> -    memset (&msg, 0, sizeof msg);
> -
> -    /* unmarshal parameters, and process it*/
> -    if (! xdr_remote_domain_event_io_error_msg(xdr, &msg) ) {
> -        remoteError(VIR_ERR_RPC, "%s",
> -                    _("Unable to demarshal IO error event"));
> -        return NULL;
> -    }
>  
> -    dom = get_nonnull_domain(conn,msg.dom);
> +    dom = get_nonnull_domain(conn, msg->dom);
>      if (!dom)
> -        return NULL;
> +        return;
>  
>      event = virDomainEventIOErrorNewFromDom(dom,
> -                                            msg.srcPath,
> -                                            msg.devAlias,
> -                                            msg.action);
> -    xdr_free ((xdrproc_t) &xdr_remote_domain_event_io_error_msg, (char *) &msg);
> -
> +                                            msg->srcPath,
> +                                            msg->devAlias,
> +                                            msg->action);
>      virDomainFree(dom);
> -    return event;
> +
> +    remoteDomainEventQueue(priv, event);
>  }
>  
>  
> -static virDomainEventPtr
> -remoteDomainReadEventIOErrorReason(virConnectPtr conn, XDR *xdr)
> +static void
> +remoteDomainBuildEventIOErrorReason(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
> +                                    virNetClientPtr client ATTRIBUTE_UNUSED,
> +                                    void *evdata, void *opaque)
>  {
> -    remote_domain_event_io_error_reason_msg msg;
> +    virConnectPtr conn = opaque;
> +    struct private_data *priv = conn->privateData;
> +    remote_domain_event_io_error_reason_msg *msg = evdata;
>      virDomainPtr dom;
>      virDomainEventPtr event = NULL;
> -    memset (&msg, 0, sizeof msg);
> -
> -    /* unmarshal parameters, and process it*/
> -    if (! xdr_remote_domain_event_io_error_reason_msg(xdr, &msg) ) {
> -        remoteError(VIR_ERR_RPC, "%s",
> -                    _("Unable to demarshal IO error reason event"));
> -        return NULL;
> -    }
>  
> -    dom = get_nonnull_domain(conn,msg.dom);
> +    dom = get_nonnull_domain(conn,msg->dom);
>      if (!dom)
> -        return NULL;
> +        return;
>  
>      event = virDomainEventIOErrorReasonNewFromDom(dom,
> -                                                  msg.srcPath,
> -                                                  msg.devAlias,
> -                                                  msg.action,
> -                                                  msg.reason);
> -    xdr_free ((xdrproc_t) &xdr_remote_domain_event_io_error_reason_msg, (char *) &msg);
> +                                                  msg->srcPath,
> +                                                  msg->devAlias,
> +                                                  msg->action,
> +                                                  msg->reason);
>  
>      virDomainFree(dom);
> -    return event;
> +
> +    remoteDomainEventQueue(priv, event);
>  }
>  
>  
> -static virDomainEventPtr
> -remoteDomainReadEventGraphics(virConnectPtr conn, XDR *xdr)
> +static void
> +remoteDomainBuildEventGraphics(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
> +                               virNetClientPtr client ATTRIBUTE_UNUSED,
> +                               void *evdata, void *opaque)
>  {
> -    remote_domain_event_graphics_msg msg;
> +    virConnectPtr conn = opaque;
> +    struct private_data *priv = conn->privateData;
> +    remote_domain_event_graphics_msg *msg = evdata;
>      virDomainPtr dom;
>      virDomainEventPtr event = NULL;
>      virDomainEventGraphicsAddressPtr localAddr = NULL;
> @@ -3879,58 +3064,48 @@ remoteDomainReadEventGraphics(virConnectPtr conn, XDR *xdr)
>      virDomainEventGraphicsSubjectPtr subject = NULL;
>      int i;
>  
> -    memset (&msg, 0, sizeof msg);
> -
> -    /* unmarshal parameters, and process it*/
> -    if (! xdr_remote_domain_event_graphics_msg(xdr, &msg) ) {
> -        remoteError(VIR_ERR_RPC, "%s",
> -                    _("Unable to demarshal graphics event"));
> -        return NULL;
> -    }
> -
> -    dom = get_nonnull_domain(conn,msg.dom);
> +    dom = get_nonnull_domain(conn, msg->dom);
>      if (!dom)
> -        return NULL;
> +        return;
>  
>      if (VIR_ALLOC(localAddr) < 0)
>          goto no_memory;
> -    localAddr->family = msg.local.family;
> -    if (!(localAddr->service = strdup(msg.local.service)) ||
> -        !(localAddr->node = strdup(msg.local.node)))
> +    localAddr->family = msg->local.family;
> +    if (!(localAddr->service = strdup(msg->local.service)) ||
> +        !(localAddr->node = strdup(msg->local.node)))
>          goto no_memory;
>  
>      if (VIR_ALLOC(remoteAddr) < 0)
>          goto no_memory;
> -    remoteAddr->family = msg.remote.family;
> -    if (!(remoteAddr->service = strdup(msg.remote.service)) ||
> -        !(remoteAddr->node = strdup(msg.remote.node)))
> +    remoteAddr->family = msg->remote.family;
> +    if (!(remoteAddr->service = strdup(msg->remote.service)) ||
> +        !(remoteAddr->node = strdup(msg->remote.node)))
>          goto no_memory;
>  
>      if (VIR_ALLOC(subject) < 0)
>          goto no_memory;
> -    if (VIR_ALLOC_N(subject->identities, msg.subject.subject_len) < 0)
> +    if (VIR_ALLOC_N(subject->identities, msg->subject.subject_len) < 0)
>          goto no_memory;
> -    subject->nidentity = msg.subject.subject_len;
> +    subject->nidentity = msg->subject.subject_len;
>      for (i = 0 ; i < subject->nidentity ; i++) {
> -        if (!(subject->identities[i].type = strdup(msg.subject.subject_val[i].type)) ||
> -            !(subject->identities[i].name = strdup(msg.subject.subject_val[i].name)))
> +        if (!(subject->identities[i].type = strdup(msg->subject.subject_val[i].type)) ||
> +            !(subject->identities[i].name = strdup(msg->subject.subject_val[i].name)))
>              goto no_memory;
>      }
>  
>      event = virDomainEventGraphicsNewFromDom(dom,
> -                                             msg.phase,
> +                                             msg->phase,
>                                               localAddr,
>                                               remoteAddr,
> -                                             msg.authScheme,
> +                                             msg->authScheme,
>                                               subject);
> -    xdr_free ((xdrproc_t) &xdr_remote_domain_event_graphics_msg, (char *) &msg);
>  
>      virDomainFree(dom);
> -    return event;
>  
> -no_memory:
> -    xdr_free ((xdrproc_t) &xdr_remote_domain_event_graphics_msg, (char *) &msg);
> +    remoteDomainEventQueue(priv, event);
> +    return;
>  
> +no_memory:
>      if (localAddr) {
>          VIR_FREE(localAddr->service);
>          VIR_FREE(localAddr->node);
> @@ -3949,34 +3124,31 @@ no_memory:
>          VIR_FREE(subject->identities);
>          VIR_FREE(subject);
>      }
> -    return NULL;
> +    return;
>  }
>  
>  
> -static virDomainEventPtr
> -remoteDomainReadEventControlError(virConnectPtr conn, XDR *xdr)
> +static void
> +remoteDomainBuildEventControlError(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
> +                                   virNetClientPtr client ATTRIBUTE_UNUSED,
> +                                   void *evdata, void *opaque)
>  {
> -    remote_domain_event_control_error_msg msg;
> +    virConnectPtr conn = opaque;
> +    struct private_data *priv = conn->privateData;
> +    remote_domain_event_control_error_msg *msg = evdata;
>      virDomainPtr dom;
>      virDomainEventPtr event = NULL;
> -    memset (&msg, 0, sizeof msg);
> -
> -    /* unmarshall parameters, and process it*/
> -    if (! xdr_remote_domain_event_control_error_msg(xdr, &msg) ) {
> -        remoteError(VIR_ERR_RPC, "%s",
> -                    _("unable to demarshall reboot event"));
> -        return NULL;
> -    }
>  
> -    dom = get_nonnull_domain(conn,msg.dom);
> +    dom = get_nonnull_domain(conn, msg->dom);
>      if (!dom)
> -        return NULL;
> +        return;
>  
>      event = virDomainEventControlErrorNewFromDom(dom);
>      xdr_free ((xdrproc_t) &xdr_remote_domain_event_control_error_msg, (char *) &msg);
>  
>      virDomainFree(dom);
> -    return event;
> +
> +    remoteDomainEventQueue(priv, event);
>  }
>  
>  
> @@ -4020,195 +3192,6 @@ done:
>      return rv;
>  }
>  
> -static struct private_stream_data *
> -remoteStreamOpen(virStreamPtr st,
> -                 unsigned int proc_nr,
> -                 unsigned int serial)
> -{
> -    struct private_data *priv = st->conn->privateData;
> -    struct private_stream_data *stpriv;
> -
> -    if (VIR_ALLOC(stpriv) < 0) {
> -        virReportOOMError();
> -        return NULL;
> -    }
> -
> -    /* Initialize call object used to receive replies */
> -    stpriv->proc_nr = proc_nr;
> -    stpriv->serial = serial;
> -
> -    stpriv->next = priv->streams;
> -    priv->streams = stpriv;
> -
> -    return stpriv;
> -}
> -
> -
> -static void
> -remoteStreamEventTimerUpdate(struct private_stream_data *privst)
> -{
> -    if (!privst->cb)
> -        return;
> -
> -    VIR_DEBUG("Check timer offset=%d %d", privst->incomingOffset, privst->cbEvents);
> -    if ((privst->incomingOffset &&
> -         (privst->cbEvents & VIR_STREAM_EVENT_READABLE)) ||
> -        (privst->cbEvents & VIR_STREAM_EVENT_WRITABLE)) {
> -        VIR_DEBUG("Enabling event timer");
> -        virEventUpdateTimeout(privst->cbTimer, 0);
> -    } else {
> -        VIR_DEBUG("Disabling event timer");
> -        virEventUpdateTimeout(privst->cbTimer, -1);
> -    }
> -}
> -
> -
> -static int
> -remoteStreamPacket(virStreamPtr st,
> -                   int status,
> -                   const char *data,
> -                   size_t nbytes)
> -{
> -    VIR_DEBUG("st=%p status=%d data=%p nbytes=%zu", st, status, data, nbytes);
> -    struct private_data *priv = st->conn->privateData;
> -    struct private_stream_data *privst = st->privateData;
> -    XDR xdr;
> -    struct remote_thread_call *thiscall;
> -    remote_message_header hdr;
> -    int ret;
> -
> -    memset(&hdr, 0, sizeof hdr);
> -
> -    if (VIR_ALLOC(thiscall) < 0) {
> -        virReportOOMError();
> -        return -1;
> -    }
> -
> -    thiscall->mode = REMOTE_MODE_WAIT_TX;
> -    thiscall->serial = privst->serial;
> -    thiscall->proc_nr = privst->proc_nr;
> -    if (status == REMOTE_OK ||
> -        status == REMOTE_ERROR)
> -        thiscall->want_reply = 1;
> -
> -    if (virCondInit(&thiscall->cond) < 0) {
> -        VIR_FREE(thiscall);
> -        remoteError(VIR_ERR_INTERNAL_ERROR, "%s",
> -                    _("cannot initialize mutex"));
> -        return -1;
> -    }
> -
> -    /* Don't fill in any other fields in 'thiscall' since
> -     * we're not expecting a reply for this */
> -
> -    hdr.prog = REMOTE_PROGRAM;
> -    hdr.vers = REMOTE_PROTOCOL_VERSION;
> -    hdr.proc = privst->proc_nr;
> -    hdr.type = REMOTE_STREAM;
> -    hdr.serial = privst->serial;
> -    hdr.status = status;
> -
> -
> -    /* Length must include the length word itself (always encoded in
> -     * 4 bytes as per RFC 4506), so offset start length. We write this
> -     * later.
> -     */
> -    thiscall->bufferLength = REMOTE_MESSAGE_HEADER_XDR_LEN;
> -
> -    /* Serialise header followed by args. */
> -    xdrmem_create (&xdr, thiscall->buffer + thiscall->bufferLength,
> -                   REMOTE_MESSAGE_MAX, XDR_ENCODE);
> -    if (!xdr_remote_message_header (&xdr, &hdr)) {
> -        remoteError(VIR_ERR_RPC, "%s", _("xdr_remote_message_header failed"));
> -        goto error;
> -    }
> -
> -    thiscall->bufferLength += xdr_getpos (&xdr);
> -    xdr_destroy (&xdr);
> -
> -    if (status == REMOTE_CONTINUE) {
> -        if (((4 + REMOTE_MESSAGE_MAX) - thiscall->bufferLength) < nbytes) {
> -            remoteError(VIR_ERR_RPC, _("data size %zu too large for payload %d"),
> -                        nbytes, ((4 + REMOTE_MESSAGE_MAX) - thiscall->bufferLength));
> -            goto error;
> -        }
> -
> -        memcpy(thiscall->buffer + thiscall->bufferLength, data, nbytes);
> -        thiscall->bufferLength += nbytes;
> -    }
> -
> -    /* Go back to packet start and encode the length word. */
> -    xdrmem_create (&xdr, thiscall->buffer, REMOTE_MESSAGE_HEADER_XDR_LEN, XDR_ENCODE);
> -    if (!xdr_u_int (&xdr, &thiscall->bufferLength)) {
> -        remoteError(VIR_ERR_RPC, "%s", _("xdr_u_int (length word)"));
> -        goto error;
> -    }
> -    xdr_destroy (&xdr);
> -
> -    ret = remoteIO(st->conn, priv, 0, thiscall);
> -    ignore_value(virCondDestroy(&thiscall->cond));
> -    VIR_FREE(thiscall);
> -    if (ret < 0)
> -        return -1;
> -
> -    return nbytes;
> -
> -error:
> -    xdr_destroy (&xdr);
> -    ignore_value(virCondDestroy(&thiscall->cond));
> -    VIR_FREE(thiscall);
> -    return -1;
> -}
> -
> -static int
> -remoteStreamHasError(virStreamPtr st) {
> -    struct private_stream_data *privst = st->privateData;
> -    if (!privst->has_error) {
> -        return 0;
> -    }
> -
> -    VIR_DEBUG("Raising async error");
> -    virRaiseErrorFull(__FILE__, __FUNCTION__, __LINE__,
> -                      privst->err.domain,
> -                      privst->err.code,
> -                      privst->err.level,
> -                      privst->err.str1 ? *privst->err.str1 : NULL,
> -                      privst->err.str2 ? *privst->err.str2 : NULL,
> -                      privst->err.str3 ? *privst->err.str3 : NULL,
> -                      privst->err.int1,
> -                      privst->err.int2,
> -                      "%s", privst->err.message ? *privst->err.message : NULL);
> -
> -    return 1;
> -}
> -
> -static void
> -remoteStreamRelease(virStreamPtr st)
> -{
> -    struct private_data *priv = st->conn->privateData;
> -    struct private_stream_data *privst = st->privateData;
> -
> -    if (priv->streams == privst)
> -        priv->streams = privst->next;
> -    else {
> -        struct private_stream_data *tmp = priv->streams;
> -        while (tmp && tmp->next) {
> -            if (tmp->next == privst) {
> -                tmp->next = privst->next;
> -                break;
> -            }
> -        }
> -    }
> -
> -    if (privst->has_error)
> -        xdr_free((xdrproc_t)xdr_remote_error,  (char *)&privst->err);
> -
> -    VIR_FREE(privst);
> -
> -    st->driver = NULL;
> -    st->privateData = NULL;
> -}
> -
>  
>  static int
>  remoteStreamSend(virStreamPtr st,
> @@ -4217,22 +3200,21 @@ remoteStreamSend(virStreamPtr st,
>  {
>      VIR_DEBUG("st=%p data=%p nbytes=%zu", st, data, nbytes);
>      struct private_data *priv = st->conn->privateData;
> +    virNetClientStreamPtr privst = st->privateData;
>      int rv = -1;
>  
>      remoteDriverLock(priv);
>  
> -    if (remoteStreamHasError(st))
> +    if (virNetClientStreamRaiseError(privst))
>          goto cleanup;
>  
> -    rv = remoteStreamPacket(st,
> -                            REMOTE_CONTINUE,
> -                            data,
> -                            nbytes);
> +    rv = virNetClientStreamSendPacket(privst,
> +                                      priv->client,
> +                                      VIR_NET_CONTINUE,
> +                                      data,
> +                                      nbytes);
>  
>  cleanup:
> -    if (rv == -1)
> -        remoteStreamRelease(st);
> -
>      remoteDriverUnlock(priv);
>  
>      return rv;
> @@ -4246,123 +3228,57 @@ remoteStreamRecv(virStreamPtr st,
>  {
>      VIR_DEBUG("st=%p data=%p nbytes=%zu", st, data, nbytes);
>      struct private_data *priv = st->conn->privateData;
> -    struct private_stream_data *privst = st->privateData;
> +    virNetClientStreamPtr privst = st->privateData;
>      int rv = -1;
>  
>      remoteDriverLock(priv);
>  
> -    if (remoteStreamHasError(st))
> +    if (virNetClientStreamRaiseError(privst))
>          goto cleanup;
>  
> -    if (!privst->incomingOffset) {
> -        struct remote_thread_call *thiscall;
> -        int ret;
> -
> -        if (st->flags & VIR_STREAM_NONBLOCK) {
> -            VIR_DEBUG("Non-blocking mode and no data available");
> -            rv = -2;
> -            goto cleanup;
> -        }
> -
> -        if (VIR_ALLOC(thiscall) < 0) {
> -            virReportOOMError();
> -            goto cleanup;
> -        }
> -
> -        /* We're not really doing an RPC calls, so we're
> -         * skipping straight to RX part */
> -        thiscall->mode = REMOTE_MODE_WAIT_RX;
> -        thiscall->serial = privst->serial;
> -        thiscall->proc_nr = privst->proc_nr;
> -        thiscall->want_reply = 1;
> -
> -        if (virCondInit(&thiscall->cond) < 0) {
> -            VIR_FREE(thiscall);
> -            remoteError(VIR_ERR_INTERNAL_ERROR, "%s",
> -                        _("cannot initialize mutex"));
> -            goto cleanup;
> -        }
> -
> -        ret = remoteIO(st->conn, priv, 0, thiscall);
> -        ignore_value(virCondDestroy(&thiscall->cond));
> -        VIR_FREE(thiscall);
> -        if (ret < 0)
> -            goto cleanup;
> -    }
> -
> -    VIR_DEBUG("After IO %d", privst->incomingOffset);
> -    if (privst->incomingOffset) {
> -        int want = privst->incomingOffset;
> -        if (want > nbytes)
> -            want = nbytes;
> -        memcpy(data, privst->incoming, want);
> -        if (want < privst->incomingOffset) {
> -            memmove(privst->incoming, privst->incoming + want, privst->incomingOffset - want);
> -            privst->incomingOffset -= want;
> -        } else {
> -            VIR_FREE(privst->incoming);
> -            privst->incomingOffset = privst->incomingLength = 0;
> -        }
> -        rv = want;
> -    } else {
> -        rv = 0;
> -    }
> -
> -    remoteStreamEventTimerUpdate(privst);
> +    rv = virNetClientStreamRecvPacket(privst,
> +                                      priv->client,
> +                                      data,
> +                                      nbytes,
> +                                      (st->flags & VIR_STREAM_NONBLOCK));
>  
>      VIR_DEBUG("Done %d", rv);
>  
>  cleanup:
> -    if (rv == -1)
> -        remoteStreamRelease(st);
>      remoteDriverUnlock(priv);
>  
>      return rv;
>  }
>  
> +struct remoteStreamCallbackData {
> +    virStreamPtr st;
> +    virStreamEventCallback cb;
> +    void *opaque;
> +    virFreeCallback ff;
> +};
>  
> -static void
> -remoteStreamEventTimer(int timer ATTRIBUTE_UNUSED, void *opaque)
> +static void remoteStreamEventCallback(virNetClientStreamPtr stream ATTRIBUTE_UNUSED,
> +                                      int events,
> +                                      void *opaque)
>  {
> -    virStreamPtr st = opaque;
> -    struct private_data *priv = st->conn->privateData;
> -    struct private_stream_data *privst = st->privateData;
> -    int events = 0;
> -
> -    remoteDriverLock(priv);
> -
> -    if (privst->cb &&
> -        (privst->cbEvents & VIR_STREAM_EVENT_READABLE) &&
> -        privst->incomingOffset)
> -        events |= VIR_STREAM_EVENT_READABLE;
> -    if (privst->cb &&
> -        (privst->cbEvents & VIR_STREAM_EVENT_WRITABLE))
> -        events |= VIR_STREAM_EVENT_WRITABLE;
> -    VIR_DEBUG("Got Timer dispatch %d %d offset=%d", events, privst->cbEvents, privst->incomingOffset);
> -    if (events) {
> -        virStreamEventCallback cb = privst->cb;
> -        void *cbOpaque = privst->cbOpaque;
> -        virFreeCallback cbFree = privst->cbFree;
> -
> -        privst->cbDispatch = 1;
> -        remoteDriverUnlock(priv);
> -        (cb)(st, events, cbOpaque);
> -        remoteDriverLock(priv);
> -        privst->cbDispatch = 0;
> -
> -        if (!privst->cb && cbFree)
> -            (cbFree)(cbOpaque);
> -    }
> +    struct remoteStreamCallbackData *cbdata = opaque;
> +    struct private_data *priv = cbdata->st->conn->privateData;
>  
>      remoteDriverUnlock(priv);
> +    (cbdata->cb)(cbdata->st, events, cbdata->opaque);
> +    remoteDriverLock(priv);
>  }
>  
>  
> -static void
> -remoteStreamEventTimerFree(void *opaque)
> +static void remoteStreamCallbackFree(void *opaque)
>  {
> -    virStreamPtr st = opaque;
> -    virUnrefStream(st);
> +    struct remoteStreamCallbackData *cbdata = opaque;
> +
> +    if (!cbdata->cb && cbdata->ff)
> +        (cbdata->ff)(cbdata->opaque);
> +
> +    virStreamFree(cbdata->st);
> +    VIR_FREE(opaque);
>  }
>  
>  
> @@ -4374,148 +3290,128 @@ remoteStreamEventAddCallback(virStreamPtr st,
>                               virFreeCallback ff)
>  {
>      struct private_data *priv = st->conn->privateData;
> -    struct private_stream_data *privst = st->privateData;
> +    virNetClientStreamPtr privst = st->privateData;
>      int ret = -1;
> +    struct remoteStreamCallbackData *cbdata;
>  
> -    remoteDriverLock(priv);
> -
> -    if (privst->cb) {
> -        remoteError(VIR_ERR_INTERNAL_ERROR,
> -                    "%s", _("multiple stream callbacks not supported"));
> -        goto cleanup;
> +    if (VIR_ALLOC(cbdata) < 0) {
> +        virReportOOMError();
> +        return -1;
>      }
> -
> +    cbdata->cb = cb;
> +    cbdata->opaque = opaque;
> +    cbdata->ff = ff;
> +    cbdata->st = st;
>      virStreamRef(st);
> -    if ((privst->cbTimer =
> -         virEventAddTimeout(-1,
> -                            remoteStreamEventTimer,
> -                            st,
> -                            remoteStreamEventTimerFree)) < 0) {
> -        virUnrefStream(st);
> -        goto cleanup;
> -    }
>  
> -    privst->cb = cb;
> -    privst->cbOpaque = opaque;
> -    privst->cbFree = ff;
> -    privst->cbEvents = events;
> -
> -    remoteStreamEventTimerUpdate(privst);
> +    remoteDriverLock(priv);
>  
> -    ret = 0;
> +    if ((ret = virNetClientStreamEventAddCallback(privst,
> +                                                  events,
> +                                                  remoteStreamEventCallback,
> +                                                  cbdata,
> +                                                  remoteStreamCallbackFree)) < 0) {
> +        VIR_FREE(cbdata);
> +        goto cleanup;
> +    }
>  
>  cleanup:
>      remoteDriverUnlock(priv);
>      return ret;
>  }
>  
> +
>  static int
>  remoteStreamEventUpdateCallback(virStreamPtr st,
>                                  int events)
>  {
>      struct private_data *priv = st->conn->privateData;
> -    struct private_stream_data *privst = st->privateData;
> +    virNetClientStreamPtr privst = st->privateData;
>      int ret = -1;
>  
>      remoteDriverLock(priv);
>  
> -    if (!privst->cb) {
> -        remoteError(VIR_ERR_INTERNAL_ERROR,
> -                    "%s", _("no stream callback registered"));
> -        goto cleanup;
> -    }
> +    ret = virNetClientStreamEventUpdateCallback(privst, events);
>  
> -    privst->cbEvents = events;
> -
> -    remoteStreamEventTimerUpdate(privst);
> -
> -    ret = 0;
> -
> -cleanup:
> -    remoteDriverUnlock(priv);
> -    return ret;
> -}
> +    remoteDriverUnlock(priv);
> +    return ret;
> +}
>  
>  
>  static int
>  remoteStreamEventRemoveCallback(virStreamPtr st)
>  {
>      struct private_data *priv = st->conn->privateData;
> -    struct private_stream_data *privst = st->privateData;
> +    virNetClientStreamPtr privst = st->privateData;
>      int ret = -1;
>  
>      remoteDriverLock(priv);
>  
> -    if (!privst->cb) {
> -        remoteError(VIR_ERR_INTERNAL_ERROR,
> -                    "%s", _("no stream callback registered"));
> -        goto cleanup;
> -    }
> -
> -    if (!privst->cbDispatch &&
> -        privst->cbFree)
> -        (privst->cbFree)(privst->cbOpaque);
> -    privst->cb = NULL;
> -    privst->cbOpaque = NULL;
> -    privst->cbFree = NULL;
> -    privst->cbEvents = 0;
> -    virEventRemoveTimeout(privst->cbTimer);
> -
> -    ret = 0;
> +    ret = virNetClientStreamEventRemoveCallback(privst);
>  
> -cleanup:
>      remoteDriverUnlock(priv);
>      return ret;
>  }
>  
> +
>  static int
>  remoteStreamFinish(virStreamPtr st)
>  {
>      struct private_data *priv = st->conn->privateData;
> +    virNetClientStreamPtr privst = st->privateData;
>      int ret = -1;
>  
>      remoteDriverLock(priv);
>  
> -    if (remoteStreamHasError(st))
> +    if (virNetClientStreamRaiseError(privst))
>          goto cleanup;
>  
> -    ret = remoteStreamPacket(st,
> -                             REMOTE_OK,
> -                             NULL,
> -                             0);
> +    ret = virNetClientStreamSendPacket(privst,
> +                                       priv->client,
> +                                       VIR_NET_OK,
> +                                       NULL,
> +                                       0);
>  
>  cleanup:
> -    remoteStreamRelease(st);
> +    virNetClientRemoveStream(priv->client, privst);
> +    virNetClientStreamFree(privst);
> +    st->privateData = NULL;
> +    st->driver = NULL;
>  
>      remoteDriverUnlock(priv);
>      return ret;
>  }
>  
> +
>  static int
>  remoteStreamAbort(virStreamPtr st)
>  {
>      struct private_data *priv = st->conn->privateData;
> +    virNetClientStreamPtr privst = st->privateData;
>      int ret = -1;
>  
>      remoteDriverLock(priv);
>  
> -    if (remoteStreamHasError(st))
> +    if (virNetClientStreamRaiseError(privst))
>          goto cleanup;
>  
> -    ret = remoteStreamPacket(st,
> -                             REMOTE_ERROR,
> -                             NULL,
> -                             0);
> +    ret = virNetClientStreamSendPacket(privst,
> +                                       priv->client,
> +                                       VIR_NET_ERROR,
> +                                       NULL,
> +                                       0);
>  
>  cleanup:
> -    remoteStreamRelease(st);
> +    virNetClientRemoveStream(priv->client, privst);
> +    virNetClientStreamFree(privst);
> +    st->privateData = NULL;
> +    st->driver = NULL;
>  
>      remoteDriverUnlock(priv);
>      return ret;
>  }
>  
>  
> -
>  static virStreamDriver remoteStreamDrv = {
>      .streamRecv = remoteStreamRecv,
>      .streamSend = remoteStreamSend,
> @@ -4526,6 +3422,7 @@ static virStreamDriver remoteStreamDrv = {
>      .streamRemoveCallback = remoteStreamEventRemoveCallback,
>  };
>  
> +
>  static int remoteDomainEventRegisterAny(virConnectPtr conn,
>                                          virDomainPtr dom,
>                                          int eventID,
> @@ -4620,6 +3517,7 @@ done:
>      return rv;
>  }
>  
> +
>  /*----------------------------------------------------------------------*/
>  
>  static int
> @@ -4793,23 +3691,28 @@ remoteDomainMigratePrepareTunnel3(virConnectPtr dconn,
>                                    const char *dom_xml)
>  {
>      struct private_data *priv = dconn->privateData;
> -    struct private_stream_data *privst = NULL;
>      int rv = -1;
>      remote_domain_migrate_prepare_tunnel3_args args;
>      remote_domain_migrate_prepare_tunnel3_ret ret;
> +    virNetClientStreamPtr netst;
>  
>      remoteDriverLock(priv);
>  
>      memset(&args, 0, sizeof(args));
>      memset(&ret, 0, sizeof(ret));
>  
> -    if (!(privst = remoteStreamOpen(st,
> -                                    REMOTE_PROC_DOMAIN_MIGRATE_PREPARE_TUNNEL3,
> -                                    priv->counter)))
> +    if (!(netst = virNetClientStreamNew(priv->remoteProgram,
> +                                        REMOTE_PROC_DOMAIN_MIGRATE_PREPARE_TUNNEL,
> +                                        priv->counter)))
>          goto done;
>  
> +    if (virNetClientAddStream(priv->client, netst) < 0) {
> +        virNetClientStreamFree(netst);
> +        goto done;
> +    }
> +
>      st->driver = &remoteStreamDrv;
> -    st->privateData = privst;
> +    st->privateData = netst;
>  
>      args.cookie_in.cookie_in_val = (char *)cookiein;
>      args.cookie_in.cookie_in_len = cookieinlen;
> @@ -4821,7 +3724,8 @@ remoteDomainMigratePrepareTunnel3(virConnectPtr dconn,
>      if (call(dconn, priv, 0, REMOTE_PROC_DOMAIN_MIGRATE_PREPARE_TUNNEL3,
>               (xdrproc_t) xdr_remote_domain_migrate_prepare_tunnel3_args, (char *) &args,
>               (xdrproc_t) xdr_remote_domain_migrate_prepare_tunnel3_ret, (char *) &ret) == -1) {
> -        remoteStreamRelease(st);
> +        virNetClientRemoveStream(priv->client, netst);
> +        virNetClientStreamFree(netst);
>          goto done;
>      }
>  
> @@ -5006,1251 +3910,41 @@ done:
>  #include "remote_client_bodies.h"
>  #include "qemu_client_bodies.h"
>  
> -
> -/*----------------------------------------------------------------------*/
> -
> -static struct remote_thread_call *
> -prepareCall(struct private_data *priv,
> -            int flags,
> -            int proc_nr,
> -            xdrproc_t args_filter, char *args,
> -            xdrproc_t ret_filter, char *ret)
> -{
> -    XDR xdr;
> -    struct remote_message_header hdr;
> -    struct remote_thread_call *rv;
> -
> -    if (VIR_ALLOC(rv) < 0) {
> -        virReportOOMError();
> -        return NULL;
> -    }
> -
> -    if (virCondInit(&rv->cond) < 0) {
> -        VIR_FREE(rv);
> -        remoteError(VIR_ERR_INTERNAL_ERROR, "%s",
> -                    _("cannot initialize mutex"));
> -        return NULL;
> -    }
> -
> -    /* Get a unique serial number for this message. */
> -    rv->serial = priv->counter++;
> -    rv->proc_nr = proc_nr;
> -    rv->ret_filter = ret_filter;
> -    rv->ret = ret;
> -    rv->want_reply = 1;
> -
> -    if (flags & REMOTE_CALL_QEMU) {
> -        hdr.prog = QEMU_PROGRAM;
> -        hdr.vers = QEMU_PROTOCOL_VERSION;
> -    }
> -    else {
> -        hdr.prog = REMOTE_PROGRAM;
> -        hdr.vers = REMOTE_PROTOCOL_VERSION;
> -    }
> -    hdr.proc = proc_nr;
> -    hdr.type = REMOTE_CALL;
> -    hdr.serial = rv->serial;
> -    hdr.status = REMOTE_OK;
> -
> -    /* Serialise header followed by args. */
> -    xdrmem_create (&xdr, rv->buffer+4, REMOTE_MESSAGE_MAX, XDR_ENCODE);
> -    if (!xdr_remote_message_header (&xdr, &hdr)) {
> -        remoteError(VIR_ERR_RPC, "%s", _("xdr_remote_message_header failed"));
> -        goto error;
> -    }
> -
> -    if (!(*args_filter) (&xdr, args)) {
> -        remoteError(VIR_ERR_RPC,
> -                    _("Unable to marshal arguments for program %d version %d procedure %d type %d status %d"),
> -                    hdr.prog, hdr.vers, hdr.proc, hdr.type, hdr.status);
> -        goto error;
> -    }
> -
> -    /* Get the length stored in buffer. */
> -    rv->bufferLength = xdr_getpos (&xdr);
> -    xdr_destroy (&xdr);
> -
> -    /* Length must include the length word itself (always encoded in
> -     * 4 bytes as per RFC 4506).
> -     */
> -    rv->bufferLength += REMOTE_MESSAGE_HEADER_XDR_LEN;
> -
> -    /* Encode the length word. */
> -    xdrmem_create (&xdr, rv->buffer, REMOTE_MESSAGE_HEADER_XDR_LEN, XDR_ENCODE);
> -    if (!xdr_u_int (&xdr, &rv->bufferLength)) {
> -        remoteError(VIR_ERR_RPC, "%s", _("xdr_u_int (length word)"));
> -        goto error;
> -    }
> -    xdr_destroy (&xdr);
> -
> -    return rv;
> -
> -error:
> -    xdr_destroy (&xdr);
> -    ignore_value(virCondDestroy(&rv->cond));
> -    VIR_FREE(rv);
> -    return NULL;
> -}
> -
> -
> -
> -static int
> -remoteIOWriteBuffer(struct private_data *priv,
> -                    const char *bytes, int len)
> -{
> -    int ret;
> -
> -    if (priv->uses_tls) {
> -    tls_resend:
> -        ret = gnutls_record_send (priv->session, bytes, len);
> -        if (ret < 0) {
> -            if (ret == GNUTLS_E_INTERRUPTED)
> -                goto tls_resend;
> -            if (ret == GNUTLS_E_AGAIN)
> -                return 0;
> -
> -            remoteError(VIR_ERR_GNUTLS_ERROR, "%s", gnutls_strerror (ret));
> -            return -1;
> -        }
> -    } else {
> -    resend:
> -        ret = send (priv->sock, bytes, len, 0);
> -        if (ret == -1) {
> -            if (errno == EINTR)
> -                goto resend;
> -            if (errno == EWOULDBLOCK)
> -                return 0;
> -
> -            virReportSystemError(errno, "%s", _("cannot send data"));
> -            return -1;
> -
> -        }
> -    }
> -
> -    return ret;
> -}
> -
> -
> -static int
> -remoteIOReadBuffer(struct private_data *priv,
> -                   char *bytes, int len)
> -{
> -    int ret;
> -
> -    if (priv->uses_tls) {
> -    tls_resend:
> -        ret = gnutls_record_recv (priv->session, bytes, len);
> -        if (ret == GNUTLS_E_INTERRUPTED)
> -            goto tls_resend;
> -        if (ret == GNUTLS_E_AGAIN)
> -            return 0;
> -
> -        /* Treat 0 == EOF as an error */
> -        if (ret <= 0) {
> -            if (ret < 0)
> -                remoteError(VIR_ERR_GNUTLS_ERROR,
> -                            _("failed to read from TLS socket %s"),
> -                            gnutls_strerror (ret));
> -            else
> -                remoteError(VIR_ERR_SYSTEM_ERROR, "%s",
> -                            _("server closed connection"));
> -            return -1;
> -        }
> -    } else {
> -    resend:
> -        ret = recv (priv->sock, bytes, len, 0);
> -        if (ret <= 0) {
> -            if (ret == -1) {
> -                if (errno == EINTR)
> -                    goto resend;
> -                if (errno == EWOULDBLOCK)
> -                    return 0;
> -
> -                char errout[1024] = "\0";
> -                if (priv->errfd != -1) {
> -                    if (saferead(priv->errfd, errout, sizeof(errout)) < 0) {
> -                        virReportSystemError(errno, "%s",
> -                                             _("cannot recv data"));
> -                        return -1;
> -                    }
> -                }
> -
> -                virReportSystemError(errno,
> -                                     _("cannot recv data: %s"), errout);
> -
> -            } else {
> -                char errout[1024] = "\0";
> -                if (priv->errfd != -1) {
> -                    if (saferead(priv->errfd, errout, sizeof(errout)) < 0) {
> -                        remoteError(VIR_ERR_SYSTEM_ERROR,
> -                                    _("server closed connection: %s"),
> -                                    virStrerror(errno, errout, sizeof errout));
> -                        return -1;
> -                    }
> -                }
> -
> -                remoteError(VIR_ERR_SYSTEM_ERROR,
> -                            _("server closed connection: %s"), errout);
> -            }
> -            return -1;
> -        }
> -    }
> -
> -    return ret;
> -}
> -
> -
> -static int
> -remoteIOWriteMessage(struct private_data *priv,
> -                     struct remote_thread_call *thecall)
> -{
> -#if HAVE_SASL
> -    if (priv->saslconn) {
> -        const char *output;
> -        unsigned int outputlen;
> -        int err, ret;
> -
> -        if (!priv->saslEncoded) {
> -            err = sasl_encode(priv->saslconn,
> -                              thecall->buffer + thecall->bufferOffset,
> -                              thecall->bufferLength - thecall->bufferOffset,
> -                              &output, &outputlen);
> -            if (err != SASL_OK) {
> -                remoteError(VIR_ERR_INTERNAL_ERROR,
> -                            _("failed to encode SASL data: %s"),
> -                            sasl_errstring(err, NULL, NULL));
> -                return -1;
> -            }
> -            priv->saslEncoded = output;
> -            priv->saslEncodedLength = outputlen;
> -            priv->saslEncodedOffset = 0;
> -
> -            thecall->bufferOffset = thecall->bufferLength;
> -        }
> -
> -        ret = remoteIOWriteBuffer(priv,
> -                                  priv->saslEncoded + priv->saslEncodedOffset,
> -                                  priv->saslEncodedLength - priv->saslEncodedOffset);
> -        if (ret < 0)
> -            return ret;
> -        priv->saslEncodedOffset += ret;
> -
> -        if (priv->saslEncodedOffset == priv->saslEncodedLength) {
> -            priv->saslEncoded = NULL;
> -            priv->saslEncodedOffset = priv->saslEncodedLength = 0;
> -            if (thecall->want_reply)
> -                thecall->mode = REMOTE_MODE_WAIT_RX;
> -            else
> -                thecall->mode = REMOTE_MODE_COMPLETE;
> -        }
> -    } else {
> -#endif
> -        int ret;
> -        ret = remoteIOWriteBuffer(priv,
> -                                  thecall->buffer + thecall->bufferOffset,
> -                                  thecall->bufferLength - thecall->bufferOffset);
> -        if (ret < 0)
> -            return ret;
> -        thecall->bufferOffset += ret;
> -
> -        if (thecall->bufferOffset == thecall->bufferLength) {
> -            thecall->bufferOffset = thecall->bufferLength = 0;
> -            if (thecall->want_reply)
> -                thecall->mode = REMOTE_MODE_WAIT_RX;
> -            else
> -                thecall->mode = REMOTE_MODE_COMPLETE;
> -        }
> -#if HAVE_SASL
> -    }
> -#endif
> -    return 0;
> -}
> -
> -
> -static int
> -remoteIOHandleOutput(struct private_data *priv) {
> -    struct remote_thread_call *thecall = priv->waitDispatch;
> -
> -    while (thecall &&
> -           thecall->mode != REMOTE_MODE_WAIT_TX)
> -        thecall = thecall->next;
> -
> -    if (!thecall)
> -        return -1; /* Shouldn't happen, but you never know... */
> -
> -    while (thecall) {
> -        int ret = remoteIOWriteMessage(priv, thecall);
> -        if (ret < 0)
> -            return ret;
> -
> -        if (thecall->mode == REMOTE_MODE_WAIT_TX)
> -            return 0; /* Blocking write, to back to event loop */
> -
> -        thecall = thecall->next;
> -    }
> -
> -    return 0; /* No more calls to send, all done */
> -}
> -
> -static int
> -remoteIOReadMessage(struct private_data *priv) {
> -    unsigned int wantData;
> -
> -    /* Start by reading length word */
> -    if (priv->bufferLength == 0)
> -        priv->bufferLength = 4;
> -
> -    wantData = priv->bufferLength - priv->bufferOffset;
> -
> -#if HAVE_SASL
> -    if (priv->saslconn) {
> -        if (priv->saslDecoded == NULL) {
> -            int ret, err;
> -            ret = remoteIOReadBuffer(priv, priv->saslTemporary,
> -                                     sizeof(priv->saslTemporary));
> -            if (ret < 0)
> -                return -1;
> -            if (ret == 0)
> -                return 0;
> -
> -            err = sasl_decode(priv->saslconn, priv->saslTemporary, ret,
> -                              &priv->saslDecoded, &priv->saslDecodedLength);
> -            if (err != SASL_OK) {
> -                remoteError(VIR_ERR_INTERNAL_ERROR,
> -                            _("failed to decode SASL data: %s"),
> -                            sasl_errstring(err, NULL, NULL));
> -                return -1;
> -            }
> -            priv->saslDecodedOffset = 0;
> -        }
> -
> -        if ((priv->saslDecodedLength - priv->saslDecodedOffset) < wantData)
> -            wantData = (priv->saslDecodedLength - priv->saslDecodedOffset);
> -
> -        memcpy(priv->buffer + priv->bufferOffset,
> -               priv->saslDecoded + priv->saslDecodedOffset,
> -               wantData);
> -        priv->saslDecodedOffset += wantData;
> -        priv->bufferOffset += wantData;
> -        if (priv->saslDecodedOffset == priv->saslDecodedLength) {
> -            priv->saslDecodedOffset = priv->saslDecodedLength = 0;
> -            priv->saslDecoded = NULL;
> -        }
> -
> -        return wantData;
> -    } else {
> -#endif
> -        int ret;
> -
> -        ret = remoteIOReadBuffer(priv,
> -                                 priv->buffer + priv->bufferOffset,
> -                                 wantData);
> -        if (ret < 0)
> -            return -1;
> -        if (ret == 0)
> -            return 0;
> -
> -        priv->bufferOffset += ret;
> -
> -        return ret;
> -#if HAVE_SASL
> -    }
> -#endif
> -}
> -
> -
> -static int
> -remoteIODecodeMessageLength(struct private_data *priv) {
> -    XDR xdr;
> -    unsigned int len;
> -
> -    xdrmem_create (&xdr, priv->buffer, priv->bufferLength, XDR_DECODE);
> -    if (!xdr_u_int (&xdr, &len)) {
> -        remoteError(VIR_ERR_RPC, "%s", _("xdr_u_int (length word, reply)"));
> -        return -1;
> -    }
> -    xdr_destroy (&xdr);
> -
> -    if (len < REMOTE_MESSAGE_HEADER_XDR_LEN) {
> -        remoteError(VIR_ERR_RPC, "%s",
> -                    _("packet received from server too small"));
> -        return -1;
> -    }
> -
> -    /* Length includes length word - adjust to real length to read. */
> -    len -= REMOTE_MESSAGE_HEADER_XDR_LEN;
> -
> -    if (len > REMOTE_MESSAGE_MAX) {
> -        remoteError(VIR_ERR_RPC, "%s",
> -                    _("packet received from server too large"));
> -        return -1;
> -    }
> -
> -    /* Extend our declared buffer length and carry
> -       on reading the header + payload */
> -    priv->bufferLength += len;
> -    VIR_DEBUG("Got length, now need %d total (%d more)", priv->bufferLength, len);
> -    return 0;
> -}
> -
> -
> -static int
> -processCallDispatchReply(virConnectPtr conn, struct private_data *priv,
> -                         remote_message_header *hdr,
> -                         XDR *xdr);
> -
> -static int
> -processCallDispatchMessage(virConnectPtr conn, struct private_data *priv,
> -                           int in_open,
> -                           remote_message_header *hdr,
> -                           XDR *xdr);
> -
> -static int
> -processCallDispatchStream(virConnectPtr conn, struct private_data *priv,
> -                          remote_message_header *hdr,
> -                          XDR *xdr);
> -
> -
> -static int
> -processCallDispatch(virConnectPtr conn, struct private_data *priv,
> -                    int flags) {
> -    XDR xdr;
> -    struct remote_message_header hdr;
> -    int len = priv->bufferLength - 4;
> -    int rv = -1;
> -    int expectedprog;
> -    int expectedvers;
> -
> -    /* Length word has already been read */
> -    priv->bufferOffset = 4;
> -
> -    /* Deserialise reply header. */
> -    xdrmem_create (&xdr, priv->buffer + priv->bufferOffset, len, XDR_DECODE);
> -    if (!xdr_remote_message_header (&xdr, &hdr)) {
> -        remoteError(VIR_ERR_RPC, "%s", _("invalid header in reply"));
> -        return -1;
> -    }
> -
> -    priv->bufferOffset += xdr_getpos(&xdr);
> -
> -    expectedprog = REMOTE_PROGRAM;
> -    expectedvers = REMOTE_PROTOCOL_VERSION;
> -    if (flags & REMOTE_CALL_QEMU) {
> -        expectedprog = QEMU_PROGRAM;
> -        expectedvers = QEMU_PROTOCOL_VERSION;
> -    }
> -
> -    /* Check program, version, etc. are what we expect. */
> -    if (hdr.prog != expectedprog) {
> -        remoteError(VIR_ERR_RPC,
> -                    _("unknown program (received %x, expected %x)"),
> -                    hdr.prog, expectedprog);
> -        return -1;
> -    }
> -    if (hdr.vers != expectedvers) {
> -        remoteError(VIR_ERR_RPC,
> -                    _("unknown protocol version (received %x, expected %x)"),
> -                    hdr.vers, expectedvers);
> -        return -1;
> -    }
> -
> -
> -    switch (hdr.type) {
> -    case REMOTE_REPLY: /* Normal RPC replies */
> -        rv = processCallDispatchReply(conn, priv, &hdr, &xdr);
> -        break;
> -
> -    case REMOTE_MESSAGE: /* Async notifications */
> -        VIR_DEBUG("Dispatch event %d %d", hdr.proc, priv->bufferLength);
> -        rv = processCallDispatchMessage(conn, priv, flags & REMOTE_CALL_IN_OPEN,
> -                                        &hdr, &xdr);
> -        break;
> -
> -    case REMOTE_STREAM: /* Stream protocol */
> -        rv = processCallDispatchStream(conn, priv, &hdr, &xdr);
> -        break;
> -
> -    default:
> -        remoteError(VIR_ERR_RPC,
> -                    _("got unexpected RPC call %d from server"),
> -                    hdr.proc);
> -        rv = -1;
> -        break;
> -    }
> -
> -    xdr_destroy(&xdr);
> -    return rv;
> -}
> -
> -
> -static int
> -processCallDispatchReply(virConnectPtr conn ATTRIBUTE_UNUSED,
> -                         struct private_data *priv,
> -                         remote_message_header *hdr,
> -                         XDR *xdr) {
> -    struct remote_thread_call *thecall;
> -
> -    /* Ok, definitely got an RPC reply now find
> -       out who's been waiting for it */
> -    thecall = priv->waitDispatch;
> -    while (thecall &&
> -           thecall->serial != hdr->serial)
> -        thecall = thecall->next;
> -
> -    if (!thecall) {
> -        remoteError(VIR_ERR_RPC,
> -                    _("no call waiting for reply with serial %d"),
> -                    hdr->serial);
> -        return -1;
> -    }
> -
> -    if (hdr->proc != thecall->proc_nr) {
> -        remoteError(VIR_ERR_RPC,
> -                    _("unknown procedure (received %x, expected %x)"),
> -                    hdr->proc, thecall->proc_nr);
> -        return -1;
> -    }
> -
> -    /* Status is either REMOTE_OK (meaning that what follows is a ret
> -     * structure), or REMOTE_ERROR (and what follows is a remote_error
> -     * structure).
> -     */
> -    switch (hdr->status) {
> -    case REMOTE_OK:
> -        if (!(*thecall->ret_filter) (xdr, thecall->ret)) {
> -            remoteError(VIR_ERR_RPC,
> -                        _("Unable to marshal reply for program %d version %d procedure %d type %d status %d"),
> -                        hdr->prog, hdr->vers, hdr->proc, hdr->type, hdr->status);
> -            return -1;
> -        }
> -        thecall->mode = REMOTE_MODE_COMPLETE;
> -        return 0;
> -
> -    case REMOTE_ERROR:
> -        memset (&thecall->err, 0, sizeof thecall->err);
> -        if (!xdr_remote_error (xdr, &thecall->err)) {
> -            remoteError(VIR_ERR_RPC,
> -                        _("Unable to marshal error for program %d version %d procedure %d type %d status %d"),
> -                        hdr->prog, hdr->vers, hdr->proc, hdr->type, hdr->status);
> -            return -1;
> -        }
> -        thecall->mode = REMOTE_MODE_ERROR;
> -        return 0;
> -
> -    default:
> -        remoteError(VIR_ERR_RPC, _("unknown status (received %x)"), hdr->status);
> -        return -1;
> -    }
> -}
> -
> -static int
> -processCallDispatchMessage(virConnectPtr conn, struct private_data *priv,
> -                           int in_open,
> -                           remote_message_header *hdr,
> -                           XDR *xdr) {
> -    virDomainEventPtr event = NULL;
> -    /* An async message has come in while we were waiting for the
> -     * response. Process it to pull it off the wire, and try again
> -     */
> -
> -    if (in_open) {
> -        VIR_DEBUG("Ignoring bogus event %d received while in open", hdr->proc);
> -        return -1;
> -    }
> -
> -    switch (hdr->proc) {
> -    case REMOTE_PROC_DOMAIN_EVENT_LIFECYCLE:
> -        event = remoteDomainReadEventLifecycle(conn, xdr);
> -        break;
> -
> -    case REMOTE_PROC_DOMAIN_EVENT_REBOOT:
> -        event = remoteDomainReadEventReboot(conn, xdr);
> -        break;
> -
> -    case REMOTE_PROC_DOMAIN_EVENT_RTC_CHANGE:
> -        event = remoteDomainReadEventRTCChange(conn, xdr);
> -        break;
> -
> -    case REMOTE_PROC_DOMAIN_EVENT_WATCHDOG:
> -        event = remoteDomainReadEventWatchdog(conn, xdr);
> -        break;
> -
> -    case REMOTE_PROC_DOMAIN_EVENT_IO_ERROR:
> -        event = remoteDomainReadEventIOError(conn, xdr);
> -        break;
> -
> -    case REMOTE_PROC_DOMAIN_EVENT_IO_ERROR_REASON:
> -        event = remoteDomainReadEventIOErrorReason(conn, xdr);
> -        break;
> -
> -    case REMOTE_PROC_DOMAIN_EVENT_GRAPHICS:
> -        event = remoteDomainReadEventGraphics(conn, xdr);
> -        break;
> -
> -    case REMOTE_PROC_DOMAIN_EVENT_CONTROL_ERROR:
> -        event = remoteDomainReadEventControlError(conn, xdr);
> -        break;
> -
> -    default:
> -        VIR_DEBUG("Unexpected event proc %d", hdr->proc);
> -        break;
> -    }
> -    VIR_DEBUG("Event ready for queue %p %p", event, conn);
> -
> -    if (!event)
> -        return -1;
> -
> -    remoteDomainEventQueue(priv, event);
> -    return 0;
> -}
> -
> -static int
> -processCallDispatchStream(virConnectPtr conn ATTRIBUTE_UNUSED,
> -                          struct private_data *priv,
> -                          remote_message_header *hdr,
> -                          XDR *xdr) {
> -    struct private_stream_data *privst;
> -    struct remote_thread_call *thecall;
> -
> -    /* Try and find a matching stream */
> -    privst = priv->streams;
> -    while (privst &&
> -           privst->serial != hdr->serial &&
> -           privst->proc_nr != hdr->proc)
> -        privst = privst->next;
> -
> -    if (!privst) {
> -        VIR_DEBUG("No registered stream matching serial=%d, proc=%d",
> -                  hdr->serial, hdr->proc);
> -        return -1;
> -    }
> -
> -    /* See if there's also a (optional) call waiting for this reply */
> -    thecall = priv->waitDispatch;
> -    while (thecall &&
> -           thecall->serial != hdr->serial)
> -        thecall = thecall->next;
> -
> -
> -    /* Status is either REMOTE_OK (meaning that what follows is a ret
> -     * structure), or REMOTE_ERROR (and what follows is a remote_error
> -     * structure).
> -     */
> -    switch (hdr->status) {
> -    case REMOTE_CONTINUE: {
> -        int avail = privst->incomingLength - privst->incomingOffset;
> -        int need = priv->bufferLength - priv->bufferOffset;
> -        VIR_DEBUG("Got a stream data packet");
> -
> -        /* XXX flag stream as complete somwhere if need==0 */
> -
> -        if (need > avail) {
> -            int extra = need - avail;
> -            if (VIR_REALLOC_N(privst->incoming,
> -                              privst->incomingLength + extra) < 0) {
> -                VIR_DEBUG("Out of memory handling stream data");
> -                return -1;
> -            }
> -            privst->incomingLength += extra;
> -        }
> -
> -        memcpy(privst->incoming + privst->incomingOffset,
> -               priv->buffer + priv->bufferOffset,
> -               priv->bufferLength - priv->bufferOffset);
> -        privst->incomingOffset += (priv->bufferLength - priv->bufferOffset);
> -
> -        if (thecall && thecall->want_reply) {
> -            VIR_DEBUG("Got sync data packet offset=%d", privst->incomingOffset);
> -            thecall->mode = REMOTE_MODE_COMPLETE;
> -        } else {
> -            VIR_DEBUG("Got aysnc data packet offset=%d", privst->incomingOffset);
> -            remoteStreamEventTimerUpdate(privst);
> -        }
> -        return 0;
> -    }
> -
> -    case REMOTE_OK:
> -        VIR_DEBUG("Got a synchronous confirm");
> -        if (!thecall) {
> -            VIR_DEBUG("Got unexpected stream finish confirmation");
> -            return -1;
> -        }
> -        thecall->mode = REMOTE_MODE_COMPLETE;
> -        return 0;
> -
> -    case REMOTE_ERROR:
> -        if (thecall && thecall->want_reply) {
> -            VIR_DEBUG("Got a synchronous error");
> -            /* Give the error straight to this call */
> -            memset (&thecall->err, 0, sizeof thecall->err);
> -            if (!xdr_remote_error (xdr, &thecall->err)) {
> -                remoteError(VIR_ERR_RPC, "%s", _("unmarshaling remote_error"));
> -                return -1;
> -            }
> -            thecall->mode = REMOTE_MODE_ERROR;
> -        } else {
> -            VIR_DEBUG("Got a asynchronous error");
> -            /* No call, so queue the error against the stream */
> -            if (privst->has_error) {
> -                VIR_DEBUG("Got unexpected duplicate stream error");
> -                return -1;
> -            }
> -            privst->has_error = 1;
> -            memset (&privst->err, 0, sizeof privst->err);
> -            if (!xdr_remote_error (xdr, &privst->err)) {
> -                VIR_DEBUG("Failed to unmarshal error");
> -                return -1;
> -            }
> -        }
> -        return 0;
> -
> -    default:
> -        VIR_WARN("Stream with unexpected serial=%d, proc=%d, status=%d",
> -                 hdr->serial, hdr->proc, hdr->status);
> -        return -1;
> -    }
> -}
> -
> -static int
> -remoteIOHandleInput(virConnectPtr conn, struct private_data *priv,
> -                    int flags)
> -{
> -    /* Read as much data as is available, until we get
> -     * EAGAIN
> -     */
> -    for (;;) {
> -        int ret = remoteIOReadMessage(priv);
> -
> -        if (ret < 0)
> -            return -1;
> -        if (ret == 0)
> -            return 0;  /* Blocking on read */
> -
> -        /* Check for completion of our goal */
> -        if (priv->bufferOffset == priv->bufferLength) {
> -            if (priv->bufferOffset == 4) {
> -                ret = remoteIODecodeMessageLength(priv);
> -                if (ret < 0)
> -                    return -1;
> -
> -                /*
> -                 * We'll carry on around the loop to immediately
> -                 * process the message body, because it has probably
> -                 * already arrived. Worst case, we'll get EAGAIN on
> -                 * next iteration.
> -                 */
> -            } else {
> -                ret = processCallDispatch(conn, priv, flags);
> -                priv->bufferOffset = priv->bufferLength = 0;
> -                /*
> -                 * We've completed one call, but we don't want to
> -                 * spin around the loop forever if there are many
> -                 * incoming async events, or replies for other
> -                 * thread's RPC calls. We want to get out & let
> -                 * any other thread take over as soon as we've
> -                 * got our reply. When SASL is active though, we
> -                 * may have read more data off the wire than we
> -                 * initially wanted & cached it in memory. In this
> -                 * case, poll() would not detect that there is more
> -                 * ready todo.
> -                 *
> -                 * So if SASL is active *and* some SASL data is
> -                 * already cached, then we'll process that now,
> -                 * before returning.
> -                 */
> -#if HAVE_SASL
> -                if (ret == 0 &&
> -                    priv->saslconn &&
> -                    priv->saslDecoded)
> -                    continue;
> -#endif
> -                return ret;
> -            }
> -        }
> -    }
> -}
> -
> -/*
> - * Process all calls pending dispatch/receive until we
> - * get a reply to our own call. Then quit and pass the buck
> - * to someone else.
> - */
> -static int
> -remoteIOEventLoop(virConnectPtr conn,
> -                  struct private_data *priv,
> -                  int flags,
> -                  struct remote_thread_call *thiscall)
> -{
> -    struct pollfd fds[2];
> -    int ret;
> -
> -    fds[0].fd = priv->sock;
> -    fds[1].fd = priv->wakeupReadFD;
> -
> -    for (;;) {
> -        struct remote_thread_call *tmp = priv->waitDispatch;
> -        struct remote_thread_call *prev;
> -        char ignore;
> -#ifdef HAVE_PTHREAD_SIGMASK
> -        sigset_t oldmask, blockedsigs;
> -#endif
> -        int timeout = -1;
> -
> -        /* If we have existing SASL decoded data we
> -         * don't want to sleep in the poll(), just
> -         * check if any other FDs are also ready
> -         */
> -#if HAVE_SASL
> -        if (priv->saslDecoded)
> -            timeout = 0;
> -#endif
> -
> -        fds[0].events = fds[0].revents = 0;
> -        fds[1].events = fds[1].revents = 0;
> -
> -        fds[1].events = POLLIN;
> -        while (tmp) {
> -            if (tmp->mode == REMOTE_MODE_WAIT_RX)
> -                fds[0].events |= POLLIN;
> -            if (tmp->mode == REMOTE_MODE_WAIT_TX)
> -                fds[0].events |= POLLOUT;
> -
> -            tmp = tmp->next;
> -        }
> -
> -        if (priv->streams)
> -            fds[0].events |= POLLIN;
> -
> -        /* Release lock while poll'ing so other threads
> -         * can stuff themselves on the queue */
> -        remoteDriverUnlock(priv);
> -
> -        /* Block SIGWINCH from interrupting poll in curses programs,
> -         * then restore the original signal mask again immediately
> -         * after the call (RHBZ#567931).  Same for SIGCHLD and SIGPIPE
> -         * at the suggestion of Paolo Bonzini and Daniel Berrange.
> -         */
> -#ifdef HAVE_PTHREAD_SIGMASK
> -        sigemptyset (&blockedsigs);
> -        sigaddset (&blockedsigs, SIGWINCH);
> -        sigaddset (&blockedsigs, SIGCHLD);
> -        sigaddset (&blockedsigs, SIGPIPE);
> -        ignore_value(pthread_sigmask(SIG_BLOCK, &blockedsigs, &oldmask));
> -#endif
> -
> -    repoll:
> -        ret = poll(fds, ARRAY_CARDINALITY(fds), timeout);
> -        if (ret < 0 && errno == EAGAIN)
> -            goto repoll;
> -
> -#ifdef HAVE_PTHREAD_SIGMASK
> -        ignore_value(pthread_sigmask(SIG_SETMASK, &oldmask, NULL));
> -#endif
> -
> -        remoteDriverLock(priv);
> -
> -        /* If we have existing SASL decoded data, pretend
> -         * the socket became readable so we consume it
> -         */
> -#if HAVE_SASL
> -        if (priv->saslDecoded)
> -            fds[0].revents |= POLLIN;
> -#endif
> -
> -        if (fds[1].revents) {
> -            ssize_t s;
> -            VIR_DEBUG("Woken up from poll by other thread");
> -            s = saferead(priv->wakeupReadFD, &ignore, sizeof(ignore));
> -            if (s < 0) {
> -                virReportSystemError(errno, "%s",
> -                                     _("read on wakeup fd failed"));
> -                goto error;
> -            } else if (s != sizeof(ignore)) {
> -                remoteError(VIR_ERR_INTERNAL_ERROR, "%s",
> -                            _("read on wakeup fd failed"));
> -                goto error;
> -            }
> -        }
> -
> -        if (ret < 0) {
> -            if (errno == EWOULDBLOCK)
> -                continue;
> -            virReportSystemError(errno,
> -                                 "%s", _("poll on socket failed"));
> -            goto error;
> -        }
> -
> -        if (fds[0].revents & POLLOUT) {
> -            if (remoteIOHandleOutput(priv) < 0)
> -                goto error;
> -        }
> -
> -        if (fds[0].revents & POLLIN) {
> -            if (remoteIOHandleInput(conn, priv, flags) < 0)
> -                goto error;
> -        }
> -
> -        /* Iterate through waiting threads and if
> -         * any are complete then tell 'em to wakeup
> -         */
> -        tmp = priv->waitDispatch;
> -        prev = NULL;
> -        while (tmp) {
> -            if (tmp != thiscall &&
> -                (tmp->mode == REMOTE_MODE_COMPLETE ||
> -                 tmp->mode == REMOTE_MODE_ERROR)) {
> -                /* Take them out of the list */
> -                if (prev)
> -                    prev->next = tmp->next;
> -                else
> -                    priv->waitDispatch = tmp->next;
> -
> -                /* And wake them up....
> -                 * ...they won't actually wakeup until
> -                 * we release our mutex a short while
> -                 * later...
> -                 */
> -                VIR_DEBUG("Waking up sleep %d %p %p", tmp->proc_nr, tmp, priv->waitDispatch);
> -                virCondSignal(&tmp->cond);
> -            } else {
> -                prev = tmp;
> -            }
> -            tmp = tmp->next;
> -        }
> -
> -        /* Now see if *we* are done */
> -        if (thiscall->mode == REMOTE_MODE_COMPLETE ||
> -            thiscall->mode == REMOTE_MODE_ERROR) {
> -            /* We're at head of the list already, so
> -             * remove us
> -             */
> -            priv->waitDispatch = thiscall->next;
> -            VIR_DEBUG("Giving up the buck %d %p %p", thiscall->proc_nr, thiscall, priv->waitDispatch);
> -            /* See if someone else is still waiting
> -             * and if so, then pass the buck ! */
> -            if (priv->waitDispatch) {
> -                VIR_DEBUG("Passing the buck to %d %p", priv->waitDispatch->proc_nr, priv->waitDispatch);
> -                virCondSignal(&priv->waitDispatch->cond);
> -            }
> -            return 0;
> -        }
> -
> -
> -        if (fds[0].revents & (POLLHUP | POLLERR)) {
> -            remoteError(VIR_ERR_INTERNAL_ERROR, "%s",
> -                        _("received hangup / error event on socket"));
> -            goto error;
> -        }
> -    }
> -
> -
> -error:
> -    priv->waitDispatch = thiscall->next;
> -    VIR_DEBUG("Giving up the buck due to I/O error %d %p %p", thiscall->proc_nr, thiscall, priv->waitDispatch);
> -    /* See if someone else is still waiting
> -     * and if so, then pass the buck ! */
> -    if (priv->waitDispatch) {
> -        VIR_DEBUG("Passing the buck to %d %p", priv->waitDispatch->proc_nr, priv->waitDispatch);
> -        virCondSignal(&priv->waitDispatch->cond);
> -    }
> -    return -1;
> -}
> -
> -/*
> - * This function sends a message to remote server and awaits a reply
> - *
> - * NB. This does not free the args structure (not desirable, since you
> - * often want this allocated on the stack or else it contains strings
> - * which come from the user).  It does however free any intermediate
> - * results, eg. the error structure if there is one.
> - *
> - * NB(2). Make sure to memset (&ret, 0, sizeof ret) before calling,
> - * else Bad Things will happen in the XDR code.
> - *
> - * NB(3) You must have the private_data lock before calling this
> - *
> - * NB(4) This is very complicated. Due to connection cloning, multiple
> - * threads can want to use the socket at once. Obviously only one of
> - * them can. So if someone's using the socket, other threads are put
> - * to sleep on condition variables. The existing thread may completely
> - * send & receive their RPC call/reply while they're asleep. Or it
> - * may only get around to dealing with sending the call. Or it may
> - * get around to neither. So upon waking up from slumber, the other
> - * thread may or may not have more work todo.
> - *
> - * We call this dance  'passing the buck'
> - *
> - *      http://en.wikipedia.org/wiki/Passing_the_buck
> - *
> - *   "Buck passing or passing the buck is the action of transferring
> - *    responsibility or blame unto another person. It is also used as
> - *    a strategy in power politics when the actions of one country/
> - *    nation are blamed on another, providing an opportunity for war."
> - *
> - * NB(5) Don't Panic!
> - */
> -static int
> -remoteIO(virConnectPtr conn,
> -         struct private_data *priv,
> -         int flags,
> -         struct remote_thread_call *thiscall)
> -{
> -    int rv;
> -
> -    VIR_DEBUG("Do proc=%d serial=%d length=%d wait=%p",
> -          thiscall->proc_nr, thiscall->serial,
> -          thiscall->bufferLength, priv->waitDispatch);
> -
> -    /* Check to see if another thread is dispatching */
> -    if (priv->waitDispatch) {
> -        /* Stick ourselves on the end of the wait queue */
> -        struct remote_thread_call *tmp = priv->waitDispatch;
> -        char ignore = 1;
> -        ssize_t s;
> -        while (tmp && tmp->next)
> -            tmp = tmp->next;
> -        if (tmp)
> -            tmp->next = thiscall;
> -        else
> -            priv->waitDispatch = thiscall;
> -
> -        /* Force other thread to wakeup from poll */
> -        s = safewrite(priv->wakeupSendFD, &ignore, sizeof(ignore));
> -        if (s < 0) {
> -            char errout[1024];
> -            remoteError(VIR_ERR_INTERNAL_ERROR,
> -                        _("failed to wake up polling thread: %s"),
> -                        virStrerror(errno, errout, sizeof errout));
> -            return -1;
> -        } else if (s != sizeof(ignore)) {
> -            remoteError(VIR_ERR_INTERNAL_ERROR, "%s",
> -                        _("failed to wake up polling thread"));
> -            return -1;
> -        }
> -
> -        VIR_DEBUG("Going to sleep %d %p %p", thiscall->proc_nr, priv->waitDispatch, thiscall);
> -        /* Go to sleep while other thread is working... */
> -        if (virCondWait(&thiscall->cond, &priv->lock) < 0) {
> -            if (priv->waitDispatch == thiscall) {
> -                priv->waitDispatch = thiscall->next;
> -            } else {
> -                tmp = priv->waitDispatch;
> -                while (tmp && tmp->next &&
> -                       tmp->next != thiscall) {
> -                    tmp = tmp->next;
> -                }
> -                if (tmp && tmp->next == thiscall)
> -                    tmp->next = thiscall->next;
> -            }
> -            remoteError(VIR_ERR_INTERNAL_ERROR, "%s",
> -                        _("failed to wait on condition"));
> -            return -1;
> -        }
> -
> -        VIR_DEBUG("Wokeup from sleep %d %p %p", thiscall->proc_nr, priv->waitDispatch, thiscall);
> -        /* Two reasons we can be woken up
> -         *  1. Other thread has got our reply ready for us
> -         *  2. Other thread is all done, and it is our turn to
> -         *     be the dispatcher to finish waiting for
> -         *     our reply
> -         */
> -        if (thiscall->mode == REMOTE_MODE_COMPLETE ||
> -            thiscall->mode == REMOTE_MODE_ERROR) {
> -            /*
> -             * We avoided catching the buck and our reply is ready !
> -             * We've already had 'thiscall' removed from the list
> -             * so just need to (maybe) handle errors & free it
> -             */
> -            goto cleanup;
> -        }
> -
> -        /* Grr, someone passed the buck onto us ... */
> -
> -    } else {
> -        /* We're first to catch the buck */
> -        priv->waitDispatch = thiscall;
> -    }
> -
> -    VIR_DEBUG("We have the buck %d %p %p", thiscall->proc_nr, priv->waitDispatch, thiscall);
> -    /*
> -     * The buck stops here!
> -     *
> -     * At this point we're about to own the dispatch
> -     * process...
> -     */
> -
> -    /*
> -     * Avoid needless wake-ups of the event loop in the
> -     * case where this call is being made from a different
> -     * thread than the event loop. These wake-ups would
> -     * cause the event loop thread to be blocked on the
> -     * mutex for the duration of the call
> -     */
> -    if (priv->watch >= 0)
> -        virEventUpdateHandle(priv->watch, 0);
> -
> -    rv = remoteIOEventLoop(conn, priv, flags, thiscall);
> -
> -    if (priv->watch >= 0)
> -        virEventUpdateHandle(priv->watch, VIR_EVENT_HANDLE_READABLE);
> -
> -    if (rv < 0)
> -        return -1;
> -
> -cleanup:
> -    VIR_DEBUG("All done with our call %d %p %p", thiscall->proc_nr,
> -          priv->waitDispatch, thiscall);
> -    if (thiscall->mode == REMOTE_MODE_ERROR) {
> -        /* Interop for virErrorNumber glitch in 0.8.0, if server is
> -         * 0.7.1 through 0.7.7; see comments in virterror.h. */
> -        switch (thiscall->err.code) {
> -        case VIR_WAR_NO_NWFILTER:
> -            /* no way to tell old VIR_WAR_NO_SECRET apart from
> -             * VIR_WAR_NO_NWFILTER, but both are very similar
> -             * warnings, so ignore the difference */
> -            break;
> -        case VIR_ERR_INVALID_NWFILTER:
> -        case VIR_ERR_NO_NWFILTER:
> -        case VIR_ERR_BUILD_FIREWALL:
> -            /* server was trying to pass VIR_ERR_INVALID_SECRET,
> -             * VIR_ERR_NO_SECRET, or VIR_ERR_CONFIG_UNSUPPORTED */
> -            if (thiscall->err.domain != VIR_FROM_NWFILTER)
> -                thiscall->err.code += 4;
> -            break;
> -        case VIR_WAR_NO_SECRET:
> -            if (thiscall->err.domain == VIR_FROM_QEMU)
> -                thiscall->err.code = VIR_ERR_OPERATION_TIMEOUT;
> -            break;
> -        case VIR_ERR_INVALID_SECRET:
> -            if (thiscall->err.domain == VIR_FROM_XEN)
> -                thiscall->err.code = VIR_ERR_MIGRATE_PERSIST_FAILED;
> -            break;
> -        default:
> -            /* Nothing to alter. */
> -            break;
> -        }
> -
> -        /* See if caller asked us to keep quiet about missing RPCs
> -         * eg for interop with older servers */
> -        if (flags & REMOTE_CALL_QUIET_MISSING_RPC &&
> -            thiscall->err.domain == VIR_FROM_REMOTE &&
> -            thiscall->err.code == VIR_ERR_RPC &&
> -            thiscall->err.level == VIR_ERR_ERROR &&
> -            thiscall->err.message &&
> -            STRPREFIX(*thiscall->err.message, "unknown procedure")) {
> -            rv = -2;
> -        } else if (thiscall->err.domain == VIR_FROM_REMOTE &&
> -                   thiscall->err.code == VIR_ERR_RPC &&
> -                   thiscall->err.level == VIR_ERR_ERROR &&
> -                   thiscall->err.message &&
> -                   STRPREFIX(*thiscall->err.message, "unknown procedure")) {
> -            /*
> -             * convert missing remote entry points into the unsupported
> -             * feature error
> -             */
> -            virRaiseErrorFull(__FILE__, __FUNCTION__, __LINE__,
> -                              thiscall->err.domain,
> -                              VIR_ERR_NO_SUPPORT,
> -                              thiscall->err.level,
> -                              thiscall->err.str1 ? *thiscall->err.str1 : NULL,
> -                              thiscall->err.str2 ? *thiscall->err.str2 : NULL,
> -                              thiscall->err.str3 ? *thiscall->err.str3 : NULL,
> -                              thiscall->err.int1,
> -                              thiscall->err.int2,
> -                              "%s", *thiscall->err.message);
> -            rv = -1;
> -        } else {
> -            virRaiseErrorFull(__FILE__, __FUNCTION__, __LINE__,
> -                              thiscall->err.domain,
> -                              thiscall->err.code,
> -                              thiscall->err.level,
> -                              thiscall->err.str1 ? *thiscall->err.str1 : NULL,
> -                              thiscall->err.str2 ? *thiscall->err.str2 : NULL,
> -                              thiscall->err.str3 ? *thiscall->err.str3 : NULL,
> -                              thiscall->err.int1,
> -                              thiscall->err.int2,
> -                              "%s", thiscall->err.message ? *thiscall->err.message : "unknown");
> -            rv = -1;
> -        }
> -        xdr_free((xdrproc_t)xdr_remote_error,  (char *)&thiscall->err);
> -    } else {
> -        rv = 0;
> -    }
> -    return rv;
> -}
> -
> -
>  /*
>   * Serial a set of arguments into a method call message,
>   * send that to the server and wait for reply
>   */
>  static int
> -call (virConnectPtr conn, struct private_data *priv,
> +call (virConnectPtr conn ATTRIBUTE_UNUSED,
> +      struct private_data *priv,
>        int flags,
>        int proc_nr,
>        xdrproc_t args_filter, char *args,
>        xdrproc_t ret_filter, char *ret)
>  {
> -    struct remote_thread_call *thiscall;
>      int rv;
> +    virNetClientProgramPtr prog = flags & REMOTE_CALL_QEMU ? priv->qemuProgram : priv->remoteProgram;
> +    int counter = priv->counter++;
> +    priv->localUses++;
>  
> -    thiscall = prepareCall(priv, flags, proc_nr, args_filter, args,
> -                           ret_filter, ret);
> -
> -    if (!thiscall) {
> -        return -1;
> -    }
> +    /* Unlock, so that if we get any async events/stream data
> +     * while processing the RPC, we don't deadlock when our
> +     * callbacks for those are invoked
> +     */
> +    remoteDriverUnlock(priv);
> +    rv = virNetClientProgramCall(prog,
> +                                 priv->client,
> +                                 counter,
> +                                 proc_nr,
> +                                 args_filter, args,
> +                                 ret_filter, ret);
> +    remoteDriverLock(priv);
> +    priv->localUses--;
>  
> -    rv = remoteIO(conn, priv, flags, thiscall);
> -    ignore_value(virCondDestroy(&thiscall->cond));
> -    VIR_FREE(thiscall);
>      return rv;
>  }
>  
>  
> -/** remoteDomainEventFired:
> - *
> - * The callback for monitoring the remote socket
> - * for event data
> - */
> -void
> -remoteDomainEventFired(int watch,
> -                       int fd,
> -                       int event,
> -                       void *opaque)
> -{
> -    virConnectPtr        conn = opaque;
> -    struct private_data *priv = conn->privateData;
> -
> -    remoteDriverLock(priv);
> -
> -    /* This should be impossible, but it doesn't hurt to check */
> -    if (priv->waitDispatch)
> -        goto done;
> -
> -    VIR_DEBUG("Event fired %d %d %d %X", watch, fd, event, event);
> -
> -    if (event & (VIR_EVENT_HANDLE_HANGUP | VIR_EVENT_HANDLE_ERROR)) {
> -         VIR_DEBUG("%s : VIR_EVENT_HANDLE_HANGUP or "
> -               "VIR_EVENT_HANDLE_ERROR encountered", __FUNCTION__);
> -         virEventRemoveHandle(watch);
> -         priv->watch = -1;
> -         goto done;
> -    }
> -
> -    if (fd != priv->sock) {
> -        virEventRemoveHandle(watch);
> -        priv->watch = -1;
> -        goto done;
> -    }
> -
> -    if (remoteIOHandleInput(conn, priv, 0) < 0)
> -        VIR_DEBUG("Something went wrong during async message processing");
> -
> -done:
> -    remoteDriverUnlock(priv);
> -}
> -
>  static void remoteDomainEventDispatchFunc(virConnectPtr conn,
>                                            virDomainEventPtr event,
>                                            virConnectDomainEventGenericCallback cb,
> @@ -6266,7 +3960,7 @@ static void remoteDomainEventDispatchFunc(virConnectPtr conn,
>      remoteDriverLock(priv);
>  }
>  
> -void
> +static void
>  remoteDomainEventQueueFlush(int timer ATTRIBUTE_UNUSED, void *opaque)
>  {
>      virConnectPtr conn = opaque;
> @@ -6282,7 +3976,7 @@ remoteDomainEventQueueFlush(int timer ATTRIBUTE_UNUSED, void *opaque)
>      remoteDriverUnlock(priv);
>  }
>  
> -void
> +static void
>  remoteDomainEventQueue(struct private_data *priv, virDomainEventPtr event)
>  {
>      virDomainEventStateQueue(priv->domainEventState, event);
> diff --git a/src/rpc/gendispatch.pl b/src/rpc/gendispatch.pl
> index 71085d9..d6264b9 100755
> --- a/src/rpc/gendispatch.pl
> +++ b/src/rpc/gendispatch.pl
> @@ -1326,7 +1326,7 @@ elsif ($opt_k) {
>          }
>  
>          if ($call->{streamflag} ne "none") {
> -            print "    struct private_stream_data *privst = NULL;\n";
> +            print "    virNetClientStreamPtr netst = NULL;\n";
>          }
>  
>          print "\n";
> @@ -1334,11 +1334,16 @@ elsif ($opt_k) {
>  
>          if ($call->{streamflag} ne "none") {
>              print "\n";
> -            print "    if (!(privst = remoteStreamOpen(st, REMOTE_PROC_$call->{UC_NAME}, priv->counter)))\n";
> +            print "    if (!(netst = virNetClientStreamNew(priv->remoteProgram, REMOTE_PROC_$call->{UC_NAME}, priv->counter)))\n";
>              print "       goto done;\n";
>              print "\n";
> +            print "    if (virNetClientAddStream(priv->client, netst) < 0) {";
> +            print "       virNetClientStreamFree(netst);\n";
> +            print "       goto done;\n";
> +            print "    }";
> +            print "\n";
>              print "    st->driver = &remoteStreamDrv;\n";
> -            print "    st->privateData = privst;\n";
> +            print "    st->privateData = netst;\n";
>          }
>  
>          if ($call->{ProcName} eq "SupportsFeature") {
> @@ -1403,7 +1408,8 @@ elsif ($opt_k) {
>          print "             (xdrproc_t)xdr_$call->{ret}, (char *)$call_ret) == -1) {\n";
>  
>          if ($call->{streamflag} ne "none") {
> -            print "        remoteStreamRelease(st);\n";
> +            print "        virNetClientRemoveStream(priv->client, netst);\n";
> +            print "        virNetClientStreamFree(netst);\n";
>          }
>  
>          print "        goto done;\n";

-- 
Eric Blake   eblake at redhat.com    +1-801-349-2682
Libvirt virtualization library http://libvirt.org

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 619 bytes
Desc: OpenPGP digital signature
URL: <http://listman.redhat.com/archives/libvir-list/attachments/20110627/85e94d49/attachment-0001.sig>


More information about the libvir-list mailing list