[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